Removed EXTERNAL_DEBUG_MODULE stuff from CoreW.bsv; added Tandem Verif control flow

This commit is contained in:
rsnikhil
2020-01-29 13:19:31 -05:00
parent d84ec657d7
commit 6078b7ce19
10 changed files with 752 additions and 333 deletions

View File

@@ -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

View File

@@ -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
// ================================================================

View File

@@ -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
// ================================================================

View File

@@ -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))

View File

@@ -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
// ================================================================

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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