Merge branch 'master' into RVFI_DII, a complex merge for the fetch stage!
This commit is contained in:
@@ -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
|
||||
@@ -69,13 +91,52 @@ import DM_CPU_Req_Rsp ::*;
|
||||
// The Core module
|
||||
|
||||
(* synthesize *)
|
||||
module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
|
||||
module mkCoreW #(Reset dm_power_on_reset)
|
||||
(CoreW_IFC #(N_External_Interrupt_Sources));
|
||||
|
||||
`ifdef EXTERNAL_DEBUG_MODULE
|
||||
// ================================================================
|
||||
// Notes on 'reset'
|
||||
|
||||
// This module's default reset (Verilog RST_N) is a
|
||||
// 'non-debug-module reset', or 'ndm-reset': it resets everything
|
||||
// in mkCoreW other than the optional RISC-V Debug Module (DM).
|
||||
|
||||
// DM is reset ONLY by 'dm_power_on_reset' (parameter of this module).
|
||||
// This is expected to be performed exactly once, on power-up.
|
||||
|
||||
// Note: DM has an internal functionality that the DM spec calls
|
||||
// 'dm_reset'. This is not really an electrical reset, it is just
|
||||
// a module initializer wholly within the DM to put it into a
|
||||
// known state. To be able to do a dm_reset, the DM has to be
|
||||
// working already, at least to the point that it can field DMI
|
||||
// requests from the external debugger asking the DM to proform a
|
||||
// dm_reset.
|
||||
|
||||
// DM can ask the environment to perform an 'ndm-reset', which the
|
||||
// environment does by asserting the default reset (RST_N). At the
|
||||
// same time, the environment may also reset part or all of the
|
||||
// rest of the SoC.
|
||||
|
||||
// DM can also individually reset each hart in mkCPU.
|
||||
// 'hart' = hardware thread = independent PC and fetch-and-execute pipeline.
|
||||
// mkCPU (instantiated in this module) has one or more harts.
|
||||
// This hart-reset logic is entirely within this module.
|
||||
|
||||
// ================================================================
|
||||
// The CPU's (hart's) reset is the ``or'' of the default reset
|
||||
// (power-on reset) and the Debug Module's 'hart_reset' control.
|
||||
|
||||
let ndm_reset <- exposeCurrentReset;
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
let clk <- exposeCurrentClock;
|
||||
let cpu_reset <- mkReset(50, True, clk);
|
||||
let cpu_halt <- mkReset(50, True, clk);
|
||||
let cpu_reset_either <- mkResetEither(cpu_reset.new_rst, cpu_halt.new_rst);
|
||||
Bool initial_reset_val = False;
|
||||
Integer hart_reset_duration = 10; // NOTE: assuming 10 cycle reset enough for hart
|
||||
let dm_hart0_reset_controller <- mkReset(hart_reset_duration, initial_reset_val, clk);
|
||||
|
||||
let hart0_reset <- mkResetEither (ndm_reset, dm_hart0_reset_controller.new_rst);
|
||||
`else
|
||||
let hart0_reset = ndm_reset;
|
||||
`endif
|
||||
|
||||
// ================================================================
|
||||
@@ -84,12 +145,9 @@ 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
|
||||
Proc_IFC proc <- mkProc;
|
||||
`endif
|
||||
// RISCY-OOO processor
|
||||
// TODO (when we do multicore): need resets for each core.
|
||||
Proc_IFC proc <- mkProc (reset_by hart0_reset);
|
||||
|
||||
// A 2x3 fabric for connecting {CPU, Debug_Module} to {Fabric, PLIC}
|
||||
Fabric_2x3_IFC fabric_2x3 <- mkFabric_2x3;
|
||||
@@ -97,231 +155,99 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
|
||||
// PLIC (Platform-Level Interrupt Controller)
|
||||
PLIC_IFC_16_2_7 plic <- mkPLIC_16_2_7;
|
||||
|
||||
// Reset requests from SoC and responses to SoC
|
||||
FIFOF #(Bit #(0)) f_reset_reqs <- mkFIFOF;
|
||||
FIFOF #(Bit #(0)) f_reset_rsps <- mkFIFOF;
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// Debug Module
|
||||
Debug_Module_IFC debug_module <- mkDebug_Module (reset_by dm_power_on_reset);
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
// The TV encoder transforms Trace_Data structures produced by the CPU and DM
|
||||
// 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
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// Debug Module
|
||||
Debug_Module_IFC debug_module <- mkDebug_Module;
|
||||
`endif
|
||||
|
||||
// HTIF locations (for debugging only)
|
||||
Reg #(Bit #(64)) rg_tohost_addr <- mkReg (0);
|
||||
Reg #(Bit #(64)) rg_fromhost_addr <- mkReg (0);
|
||||
|
||||
// ================================================================
|
||||
// RESET
|
||||
// There are two sources of reset requests to the CPU: externally
|
||||
// from the SoC and, optionally, the DM. The SoC requires a
|
||||
// response, the DM does not. When both requestors are present
|
||||
// (i.e., DM is present), we merge the reset requests into the CPU,
|
||||
// and we remember which one was the requestor in
|
||||
// f_reset_requestor, so that we know whether or not to respond to
|
||||
// the SoC.
|
||||
|
||||
Bit #(1) reset_requestor_dm = 0;
|
||||
Bit #(1) reset_requestor_soc = 1;
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
FIFOF #(Bit #(1)) f_reset_requestor <- mkFIFOF;
|
||||
`endif
|
||||
|
||||
// Reset-hart0 request from SoC
|
||||
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
|
||||
// Hart-reset from DM
|
||||
|
||||
`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);
|
||||
Reg #(Bit #(8)) rg_hart0_reset_delay <- mkReg (0);
|
||||
Reg #(Bit #(64)) rg_tohost_addr <- mkReg (0);
|
||||
Reg #(Bit #(64)) rg_fromhost_addr <- mkReg (0);
|
||||
|
||||
rule rl_dm_hart0_reset (rg_hart0_reset_delay == 0);
|
||||
let x <- debug_module.hart0_reset_client.request.get;
|
||||
dm_hart0_reset_controller.assertReset;
|
||||
rg_hart0_reset_delay <= fromInteger (hart_reset_duration + 200); // NOTE: heuristic
|
||||
|
||||
$display ("%0d: %m.rl_dm_hart0_reset: asserting hart0 reset for %0d cycles",
|
||||
cur_cycle, hart_reset_duration);
|
||||
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;
|
||||
rule rl_dm_hart0_reset_wait (rg_hart0_reset_delay != 0);
|
||||
if (rg_hart0_reset_delay == 1) begin
|
||||
let pc = soc_map_struct.pc_reset_value;
|
||||
proc.start (pc, rg_tohost_addr, rg_fromhost_addr);
|
||||
|
||||
proc.hart0_server_reset.request.put (?); // CPU
|
||||
plic.server_reset.request.put (?); // PLIC
|
||||
fabric_2x3.reset; // Local 2x3 fabric
|
||||
|
||||
// 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),
|
||||
zeroExtend (soc_map.m_plic_addr_lim));
|
||||
|
||||
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);
|
||||
Bool is_running = True;
|
||||
debug_module.hart0_reset_client.response.put (is_running);
|
||||
$display ("%0d: %m.rl_dm_hart0_reset_wait: proc.start (pc %0h, tohostAddr %0h, fromhostAddr %0h",
|
||||
cur_cycle, pc, rg_tohost_addr, rg_fromhost_addr);
|
||||
end
|
||||
rg_hart0_reset_delay <= rg_hart0_reset_delay - 1;
|
||||
endrule
|
||||
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// ================================================================
|
||||
// Direct DM-to-CPU connections
|
||||
// Direct DM-to-CPU connections for run-control and other misc requests
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
`ifndef EXTERNAL_DEBUG_MODULE
|
||||
// DM to CPU connections for run-control and other misc requests
|
||||
mkConnection (debug_module.hart0_client_run_halt, proc.hart0_server_run_halt);
|
||||
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_server_run_halt;
|
||||
let tmp <- proc.hart0_server_run_halt.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
|
||||
@@ -330,9 +256,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
|
||||
@@ -342,25 +268,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);
|
||||
|
||||
@@ -371,33 +297,30 @@ 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
|
||||
// TV, no DM: stub out the dm input to TV
|
||||
Get #(Trace_Data) gs = getstub;
|
||||
mkConnection (tv_encode.dm_in, gs);
|
||||
`endif
|
||||
|
||||
`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
|
||||
@@ -407,12 +330,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);
|
||||
|
||||
// TODO: This slave can be connected to mkLLCDmaConnect for Debug Module System Bus Access
|
||||
AXI4_Slave_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) dummy_slave = dummy_AXI4_Slave_ifc;
|
||||
mkConnection (fabric_2x3.v_to_slaves [near_mem_io_slave_num], dummy_slave);
|
||||
// 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
|
||||
@@ -427,13 +348,6 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
|
||||
// $display ("%0d: Core.rl_relay_external_interrupts: relaying: %d", cur_cycle, pack (x));
|
||||
endrule
|
||||
|
||||
// TODO: fixup. Need to combine NMIs from multiple sources (cache, fabric, devices, ...)
|
||||
rule rl_relay_non_maskable_interrupt;
|
||||
proc.non_maskable_interrupt_req (False);
|
||||
|
||||
// $display ("%0d: Core.rl_relay_non_maskable_interrupts: relaying: %d", cur_cycle, pack (x));
|
||||
endrule
|
||||
|
||||
// ================================================================
|
||||
// INTERFACE
|
||||
|
||||
@@ -445,16 +359,26 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
|
||||
proc.set_verbosity (verbosity);
|
||||
endmethod
|
||||
|
||||
method Action set_htif_addrs (Bit #(64) tohost_addr, Bit #(64) fromhost_addr);
|
||||
// ----------------------------------------------------------------
|
||||
// Start
|
||||
|
||||
method Action start (Bit #(64) tohost_addr, Bit #(64) fromhost_addr);
|
||||
plic.set_addr_map (zeroExtend (soc_map.m_plic_addr_base),
|
||||
zeroExtend (soc_map.m_plic_addr_lim));
|
||||
|
||||
let pc = soc_map_struct.pc_reset_value;
|
||||
proc.start (pc, tohost_addr, fromhost_addr);
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// Save for potential future use by rl_dm_hart0_reset
|
||||
rg_tohost_addr <= tohost_addr;
|
||||
rg_fromhost_addr <= fromhost_addr;
|
||||
`endif
|
||||
|
||||
$display ("%0d: %m.method start: proc.start (pc %0h, tohostAddr %0h, fromhostAddr %0h)",
|
||||
cur_cycle, pc, tohost_addr, fromhost_addr);
|
||||
endmethod
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Soft reset
|
||||
|
||||
interface Server cpu_reset_server = toGPServer (f_reset_reqs, f_reset_rsps);
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// AXI4 Fabric interfaces
|
||||
|
||||
@@ -469,43 +393,44 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
|
||||
|
||||
interface core_external_interrupt_sources = plic.v_sources;
|
||||
|
||||
// ----------------
|
||||
// External interrupt [14] to go into Debug Mode
|
||||
|
||||
method Action debug_external_interrupt_req (Bool set_not_clear);
|
||||
proc.debug_external_interrupt_req (set_not_clear);
|
||||
endmethod
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Optional TV interface
|
||||
// Non-maskable interrupt request
|
||||
|
||||
`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
|
||||
method Action nmi_req (Bool set_not_clear);
|
||||
// TODO: fixup; passing const False for now
|
||||
proc.non_maskable_interrupt_req (False);
|
||||
endmethod
|
||||
|
||||
`ifdef RVFI_DII
|
||||
interface Toooba_RVFI_DII_Server rvfi_dii_server = proc.rvfi_dii_server;
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// ----------------------------------------------------------------
|
||||
// Optional DM interfaces
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// ----------------
|
||||
// DMI (Debug Module Interface) facing remote debugger
|
||||
|
||||
interface DMI dm_dmi = debug_module.dmi;
|
||||
interface DMI dmi = debug_module.dmi;
|
||||
|
||||
// ----------------
|
||||
// Facing Platform
|
||||
|
||||
// Non-Debug-Module Reset (reset all except DM)
|
||||
interface Get dm_ndm_reset_req_get = debug_module.get_ndm_reset_req;
|
||||
interface Client ndm_reset_client = debug_module.ndm_reset_client;
|
||||
`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
|
||||
@@ -531,12 +456,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
|
||||
@@ -561,9 +483,9 @@ module mkFabric_2x3 (Fabric_2x3_IFC);
|
||||
// Any addr is legal, and there is only one slave to service it.
|
||||
|
||||
function Tuple2 #(Bool, Slave_Num_2x3) fn_addr_to_slave_num_2x3 (Fabric_Addr addr);
|
||||
if ( (soc_map.m_near_mem_io_addr_base <= addr)
|
||||
&& (addr < soc_map.m_near_mem_io_addr_lim))
|
||||
return tuple2 (True, near_mem_io_slave_num);
|
||||
if ( (soc_map.m_mem0_controller_addr_base <= addr)
|
||||
&& (addr < soc_map.m_mem0_controller_addr_lim))
|
||||
return tuple2 (True, llc_slave_num);
|
||||
|
||||
else if ( (soc_map.m_plic_addr_base <= addr)
|
||||
&& (addr < soc_map.m_plic_addr_lim))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2018-2019 Bluespec, Inc. All Rights Reserved.
|
||||
// Copyright (c) 2018-2020 Bluespec, Inc. All Rights Reserved.
|
||||
|
||||
package CoreW_IFC;
|
||||
|
||||
@@ -6,9 +6,8 @@ package CoreW_IFC;
|
||||
// This package defines the interface of a CoreW module which
|
||||
// contains:
|
||||
// - mkProc (the RISC-V CPU; this a variant of MIT's RISCY-OOO mkProc)
|
||||
// Note: MIT's RISCY-OOO internally contains a 'mkCore'
|
||||
// and hence this interface and its module is called
|
||||
// 'CoreW', to disambiguate.
|
||||
// Note: MIT's RISCY-OOO internally has a 'mkCore' and hence this
|
||||
// interface and its module is called 'CoreW', to disambiguate.
|
||||
// - mkFabric_2x3
|
||||
// - mkNear_Mem_IO_AXI4
|
||||
// - mkPLIC_16_2_7
|
||||
@@ -32,10 +31,6 @@ 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
|
||||
@@ -44,22 +39,26 @@ import Debug_Module :: *;
|
||||
import Types :: *;
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
import ProcTypes :: *;
|
||||
import Trace_Data2 :: *;
|
||||
import TV_Info :: *;
|
||||
`endif
|
||||
|
||||
// ================================================================
|
||||
// The CoreW interface
|
||||
|
||||
interface CoreW_IFC #(numeric type t_n_interrupt_sources);
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Debugging: set core's verbosity, htif addrs
|
||||
// Debugging: set core's verbosity
|
||||
|
||||
method Action set_verbosity (Bit #(4) verbosity, Bit #(64) logdelay);
|
||||
|
||||
method Action set_htif_addrs (Bit #(64) tohost_addr, Bit #(64) fromhost_addr);
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Soft reset
|
||||
// Start
|
||||
|
||||
interface Server #(Bit #(0), Bit #(0)) cpu_reset_server;
|
||||
method Action start (Bit #(64) tohost_addr, Bit #(64) fromhost_addr);
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// AXI4 Fabric interfaces
|
||||
@@ -75,40 +74,41 @@ interface CoreW_IFC #(numeric type t_n_interrupt_sources);
|
||||
|
||||
interface Vector #(t_n_interrupt_sources, PLIC_Source_IFC) core_external_interrupt_sources;
|
||||
|
||||
// ----------------
|
||||
// External interrupt [14] to go into Debug Mode
|
||||
// ----------------------------------------------------------------
|
||||
// Non-maskable interrupt request
|
||||
|
||||
(* 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
|
||||
method Action nmi_req (Bool set_not_clear);
|
||||
|
||||
`ifdef RVFI_DII
|
||||
interface Toooba_RVFI_DII_Server rvfi_dii_server;
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// ----------------------------------------------------------------
|
||||
// Optional Debug Module interfaces
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// ----------------
|
||||
// DMI (Debug Module Interface) facing remote debugger
|
||||
|
||||
interface DMI dm_dmi;
|
||||
interface DMI dmi;
|
||||
|
||||
// ----------------
|
||||
// Facing Platform
|
||||
// Non-Debug-Module Reset (reset all except DM)
|
||||
|
||||
interface Get #(Bit #(0)) dm_ndm_reset_req_get;
|
||||
interface Client #(Bool, Bool) ndm_reset_client;
|
||||
`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
|
||||
|
||||
// ================================================================
|
||||
|
||||
@@ -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,26 +22,37 @@ 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 :: *;
|
||||
|
||||
// ================================================================
|
||||
|
||||
interface TV_Encode_IFC;
|
||||
method Action reset;
|
||||
// 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;
|
||||
|
||||
// This module receives Trace_Data structs from the CPU and Debug Module
|
||||
interface Put #(Trace_Data) trace_data_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 +60,58 @@ endinterface
|
||||
(* synthesize *)
|
||||
module mkTV_Encode (TV_Encode_IFC);
|
||||
|
||||
Reg #(Bool) rg_reset_done <- mkReg (True);
|
||||
Integer verbosity = 0; // For debugging
|
||||
|
||||
// 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;
|
||||
// Superscalar-wide inputs from CPU
|
||||
Vector #(SupSize, FIFOF #(Tuple2 #(Bit #(64), Trace_Data))) v_f_cpu_ins <- replicateM (mkFIFOF);
|
||||
Reg #(Bit #(64)) rg_serialnum <- mkReg (0);
|
||||
|
||||
// Input from Debug Module
|
||||
FIFOF #(Trace_Data) f_dm_in <- mkFIFOF;
|
||||
|
||||
// Merges CPU and Debug Module inputs
|
||||
FIFOF #(Trace_Data) f_merged <- mkFIFOF;
|
||||
|
||||
// Encoded output
|
||||
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); // Surprise: this gives no type-check error?
|
||||
let td = f_dm_in.first; f_dm_in.deq;
|
||||
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 (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 +123,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 (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 +141,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 (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 +159,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 (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 +177,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 (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 +210,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 (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 +228,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 (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 +251,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 (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 (csr_addr_fflags), td.word2);
|
||||
match { .n5, .vb5 } = encode_reg (fv_csr_regnum (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 (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 (csr_addr_fflags), td.word2);
|
||||
match { .n5, .vb5 } = encode_reg (fv_csr_regnum (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 (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 +330,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 (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 (csr_addr_mstatus), td.word4);
|
||||
match { .nN, .vbN } = encode_byte (te_op_end_group);
|
||||
|
||||
// Concatenate components into a single byte vec
|
||||
@@ -256,16 +352,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 (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 +380,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 (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 (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,20 +432,31 @@ 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 (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);
|
||||
match { .n1, .vb1 } = encode_pc (td.pc);
|
||||
match { .n2, .vb2 } = encode_instr (td.instr_sz, td.instr);
|
||||
match { .n3, .vb3 } = encode_reg (fv_gpr_regnum (td.rd), td.word1);
|
||||
match { .n4, .vb4 } = ((td.word2 == 0)
|
||||
? tuple2 (0, ?) // CSR was not written
|
||||
: encode_reg (fv_csr_regnum (truncate (td.word3)), td.word4));
|
||||
Bool csr_written = (td.word2 [0] == 1'b1);
|
||||
match { .n4, .vb4 } = (csr_written
|
||||
? encode_reg (fv_csr_regnum (truncate (td.word3)), td.word4)
|
||||
: tuple2 (0, ?));
|
||||
`ifdef ISA_F
|
||||
// MSTATUS.FS and .SD also updated if CSR instr wrote FFLAGS, FRM or FCSR
|
||||
Bool mstatus_written = (td.word2 [1] == 1'b1);
|
||||
match { .n5, .vb5 } = (mstatus_written
|
||||
? encode_reg (fv_csr_regnum (csr_addr_mstatus), td.word5)
|
||||
: tuple2 (0, ?));
|
||||
`endif
|
||||
match { .nN, .vbN } = encode_byte (te_op_end_group);
|
||||
|
||||
// Concatenate components into a single byte vec
|
||||
@@ -332,13 +465,18 @@ 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);
|
||||
`ifdef ISA_F
|
||||
match { .nn5, .x5 } = vsubst (nn4, x4, n5, vb5);
|
||||
match { .nnN, .xN } = vsubst (nn5, x5, nN, vbN);
|
||||
`else
|
||||
match { .nnN, .xN } = vsubst (nn4, x4, nN, vbN);
|
||||
`endif
|
||||
|
||||
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 (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 +525,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 (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 +570,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 (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 +592,15 @@ 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 ();
|
||||
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 +784,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 +878,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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2018-2019 Bluespec, Inc. All Rights Reserved.
|
||||
// Copyright (c) 2018-2020 Bluespec, Inc. All Rights Reserved.
|
||||
|
||||
package TV_Taps;
|
||||
|
||||
@@ -73,24 +73,35 @@ module mkDM_Mem_Tap (DM_Mem_Tap_IFC);
|
||||
master_xactor.i_wr_data.enq (wr_data);
|
||||
|
||||
// Tap
|
||||
Bit #(64) paddr = ?;
|
||||
Bit #(64) stval = ?;
|
||||
Bit #(64) paddr = ?;
|
||||
Bit #(64) stval = ?;
|
||||
Integer sh = 0;
|
||||
Fabric_Data mask = 0;
|
||||
MemReqSize sz = ?;
|
||||
|
||||
case (wr_data.wstrb)
|
||||
`ifdef FABRIC64
|
||||
if (wr_data.wstrb == 'h0f) begin
|
||||
paddr = zeroExtend (wr_addr.awaddr);
|
||||
stval = (wr_data.wdata & 'h_FFFF_FFFF);
|
||||
end
|
||||
else if (wr_data.wstrb == 'hf0) begin
|
||||
paddr = zeroExtend (wr_addr.awaddr);
|
||||
stval = ((wr_data.wdata >> 32) & 'h_FFFF_FFFF);
|
||||
end
|
||||
else
|
||||
dynamicAssert(False, "mkDM_Mem_Tap: unsupported byte enables");
|
||||
`else
|
||||
'hFF: begin sh= 0; mask = 'hFFFF_FFFF_FFFF_FFFF; sz=f3_SIZE_D; end
|
||||
'hF0: begin sh=32; mask = 'hFFFF_FFFF; sz=f3_SIZE_W; end
|
||||
'hC0: begin sh=48; mask = 'hFFFF; sz=f3_SIZE_H; end
|
||||
'h30: begin sh=32; mask = 'hFFFF; sz=f3_SIZE_H; end
|
||||
'h80: begin sh=56; mask = 'hFF; sz=f3_SIZE_B; end
|
||||
'h40: begin sh=48; mask = 'hFF; sz=f3_SIZE_B; end
|
||||
'h20: begin sh=40; mask = 'hFF; sz=f3_SIZE_B; end
|
||||
'h10: begin sh=32; mask = 'hFF; sz=f3_SIZE_B; end
|
||||
`endif
|
||||
'hF: begin sh= 0; mask = 'hFFFF_FFFF; sz=f3_SIZE_W; end
|
||||
'hC: begin sh=16; mask = 'hFFFF; sz=f3_SIZE_H; end
|
||||
'h3: begin sh= 0; mask = 'hFFFF; sz=f3_SIZE_H; end
|
||||
'h8: begin sh=24; mask = 'hFF; sz=f3_SIZE_B; end
|
||||
'h4: begin sh=16; mask = 'hFF; sz=f3_SIZE_B; end
|
||||
'h2: begin sh= 8; mask = 'hFF; sz=f3_SIZE_B; end
|
||||
'h1: begin sh= 0; mask = 'hFF; sz=f3_SIZE_B; end
|
||||
default: dynamicAssert(False, "mkDM_Mem_Tap: unsupported byte enables");
|
||||
endcase
|
||||
paddr = zeroExtend (wr_addr.awaddr);
|
||||
stval = zeroExtend (wr_data.wdata);
|
||||
`endif
|
||||
Trace_Data td = mkTrace_MEM_WRITE (f3_SIZE_W, truncate (stval), paddr);
|
||||
stval = ((zeroExtend (wr_data.wdata) >> sh) & mask);
|
||||
Trace_Data td = mkTrace_MEM_WRITE (sz, truncate (stval), paddr);
|
||||
f_trace_data.enq (td);
|
||||
endrule
|
||||
|
||||
|
||||
60
src_Core/Core/Trace_Data2.bsv
Normal file
60
src_Core/Core/Trace_Data2.bsv
Normal file
@@ -0,0 +1,60 @@
|
||||
// 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 {
|
||||
// TV message serial number
|
||||
Bit #(64) serial_num;
|
||||
|
||||
// For asynchronous CSR updates (e.g., MIP change on external interrupt)
|
||||
Maybe #(Tuple2 #(Bit #(12), Data)) maybe_csr_upd;
|
||||
|
||||
// Remaining fields relevant only if maybe_csr_upd is Invalid
|
||||
Addr pc;
|
||||
Bit #(32) orig_inst; // original 16b or 32b instruction ([1:0] will distinguish 16b or 32b)
|
||||
IType iType;
|
||||
Maybe#(ArchRIndx) dst; // Invalid, GPR or FPR destination ("Rd")
|
||||
Data dst_data;
|
||||
Data store_data; // For mem instrs that store data
|
||||
ByteEn store_data_BE;
|
||||
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
|
||||
Data mstatus; // For Fpu ops, since [MX] bit may have changed
|
||||
|
||||
// Trap updates
|
||||
Bit #(2) prv;
|
||||
Addr tvec;
|
||||
Data status;
|
||||
Data cause;
|
||||
Data epc;
|
||||
} Trace_Data2
|
||||
deriving (Bits, Eq, FShow);
|
||||
|
||||
// ================================================================
|
||||
|
||||
endpackage
|
||||
252
src_Core/Core/Trace_Data2_to_Trace_Data.bsv
Normal file
252
src_Core/Core/Trace_Data2_to_Trace_Data.bsv
Normal file
@@ -0,0 +1,252 @@
|
||||
// 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 (serial_num, 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;
|
||||
// From Toooba's CommitStage
|
||||
interface Put #(Trace_Data2) in;
|
||||
|
||||
// To Trace Encoder
|
||||
interface Get #(Tuple2 #(Bit #(64), Trace_Data)) out;
|
||||
endinterface
|
||||
|
||||
// ================================================================
|
||||
|
||||
(* synthesize *)
|
||||
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 -> (serial_num, Trace_Data)
|
||||
|
||||
function ActionValue #(Tuple2 #(Bit #(64), Trace_Data)) fav_td2_to_td (Trace_Data2 td2);
|
||||
actionvalue
|
||||
let serial_num = td2.serial_num;
|
||||
Trace_Data td = ?;
|
||||
ISize isize = ((td2.orig_inst [1:0] == 2'b11) ? ISIZE32BIT : ISIZE16BIT);
|
||||
Addr fall_thru_PC = td2.pc + ((td2.orig_inst [1:0] == 2'b11) ? 4 : 2);
|
||||
|
||||
Bit #(3) st_funct3 = (td2.store_data_BE [7] ? 3'b_011 // Doubleword
|
||||
: (td2.store_data_BE [3] ? 3'b_010 // Word
|
||||
: (td2.store_data_BE [1] ? 3'b_001 // HalfWord
|
||||
: 3'b000))); // Byte
|
||||
|
||||
Bit #(5) gpr_rd = 0;
|
||||
if (td2.dst matches tagged Valid (tagged Gpr .r)) gpr_rd = r;
|
||||
|
||||
if (serial_num == 0)
|
||||
td = mkTrace_RESET;
|
||||
|
||||
else if (td2.maybe_csr_upd matches tagged Valid { .csr_addr, .csr_value })
|
||||
td = mkTrace_CSR_WRITE (csr_addr, csr_value);
|
||||
|
||||
else if (isValid (td2.trap))
|
||||
td = mkTrace_TRAP (td2.tvec,
|
||||
isize,
|
||||
td2.orig_inst,
|
||||
td2.prv,
|
||||
td2.status,
|
||||
td2.cause,
|
||||
td2.epc,
|
||||
td2.tval);
|
||||
|
||||
else if (td2.ppc_vaddr_csrData matches tagged PPC .target_addr
|
||||
&&& (td2.iType == Br))
|
||||
td = mkTrace_OTHER (target_addr, isize, td2.orig_inst);
|
||||
|
||||
else if (td2.ppc_vaddr_csrData matches tagged PPC .target_addr
|
||||
&&& ( (td2.iType == J)
|
||||
|| (td2.iType == Jr)))
|
||||
td = mkTrace_I_RD (target_addr,
|
||||
isize,
|
||||
td2.orig_inst,
|
||||
gpr_rd,
|
||||
td2.dst_data); // return-pc
|
||||
|
||||
else if ( (td2.iType == Alu)
|
||||
|| (td2.iType == Auipc))
|
||||
td = mkTrace_I_RD (fall_thru_PC,
|
||||
isize,
|
||||
td2.orig_inst,
|
||||
gpr_rd,
|
||||
td2.dst_data); // rd_val
|
||||
|
||||
else if (td2.dst matches tagged Valid (tagged Fpu .fpr_rd)
|
||||
&&& (td2.iType == Fpu))
|
||||
td = mkTrace_F_FRD (fall_thru_PC,
|
||||
isize,
|
||||
td2.orig_inst,
|
||||
fpr_rd,
|
||||
td2.dst_data, // rdval
|
||||
td2.fflags,
|
||||
td2.mstatus); // [FX] updated
|
||||
|
||||
else if (td2.iType == Fpu)
|
||||
td = mkTrace_F_GRD (fall_thru_PC,
|
||||
isize,
|
||||
td2.orig_inst,
|
||||
gpr_rd,
|
||||
td2.dst_data, // rdval
|
||||
td2.fflags,
|
||||
td2.mstatus); // [FX] updated
|
||||
|
||||
else if (td2.ppc_vaddr_csrData matches tagged VAddr .eaddr
|
||||
&&& td2.dst matches tagged Valid (tagged Fpu .fpr_rd)
|
||||
&&& (td2.iType == Ld))
|
||||
td = mkTrace_F_LOAD (fall_thru_PC,
|
||||
isize,
|
||||
td2.orig_inst,
|
||||
fpr_rd,
|
||||
td2.dst_data, // rd_val
|
||||
eaddr,
|
||||
td2.mstatus);
|
||||
|
||||
else if (td2.ppc_vaddr_csrData matches tagged VAddr .eaddr
|
||||
&&& (td2.iType == Ld))
|
||||
td = mkTrace_I_LOAD (fall_thru_PC,
|
||||
isize,
|
||||
td2.orig_inst,
|
||||
gpr_rd,
|
||||
td2.dst_data, // rd_val
|
||||
eaddr);
|
||||
|
||||
else if (td2.ppc_vaddr_csrData matches tagged VAddr .eaddr
|
||||
&&& (td2.iType == St))
|
||||
td = mkTrace_I_STORE (fall_thru_PC,
|
||||
st_funct3,
|
||||
isize,
|
||||
td2.orig_inst,
|
||||
td2.store_data, // rs2_val
|
||||
eaddr);
|
||||
|
||||
else if (td2.ppc_vaddr_csrData matches tagged CSRData .csr_data
|
||||
&&& (td2.iType == Csr))
|
||||
begin
|
||||
Bit #(3) funct3 = td2.orig_inst [14:12];
|
||||
Bit #(5) rs1_or_imm = td2.orig_inst [19:15];
|
||||
Bool csr_valid = False;
|
||||
CSR_Addr csr_addr = 0;
|
||||
if (td2.csr matches tagged Valid .c) begin
|
||||
csr_addr = pack (c);
|
||||
csr_valid = ( (funct3 [1:0] == 2'b01) // CSRRW, CSRRWI
|
||||
|| ( ( (funct3 [1:0] == 2'b10) // CSRRS, CSRRSI
|
||||
|| (funct3 [1:0] == 2'b11)) // CSRRC, CSRRCI
|
||||
&& (rs1_or_imm != 0)));
|
||||
end
|
||||
td = mkTrace_CSRRX (fall_thru_PC,
|
||||
isize,
|
||||
td2.orig_inst,
|
||||
gpr_rd,
|
||||
td2.dst_data, // rdval
|
||||
csr_valid,
|
||||
csr_addr,
|
||||
csr_data,
|
||||
// For CSR writes to FFLAGS/FRM/FCSR, also changes MSTATUS
|
||||
td2.will_dirty_fpu_state,
|
||||
td2.mstatus);
|
||||
end
|
||||
|
||||
else if ( (td2.iType == Mret)
|
||||
|| (td2.iType == Sret))
|
||||
td = mkTrace_RET (td2.pc, isize, td2.orig_inst, td2.prv, td2.status);
|
||||
|
||||
else if ( (td2.iType == Fence)
|
||||
|| (td2.iType == FenceI)
|
||||
|| (td2.iType == SFence)
|
||||
|| (td2.iType == Ecall) // Handled by TRAP above?
|
||||
|| (td2.iType == Ebreak)) // Handled by TRAP above?
|
||||
td = mkTrace_OTHER (fall_thru_PC, isize, td2.orig_inst);
|
||||
|
||||
else if (td2.ppc_vaddr_csrData matches tagged VAddr .eaddr
|
||||
&&& ( (td2.iType == Amo)
|
||||
|| (td2.iType == Lr)
|
||||
|| (td2.iType == Sc)))
|
||||
td = mkTrace_AMO (fall_thru_PC,
|
||||
st_funct3,
|
||||
isize,
|
||||
td2.orig_inst,
|
||||
gpr_rd,
|
||||
td2.dst_data, // rd_val
|
||||
td2.store_data, // rs2_val
|
||||
eaddr);
|
||||
|
||||
else if ( (td2.iType == Unsupported)
|
||||
|| (td2.iType == Nop)
|
||||
|| (td2.iType == Interrupt))
|
||||
td = mkTrace_OTHER (fall_thru_PC, isize, td2.orig_inst);
|
||||
|
||||
else begin
|
||||
if (verbosity > 0) begin
|
||||
$display (" fav_td2_to_td: TBD: Unknown iType: Using mkTrace_OTHER for now");
|
||||
$display (" ", fshow (td2));
|
||||
end
|
||||
td = mkTrace_OTHER (fall_thru_PC, isize, td2.orig_inst);
|
||||
end
|
||||
return tuple2 (serial_num, td);
|
||||
endactionvalue
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
// RULES
|
||||
|
||||
rule rl_td2_to_td;
|
||||
Trace_Data2 td2 <- pop (f_in);
|
||||
|
||||
if (verbosity > 1)
|
||||
$display ("%0d: %m.rl_td2_to_td: serial_num:%0d PC:0x%0h instr:0x%08h",
|
||||
cur_cycle, td2.serial_num, td2.pc, td2.orig_inst,
|
||||
" iType:", fshow (td2.iType));
|
||||
|
||||
match { .serial_num, .td } <- fav_td2_to_td (td2);
|
||||
f_out.enq (tuple2 (serial_num, td));
|
||||
endrule
|
||||
|
||||
// ================================================================
|
||||
// INTERFACE
|
||||
|
||||
interface in = toPut (f_in);
|
||||
interface out = toGet (f_out);
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
|
||||
endpackage
|
||||
Reference in New Issue
Block a user