diff --git a/src_Core/CPU/Core.bsv b/src_Core/CPU/Core.bsv index 4cf522b..9145f81 100644 --- a/src_Core/CPU/Core.bsv +++ b/src_Core/CPU/Core.bsv @@ -22,8 +22,6 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// Portions Copyright (c) Bluespec, Inc. - `include "ProcConfig.bsv" import Vector::*; @@ -96,6 +94,10 @@ import GetPut_Aux :: *; import DM_CPU_Req_Rsp :: *; `endif +`ifdef INCLUDE_TANDEM_VERIF +import Trace_Data2 :: *; +`endif + // ================================================================ `ifdef SECURITY @@ -167,6 +169,16 @@ interface Core; `endif interface Server #(DM_CPU_Req #(12, 64), DM_CPU_Rsp #(64)) hart0_csr_mem_server; `endif + +`ifdef INCLUDE_TANDEM_VERIF + // Note: this is a SupSize vector of streams of Trace_Data2 structs, + // each of which has a serialnum field. Each of the SupSize + // streams has serialnums in increasing order. Each serialnum + // appears exactly once in exactly one of the streams. Thus, the + // channels can easily be merged into a single program-order stream. + interface Vector #(SupSize, Get #(Trace_Data2)) v_to_TV; +`endif + endinterface // fixpoint to instantiate modules @@ -205,6 +217,10 @@ module mkCore#(CoreId coreId)(Core); Reg #(Core_Run_State) rg_core_run_state <- mkConfigReg (CORE_RUNNING); `endif +`ifdef INCLUDE_TANDEM_VERIF + Vector #(SupSize, FIFOF #(Trace_Data2)) v_f_to_TV <- replicateM (mkFIFOF); +`endif + // front end FetchStage fetchStage <- mkFetchStage; ITlb iTlb = fetchStage.iTlbIfc; @@ -581,6 +597,11 @@ module mkCore#(CoreId coreId)(Core); return False; `endif endmethod + +`ifdef INCLUDE_TANDEM_VERIF + interface v_to_TV = map (toPut, v_f_to_TV); +`endif + endinterface); CommitStage commitStage <- mkCommitStage(commitInput); @@ -1342,4 +1363,8 @@ module mkCore#(CoreId coreId)(Core); interface Server hart0_csr_mem_server = toGPServer (f_csr_reqs, f_csr_rsps); `endif +`ifdef INCLUDE_TANDEM_VERIF + interface v_to_TV = map (toGet, v_f_to_TV); +`endif + endmodule diff --git a/src_Core/CPU/Proc.bsv b/src_Core/CPU/Proc.bsv index 4492ef4..ccaf74e 100644 --- a/src_Core/CPU/Proc.bsv +++ b/src_Core/CPU/Proc.bsv @@ -23,8 +23,6 @@ package Proc; // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// Portions Copyright (c) 2019 Bluespec, Inc. - // ================================================================ // BSV lib imports @@ -78,14 +76,15 @@ import SoC_Map :: *; import AXI4_Types :: *; import Fabric_Defs :: *; -`ifdef INCLUDE_TANDEM_VERIF -import TV_Info :: *; -`endif - `ifdef INCLUDE_GDB_CONTROL import DM_CPU_Req_Rsp :: *; `endif +`ifdef INCLUDE_TANDEM_VERIF +import ProcTypes :: *; +import Trace_Data2 :: *; +`endif + // ================================================================ (* synthesize *) @@ -110,13 +109,6 @@ module mkProc (Proc_IFC); FIFOF #(Bit #(0)) f_reset_reqs <- mkFIFOF; FIFOF #(Bit #(0)) f_reset_rsps <- mkFIFOF; - // ---------------- - // Tandem Verification (TODO: to be implemented) - -`ifdef INCLUDE_TANDEM_VERIF - FIFOF #(Trace_Data) f_trace_data <- mkFIFOF; -`endif - // ---------------- // MMIO @@ -309,13 +301,6 @@ module mkProc (Proc_IFC); cfg_verbosity <= verbosity; endmethod - // ---------------- - // Optional interface to Tandem Verifier - -`ifdef INCLUDE_TANDEM_VERIF - interface Get trace_data_out = toGet (f_trace_data); -`endif - // ---------------- // Coherent port into LLC (used by Debug Module, DMA engines, ... to read/write memory) @@ -341,6 +326,10 @@ module mkProc (Proc_IFC); endinterface `endif +`ifdef INCLUDE_TANDEM_VERIF + interface v_to_TV = core [0].v_to_TV; +`endif + endmodule: mkProc // ================================================================ diff --git a/src_Core/CPU/Proc_IFC.bsv b/src_Core/CPU/Proc_IFC.bsv index d74a88e..b99bc05 100644 --- a/src_Core/CPU/Proc_IFC.bsv +++ b/src_Core/CPU/Proc_IFC.bsv @@ -5,6 +5,7 @@ package Proc_IFC; // ================================================================ // BSV library imports +import Vector :: *; import GetPut :: *; import ClientServer :: *; @@ -21,7 +22,8 @@ import DM_CPU_Req_Rsp :: *; `endif `ifdef INCLUDE_TANDEM_VERIF -import TV_Info :: *; +import ProcTypes :: *; +import Trace_Data2 :: *; `endif // ================================================================ @@ -74,13 +76,6 @@ interface Proc_IFC; method Action set_verbosity (Bit #(4) verbosity); - // ---------------- - // Optional interface to Tandem Verifier - -`ifdef INCLUDE_TANDEM_VERIF - interface Get #(Trace_Data) trace_data_out; -`endif - // ---------------- // Coherent port into LLC (used by Debug Module, DMA engines, ... to read/write memory) @@ -101,6 +96,15 @@ interface Proc_IFC; interface Put #(Bit #(4)) hart0_put_other_req; `endif +`ifdef INCLUDE_TANDEM_VERIF + // Note: this is a SupSize vector of streams of Trace_Data2 structs, + // each of which has a serialnum field. Each of the SupSize + // streams has serialnums in increasing order. Each serialnum + // appears exactly once in exactly one of the streams. Thus, the + // channels can easily be merged into a single program-order stream. + interface Vector #(SupSize, Get #(Trace_Data2)) v_to_TV; +`endif + endinterface // ================================================================ diff --git a/src_Core/Core/CoreW.bsv b/src_Core/Core/CoreW.bsv index eac3816..ecfde3e 100644 --- a/src_Core/Core/CoreW.bsv +++ b/src_Core/Core/CoreW.bsv @@ -1,8 +1,21 @@ -// Copyright (c) 2018-2019 Bluespec, Inc. All Rights Reserved. +// Copyright (c) 2018-2020 Bluespec, Inc. All Rights Reserved. package CoreW; // ================================================================ +// This package is called 'CoreW' for 'Core Wrapper' +// and corresponds to 'Core' in Piccolo and Flute. +// +// Here in Toooba, we use the name 'CoreW' to avoid a name-clash with +// an inner module called 'Core' in MIT's RISCY-OOO. +// +// The specific correspondence with Piccolo/Flute structure is: +// Piccolo/Flute Toooba +// mkCore mkCoreW +// mkProc +// mkCPU mkCore + + // This package defines: // Core_IFC // mkCore #(Core_IFC) @@ -19,12 +32,12 @@ package CoreW; // ================================================================ // BSV library imports -import Vector :: *; -import FIFOF :: *; -import GetPut :: *; -import ClientServer :: *; -import Connectable :: *; -import Clocks :: *; +import Vector :: *; +import FIFOF :: *; +import GetPut :: *; +import ClientServer :: *; +import Connectable :: *; +import Clocks :: *; // ---------------- // BSV additional libs @@ -35,6 +48,13 @@ import GetPut_Aux :: *; // ================================================================ // Project imports +// ---------------- +// From RISCY-ooo +import ProcTypes :: *; + +// ---------------- +// From Toooba + // Main fabric import AXI4_Types :: *; import AXI4_Fabric :: *; @@ -52,8 +72,10 @@ import Proc_IFC :: *; import Proc :: *; `ifdef INCLUDE_TANDEM_VERIF -import TV_Info :: *; -import TV_Encode :: *; +import TV_Info :: *; +import Trace_Data2 :: *; +import TV_Encode :: *; +import Trace_Data2_to_Trace_Data :: *; `endif // TV_Taps needed when both GDB_CONTROL and TANDEM_VERIF are present @@ -66,7 +88,7 @@ import TV_Taps :: *; import DM_CPU_Req_Rsp ::*; // ================================================================ -// EXTERNAL_DEBUG_MODULE is used in situations where we DO NOTt have a +// EXTERNAL_DEBUG_MODULE is used in situations where we DO NOT have a // Debug Module controlling the CPU. In that case, the CPU is // 'halted' by asserting the reset signal, during which the external // debugger can read/write memory etc. @@ -96,12 +118,8 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources)); // System address map SoC_Map_IFC soc_map <- mkSoC_Map; - // McStriiv processor -`ifdef EXTERNAL_DEBUG_MODULE - Proc_IFC proc <- mkProc(reset_by cpu_reset_either); -`else + // RISCY-OOO processor Proc_IFC proc <- mkProc; -`endif // A 2x3 fabric for connecting {CPU, Debug_Module} to {Fabric, PLIC} Fabric_2x3_IFC fabric_2x3 <- mkFabric_2x3; @@ -113,17 +131,21 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources)); FIFOF #(Bit #(0)) f_reset_reqs <- mkFIFOF; FIFOF #(Bit #(0)) f_reset_rsps <- mkFIFOF; -`ifdef INCLUDE_TANDEM_VERIF - // The TV encoder transforms Trace_Data structures produced by the CPU and DM - // into encoded byte vectors for transmission to the Tandem Verifier - TV_Encode_IFC tv_encode <- mkTV_Encode; -`endif - `ifdef INCLUDE_GDB_CONTROL // Debug Module Debug_Module_IFC debug_module <- mkDebug_Module; `endif +`ifdef INCLUDE_TANDEM_VERIF + // The following are a superscalar-wide set of transformers from RISCY-OOO output Trace_Data2 + // to Trace_Data which is input to the TV encoder + Vector #(SupSize, Trace_Data2_to_Trace_Data_IFC) v_td2_to_td <- replicateM (mkTrace_Data2_to_Trace_Data); + + // The TV encoder transforms Trace_Data structures from the CPU and DM + // into encoded byte vectors for transmission to the Tandem Verifier + TV_Encode_IFC tv_encode <- mkTV_Encode; +`endif + // HTIF locations (for debugging only) Reg #(Bit #(64)) rg_tohost_addr <- mkReg (0); Reg #(Bit #(64)) rg_fromhost_addr <- mkReg (0); @@ -148,25 +170,21 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources)); rule rl_cpu_hart0_reset_from_soc_start; let req <- pop (f_reset_reqs); -`ifdef EXTERNAL_DEBUG_MODULE - cpu_reset.assertReset; -`else proc.hart0_server_reset.request.put (?); // CPU -`endif plic.server_reset.request.put (?); // PLIC fabric_2x3.reset; // Local 2x3 Fabric +`ifdef INCLUDE_TANDEM_VERIF + tv_encode.reset; +`endif `ifdef INCLUDE_GDB_CONTROL -`ifndef EXTERNAL_DEBUG_MODULE // Remember the requestor, so we can respond to it f_reset_requestor.enq (reset_requestor_soc); -`endif `endif $display ("%0d: Core.rl_cpu_hart0_reset_from_soc_start", cur_cycle); endrule `ifdef INCLUDE_GDB_CONTROL -`ifndef EXTERNAL_DEBUG_MODULE // Reset-hart0 from Debug Module rule rl_cpu_hart0_reset_from_dm_start; let req <- debug_module.hart0_get_reset_req.get; @@ -174,20 +192,18 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources)); proc.hart0_server_reset.request.put (?); // CPU plic.server_reset.request.put (?); // PLIC fabric_2x3.reset; // Local 2x3 fabric +`ifdef INCLUDE_TANDEM_VERIF + tv_encode.reset; +`endif // Remember the requestor, so we can respond to it f_reset_requestor.enq (reset_requestor_dm); $display ("%0d: Core.rl_cpu_hart0_reset_from_dm_start", cur_cycle); endrule `endif -`endif -`ifdef EXTERNAL_DEBUG_MODULE - rule rl_cpu_hart0_reset_complete(!cpu_reset.isAsserted); -`else rule rl_cpu_hart0_reset_complete; let rsp1 <- proc.hart0_server_reset.response.get; // CPU -`endif let rsp3 <- plic.server_reset.response.get; // PLIC plic.set_addr_map (zeroExtend (soc_map.m_plic_addr_base), @@ -195,145 +211,65 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources)); Bit #(1) requestor = reset_requestor_soc; `ifdef INCLUDE_GDB_CONTROL -`ifndef EXTERNAL_DEBUG_MODULE requestor <- pop (f_reset_requestor); -`endif `endif if (requestor == reset_requestor_soc) f_reset_rsps.enq (?); -`ifndef EXTERNAL_DEBUG_MODULE // Start running the cores proc.start (soc_map_struct.pc_reset_value, rg_tohost_addr, rg_fromhost_addr); -`endif $display ("%0d: Core.rl_cpu_hart0_reset_complete; started running proc", cur_cycle); endrule - // ================================================================ - // Direct DM-to-CPU connections - `ifdef INCLUDE_GDB_CONTROL -`ifndef EXTERNAL_DEBUG_MODULE - // DM to CPU connections for run-control and other misc requests + // ================================================================ + // Direct DM-to-CPU connections for run-control and other misc requests + mkConnection (debug_module.hart0_client_run_halt, proc.hart0_run_halt_server); mkConnection (debug_module.hart0_get_other_req, proc.hart0_put_other_req); -`endif -`endif - - // external debug module connections -`ifdef INCLUDE_GDB_CONTROL -`ifdef EXTERNAL_DEBUG_MODULE - - Reg#(Bool) once <- mkReg(False, reset_by cpu_reset_either); - - rule rl_once(!once && !cpu_reset.isAsserted && !cpu_halt.isAsserted); - proc.hart0_server_reset.request.put(?); - once <= True; - endrule - - rule rl_hart0_server_reset; - let tmp <- proc.hart0_server_reset.response.get; - - proc.start (soc_map_struct.pc_reset_value, - rg_tohost_addr, - rg_fromhost_addr); - endrule - - rule rl_hart0_run_halt_server; - let tmp <- proc.hart0_run_halt_server.response.get; - endrule - - Reg#(Bool) hart0_halt <- mkReg(False); - - rule rl_halt_reset(hart0_halt); - cpu_halt.assertReset; - endrule - - rule rl_halt; - let halt <- debug_module.hart0_client_run_halt.request.get; - hart0_halt <= !halt; - debug_module.hart0_client_run_halt.response.put(halt); - endrule - - rule rl_gpr; - let req <- debug_module.hart0_gpr_mem_client.request.get; - debug_module.hart0_gpr_mem_client.response.put(DM_CPU_Rsp { ok: True, data: 0 }); - endrule - -`ifdef ISA_F - rule rl_fpr; - let req <- debug_module.hart0_fpr_mem_client.request.get; - debug_module.hart0_fpr_mem_client.response.put(DM_CPU_Rsp { ok: True, data: 0 }); - endrule -`endif - - rule rl_csr; - let req <- debug_module.hart0_csr_mem_client.request.get; - debug_module.hart0_csr_mem_client.response.put(DM_CPU_Rsp { ok: True, data: 0 }); - endrule - - rule rl_cpu_hart0_reset_from_dm_start; - let req <- debug_module.hart0_get_reset_req.get; - cpu_reset.assertReset; - f_reset_requestor.enq (reset_requestor_dm); - endrule - - rule rl_cpu_hart0_reset_from_dm_complete (f_reset_requestor.first == reset_requestor_dm && !cpu_reset.isAsserted); - f_reset_requestor.deq; - endrule - -`endif `endif +`ifdef INCLUDE_TANDEM_VERIF // ================================================================ - // Other CPU/DM/TV connections - // (depends on whether DM, TV or both are present) + // Direct CPU-to-TV connections for TV trace data + + for (Integer j = 0; j < valueOf (SupSize); j = j + 1) begin + // CPU Trace_Data2 output streams to Trace_Data2_to_Trace_Data converters + mkConnection (proc.v_to_TV [j], v_td2_to_td [j].in); + // Trace_Data2_to_Trace_Data converters to TV encoder + mkConnection (v_td2_to_td [j].out, tv_encode.v_cpu_in [j]); + end +`endif `ifdef INCLUDE_GDB_CONTROL `ifdef INCLUDE_TANDEM_VERIF - // BEGIN SECTION: GDB and TV - // ---------------------------------------------------------------- - // DM and TV both present. We instantiate 'taps' into connections - // where the DM writes CPU GPRs, CPU FPRs, CPU CSRs, and main memory, - // in order to produce corresponding writes for the Tandem Verifier. - // Then, we merge the Trace_Data from these three taps with the - // Trace_Data produced by the PROC. - - FIFOF #(Trace_Data) f_trace_data_merged <- mkFIFOF; - - // Connect merged trace data to trace encoder - mkConnection (toGet (f_trace_data_merged), tv_encode.trace_data_in); - - // Merge-in CPU's trace data. - // This is equivalent to: mkConnection (proc.trace_data_out, toPut (f_trace_data_merged)) - // but using a rule allows us to name it in scheduling attributes. - rule merge_cpu_trace_data; - let tmp <- proc.trace_data_out.get; - f_trace_data_merged.enq (tmp); - endrule + // ================================================================ + // BEGIN SECTION: DM and TV both present + // We instantiate 'taps' into connections where DM writes CPU GPRs, + // FPRs, CSRs, and main memory. The tap outputs go the TV encoder, + // to keep the tandem verifier in sync with DM updates to the CPU. // Create a tap for DM's memory-writes to the bus, and merge-in the trace data. DM_Mem_Tap_IFC dm_mem_tap <- mkDM_Mem_Tap; mkConnection (debug_module.master, dm_mem_tap.slave); let dm_master_local = dm_mem_tap.master; - rule merge_dm_mem_trace_data; + rule rl_merge_dm_mem_trace_data; let tmp <- dm_mem_tap.trace_data_out.get; - f_trace_data_merged.enq (tmp); + tv_encode.dm_in.put (tmp); endrule -`ifndef EXTERNAL_DEBUG_MODULE // Create a tap for DM's GPR writes to the CPU, and merge-in the trace data. DM_GPR_Tap_IFC dm_gpr_tap_ifc <- mkDM_GPR_Tap; mkConnection (debug_module.hart0_gpr_mem_client, dm_gpr_tap_ifc.server); mkConnection (dm_gpr_tap_ifc.client, proc.hart0_gpr_mem_server); - rule merge_dm_gpr_trace_data; + rule rl_merge_dm_gpr_trace_data; let tmp <- dm_gpr_tap_ifc.trace_data_out.get; - f_trace_data_merged.enq (tmp); + tv_encode.dm_in.put (tmp); endrule `ifdef ISA_F_OR_D @@ -342,9 +278,9 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources)); mkConnection (debug_module.hart0_fpr_mem_client, dm_fpr_tap_ifc.server); mkConnection (dm_fpr_tap_ifc.client, proc.hart0_fpr_mem_server); - rule merge_dm_fpr_trace_data; + rule rl_merge_dm_fpr_trace_data; let tmp <- dm_fpr_tap_ifc.trace_data_out.get; - f_trace_data_merged.enq (tmp); + tv_encode.dm_in.put (tmp); endrule `endif // for ifdef ISA_F_OR_D @@ -354,25 +290,25 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources)); mkConnection(debug_module.hart0_csr_mem_client, dm_csr_tap.server); mkConnection(dm_csr_tap.client, proc.hart0_csr_mem_server); -`ifdef ISA_F_OR_D - (* descending_urgency = "merge_dm_fpr_trace_data, merge_dm_gpr_trace_data" *) -`endif - (* descending_urgency = "merge_dm_gpr_trace_data, merge_dm_csr_trace_data" *) - (* descending_urgency = "merge_dm_csr_trace_data, merge_dm_mem_trace_data" *) - (* descending_urgency = "merge_dm_mem_trace_data, merge_cpu_trace_data" *) - rule merge_dm_csr_trace_data; + rule rl_merge_dm_csr_trace_data; let tmp <- dm_csr_tap.trace_data_out.get; - f_trace_data_merged.enq(tmp); + tv_encode.dm_in.put(tmp); endrule + +`ifdef ISA_F_OR_D + (* descending_urgency = "rl_merge_dm_fpr_trace_data, rl_merge_dm_gpr_trace_data" *) `endif + (* descending_urgency = "rl_merge_dm_gpr_trace_data, rl_merge_dm_csr_trace_data" *) + (* descending_urgency = "rl_merge_dm_csr_trace_data, rl_merge_dm_mem_trace_data" *) + rule rl_bogus_for_sched_attributes; + endrule - // END SECTION: GDB and TV -`else - // for ifdef INCLUDE_TANDEM_VERIF - // ---------------------------------------------------------------- - // BEGIN SECTION: GDB and no TV + // END SECTION: DM and TV + // ================================================================ +`else // of ifdef INCLUDE_TANDEM_VERIF + // ================================================================ + // BEGIN SECTION: DM, no TV -`ifndef EXTERNAL_DEBUG_MODULE // Connect DM's GPR interface directly to CPU mkConnection (debug_module.hart0_gpr_mem_client, proc.hart0_gpr_mem_server); @@ -383,33 +319,24 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources)); // Connect DM's CSR interface directly to CPU mkConnection (debug_module.hart0_csr_mem_client, proc.hart0_csr_mem_server); -`endif // DM's bus master is directly the bus master let dm_master_local = debug_module.master; - // END SECTION: GDB and no TV -`endif - // for ifdef INCLUDE_TANDEM_VERIF + // END SECTION: DM, no TV + // ================================================================ +`endif // for ifdef INCLUDE_TANDEM_VERIF + // ================================================================ +`else // for ifdef INCLUDE_GDB_CONTROL + // ================================================================ + // BEGIN SECTION: no DM -`else - // for ifdef INCLUDE_GDB_CONTROL - // BEGIN SECTION: no GDB - - // No DM, so 'DM bus master' is dummy + // No DM, so 'DM bus master' is AXI4 dummy AXI4_Master_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) dm_master_local = dummy_AXI4_Master_ifc; -`ifdef INCLUDE_TANDEM_VERIF - // ---------------------------------------------------------------- - // BEGIN SECTION: no GDB, TV +`endif // for ifdef INCLUDE_GDB_CONTROL - // Connect CPU's TV out directly to TV encoder - mkConnection (proc.trace_data_out, tv_encode.trace_data_in); - // END SECTION: no GDB, TV -`endif -`endif - // for ifdef INCLUDE_GDB_CONTROL // ================================================================ // Connect the local 2x3 fabric @@ -419,9 +346,10 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources)); mkConnection (dm_master_local, fabric_2x3.v_from_masters [debug_module_sba_master_num]); // Slaves on the local 2x3 fabric - // default slave is taken out directly to the Core interface - mkConnection (fabric_2x3.v_to_slaves [plic_slave_num], plic.axi4_slave); - mkConnection (fabric_2x3.v_to_slaves [near_mem_io_slave_num], proc.debug_module_mem_server); + // Two of the slaves are connected here. + // The third slave (default slave) is taken out directly to the Core interface + mkConnection (fabric_2x3.v_to_slaves [plic_slave_num], plic.axi4_slave); + mkConnection (fabric_2x3.v_to_slaves [llc_slave_num], proc.debug_module_mem_server); // ================================================================ // Connect external interrupt lines from PLIC to CPU @@ -485,22 +413,10 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources)); proc.debug_external_interrupt_req (set_not_clear); endmethod - // ---------------------------------------------------------------- - // Optional TV interface - -`ifdef INCLUDE_TANDEM_VERIF - interface Get tv_verifier_info_get; - method ActionValue #(Info_CPU_to_Verifier) get(); - match { .n, .v } <- tv_encode.tv_vb_out.get; - return (Info_CPU_to_Verifier { num_bytes: n, vec_bytes: v }); - endmethod - endinterface -`endif - +`ifdef INCLUDE_GDB_CONTROL // ---------------------------------------------------------------- // Optional DM interfaces -`ifdef INCLUDE_GDB_CONTROL // ---------------- // DMI (Debug Module Interface) facing remote debugger @@ -513,6 +429,18 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources)); interface Get dm_ndm_reset_req_get = debug_module.get_ndm_reset_req; `endif +`ifdef INCLUDE_TANDEM_VERIF + // ---------------------------------------------------------------- + // Optional TV interface + + interface Get tv_verifier_info_get; + method ActionValue #(Info_CPU_to_Verifier) get(); + match { .n, .v } <- tv_encode.out.get; + return (Info_CPU_to_Verifier { num_bytes: n, vec_bytes: v }); + endmethod + endinterface +`endif + endmodule: mkCoreW // ================================================================ @@ -536,12 +464,9 @@ typedef 3 Num_Slaves_2x3; typedef Bit #(TLog #(Num_Slaves_2x3)) Slave_Num_2x3; -Slave_Num_2x3 default_slave_num = 0; -Slave_Num_2x3 plic_slave_num = 1; - -// TODO: repurpose this for Debug Module System Bus Access to connect to mkLLCDramConnect -Slave_Num_2x3 near_mem_io_slave_num = 2; - +Slave_Num_2x3 default_slave_num = 0; // for I/O, uncached memory, etc. +Slave_Num_2x3 plic_slave_num = 1; // PLIC mem-mapped registers +Slave_Num_2x3 llc_slave_num = 2; // Normal cached memory (connects to coherent Last-Level Cache) // ---------------- // Specialization of parameterized AXI4 fabric for 2x3 Core fabric @@ -568,7 +493,7 @@ module mkFabric_2x3 (Fabric_2x3_IFC); function Tuple2 #(Bool, Slave_Num_2x3) fn_addr_to_slave_num_2x3 (Fabric_Addr addr); if ( (soc_map.m_mem0_controller_addr_base <= addr) && (addr < soc_map.m_mem0_controller_addr_lim)) - return tuple2 (True, near_mem_io_slave_num); + return tuple2 (True, llc_slave_num); else if ( (soc_map.m_plic_addr_base <= addr) && (addr < soc_map.m_plic_addr_lim)) diff --git a/src_Core/Core/CoreW_IFC.bsv b/src_Core/Core/CoreW_IFC.bsv index 84b2968..419c2af 100644 --- a/src_Core/Core/CoreW_IFC.bsv +++ b/src_Core/Core/CoreW_IFC.bsv @@ -32,14 +32,16 @@ import Fabric_Defs :: *; // External interrupt request interface import PLIC :: *; -`ifdef INCLUDE_TANDEM_VERIF -import TV_Info :: *; -`endif - `ifdef INCLUDE_GDB_CONTROL import Debug_Module :: *; `endif +`ifdef INCLUDE_TANDEM_VERIF +import ProcTypes :: *; +import Trace_Data2 :: *; +import TV_Info :: *; +`endif + // ================================================================ // The CoreW interface @@ -77,19 +79,10 @@ interface CoreW_IFC #(numeric type t_n_interrupt_sources); (* always_ready, always_enabled *) method Action debug_external_interrupt_req (Bool set_not_clear); - // ---------------------------------------------------------------- - // Optional Tandem Verifier interface output tuples (n,vb), - // where 'vb' is a vector of bytes - // with relevant bytes in locations [0]..[n-1] - -`ifdef INCLUDE_TANDEM_VERIF - interface Get #(Info_CPU_to_Verifier) tv_verifier_info_get; -`endif - +`ifdef INCLUDE_GDB_CONTROL // ---------------------------------------------------------------- // Optional Debug Module interfaces -`ifdef INCLUDE_GDB_CONTROL // ---------------- // DMI (Debug Module Interface) facing remote debugger @@ -101,6 +94,16 @@ interface CoreW_IFC #(numeric type t_n_interrupt_sources); interface Get #(Bit #(0)) dm_ndm_reset_req_get; `endif + +`ifdef INCLUDE_TANDEM_VERIF + // ---------------------------------------------------------------- + // Optional Tandem Verifier interface output tuples (n,vb), + // where 'vb' is a vector of bytes + // with relevant bytes in locations [0]..[n-1] + + interface Get #(Info_CPU_to_Verifier) tv_verifier_info_get; +`endif + endinterface // ================================================================ diff --git a/src_Core/Core/TV_Encode.bsv b/src_Core/Core/TV_Encode.bsv index 46c45c8..ccb086d 100644 --- a/src_Core/Core/TV_Encode.bsv +++ b/src_Core/Core/TV_Encode.bsv @@ -1,10 +1,14 @@ -// Copyright (c) 2013-2019 Bluespec, Inc. All Rights Reserved. +// Copyright (c) 2013-2020 Bluespec, Inc. All Rights Reserved. package TV_Encode; // ================================================================ -// module mkTV_Encode is a transforming FIFO -// converting Trace_Data into encoded byte vectors +// module mkTV_Encode inputs: +// - A superscalar-wide vector of (serial_num, Trace_Data) streams +// from a superscalar CPU +// - A Trace_Data stream +// from the Debug Module +// and produces an output stream of encoded byte vectors. // ================================================================ // BSV lib imports @@ -18,11 +22,20 @@ import Connectable :: *; // ---------------- // BSV additional libs +import Cur_Cycle :: *; import GetPut_Aux :: *; // ================================================================ // Project imports +// ---------------- +// From RISCY-OOO + +import ProcTypes :: *; + +// ---------------- +// From Toooba + import ISA_Decls :: *; import TV_Info :: *; @@ -31,13 +44,17 @@ import TV_Info :: *; interface TV_Encode_IFC; method Action reset; - // This module receives Trace_Data structs from the CPU and Debug Module - interface Put #(Trace_Data) trace_data_in; + // Superscalar trace data from the CPU. + // Each item in the stream is (serialnum, td). + interface Vector #(SupSize, Put #(Tuple2 #(Bit #(64), Trace_Data))) v_cpu_in; + + // Trace data from the Debug Module + interface Put #(Trace_Data) dm_in; // This module produces tuples (n,vb), // where 'vb' is a vector of bytes // with relevant bytes in locations [0]..[n-1] - interface Get #(Tuple2 #(Bit #(32), TV_Vec_Bytes)) tv_vb_out; + interface Get #(Tuple2 #(Bit #(32), TV_Vec_Bytes)) out; endinterface // ================================================================ @@ -45,20 +62,55 @@ endinterface (* synthesize *) module mkTV_Encode (TV_Encode_IFC); - Reg #(Bool) rg_reset_done <- mkReg (True); + Integer verbosity = 1; // For debugging + + Reg #(Bool) rg_reset_done <- mkReg (False); // Keep track of last PC for more efficient encoding of incremented PCs // TODO: currently always sending full PC Reg #(WordXL) rg_last_pc <- mkReg (0); - FIFOF #(Trace_Data) f_trace_data <- mkFIFOF; - FIFOF #(Tuple2 #(Bit #(32), TV_Vec_Bytes)) f_vb <- mkFIFOF; + Vector #(SupSize, FIFOF #(Tuple2 #(Bit #(64), Trace_Data))) v_f_cpu_ins <- replicateM (mkFIFOF); + Reg #(Bit #(64)) rg_serialnum <- mkReg (0); + + FIFOF #(Trace_Data) f_dm_in <- mkFIFOF; + + FIFOF #(Trace_Data) f_merged <- mkFIFOF; + + FIFOF #(Tuple2 #(Bit #(32), TV_Vec_Bytes)) f_out <- mkFIFOF; // ---------------------------------------------------------------- - // BEHAVIOR + // BEHAVIOR: MERGING + // v_f_cpu_ins and f_dm_in are merged into f_merged - rule rl_log_trace_RESET (rg_reset_done && (f_trace_data.first.op == TRACE_RESET)); - let td <- pop (f_trace_data); + // v_f_cpu_ins are merged in program order (using serialnum) + for (Integer j = 0; j < valueOf (SupSize); j = j + 1) + rule rl_merge_cpu_ins (tpl_1 (v_f_cpu_ins [j].first) == rg_serialnum); + let td = tpl_2 (v_f_cpu_ins [j].first); + v_f_cpu_ins [j].deq; + f_merged.enq (td); + rg_serialnum <= rg_serialnum + 1; + + if (verbosity != 0) begin + $display ("%0d: %m.rl_merge_cpu_in [%0d]: serialnum = %0d", cur_cycle, j, rg_serialnum); + end + endrule + + // f_dm_ins is merged in at any time + rule rl_merge_dm_in; + let td <- pop (f_dm_in.first); + f_merged.enq (td); + + if (verbosity != 0) begin + $display ("%0d: %m.rl_merge_dm_in", cur_cycle); + end + endrule + + // ---------------------------------------------------------------- + // BEHAVIOR: ENCODING + + rule rl_log_trace_RESET (rg_reset_done && (f_merged.first.op == TRACE_RESET)); + let td <- pop (f_merged); // Encode components of td into byte vecs match { .n0, .vb0 } = encode_byte (te_op_begin_group); @@ -70,11 +122,11 @@ module mkTV_Encode (TV_Encode_IFC); match { .nn1, .x1 } = vsubst (nn0, x0, n1, vb1); match { .nnN, .xN } = vsubst (nn1, x1, nN, vbN); - f_vb.enq (tuple2 (nnN, xN)); + f_out.enq (tuple2 (nnN, xN)); endrule - rule rl_log_trace_GPR_WRITE (rg_reset_done && (f_trace_data.first.op == TRACE_GPR_WRITE)); - let td <- pop (f_trace_data); + rule rl_log_trace_GPR_WRITE (rg_reset_done && (f_merged.first.op == TRACE_GPR_WRITE)); + let td <- pop (f_merged); // Encode components of td into byte vecs match { .n0, .vb0 } = encode_byte (te_op_begin_group); @@ -88,11 +140,11 @@ module mkTV_Encode (TV_Encode_IFC); match { .nn2, .x2 } = vsubst (nn1, x1, n2, vb2); match { .nnN, .xN } = vsubst (nn2, x2, nN, vbN); - f_vb.enq (tuple2 (nnN, xN)); + f_out.enq (tuple2 (nnN, xN)); endrule - rule rl_log_trace_FPR_WRITE (rg_reset_done && (f_trace_data.first.op == TRACE_FPR_WRITE)); - let td <- pop (f_trace_data); + rule rl_log_trace_FPR_WRITE (rg_reset_done && (f_merged.first.op == TRACE_FPR_WRITE)); + let td <- pop (f_merged); // Encode components of td into byte vecs match { .n0, .vb0 } = encode_byte (te_op_begin_group); @@ -106,11 +158,11 @@ module mkTV_Encode (TV_Encode_IFC); match { .nn2, .x2 } = vsubst (nn1, x1, n2, vb2); match { .nnN, .xN } = vsubst (nn2, x2, nN, vbN); - f_vb.enq (tuple2 (nnN, xN)); + f_out.enq (tuple2 (nnN, xN)); endrule - rule rl_log_trace_CSR_WRITE (rg_reset_done && (f_trace_data.first.op == TRACE_CSR_WRITE)); - let td <- pop (f_trace_data); + rule rl_log_trace_CSR_WRITE (rg_reset_done && (f_merged.first.op == TRACE_CSR_WRITE)); + let td <- pop (f_merged); // Encode components of td into byte vecs match { .n0, .vb0 } = encode_byte (te_op_begin_group); @@ -124,11 +176,11 @@ module mkTV_Encode (TV_Encode_IFC); match { .nn2, .x2 } = vsubst (nn1, x1, n2, vb2); match { .nnN, .xN } = vsubst (nn2, x2, nN, vbN); - f_vb.enq (tuple2 (nnN, xN)); + f_out.enq (tuple2 (nnN, xN)); endrule - rule rl_log_trace_MEM_WRITE (rg_reset_done && (f_trace_data.first.op == TRACE_MEM_WRITE)); - let td <- pop (f_trace_data); + rule rl_log_trace_MEM_WRITE (rg_reset_done && (f_merged.first.op == TRACE_MEM_WRITE)); + let td <- pop (f_merged); Bit #(2) mem_req_size = td.word1 [1:0]; Byte size_and_mem_req_op = { 2'b0, mem_req_size, te_mem_req_op_Store }; @@ -157,11 +209,11 @@ module mkTV_Encode (TV_Encode_IFC); //match { .nnN, .xN } = vsubst (nn7, x7, nN, vbN); match { .nnN, .xN } = vsubst (nn5, x5, nN, vbN); - f_vb.enq (tuple2 (nnN, xN)); + f_out.enq (tuple2 (nnN, xN)); endrule - rule rl_log_trace_OTHER (rg_reset_done && (f_trace_data.first.op == TRACE_OTHER)); - let td <- pop (f_trace_data); + rule rl_log_trace_OTHER (rg_reset_done && (f_merged.first.op == TRACE_OTHER)); + let td <- pop (f_merged); // Encode components of td into byte vecs match { .n0, .vb0 } = encode_byte (te_op_begin_group); @@ -175,11 +227,14 @@ module mkTV_Encode (TV_Encode_IFC); match { .nn2, .x2 } = vsubst (nn1, x1, n2, vb2); match { .nnN, .xN } = vsubst (nn2, x2, nN, vbN); - f_vb.enq (tuple2 (nnN, xN)); + f_out.enq (tuple2 (nnN, xN)); + + if (verbosity != 0) + $display ("%0d: %m.rl_log_trace_OTHER, pc = %0h", cur_cycle, td.pc); endrule - rule rl_log_trace_I_RD (rg_reset_done && (f_trace_data.first.op == TRACE_I_RD)); - let td <- pop (f_trace_data); + rule rl_log_trace_I_RD (rg_reset_done && (f_merged.first.op == TRACE_I_RD)); + let td <- pop (f_merged); // Encode components of td into byte vecs match { .n0, .vb0 } = encode_byte (te_op_begin_group); @@ -195,30 +250,68 @@ module mkTV_Encode (TV_Encode_IFC); match { .nn3, .x3 } = vsubst (nn2, x2, n3, vb3); match { .nnN, .xN } = vsubst (nn3, x3, nN, vbN); - f_vb.enq (tuple2 (nnN, xN)); + f_out.enq (tuple2 (nnN, xN)); + + if (verbosity != 0) + $display ("%0d: %m.rl_log_trace_I_RD, pc = %0h", cur_cycle, td.pc); endrule - rule rl_log_trace_F_RD (rg_reset_done && (f_trace_data.first.op == TRACE_F_RD)); - let td <- pop (f_trace_data); +`ifdef ISA_F + // New opcode to track GPR updates due to F/D instructions. Also updates + // the CSR FFLAGS + rule rl_log_trace_F_GRD (rg_reset_done && (f_merged.first.op == TRACE_F_GRD)); + let td <- pop (f_merged); // Encode components of td into byte vecs match { .n0, .vb0 } = encode_byte (te_op_begin_group); match { .n1, .vb1 } = encode_pc (td.pc); match { .n2, .vb2 } = encode_instr (td.instr_sz, td.instr); - match { .n3, .vb3 } = encode_reg (fv_fpr_regnum (td.rd), td.word1); + match { .n3, .vb3 } = encode_reg (fv_gpr_regnum (td.rd), td.word1); + match { .n4, .vb4 } = encode_reg (fv_csr_regnum (extend (csr_addr_fflags)), td.word2); + match { .n5, .vb5 } = encode_reg (fv_csr_regnum (extend (csr_addr_mstatus)), td.word4); match { .nN, .vbN } = encode_byte (te_op_end_group); // Concatenate components into a single byte vec match { .nn0, .x0 } = vsubst ( 0, ?, n0, vb0); match { .nn1, .x1 } = vsubst (nn0, x0, n1, vb1); match { .nn2, .x2 } = vsubst (nn1, x1, n2, vb2); - match { .nnN, .xN } = vsubst (nn2, x2, nN, vbN); + match { .nn3, .x3 } = vsubst (nn2, x2, n3, vb3); + match { .nn4, .x4 } = vsubst (nn3, x3, n4, vb4); + match { .nn5, .x5 } = vsubst (nn4, x4, n5, vb5); + match { .nnN, .xN } = vsubst (nn5, x5, nN, vbN); - f_vb.enq (tuple2 (nnN, xN)); + f_out.enq (tuple2 (nnN, xN)); endrule - rule rl_log_trace_I_LOAD (rg_reset_done && (f_trace_data.first.op == TRACE_I_LOAD)); - let td <- pop (f_trace_data); + // New opcode to track FPR updates due to F/D instructions. Also updates + // the CSRs FFLAGS and MSTATUS + rule rl_log_trace_F_FRD (rg_reset_done && (f_merged.first.op == TRACE_F_FRD)); + let td <- pop (f_merged); + + // Encode components of td into byte vecs + match { .n0, .vb0 } = encode_byte (te_op_begin_group); + match { .n1, .vb1 } = encode_pc (td.pc); + match { .n2, .vb2 } = encode_instr (td.instr_sz, td.instr); + match { .n3, .vb3 } = encode_fpr (fv_fpr_regnum (td.rd), td.word5); + match { .n4, .vb4 } = encode_reg (fv_csr_regnum (extend (csr_addr_fflags)), td.word2); + match { .n5, .vb5 } = encode_reg (fv_csr_regnum (extend (csr_addr_mstatus)), td.word4); + match { .nN, .vbN } = encode_byte (te_op_end_group); + + // Concatenate components into a single byte vec + match { .nn0, .x0 } = vsubst ( 0, ?, n0, vb0); + match { .nn1, .x1 } = vsubst (nn0, x0, n1, vb1); + match { .nn2, .x2 } = vsubst (nn1, x1, n2, vb2); + match { .nn3, .x3 } = vsubst (nn2, x2, n3, vb3); + match { .nn4, .x4 } = vsubst (nn3, x3, n4, vb4); + match { .nn5, .x5 } = vsubst (nn4, x4, n5, vb5); + match { .nnN, .xN } = vsubst (nn5, x5, nN, vbN); + + f_out.enq (tuple2 (nnN, xN)); + endrule +`endif + + rule rl_log_trace_I_LOAD (rg_reset_done && (f_merged.first.op == TRACE_I_LOAD)); + let td <- pop (f_merged); // Encode components of td into byte vecs match { .n0, .vb0 } = encode_byte (te_op_begin_group); @@ -236,18 +329,20 @@ module mkTV_Encode (TV_Encode_IFC); match { .nn4, .x4 } = vsubst (nn3, x3, n4, vb4); match { .nnN, .xN } = vsubst (nn4, x4, nN, vbN); - f_vb.enq (tuple2 (nnN, xN)); + f_out.enq (tuple2 (nnN, xN)); endrule - rule rl_log_trace_F_LOAD (rg_reset_done && (f_trace_data.first.op == TRACE_F_LOAD)); - let td <- pop (f_trace_data); +`ifdef ISA_F + rule rl_log_trace_F_LOAD (rg_reset_done && (f_merged.first.op == TRACE_F_LOAD)); + let td <- pop (f_merged); // Encode components of td into byte vecs match { .n0, .vb0 } = encode_byte (te_op_begin_group); match { .n1, .vb1 } = encode_pc (td.pc); match { .n2, .vb2 } = encode_instr (td.instr_sz, td.instr); - match { .n3, .vb3 } = encode_reg (fv_fpr_regnum (td.rd), td.word1); + match { .n3, .vb3 } = encode_fpr (fv_fpr_regnum (td.rd), td.word5); match { .n4, .vb4 } = encode_eaddr (truncate (td.word3)); + match { .n5, .vb5 } = encode_reg (fv_csr_regnum (extend (csr_addr_mstatus)), td.word4); match { .nN, .vbN } = encode_byte (te_op_end_group); // Concatenate components into a single byte vec @@ -256,16 +351,17 @@ module mkTV_Encode (TV_Encode_IFC); match { .nn2, .x2 } = vsubst (nn1, x1, n2, vb2); match { .nn3, .x3 } = vsubst (nn2, x2, n3, vb3); match { .nn4, .x4 } = vsubst (nn3, x3, n4, vb4); - match { .nnN, .xN } = vsubst (nn4, x4, nN, vbN); + match { .nn5, .x5 } = vsubst (nn4, x4, n5, vb5); + match { .nnN, .xN } = vsubst (nn5, x5, nN, vbN); - f_vb.enq (tuple2 (nnN, xN)); + f_out.enq (tuple2 (nnN, xN)); endrule +`endif - rule rl_log_trace_STORE (rg_reset_done && (f_trace_data.first.op == TRACE_STORE)); - let td <- pop (f_trace_data); + rule rl_log_trace_I_STORE (rg_reset_done && (f_merged.first.op == TRACE_I_STORE)); + let td <- pop (f_merged); - let funct3 = instr_funct3 (td.instr); // TODO: what if it's a 16b instr? - let mem_req_size = funct3 [1:0]; + let mem_req_size = td.word1 [1:0]; // funct3 // Encode components of td into byte vecs match { .n0, .vb0 } = encode_byte (te_op_begin_group); @@ -283,14 +379,39 @@ module mkTV_Encode (TV_Encode_IFC); match { .nn4, .x4 } = vsubst (nn3, x3, n4, vb4); match { .nnN, .xN } = vsubst (nn4, x4, nN, vbN); - f_vb.enq (tuple2 (nnN, xN)); + f_out.enq (tuple2 (nnN, xN)); endrule - rule rl_log_trace_AMO (rg_reset_done && (f_trace_data.first.op == TRACE_AMO)); - let td <- pop (f_trace_data); +`ifdef ISA_F + rule rl_log_trace_F_STORE (rg_reset_done && (f_merged.first.op == TRACE_F_STORE)); + let td <- pop (f_merged); - let funct3 = instr_funct3 (td.instr); // TODO: what if it's a 16b instr? - let mem_req_size = funct3 [1:0]; + let mem_req_size = td.word1 [1:0]; // funct3 + + // Encode components of td into byte vecs + match { .n0, .vb0 } = encode_byte (te_op_begin_group); + match { .n1, .vb1 } = encode_pc (td.pc); + match { .n2, .vb2 } = encode_instr (td.instr_sz, td.instr); + match { .n3, .vb3 } = encode_fstval (mem_req_size, td.word5); + match { .n4, .vb4 } = encode_eaddr (truncate (td.word3)); + match { .nN, .vbN } = encode_byte (te_op_end_group); + + // Concatenate components into a single byte vec + match { .nn0, .x0 } = vsubst ( 0, ?, n0, vb0); + match { .nn1, .x1 } = vsubst (nn0, x0, n1, vb1); + match { .nn2, .x2 } = vsubst (nn1, x1, n2, vb2); + match { .nn3, .x3 } = vsubst (nn2, x2, n3, vb3); + match { .nn4, .x4 } = vsubst (nn3, x3, n4, vb4); + match { .nnN, .xN } = vsubst (nn4, x4, nN, vbN); + + f_out.enq (tuple2 (nnN, xN)); + endrule +`endif + + rule rl_log_trace_AMO (rg_reset_done && (f_merged.first.op == TRACE_AMO)); + let td <- pop (f_merged); + + let mem_req_size = td.word4 [1:0]; // funct3 // Encode components of td into byte vecs match { .n0, .vb0 } = encode_byte (te_op_begin_group); @@ -310,11 +431,14 @@ module mkTV_Encode (TV_Encode_IFC); match { .nn5, .x5 } = vsubst (nn4, x4, n5, vb5); match { .nnN, .xN } = vsubst (nn5, x5, nN, vbN); - f_vb.enq (tuple2 (nnN, xN)); + f_out.enq (tuple2 (nnN, xN)); + + if (verbosity != 0) + $display ("%0d: %m.rl_log_trace_AMO, pc = %0h", cur_cycle, td.pc); endrule - rule rl_log_trace_CSRRX (rg_reset_done && (f_trace_data.first.op == TRACE_CSRRX)); - let td <- pop (f_trace_data); + rule rl_log_trace_CSRRX (rg_reset_done && (f_merged.first.op == TRACE_CSRRX)); + let td <- pop (f_merged); // Encode components of td into byte vecs match { .n0, .vb0 } = encode_byte (te_op_begin_group); @@ -334,11 +458,11 @@ module mkTV_Encode (TV_Encode_IFC); match { .nn4, .x4 } = vsubst (nn3, x3, n4, vb4); match { .nnN, .xN } = vsubst (nn4, x4, nN, vbN); - f_vb.enq (tuple2 (nnN, xN)); + f_out.enq (tuple2 (nnN, xN)); endrule - rule rl_log_trace_TRAP (rg_reset_done && (f_trace_data.first.op == TRACE_TRAP)); - let td <- pop (f_trace_data); + rule rl_log_trace_TRAP (rg_reset_done && (f_merged.first.op == TRACE_TRAP)); + let td <- pop (f_merged); // Use new priv mode to decide which trap regs are updated (M, S or U priv) Priv_Mode priv = truncate (td.rd); @@ -387,11 +511,11 @@ module mkTV_Encode (TV_Encode_IFC); match { .nn7, .x7 } = vsubst (nn6, x6, n7, vb7); match { .nnN, .xN } = vsubst (nn7, x7, nN, vbN); - f_vb.enq (tuple2 (nnN, xN)); + f_out.enq (tuple2 (nnN, xN)); endrule - rule rl_log_trace_INTR (rg_reset_done && (f_trace_data.first.op == TRACE_INTR)); - let td <- pop (f_trace_data); + rule rl_log_trace_INTR (rg_reset_done && (f_merged.first.op == TRACE_INTR)); + let td <- pop (f_merged); // Use new priv mode to decide which trap regs are updated (M, S or U priv) Priv_Mode priv = truncate (td.rd); @@ -432,11 +556,11 @@ module mkTV_Encode (TV_Encode_IFC); match { .nn6, .x6 } = vsubst (nn5, x5, n6, vb6); match { .nnN, .xN } = vsubst (nn6, x6, nN, vbN); - f_vb.enq (tuple2 (nnN, xN)); + f_out.enq (tuple2 (nnN, xN)); endrule - rule rl_log_trace_RET (rg_reset_done && (f_trace_data.first.op == TRACE_RET)); - let td <- pop (f_trace_data); + rule rl_log_trace_RET (rg_reset_done && (f_merged.first.op == TRACE_RET)); + let td <- pop (f_merged); // Encode components of td into byte vecs match { .n0, .vb0 } = encode_byte (te_op_begin_group); @@ -454,17 +578,24 @@ module mkTV_Encode (TV_Encode_IFC); match { .nn4, .x4 } = vsubst (nn3, x3, n4, vb4); match { .nnN, .xN } = vsubst (nn4, x4, nN, vbN); - f_vb.enq (tuple2 (nnN, xN)); + f_out.enq (tuple2 (nnN, xN)); endrule // ---------------------------------------------------------------- // INTERFACE - method Action reset (); + method Action reset () if (! rg_reset_done); + for (Integer j = 0; j < valueOf (SupSize); j = j + 1) + v_f_cpu_ins [j].clear; + f_dm_in.clear; + f_out.clear; + rg_serialnum <= 0; + rg_reset_done <= True; endmethod - interface Put trace_data_in = toPut (f_trace_data); - interface Get tv_vb_out = toGet (f_vb); + interface v_cpu_in = map (toPut, v_f_cpu_ins); + interface dm_in = toPut (f_dm_in); + interface out = toGet (f_out); endmodule // **************************************************************** @@ -648,6 +779,29 @@ function Tuple2 #(Bit #(32), Vector #(TV_VB_SIZE, Byte)) encode_reg (Bit #(16) r return tuple2 (n, vb); endfunction +`ifdef ISA_F +function Tuple2 #(Bit #(32), Vector #(TV_VB_SIZE, Byte)) encode_fpr (Bit #(16) regnum, WordFL word); + Vector #(TV_VB_SIZE, Byte) vb = newVector; + Bit #(32) n = 0; + vb [0] = te_op_full_reg; + vb [1] = regnum [7:0]; + vb [2] = regnum [15:8]; + vb [3] = word[7:0]; + vb [4] = word [15:8]; + vb [5] = word [23:16]; + vb [6] = word [31:24]; + n = 7; +`ifdef ISA_D + vb [7] = word [39:32]; + vb [8] = word [47:40]; + vb [9] = word [55:48]; + vb [10] = word [63:56]; + n = 11; +`endif + return tuple2 (n, vb); +endfunction +`endif + function Tuple2 #(Bit #(32), Vector #(TV_VB_SIZE, Byte)) encode_priv (Bit #(5) priv); Vector #(TV_VB_SIZE, Byte) vb = newVector; vb [0] = te_op_addl_state; @@ -719,6 +873,31 @@ function Tuple2 #(Bit #(32), Vector #(TV_VB_SIZE, Byte)) encode_stval (MemReqSiz return tuple2 (n, vb); endfunction +`ifdef ISA_F +function Tuple2 #(Bit #(32), Vector #(TV_VB_SIZE, Byte)) encode_fstval (MemReqSize mem_req_size, WordFL word); + Vector #(TV_VB_SIZE, Byte) vb = newVector; + vb [0] = te_op_addl_state; + vb [1] = case (mem_req_size) + f3_SIZE_B: te_op_addl_state_data8; // not possible + f3_SIZE_H: te_op_addl_state_data16; // not possible + f3_SIZE_W: te_op_addl_state_data32; + f3_SIZE_D: te_op_addl_state_data64; + endcase; + vb [2] = word [7:0]; + vb [3] = word [15:8]; + vb [4] = word [23:16]; + vb [5] = word [31:24]; +`ifdef ISA_D + vb [6] = word [39:32]; + vb [7] = word [47:40]; + vb [8] = word [55:48]; + vb [9] = word [63:56]; +`endif + Bit #(32) n = (1 << pack(mem_req_size)) + 2; + return tuple2 (n, vb); +endfunction +`endif + // ================================================================ endpackage diff --git a/src_Core/Core/Trace_Data2.bsv b/src_Core/Core/Trace_Data2.bsv new file mode 100644 index 0000000..e532e39 --- /dev/null +++ b/src_Core/Core/Trace_Data2.bsv @@ -0,0 +1,42 @@ +// Copyright (c) 2020 Bluespec, Inc. All Rights Reserved. + +package Trace_Data2; + +// ================================================================ +// Project imports + +// ---------------- +// From RISCY-OOO + +import Types :: *; +import ProcTypes :: *; +import ReorderBuffer :: *; + +// ================================================================ +// This struct has a subset of the fields of struct ToReorderBuffer in +// Toooba/RISCY-OOO, to be encoded and emitted for Tandem +// Verification. + +// In RISCY-OOO's CommitStage, when we dequeue (retire) an entry +// (struct ToReorderBuffer), we simply copy out these fields and +// enqueue this struct into a FIFO. All transformations/encoding for +// TV are done on the dequeue side of the FIFO. Thus, this should not +// add to the critical path or scheduling requirements of CommitStage. + +typedef struct { + Bit #(64) serialnum; // instruction serial number + Addr pc; + Bit #(32) orig_inst; // original 16b or 32b instruction ([1:0] will distinguish 16b or 32b) + IType iType; + Maybe #(CSR) csr; + Maybe #(Trap) trap; + Addr tval; // in case of trap + PPCVAddrCSRData ppc_vaddr_csrData; + Bit #(5) fflags; + Bool will_dirty_fpu_state; // True means 2'b11 will be written to FS + } Trace_Data2 +deriving (Bits, Eq, FShow); + +// ================================================================ + +endpackage diff --git a/src_Core/Core/Trace_Data2_to_Trace_Data.bsv b/src_Core/Core/Trace_Data2_to_Trace_Data.bsv new file mode 100644 index 0000000..bca1692 --- /dev/null +++ b/src_Core/Core/Trace_Data2_to_Trace_Data.bsv @@ -0,0 +1,142 @@ +// Copyright (c) 2020 Bluespec, Inc. All Rights Reserved. + +package Trace_Data2_to_Trace_Data; + +// ================================================================ +// This package defines a module to transform a stream of Trace_Data2 +// to a stream of (serialnum, Trace_Data) + +// ================================================================ +// BSV library imports + +import FIFOF :: *; +import GetPut :: *; + +// ---------------- +// BSV additional libs + +import Cur_Cycle :: *; +import GetPut_Aux :: *; + +// ================================================================ +// Project riscy-ooo imports (for fields in Trace_Data2) + +import Types :: *; +import ProcTypes :: *; +import ReorderBuffer :: *; // for PPCVAddrCSRData + +// ================================================================ +// Project Toooba imports + +import ISA_Decls :: *; +import TV_Info :: *; +import Trace_Data2 :: *; + +// ================================================================ + +interface Trace_Data2_to_Trace_Data_IFC; + method Action init; + + // From Toooba's CommitStage + interface Put #(Trace_Data2) in; + + interface Get #(Tuple2 #(Bit #(64), Trace_Data)) out; +endinterface + +// ================================================================ + +module mkTrace_Data2_to_Trace_Data (Trace_Data2_to_Trace_Data_IFC); + + Integer verbosity = 1; // for debugging + + // Input stream + FIFOF #(Trace_Data2) f_in <- mkFIFOF; + + // Output stream + FIFOF #(Tuple2 #(Bit #(64), Trace_Data)) f_out <- mkFIFOF; + + // ================================================================ + // Transformer: Trace_Data2 -> (serialnum, Trace_Data) + + function ActionValue #(Tuple2 #(Bit #(64), Trace_Data)) fav_xform (Trace_Data2 td2); + actionvalue + let serialnum = td2.serialnum; + Trace_Data td = ?; + ISize isize = ((td2.orig_inst [1:0] == 2'b11) ? ISIZE32BIT : ISIZE16BIT); + + if ( (td2.iType == Alu) + || (td2.iType == J) + || (td2.iType == Jr) + || (td2.iType == Auipc)) + td = mkTrace_I_RD (td2.pc, + isize, + td2.orig_inst, + 0, // TODO: rd + 0); // TODO: rd_val + + else if ( (td2.iType == Br) + || (td2.iType == Fence) + || (td2.iType == FenceI) + || (td2.iType == SFence) + || (td2.iType == Ecall) + || (td2.iType == Ebreak) + || (td2.iType == Mret) + || (td2.iType == Sret)) + td = mkTrace_OTHER (td2.pc, isize, td2.orig_inst); + + else if ( (td2.iType == Amo) + || (td2.iType == Lr) + || (td2.iType == Sc)) + td = mkTrace_AMO (td2.pc, + 0, // TODO: funct3 + isize, + td2.orig_inst, + 0, // TODO: rd + 0, // TODO: rd_val + 0, // TODO: rs2_val + 0 // TODO: eaddr + ); + else begin + if (verbosity != 0) begin + $display (" fav_xform: TBD: Using mkTrace_I_RD for now"); + $display (" ", fshow (td2)); + end + td = mkTrace_I_RD (td2.pc, + isize, + td2.orig_inst, + 0, // TODO: rd + 0); // TODO: rd_val + end + return tuple2 (serialnum, td); + endactionvalue + endfunction + + // ================================================================ + // RULES + + rule rl_xform; + Trace_Data2 td2 <- pop (f_in); + match { .serialnum, .td } <- fav_xform (td2); + f_out.enq (tuple2 (serialnum, td)); + + if (verbosity != 0) + $display ("%0d: %m.rl_xform: serialnum:%0d PC:0x%0h instr:0x%08h", + cur_cycle, td2.serialnum, td2.pc, td2.orig_inst, + " iType:", fshow (td2.iType)); + endrule + + // ================================================================ + // INTERFACE + + method Action init; + f_in.clear; + f_out.clear; + endmethod + + interface in = toPut (f_in); + interface out = toGet (f_out); +endmodule + +// ================================================================ + +endpackage diff --git a/src_Core/ISA/TV_Info.bsv b/src_Core/ISA/TV_Info.bsv index dc3b971..454ce72 100644 --- a/src_Core/ISA/TV_Info.bsv +++ b/src_Core/ISA/TV_Info.bsv @@ -33,9 +33,9 @@ typedef enum {// These are not from instruction flow and do not have a PC or ins // These are from instruction flow and have a PC and instruction TRACE_OTHER, - TRACE_I_RD, TRACE_F_RD, + TRACE_I_RD, TRACE_F_GRD, TRACE_F_FRD, TRACE_I_LOAD, TRACE_F_LOAD, - TRACE_STORE, + TRACE_I_STORE, TRACE_F_STORE, TRACE_AMO, TRACE_TRAP, TRACE_RET, @@ -56,6 +56,9 @@ typedef struct { WordXL word2; Bit #(64) word3; // Wider than WordXL because can contain paddr (in RV32, paddr can be 34 bits) WordXL word4; +`ifdef ISA_F + WordFL word5; +`endif } Trace_Data deriving (Bits); @@ -139,19 +142,39 @@ function Trace_Data mkTrace_I_RD (WordXL pc, ISize isize, Bit #(32) instr, RegNa return td; endfunction -// F_RD -// op pc instr_sz instr rd word1 word2 word3 word4 -// x x x x x rdval -function Trace_Data mkTrace_F_RD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordXL rdval); +`ifdef ISA_F +// F_FRD +// op pc instr_sz instr rd word1 word2 word3 word4 word5 +// x x x x x fflags mstatus rdval +function Trace_Data mkTrace_F_FRD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordFL rdval, Bit#(5) fflags, WordXL mstatus); Trace_Data td = ?; - td.op = TRACE_F_RD; + td.op = TRACE_F_FRD; + td.pc = pc; + td.instr_sz = isize; + td.instr = instr; + td.rd = rd; + td.word2 = extend (fflags); + td.word4 = mstatus; + td.word5 = rdval; + return td; +endfunction + +// F_GRD +// op pc instr_sz instr rd word1 word2 word3 word4 word5 +// x x x x x rdval fflags mstatus +function Trace_Data mkTrace_F_GRD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordXL rdval, Bit#(5) fflags, WordXL mstatus); + Trace_Data td = ?; + td.op = TRACE_F_GRD; td.pc = pc; td.instr_sz = isize; td.instr = instr; td.rd = rd; td.word1 = rdval; + td.word2 = extend (fflags); + td.word4 = mstatus; return td; endfunction +`endif // I_LOAD // op pc instr_sz instr rd word1 word2 word3 word4 @@ -168,39 +191,69 @@ function Trace_Data mkTrace_I_LOAD (WordXL pc, ISize isize, Bit #(32) instr, Reg return td; endfunction -// F_LOAD +// I_STORE // op pc instr_sz instr rd word1 word2 word3 word4 -// x x x x x rdval eaddr -function Trace_Data mkTrace_F_LOAD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordXL rdval, WordXL eaddr); +// x x x x funct3 stval eaddr +function Trace_Data mkTrace_I_STORE (WordXL pc, Bit #(3) funct3, ISize isize, Bit #(32) instr, WordXL stval, WordXL eaddr); + Trace_Data td = ?; + td.op = TRACE_I_STORE; + td.pc = pc; + td.instr_sz = isize; + td.instr = instr; + td.word1 = zeroExtend (funct3); + td.word2 = stval; + td.word3 = zeroExtend (eaddr); + return td; +endfunction + +`ifdef ISA_F +// F_LOAD +// op pc instr_sz instr rd word1 word2 word3 word4 word5 +// x x x x x eaddr mstatus rdval +function Trace_Data mkTrace_F_LOAD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordFL rdval, WordXL eaddr, WordXL mstatus); Trace_Data td = ?; td.op = TRACE_F_LOAD; td.pc = pc; td.instr_sz = isize; td.instr = instr; td.rd = rd; - td.word1 = rdval; td.word3 = zeroExtend (eaddr); + td.word4 = mstatus; + td.word5 = rdval; return td; endfunction -// STORE -// op pc instr_sz instr rd word1 word2 word3 word4 -// x x x x stval eaddr -function Trace_Data mkTrace_STORE (WordXL pc, ISize isize, Bit #(32) instr, WordXL stval, WordXL eaddr); +// F_STORE +// op pc instr_sz instr rd word1 word2 word3 word4 word5 +// x x x x funct3 eaddr stval +function Trace_Data mkTrace_F_STORE (WordXL pc, Bit #(3) funct3, ISize isize, Bit #(32) instr, WordFL stval, WordXL eaddr); Trace_Data td = ?; - td.op = TRACE_STORE; + td.op = TRACE_F_STORE; td.pc = pc; td.instr_sz = isize; td.instr = instr; - td.word2 = stval; td.word3 = zeroExtend (eaddr); + td.word5 = stval; return td; endfunction +function Trace_Data fv_trace_update_mstatus_fs (Trace_Data td, Bit #(2) fs); + let ntd = td; + ntd.word4 = fv_assign_bits (td.word4, fromInteger (mstatus_fs_bitpos), fs); + return (ntd); +endfunction + +function Trace_Data fv_trace_update_fcsr_fflags (Trace_Data td, Bit #(5) fflags); + let ntd = td; + ntd.word2 = (td.word2 | extend (fflags)); + return (ntd); +endfunction +`endif + // AMO // op pc instr_sz instr rd word1 word2 word3 word4 -// x x x x x rdval stval eaddr -function Trace_Data mkTrace_AMO (WordXL pc, ISize isize, Bit #(32) instr, +// x x x x x rdval stval eaddr funct3 +function Trace_Data mkTrace_AMO (WordXL pc, Bit #(3) funct3, ISize isize, Bit #(32) instr, RegName rd, WordXL rdval, WordXL stval, WordXL eaddr); Trace_Data td = ?; td.op = TRACE_AMO; @@ -211,6 +264,7 @@ function Trace_Data mkTrace_AMO (WordXL pc, ISize isize, Bit #(32) instr, td.word1 = rdval; td.word2 = stval; td.word3 = zeroExtend (eaddr); + td.word4 = zeroExtend (funct3); return td; endfunction @@ -305,14 +359,27 @@ instance FShow #(Trace_Data); if (td.op != TRACE_INTR) fmt = fmt + $format (" instr.%0d %0h:", pack (td.instr_sz), td.instr); - if ((td.op == TRACE_I_RD) || (td.op == TRACE_F_RD)) + if (td.op == TRACE_I_RD) fmt = fmt + $format (" rd %0d rdval %0h", td.rd, td.word1); +`ifdef ISA_F + else if (td.op == TRACE_F_FRD) + fmt = fmt + $format (" rd %0d rdval %0h fflags %05b", td.rd, td.word5, td.word2); - else if ((td.op == TRACE_I_LOAD) || (td.op == TRACE_F_LOAD)) + else if (td.op == TRACE_F_GRD) + fmt = fmt + $format (" rd %0d rdval %0h fflags %05b", td.rd, td.word1, td.word2); + + else if (td.op == TRACE_F_LOAD) + fmt = fmt + $format (" rd %0d rdval %0h eaddr %0h", + td.rd, td.word5, td.word3); + + else if (td.op == TRACE_F_STORE) + fmt = fmt + $format (" stval %0h eaddr %0h", td.word5, td.word3); +`endif + else if (td.op == TRACE_I_LOAD) fmt = fmt + $format (" rd %0d rdval %0h eaddr %0h", td.rd, td.word1, td.word3); - else if (td.op == TRACE_STORE) + else if (td.op == TRACE_I_STORE) fmt = fmt + $format (" stval %0h eaddr %0h", td.word2, td.word3); else if (td.op == TRACE_AMO) diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv index 7ff003d..ca63625 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv @@ -42,6 +42,10 @@ import RenameDebugIF::*; import Cur_Cycle :: *; +`ifdef INCLUDE_TANDEM_VERIF +import Trace_Data2 :: *; +`endif + typedef struct { // info about the inst blocking at ROB head Addr pc; @@ -99,6 +103,10 @@ interface CommitInput; method Bool doStats; // deadlock check method Bool checkDeadlock; + +`ifdef INCLUDE_TANDEM_VERIF + interface Vector #(SupSize, Put #(Trace_Data2)) v_to_TV; +`endif endinterface typedef struct { @@ -148,13 +156,35 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); Bool verbose = False; Integer verbosity = 1; // Bluespec: for lightweight verbosity trace - Reg #(Bit #(64)) rg_instret <- mkReg (0); + + // Used to inform tandem-verifier about program order. + // TODO: we could use fewer bits and allow and recognize wraparound. + Reg #(Bit #(64)) rg_serialnum <- mkReg (0); `ifdef INCLUDE_GDB_CONTROL Reg #(Run_State) rg_run_state <- mkReg (RUN_STATE_RUNNING); `endif +`ifdef INCLUDE_TANDEM_VERIF + function Action fa_to_TV (Bit #(64) serialnum, ToReorderBuffer deq_data, Integer way); + action + let x = Trace_Data2 {serialnum: serialnum, + pc: deq_data.pc, + orig_inst: deq_data.orig_inst, + iType: deq_data.iType, + csr: deq_data.csr, + trap: deq_data.trap, + tval: deq_data.tval, + ppc_vaddr_csrData: deq_data.ppc_vaddr_csrData, + fflags: deq_data.fflags, + will_dirty_fpu_state: deq_data.will_dirty_fpu_state}; + inIfc.v_to_TV [way].put (x); + endaction + endfunction + +`endif + // func units ReorderBufferSynth rob = inIfc.robIfc; RegRenamingTable regRenamingTable = inIfc.rtIfc; @@ -437,8 +467,12 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); }); commitTrap <= commitTrap_val; +`ifdef INCLUDE_TANDEM_VERIF + fa_to_TV (rg_serialnum, x, 0); +`endif + if (verbosity >= 1) begin - $display ("instret:%0d PC:0x%0h instr:0x%08h", rg_instret, x.pc, x.orig_inst, + $display ("instret:%0d PC:0x%0h instr:0x%08h", rg_serialnum, x.pc, x.orig_inst, " iType:", fshow (x.iType), " [doCommitTrap]"); end if (verbose) begin @@ -592,11 +626,16 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); ); rob.deqPort[0].deq; let x = rob.deqPort[0].deq_data; + +`ifdef INCLUDE_TANDEM_VERIF + fa_to_TV (rg_serialnum, x, 0); +`endif + if(verbose) $display("[doCommitSystemInst] ", fshow(x)); if (verbosity >= 1) begin - $display("instret:%0d PC:0x%0h instr:0x%08h", rg_instret, x.pc, x.orig_inst, + $display("instret:%0d PC:0x%0h instr:0x%08h", rg_serialnum, x.pc, x.orig_inst, " iType:", fshow (x.iType), " [doCommitSystemInst]"); - rg_instret <= rg_instret + 1; + rg_serialnum <= rg_serialnum + 1; end // we claim a phy reg for every inst, so commit its renaming @@ -756,10 +795,14 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); stop = True; end else begin +`ifdef INCLUDE_TANDEM_VERIF + fa_to_TV (rg_serialnum + instret, x, i); +`endif + if (verbose) $display("[doCommitNormalInst - %d] ", i, fshow(inst_tag), " ; ", fshow(x)); if (verbosity >= 1) begin - $display("instret:%0d PC:0x%0h instr:0x%08h", rg_instret + instret, x.pc, x.orig_inst, + $display("instret:%0d PC:0x%0h instr:0x%08h", rg_serialnum + instret, x.pc, x.orig_inst, " iType:", fshow (x.iType), " [doCommitNormalInst [%0d]]", i); instret = instret + 1; end @@ -815,7 +858,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); end end end - rg_instret <= rg_instret + instret; + rg_serialnum <= rg_serialnum + instret; // write FPU csr if(csrf.fpuInstNeedWr(fflags, will_dirty_fpu_state)) begin