Fixed up logic for "Non-Debug-Module reset" request/response from the Debug Module
Now able to run multiple ISA tests in a single simulation run connected to remote debugger DSharp, using either hart_reset or ndm_reset between tests to bring the system back into reset state. All Debug Module commands working: - dm_reset, hart_reset, ndm_reset - break (set breakpoint) - step - continue (until breakpoint of 'halt' command) - halt - read/write GPR, FPR, CSR, memory - elf_load
This commit is contained in:
@@ -136,9 +136,6 @@ interface CoreRenameDebug;
|
||||
endinterface
|
||||
|
||||
interface Core;
|
||||
// Initialize
|
||||
interface Server #(Bit #(0), Bit #(0)) init_server;
|
||||
|
||||
// core request & indication
|
||||
interface CoreReq coreReq;
|
||||
interface CoreIndInv coreIndInv;
|
||||
@@ -206,13 +203,6 @@ module mkCore#(CoreId coreId)(Core);
|
||||
// ================================================================
|
||||
Integer verbosity = 0; // More levels of verbosity control than 'Bool verbose'
|
||||
|
||||
// ----------------
|
||||
// Init requests and responses
|
||||
|
||||
FIFOF #(Bit #(0)) f_init_reqs <- mkFIFOF;
|
||||
FIFOF #(Bit #(0)) f_init_rsps <- mkFIFOF;
|
||||
|
||||
|
||||
Reg#(Bool) outOfReset <- mkReg(False);
|
||||
rule rl_outOfReset if (!outOfReset);
|
||||
$fwrite(stderr, "mkProc came out of reset\n");
|
||||
@@ -1297,28 +1287,9 @@ module mkCore#(CoreId coreId)(Core);
|
||||
// ================================================================
|
||||
`endif
|
||||
|
||||
// ================================================================
|
||||
// Init interface
|
||||
|
||||
rule rl_init;
|
||||
let tok <- pop (f_init_reqs);
|
||||
|
||||
csrf.init;
|
||||
started <= False;
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
rg_core_run_state <= CORE_RUNNING;
|
||||
`endif
|
||||
|
||||
f_init_rsps.enq (tok);
|
||||
endrule
|
||||
|
||||
// ================================================================
|
||||
// INTERFACE
|
||||
|
||||
// Initialize
|
||||
interface init_server = toGPServer (f_init_reqs, f_init_rsps);
|
||||
|
||||
interface CoreReq coreReq;
|
||||
method Action start(
|
||||
Bit#(64) startpc,
|
||||
@@ -1330,7 +1301,7 @@ module mkCore#(CoreId coreId)(Core);
|
||||
rg_core_run_state <= CORE_RUNNING;
|
||||
`endif
|
||||
mmio.setHtifAddrs(toHostAddr, fromHostAddr);
|
||||
// start rename debug
|
||||
|
||||
commitStage.startRenameDebug;
|
||||
endmethod
|
||||
|
||||
|
||||
@@ -49,9 +49,6 @@ import SoC_Map :: *;
|
||||
// ================================================================
|
||||
|
||||
interface CsrFile;
|
||||
// Initialize to platform-level reset spec
|
||||
method Action init;
|
||||
|
||||
// Read
|
||||
method Data rd(CSR csr);
|
||||
// normal write by CSRXXX inst to any CSR
|
||||
@@ -672,28 +669,6 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
// ================================================================
|
||||
// INTERFACE
|
||||
|
||||
method Action init;
|
||||
// Note: we initialize only certain CSRs (platform-level spec)
|
||||
// Current privilege
|
||||
prv_reg <= prvM;
|
||||
|
||||
// Machine-level CSRs
|
||||
mstatus_csr <= 0;
|
||||
mie_csr <= 0;
|
||||
mip_csr <= 0;
|
||||
minstret_csr <= 0;
|
||||
mcycle_csr <= 0;
|
||||
|
||||
// User-level CSRs
|
||||
time_reg <= 0;
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// Debug Module CSRs
|
||||
rg_dcsr <= zeroExtend (dcsr_reset_value);
|
||||
rg_dpc <= truncate (soc_map_struct.pc_reset_value);
|
||||
`endif
|
||||
endmethod
|
||||
|
||||
method Data rd(CSR csr);
|
||||
return get_csr(csr)._read;
|
||||
endmethod
|
||||
|
||||
@@ -107,8 +107,7 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
|
||||
awregion: fabric_default_region,
|
||||
awuser: fabric_default_user};
|
||||
|
||||
let mem_req_wr_data = AXI4_Wr_Data {wid: fabric_default_id,
|
||||
wdata: st_val,
|
||||
let mem_req_wr_data = AXI4_Wr_Data {wdata: st_val,
|
||||
wstrb: strb,
|
||||
wlast: True,
|
||||
wuser: fabric_default_user};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright (c) 2018 Massachusetts Institute of Technology
|
||||
// Portions (c) 2019-2020 Bluespec, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
@@ -21,8 +22,6 @@
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
// Portions (c) 2019 Bluespec, Inc.
|
||||
|
||||
// This file is adapted from: MIT-riscy/riscy-OOO/procs/lib/MMIOPlatform.bsv
|
||||
// Modifications to fit into Bluespec's RISC-V execution environments.
|
||||
|
||||
|
||||
@@ -108,8 +108,7 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
|
||||
awregion: fabric_default_region,
|
||||
awuser: fabric_default_user};
|
||||
|
||||
let mem_req_wr_data = AXI4_Wr_Data {wid: fabric_default_id,
|
||||
wdata: st_val,
|
||||
let mem_req_wr_data = AXI4_Wr_Data {wdata: st_val,
|
||||
wstrb: strb,
|
||||
wlast: True,
|
||||
wuser: fabric_default_user};
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package Proc;
|
||||
|
||||
// Note: this module corresponds to module 'mkCPU' in Piccolo/Flute.
|
||||
|
||||
// Copyright (c) 2018 Massachusetts Institute of Technology
|
||||
// Portions Copyright (c) 2019-2020 Bluespec, Inc.
|
||||
//
|
||||
@@ -103,12 +105,6 @@ module mkProc (Proc_IFC);
|
||||
// Verbosity: 0=quiet; 1=instruction trace; 2=more detail
|
||||
Reg #(Bit #(4)) cfg_verbosity <- mkConfigReg (0);
|
||||
|
||||
// ----------------
|
||||
// Init requests and responses
|
||||
|
||||
FIFOF #(Bit #(0)) f_init_reqs <- mkFIFOF;
|
||||
FIFOF #(Bit #(0)) f_init_rsps <- mkFIFOF;
|
||||
|
||||
// ----------------
|
||||
// MMIO
|
||||
|
||||
@@ -201,25 +197,6 @@ module mkProc (Proc_IFC);
|
||||
end
|
||||
|
||||
// ================================================================
|
||||
// Init
|
||||
|
||||
rule rl_init_start;
|
||||
let x <- pop (f_init_reqs);
|
||||
|
||||
llc_axi4_adapter.reset;
|
||||
mmio_axi4_adapter.reset;
|
||||
for (Integer j = 0; j < valueof(CoreNum); j = j+1)
|
||||
core [j].init_server.request.put (?);
|
||||
endrule
|
||||
|
||||
rule rl_init_finish;
|
||||
for (Integer j = 0; j < valueof(CoreNum); j = j+1)
|
||||
let tok <- core [j].init_server.response.get;
|
||||
|
||||
f_init_rsps.enq (?);
|
||||
endrule
|
||||
|
||||
// ----------------
|
||||
// Termination detection
|
||||
|
||||
for(Integer i = 0; i < valueof(CoreNum); i = i+1) begin
|
||||
@@ -229,7 +206,9 @@ module mkProc (Proc_IFC);
|
||||
endrule
|
||||
end
|
||||
|
||||
// ================================================================
|
||||
// Print out values written 'tohost'
|
||||
|
||||
rule rl_tohost;
|
||||
let x <- mmioPlatform.to_host;
|
||||
$display ("%0d: mmioPlatform.rl_tohost: 0x%0x (= %0d)", cur_cycle, x, x);
|
||||
@@ -251,11 +230,9 @@ module mkProc (Proc_IFC);
|
||||
// ================================================================
|
||||
// INTERFACE
|
||||
|
||||
// Reset
|
||||
interface Server init_server = toGPServer (f_init_reqs, f_init_rsps);
|
||||
|
||||
// ----------------
|
||||
// Start the cores running
|
||||
// Use toHostAddr = 0 if not monitoring tohost
|
||||
method Action start (Addr startpc, Addr tohostAddr, Addr fromhostAddr);
|
||||
action
|
||||
for(Integer i = 0; i < valueof(CoreNum); i = i+1)
|
||||
@@ -264,8 +241,8 @@ module mkProc (Proc_IFC);
|
||||
|
||||
mmioPlatform.start (tohostAddr, fromhostAddr);
|
||||
|
||||
$display ("Proc.start: startpc = 0x%0h, tohostAddr = 0x%0h, fromhostAddr = %0h",
|
||||
startpc, tohostAddr, fromhostAddr);
|
||||
$display ("%0d: %m.method start: startpc %0h, tohostAddr %0h, fromhostAddr %0h",
|
||||
cur_cycle, startpc, tohostAddr, fromhostAddr);
|
||||
endmethod
|
||||
|
||||
// ----------------
|
||||
@@ -312,18 +289,19 @@ module mkProc (Proc_IFC);
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// run/halt, gpr, mem and csr control goes to core
|
||||
interface Server hart0_run_halt_server = core [0].hart0_run_halt_server;
|
||||
|
||||
interface Put hart0_put_other_req;
|
||||
method Action put (Bit #(4) req);
|
||||
cfg_verbosity <= req;
|
||||
endmethod
|
||||
endinterface
|
||||
|
||||
interface Server hart0_gpr_mem_server = core[0].hart0_gpr_mem_server;
|
||||
`ifdef ISA_F
|
||||
interface Server hart0_fpr_mem_server = core[0].hart0_fpr_mem_server;
|
||||
`endif
|
||||
interface Server hart0_csr_mem_server = core[0].hart0_csr_mem_server;
|
||||
|
||||
// We don't implement 'other' functionality
|
||||
interface Put hart0_put_other_req;
|
||||
method Action put (Bit #(4) req);
|
||||
cfg_verbosity <= req;
|
||||
endmethod
|
||||
endinterface
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2019 Bluespec, Inc. All Rights Reserved
|
||||
// Copyright (c) 2016-2020 Bluespec, Inc. All Rights Reserved
|
||||
|
||||
package Proc_IFC;
|
||||
|
||||
@@ -34,11 +34,10 @@ import Trace_Data2 :: *;
|
||||
// because the RISCY-OOO mkProc contains those elements.
|
||||
|
||||
interface Proc_IFC;
|
||||
// Init
|
||||
interface Server #(Token, Token) init_server;
|
||||
|
||||
// ----------------
|
||||
// Start the cores running
|
||||
// Use toHostAddr = 0 if not monitoring tohost
|
||||
method Action start (Addr startpc, Addr tohostAddr, Addr fromhostAddr);
|
||||
|
||||
// ----------------
|
||||
|
||||
@@ -91,7 +91,53 @@ 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));
|
||||
|
||||
// ================================================================
|
||||
// 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;
|
||||
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
|
||||
|
||||
// ================================================================
|
||||
// STATE
|
||||
@@ -100,7 +146,8 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
|
||||
SoC_Map_IFC soc_map <- mkSoC_Map;
|
||||
|
||||
// RISCY-OOO processor
|
||||
Proc_IFC proc <- mkProc;
|
||||
// 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;
|
||||
@@ -108,13 +155,9 @@ 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;
|
||||
Debug_Module_IFC debug_module <- mkDebug_Module (reset_by dm_power_on_reset);
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
@@ -127,97 +170,37 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
|
||||
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);
|
||||
|
||||
// ================================================================
|
||||
// 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.
|
||||
|
||||
// TODO (multicore): currently the incoming 'init' token is from
|
||||
// Debug Module's hart0_get_reset_req, but when we call
|
||||
// proc.init_server here, we are resetting all the cores, i.e., all
|
||||
// the harts. Needs to be cleaned up.
|
||||
|
||||
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);
|
||||
|
||||
proc.init_server.request.put (?); // CPU
|
||||
plic.server_reset.request.put (?); // PLIC
|
||||
fabric_2x3.reset; // Local 2x3 Fabric
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
tv_encode.reset;
|
||||
`endif
|
||||
// Hart-reset from DM
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// Remember the requestor, so we can respond to it
|
||||
f_reset_requestor.enq (reset_requestor_soc);
|
||||
`endif
|
||||
$display ("%0d: Core.rl_cpu_hart0_reset_from_soc_start (requestor %0d)", cur_cycle, reset_requestor_soc);
|
||||
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
|
||||
// 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.init_server.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 (requestor %0d)", cur_cycle, reset_requestor_dm);
|
||||
endrule
|
||||
`endif
|
||||
|
||||
FIFOF #(Bit #(0)) f_proc_start <- mkFIFOF;
|
||||
|
||||
rule rl_cpu_hart0_reset_complete;
|
||||
let rsp1 <- proc.init_server.response.get; // CPU
|
||||
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
|
||||
requestor <- pop (f_reset_requestor);
|
||||
`endif
|
||||
if (requestor == reset_requestor_soc)
|
||||
f_reset_rsps.enq (?);
|
||||
|
||||
// Start running the cores
|
||||
f_proc_start.enq (?);
|
||||
|
||||
$display ("%0d: Core.rl_cpu_hart0_reset_complete; starting proc", cur_cycle);
|
||||
endrule
|
||||
|
||||
rule rl_cpu_hart0_reset_proc_start;
|
||||
let x <- pop (f_proc_start);
|
||||
proc.start (soc_map_struct.pc_reset_value,
|
||||
rg_tohost_addr,
|
||||
rg_fromhost_addr);
|
||||
$display ("%0d: Core.rl_cpu_hart0_reset_proc_start; 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
|
||||
// ================================================================
|
||||
@@ -359,13 +342,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
|
||||
|
||||
@@ -377,16 +353,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 %0d, 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
|
||||
|
||||
@@ -401,6 +387,14 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
|
||||
|
||||
interface core_external_interrupt_sources = plic.v_sources;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Non-maskable interrupt request
|
||||
|
||||
method Action nmi_req (Bool set_not_clear);
|
||||
// TODO: fixup; passing const False for now
|
||||
proc.non_maskable_interrupt_req (False);
|
||||
endmethod
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// ----------------------------------------------------------------
|
||||
// Optional DM interfaces
|
||||
@@ -408,13 +402,13 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
|
||||
// ----------------
|
||||
// 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
|
||||
|
||||
@@ -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
|
||||
@@ -48,16 +47,14 @@ import TV_Info :: *;
|
||||
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
|
||||
@@ -73,6 +70,12 @@ interface CoreW_IFC #(numeric type t_n_interrupt_sources);
|
||||
|
||||
interface Vector #(t_n_interrupt_sources, PLIC_Source_IFC) core_external_interrupt_sources;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Non-maskable interrupt request
|
||||
|
||||
(* always_ready, always_enabled *)
|
||||
method Action nmi_req (Bool set_not_clear);
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// ----------------------------------------------------------------
|
||||
// Optional Debug Module interfaces
|
||||
@@ -80,13 +83,13 @@ interface CoreW_IFC #(numeric type t_n_interrupt_sources);
|
||||
// ----------------
|
||||
// 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
|
||||
|
||||
@@ -58,18 +58,18 @@ module mkDM_Abstract_Commands (DM_Abstract_Commands_IFC);
|
||||
Reg #(Bool) rg_start_reg_access <- mkReg (False);
|
||||
|
||||
// FIFOs for request/response to access GPRs
|
||||
FIFOF #(DM_CPU_Req #(5, XLEN)) f_hart0_gpr_reqs <- mkFIFOF1;
|
||||
FIFOF #(DM_CPU_Rsp #(XLEN)) f_hart0_gpr_rsps <- mkFIFOF1;
|
||||
FIFOF #(DM_CPU_Req #(5, XLEN)) f_hart0_gpr_reqs <- mkFIFOF;
|
||||
FIFOF #(DM_CPU_Rsp #(XLEN)) f_hart0_gpr_rsps <- mkFIFOF;
|
||||
|
||||
// FIFOs for request/response to access FPRs
|
||||
`ifdef ISA_F
|
||||
FIFOF #(DM_CPU_Req #(5, FLEN)) f_hart0_fpr_reqs <- mkFIFOF1;
|
||||
FIFOF #(DM_CPU_Rsp #(FLEN)) f_hart0_fpr_rsps <- mkFIFOF1;
|
||||
FIFOF #(DM_CPU_Req #(5, FLEN)) f_hart0_fpr_reqs <- mkFIFOF;
|
||||
FIFOF #(DM_CPU_Rsp #(FLEN)) f_hart0_fpr_rsps <- mkFIFOF;
|
||||
`endif
|
||||
|
||||
// FIFOs for request/response to access CSRs
|
||||
FIFOF #(DM_CPU_Req #(12, XLEN)) f_hart0_csr_reqs <- mkFIFOF1;
|
||||
FIFOF #(DM_CPU_Rsp #(XLEN)) f_hart0_csr_rsps <- mkFIFOF1;
|
||||
FIFOF #(DM_CPU_Req #(12, XLEN)) f_hart0_csr_reqs <- mkFIFOF;
|
||||
FIFOF #(DM_CPU_Rsp #(XLEN)) f_hart0_csr_rsps <- mkFIFOF;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// rg_data0
|
||||
@@ -89,15 +89,18 @@ module mkDM_Abstract_Commands (DM_Abstract_Commands_IFC);
|
||||
Reg #(Bool) rg_abstractcs_busy <- mkRegU;
|
||||
Reg #(DM_abstractcs_cmderr) rg_abstractcs_cmderr <- mkRegU;
|
||||
|
||||
Bit #(5) abstractcs_progsize = 0;
|
||||
Bit #(5) abstractcs_datacount = 0;
|
||||
// Size of program buffer, in 32b words
|
||||
Bit #(5) abstractcs_progbufsize = 0;
|
||||
// Number of data registers implemented (rg_data0, rg_data1)
|
||||
Bit #(4) abstractcs_datacount = ((xlen == 32) ? 1 : 2);
|
||||
|
||||
DM_Word virt_rg_abstractcs = {3'b0,
|
||||
abstractcs_progsize,
|
||||
abstractcs_progbufsize,
|
||||
11'b0,
|
||||
pack (rg_abstractcs_busy),
|
||||
1'b0,
|
||||
pack (rg_abstractcs_cmderr),
|
||||
3'b0,
|
||||
4'b0,
|
||||
abstractcs_datacount};
|
||||
|
||||
function Action fa_rg_abstractcs_write (DM_Word dm_word);
|
||||
|
||||
@@ -9,9 +9,15 @@ package DM_Run_Control;
|
||||
// ================================================================
|
||||
// BSV library imports
|
||||
|
||||
import FIFOF :: *;
|
||||
import GetPut :: *;
|
||||
import ClientServer :: *;
|
||||
import FIFOF :: *;
|
||||
import GetPut :: *;
|
||||
import ClientServer :: *;
|
||||
|
||||
// ----------------
|
||||
// Other library imports
|
||||
|
||||
import Cur_Cycle :: *;
|
||||
import GetPut_Aux :: *;
|
||||
|
||||
// ================================================================
|
||||
// Project imports
|
||||
@@ -33,13 +39,14 @@ interface DM_Run_Control_IFC;
|
||||
|
||||
// ----------------
|
||||
// Facing a hart: reset and run-control
|
||||
interface Get #(Token) hart0_get_reset_req;
|
||||
interface Client #(Bool, Bool) hart0_reset_client;
|
||||
interface Client #(Bool, Bool) hart0_client_run_halt;
|
||||
interface Get #(Bit #(4)) hart0_get_other_req;
|
||||
|
||||
// ----------------
|
||||
// Facing Platform: Non-Debug-Module Reset (reset all except DM)
|
||||
interface Get #(Token) get_ndm_reset_req;
|
||||
// Bool indicates 'running' hart state.
|
||||
interface Client #(Bool, Bool) ndm_reset_client;
|
||||
endinterface
|
||||
|
||||
// ================================================================
|
||||
@@ -52,7 +59,8 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
|
||||
// ----------------------------------------------------------------
|
||||
// NDM Reset
|
||||
|
||||
FIFOF #(Token) f_ndm_reset_reqs <- mkFIFOF;
|
||||
FIFOF #(Bool) f_ndm_reset_reqs <- mkFIFOF;
|
||||
FIFOF #(Bool) f_ndm_reset_rsps <- mkFIFOF;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Hart0 run control
|
||||
@@ -60,7 +68,8 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
|
||||
Reg #(Bool) rg_hart0_running <- mkRegU;
|
||||
|
||||
// Reset requests to hart
|
||||
FIFOF #(Token) f_hart0_reset_reqs <- mkFIFOF;
|
||||
FIFOF #(Bool) f_hart0_reset_reqs <- mkFIFOF;
|
||||
FIFOF #(Bool) f_hart0_reset_rsps <- mkFIFOF;
|
||||
|
||||
// Run/halt requests to hart and responses
|
||||
FIFOF #(Bool) f_hart0_run_halt_reqs <- mkFIFOF;
|
||||
@@ -81,7 +90,13 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
|
||||
// 'anyXX' = 'allXX'
|
||||
// 'allrunning' = NOT 'allhalted'
|
||||
|
||||
Reg#(Bool) rg_dmstatus_allresumeack <- mkRegU;
|
||||
Bool dmstatus_impebreak = False;
|
||||
|
||||
Reg #(Bool) rg_hart0_hasreset <- mkRegU;
|
||||
Bool dmstatus_allhavereset = rg_hart0_hasreset;
|
||||
Bool dmstatus_anyhavereset = rg_hart0_hasreset;
|
||||
|
||||
Reg #(Bool) rg_dmstatus_allresumeack <- mkRegU;
|
||||
|
||||
Bool dmstatus_allresumeack = rg_dmstatus_allresumeack;
|
||||
Bool dmstatus_anyresumeack = rg_dmstatus_allresumeack;
|
||||
@@ -89,8 +104,9 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
|
||||
Bool dmstatus_allnonexistent = False;
|
||||
Bool dmstatus_anynonexistent = dmstatus_allnonexistent;
|
||||
|
||||
Bool dmstatus_allunavail = False;
|
||||
Bool dmstatus_anyunavail = dmstatus_allunavail;
|
||||
Reg #(Bool) rg_dmstatus_allunavail <- mkReg (False);
|
||||
Bool dmstatus_allunavail = rg_dmstatus_allunavail;
|
||||
Bool dmstatus_anyunavail = rg_dmstatus_allunavail;
|
||||
|
||||
Bool dmstatus_allrunning = rg_hart0_running;
|
||||
Bool dmstatus_anyrunning = dmstatus_allrunning;
|
||||
@@ -98,7 +114,11 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
|
||||
Bool dmstatus_allhalted = (! rg_hart0_running);
|
||||
Bool dmstatus_anyhalted = dmstatus_allhalted;
|
||||
|
||||
DM_Word virt_rg_dmstatus = {14'b0,
|
||||
DM_Word virt_rg_dmstatus = {9'b0,
|
||||
pack (dmstatus_impebreak),
|
||||
2'b0,
|
||||
pack (dmstatus_allhavereset),
|
||||
pack (dmstatus_anyhavereset),
|
||||
pack (dmstatus_allresumeack),
|
||||
pack (dmstatus_anyresumeack),
|
||||
pack (dmstatus_allnonexistent),
|
||||
@@ -151,19 +171,17 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
|
||||
// Debug Module reset
|
||||
if (! dmactive) begin
|
||||
// Reset the DM module itself
|
||||
$display ("DM_Run_Control.write: dmcontrol 0x%08h (dmactive=0): resetting Debug Module",
|
||||
dm_word);
|
||||
$display ("%0d: %m.dmcontrol_write 0x%08h (dmactive=0): resetting Debug Module",
|
||||
cur_cycle, dm_word);
|
||||
|
||||
// Error-checking
|
||||
if (ndmreset) begin
|
||||
$display ("DM_Run_Control.write: WARNING: in word written to dmcontrol (0x%08h):",
|
||||
dm_word);
|
||||
$display (" WARNING: DM_Run_Control: dmcontrol_write 0x%08h:", dm_word);
|
||||
$display (" [1] (ndmreset) and [0] (dmactive) both asserted");
|
||||
$display (" dmactive has priority; ignoring ndmreset");
|
||||
end
|
||||
if (hartreset) begin
|
||||
$display ("DM_Run_Control.write: WARNING: in word written to dmcontrol (0x%08h):",
|
||||
dm_word);
|
||||
$display (" WARNING: DM_Run_Control: dmcontrol_write 0x%08h:", dm_word);
|
||||
$display (" [29] (hartreset) and [0] (dmactive) both asserted");
|
||||
$display (" dmactive has priority; ignoring hartreset");
|
||||
end
|
||||
@@ -172,63 +190,84 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
|
||||
noAction;
|
||||
end
|
||||
|
||||
// Platform reset (non-Debug Module)
|
||||
else if (ndmreset) begin
|
||||
$display ("DM_Run_Control.write: dmcontrol 0x%08h: ndmreset=1: resetting platform",
|
||||
dm_word);
|
||||
f_ndm_reset_reqs.enq (?);
|
||||
rg_hart0_running <= True; // Must be same as run/halt state of CPU after hart_reset!
|
||||
// Ignore if NDM reset is in progress
|
||||
else if (rg_dmstatus_allunavail) begin
|
||||
$display ("%0d: %m.dmcontrol_write 0x%0h: ndm reset in progress; ignoring this write",
|
||||
cur_cycle, dm_word);
|
||||
end
|
||||
|
||||
// Non-Debug-Module reset (platform reset) posedge: ignore
|
||||
else if ((! rg_dmcontrol_ndmreset) && ndmreset) begin
|
||||
if (verbosity != 0)
|
||||
$display ("%0d: %m.dmcontrol_write 0x%08h: ndmreset: 0->1: ignoring",
|
||||
cur_cycle, dm_word);
|
||||
end
|
||||
|
||||
// Non-Debug-Module reset (platform reset) negedge: do it
|
||||
else if (rg_dmcontrol_ndmreset && (! ndmreset)) begin
|
||||
Bool running = (! haltreq);
|
||||
if (verbosity != 0) begin
|
||||
$display ("%0d: %m.dmcontrol_write 0x%08h: ndmreset: 1->0: resetting platform",
|
||||
cur_cycle, dm_word);
|
||||
$display (" Requested 'running' state = ", fshow (running));
|
||||
end
|
||||
|
||||
f_ndm_reset_reqs.enq (running);
|
||||
rg_dmstatus_allunavail <= True;
|
||||
|
||||
// Error-checking
|
||||
if (hartreset) begin
|
||||
$display ("DM_Run_Control.write: WARNING: in word written to dmcontrol (0x%08h):",
|
||||
dm_word);
|
||||
$display (" Both ndmreset (bit 1) and hartreset (bit 29) are asserted");
|
||||
$display (" WARNING: %m.dmcontrol_write 0x%08h:", dm_word);
|
||||
$display (" Both ndmreset [1] and hartreset [29] are asserted");
|
||||
$display (" ndmreset has priority; ignoring hartreset");
|
||||
end
|
||||
|
||||
end
|
||||
else begin
|
||||
|
||||
// Hart reset
|
||||
else if (hartreset) begin
|
||||
Bool running = (! haltreq);
|
||||
f_hart0_reset_reqs.enq (running);
|
||||
rg_hart0_hasreset <= True;
|
||||
|
||||
// Deassert platform reset
|
||||
if ((verbosity != 0) && rg_dmcontrol_ndmreset)
|
||||
$display ("DM_Run_Control.write: dmcontrol 0x%08h: clearing ndmreset", dm_word);
|
||||
|
||||
// Hart reset
|
||||
if (hartreset) begin
|
||||
if (verbosity != 0)
|
||||
$display ("DM_Run_Control.write: dmcontrol 0x%08h: hartreset=1: resetting hart",
|
||||
dm_word);
|
||||
f_hart0_reset_reqs.enq (?);
|
||||
rg_hart0_running <= True; // Must be same as run/halt state of CPU after hart_reset!
|
||||
if (verbosity != 0) begin
|
||||
$display ("%0d: %m.dmcontrol_write 0x%08h: hartreset=1: resetting hart",
|
||||
cur_cycle, dm_word);
|
||||
$display (" Requested 'running' state = ", fshow (running));
|
||||
end
|
||||
else begin
|
||||
// Deassert hart reset
|
||||
if ((verbosity != 0) && rg_dmcontrol_hartreset)
|
||||
$display ("DM_Run_Control.write: dmcontrol 0x%08h: clearing hartreset", dm_word);
|
||||
end
|
||||
|
||||
if (hasel)
|
||||
$display ("DM_Run_Control.write: ERROR: dmcontrol 0x%08h: 'hasel' is not supported",
|
||||
dm_word);
|
||||
// run/halt commands
|
||||
else begin
|
||||
// Deassert hart reset
|
||||
if ((verbosity != 0) && rg_dmcontrol_hartreset)
|
||||
$display ("%0d: %m.dmcontrol_write 0x%08h: clearing hartreset",
|
||||
cur_cycle, dm_word);
|
||||
|
||||
if (hartsel != 0)
|
||||
$display ("DM_Run_Control.write: ERROR: dmcontrol 0x%08h: hartsel 0x%0h not supported",
|
||||
dm_word, hartsel);
|
||||
if (hasel)
|
||||
$display ("%0d:ERROR: %m.dmcontrol_write 0x%08h: hasel is not supported",
|
||||
cur_cycle, dm_word);
|
||||
|
||||
if (haltreq && resumereq) begin
|
||||
$display ("DM_Run_Control.write: ERROR: dmcontrol 0x%08h: haltreq=1 and resumereq=1",
|
||||
dm_word);
|
||||
$display (" This behavior is 'undefined' in the spec; ignoring");
|
||||
end
|
||||
// Resume hart(s) if not running
|
||||
else if (resumereq && (! rg_hart0_running)) begin
|
||||
f_hart0_run_halt_reqs.enq (True);
|
||||
rg_dmstatus_allresumeack <= False;
|
||||
$display ("DM_Run_Control.write: hart0 resume request");
|
||||
end
|
||||
// Halt hart(s)
|
||||
else if (haltreq && rg_hart0_running) begin
|
||||
f_hart0_run_halt_reqs.enq (False);
|
||||
$display ("DM_Run_Control.write: hart0 halt request");
|
||||
end
|
||||
if (hartsel != 0)
|
||||
$display ("%0d:ERROR: %m.dmcontrol_write 0x%08h: hartsel 0x%0h not supported",
|
||||
cur_cycle, dm_word, hartsel);
|
||||
|
||||
if (haltreq && resumereq) begin
|
||||
$display ("%0d:ERROR: %m.dmcontrol_write 0x%08h: haltreq=1 and resumereq=1",
|
||||
cur_cycle, dm_word);
|
||||
$display (" This behavior is 'undefined' in the spec; ignoring");
|
||||
end
|
||||
// Resume hart(s) if not running
|
||||
else if (resumereq && (! rg_hart0_running)) begin
|
||||
f_hart0_run_halt_reqs.enq (True);
|
||||
rg_dmstatus_allresumeack <= False;
|
||||
$display ("%0d: %m.dmcontrol_write: hart0 resume request", cur_cycle);
|
||||
end
|
||||
// Halt hart(s)
|
||||
else if (haltreq && rg_hart0_running) begin
|
||||
f_hart0_run_halt_reqs.enq (False);
|
||||
$display ("%0d: %m.dmcontrol_write: hart0 halt request", cur_cycle);
|
||||
end
|
||||
end
|
||||
endaction
|
||||
@@ -250,19 +289,37 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
|
||||
Reg #(Bit #(4)) rg_verbosity <- mkRegU;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// System responses
|
||||
|
||||
rule rl_hart0_run_rsp;
|
||||
let x = f_hart0_run_halt_rsps.first;
|
||||
f_hart0_run_halt_rsps.deq;
|
||||
// Response from system for hart0 reset
|
||||
rule rl_hart0_reset_rsp;
|
||||
Bool running <- pop (f_hart0_reset_rsps);
|
||||
rg_hart0_hasreset <= False;
|
||||
rg_hart0_running <= running;
|
||||
|
||||
rg_hart0_running <= x;
|
||||
if (x) begin
|
||||
if (verbosity != 0)
|
||||
$display ("%0d: %m.rl_hart0_reset_rsp: hart running = ", cur_cycle, fshow (running));
|
||||
endrule
|
||||
|
||||
// Response from system for NDM reset
|
||||
rule rl_ndm_reset_rsp;
|
||||
Bool running <- pop (f_ndm_reset_rsps);
|
||||
rg_hart0_running <= running;
|
||||
rg_dmstatus_allunavail <= False;
|
||||
|
||||
// if (verbosity != 0) TODO: UNCOMMENT AFTER DEBUGGING
|
||||
$display ("%0d: %m.rl_ndm_reset_rsp: hart running = ", cur_cycle, fshow (running));
|
||||
endrule
|
||||
|
||||
// Response from system for run/halt request
|
||||
rule rl_hart0_run_rsp (! f_ndm_reset_rsps.notEmpty);
|
||||
let running <- pop (f_hart0_run_halt_rsps);
|
||||
rg_hart0_running <= running;
|
||||
if (running)
|
||||
rg_dmstatus_allresumeack <= True;
|
||||
$display ("DM_Run_Control: hart0 running");
|
||||
end
|
||||
else begin
|
||||
$display ("DM_Run_Control: hart0 halted");
|
||||
end
|
||||
|
||||
if (verbosity != 0)
|
||||
$display ("%0d: %m.rl_hart0_run_rsp: 'running' = ", cur_cycle, fshow (running));
|
||||
endrule
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
@@ -274,9 +331,12 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
|
||||
|
||||
method Action reset;
|
||||
f_ndm_reset_reqs.clear;
|
||||
f_ndm_reset_rsps.clear;
|
||||
|
||||
rg_hart0_running <= True; // Must be same as run/halt state of CPU after hart_reset!
|
||||
f_hart0_reset_reqs.clear;
|
||||
f_hart0_reset_rsps.clear;
|
||||
|
||||
rg_hart0_running <= True; // Safe approximation of whether the CPU is running or not
|
||||
f_hart0_run_halt_reqs.clear;
|
||||
f_hart0_run_halt_rsps.clear;
|
||||
|
||||
@@ -285,12 +345,14 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
|
||||
rg_dmcontrol_ndmreset <= False;
|
||||
rg_dmcontrol_dmactive <= True; // DM module is now active
|
||||
|
||||
rg_hart0_hasreset <= False;
|
||||
rg_dmstatus_allresumeack <= False;
|
||||
rg_dmstatus_allunavail <= False; // NDM not in progress
|
||||
|
||||
rg_verbosity <= 0;
|
||||
|
||||
if (verbosity != 0)
|
||||
$display ("DM_Run_Control: reset");
|
||||
$display ("%0d: %m.reset", cur_cycle);
|
||||
endmethod
|
||||
|
||||
// ----------------
|
||||
@@ -307,7 +369,7 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
|
||||
endcase;
|
||||
|
||||
if (verbosity != 0)
|
||||
$display ("DM_Run_Control.av_read: [", fshow_dm_addr (dm_addr), "] => 0x%08h", dm_word);
|
||||
$display ("%0d: %m.av_read: [", cur_cycle, fshow_dm_addr (dm_addr), "] => 0x%08h", dm_word);
|
||||
|
||||
return dm_word;
|
||||
endactionvalue
|
||||
@@ -316,7 +378,7 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
|
||||
method Action write (DM_Addr dm_addr, DM_Word dm_word);
|
||||
action
|
||||
if (verbosity != 0)
|
||||
$display ("DM_Run_Control.write: [", fshow_dm_addr (dm_addr), "] <= 0x%08h", dm_word);
|
||||
$display ("%0d: %m.write: [", cur_cycle, fshow_dm_addr (dm_addr), "] <= 0x%08h", dm_word);
|
||||
|
||||
case (dm_addr)
|
||||
dm_addr_dmcontrol: fa_rg_dmcontrol_write (dm_word);
|
||||
@@ -331,13 +393,13 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
|
||||
|
||||
// ----------------
|
||||
// Facing Hart: Reset, Run-control, etc.
|
||||
interface Get hart0_get_reset_req = toGet (f_hart0_reset_reqs);
|
||||
interface Client hart0_reset_client = toGPClient (f_hart0_reset_reqs, f_hart0_reset_rsps);
|
||||
interface Client hart0_client_run_halt = toGPClient (f_hart0_run_halt_reqs, f_hart0_run_halt_rsps);
|
||||
interface Get hart0_get_other_req = toGet (f_hart0_other_reqs);
|
||||
|
||||
// ----------------
|
||||
// Facing Platform: Non-Debug-Module Reset (reset all except DM)
|
||||
interface Get get_ndm_reset_req = toGet (f_ndm_reset_reqs);
|
||||
interface Client ndm_reset_client = toGPClient (f_ndm_reset_reqs, f_ndm_reset_rsps);
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
|
||||
@@ -179,7 +179,7 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
// Interface to memory fabric
|
||||
AXI4_Master_Xactor_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) master_xactor <- mkAXI4_Master_Xactor_2;
|
||||
AXI4_Master_Xactor_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) master_xactor <- mkAXI4_Master_Xactor;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// System Bus state
|
||||
@@ -318,8 +318,7 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
|
||||
awuser: fabric_default_user};
|
||||
master_xactor.i_wr_addr.enq (wra);
|
||||
|
||||
let wrd = AXI4_Wr_Data {wid: fabric_default_id,
|
||||
wdata: fabric_data,
|
||||
let wrd = AXI4_Wr_Data {wdata: fabric_data,
|
||||
wstrb: fabric_strb,
|
||||
wlast: True,
|
||||
wuser: fabric_default_user};
|
||||
|
||||
@@ -96,7 +96,7 @@ interface Debug_Module_IFC;
|
||||
// This section replicated for additional harts.
|
||||
|
||||
// Reset and run-control
|
||||
interface Get #(Token) hart0_get_reset_req;
|
||||
interface Client #(Bool, Bool) hart0_reset_client;
|
||||
interface Client #(Bool, Bool) hart0_client_run_halt;
|
||||
interface Get #(Bit #(4)) hart0_get_other_req;
|
||||
|
||||
@@ -115,7 +115,8 @@ interface Debug_Module_IFC;
|
||||
// Facing Platform
|
||||
|
||||
// Non-Debug-Module Reset (reset all except DM)
|
||||
interface Get #(Token) get_ndm_reset_req;
|
||||
// Bool indicates 'running' hart state.
|
||||
interface Client #(Bool, Bool) ndm_reset_client;
|
||||
|
||||
// Read/Write RISC-V memory
|
||||
interface AXI4_Master_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) master;
|
||||
@@ -126,6 +127,9 @@ endinterface
|
||||
(* synthesize *)
|
||||
module mkDebug_Module (Debug_Module_IFC);
|
||||
|
||||
// Local verbosity: 0 = quiet; 1 = print DMI transactions
|
||||
Integer verbosity = 0;
|
||||
|
||||
// The three parts
|
||||
DM_Run_Control_IFC dm_run_control <- mkDM_Run_Control;
|
||||
DM_Abstract_Commands_IFC dm_abstract_commands <- mkDM_Abstract_Commands;
|
||||
@@ -152,6 +156,9 @@ module mkDebug_Module (Debug_Module_IFC);
|
||||
interface DMI dmi;
|
||||
method Action read_addr (DM_Addr dm_addr);
|
||||
f_read_addr.enq(dm_addr);
|
||||
|
||||
if (verbosity != 0)
|
||||
$display ("%0d: %m.DMI read: dm_addr 0x%0h", cur_cycle, dm_addr);
|
||||
endmethod
|
||||
|
||||
method ActionValue #(DM_Word) read_data;
|
||||
@@ -209,6 +216,10 @@ module mkDebug_Module (Debug_Module_IFC);
|
||||
dm_word = 0;
|
||||
end
|
||||
|
||||
if (verbosity != 0)
|
||||
$display ("%0d: %m.DMI read response: dm_addr 0x%0h, dm_word 0x%0h",
|
||||
cur_cycle, dm_addr, dm_word);
|
||||
|
||||
return dm_word;
|
||||
endmethod
|
||||
|
||||
@@ -261,6 +272,10 @@ module mkDebug_Module (Debug_Module_IFC);
|
||||
// TODO: set error status?
|
||||
noAction;
|
||||
end
|
||||
|
||||
if (verbosity != 0)
|
||||
$display ("%0d: %m.DMI write: dm_addr 0x%0h, dm_word 0x%0h",
|
||||
cur_cycle, dm_addr, dm_word);
|
||||
endmethod
|
||||
endinterface
|
||||
|
||||
@@ -268,7 +283,7 @@ module mkDebug_Module (Debug_Module_IFC);
|
||||
// Facing CPU/hart0
|
||||
|
||||
// Reset and run-control
|
||||
interface Get hart0_get_reset_req = dm_run_control.hart0_get_reset_req;
|
||||
interface Client hart0_reset_client = dm_run_control.hart0_reset_client;
|
||||
interface Client hart0_client_run_halt = dm_run_control.hart0_client_run_halt;
|
||||
interface Get hart0_get_other_req = dm_run_control.hart0_get_other_req;
|
||||
|
||||
@@ -287,7 +302,7 @@ module mkDebug_Module (Debug_Module_IFC);
|
||||
// Facing Platform
|
||||
|
||||
// Non-Debug-Module Reset (reset all except DM)
|
||||
interface Get get_ndm_reset_req = dm_run_control.get_ndm_reset_req;
|
||||
interface Client ndm_reset_client = dm_run_control.ndm_reset_client;
|
||||
|
||||
// Read/Write RISC-V memory
|
||||
interface AXI4_Master_IFC master = dm_system_bus.master;
|
||||
|
||||
@@ -1,3 +1,206 @@
|
||||
'Debug_Module' implements a Debug Module for RISC-V processors in
|
||||
accordance with the RISC-V standard "External Debug Support" spec:
|
||||
|
||||
RISC-V External Debug Support
|
||||
Version 0.13.2
|
||||
d5029366d59e8563c08b6b9435f82573b603e48e
|
||||
Fri Mar 22 09:06:04 2019 -0700
|
||||
|
||||
Note: the spec is independent of any particular RISC-V CPU
|
||||
implementation. It just specifies the standard registers in the Debug
|
||||
Module that can be read and written by an external debugger (such as
|
||||
GDB). It specifies the address map of these registers, and the
|
||||
semantics, i.e., what happens when one reads or writes these
|
||||
registers. The spec does not say anything about how this spec is
|
||||
implemented.
|
||||
|
||||
Please see comments in Debug_Module.bsv for more details on our
|
||||
implementation of the Debug Module spec. This implementation is also
|
||||
not specific to any particular CPU implementation. We use it in
|
||||
multiple Bluespec RISC-V CPU implementations, and it could be used
|
||||
with other CPU implementations as well.
|
||||
|
||||
// ================================================================
|
||||
What follows is a concise cheat-sheet for the registers in the Debug Module.
|
||||
|
||||
DM_Addr dm_addr_data0 = 'h04;
|
||||
DM_Addr dm_addr_data1 = 'h05;
|
||||
DM_Addr dm_addr_data2 = 'h06;
|
||||
DM_Addr dm_addr_data3 = 'h07;
|
||||
DM_Addr dm_addr_data4 = 'h08;
|
||||
DM_Addr dm_addr_data5 = 'h09;
|
||||
DM_Addr dm_addr_data6 = 'h0a;
|
||||
DM_Addr dm_addr_data7 = 'h0b;
|
||||
DM_Addr dm_addr_data8 = 'h0c;
|
||||
DM_Addr dm_addr_data9 = 'h0d;
|
||||
DM_Addr dm_addr_data10 = 'h0d;
|
||||
DM_Addr dm_addr_data11 = 'h0f;
|
||||
|
||||
// ----------------
|
||||
// Run Control
|
||||
|
||||
DM_Addr dm_addr_dmcontrol = 'h10;
|
||||
31.30.29.28| 27.26.25.24| 23.22.21.20| 19.18.17.16| 15.14.13.12| 11.10.9.8| 7.6.5.4| 3.2.1.0|
|
||||
| | | | 0 | | | | | 0 0 | | | |dmactive
|
||||
| | | | | | | | | | | |ndmreset
|
||||
| | | | | | | | | | |clrresethaltreq
|
||||
| | | | | | | | | |setresethaltreq
|
||||
| | | | | | | |-----------10-----------|hartselhi
|
||||
| | | | | |------------10--------------|hartsello
|
||||
| | | | |hasel
|
||||
| | | | 0: Single hart selected (hartsel)
|
||||
| | | | 1: Multiple harts selected (hartsel + hart array mask)
|
||||
| | | |ackhavereset
|
||||
| | |hartreset
|
||||
| |resumereq
|
||||
|haltreq
|
||||
|
||||
DM_Addr dm_addr_dmstatus = 'h11;
|
||||
31.30.29.28| 27.26.25.24| 23.22.21.20| 19.18.17.16| 15.14.13.12| 11.10.9.8| 7.6.5.4| 3.2.1.0|
|
||||
0 0 0 0 0 0 0 0 | | 0 0 | | | | | | | | | | | | | | | | |--4--|version
|
||||
| | | | | | | | | | | | | | | | | | | 0: no DM present
|
||||
| | | | | | | | | | | | | | | | | | | 1: DM v011
|
||||
| | | | | | | | | | | | | | | | | | | 2: DM v013
|
||||
| | | | | | | | | | | | | | | | | | | 15: DM vUnknown
|
||||
| | | | | | | | | | | | | | | | | |confstrptrvalid
|
||||
| | | | | | | | | | | | | | | | |hasresethaltreq
|
||||
| | | | | | | | | | | | | | | |authbusy
|
||||
| | | | | | | | | | | | | | |authenticated
|
||||
| | | | | | | | | | | | | |anyhalted
|
||||
| | | | | | | | | | | | |allhalted
|
||||
| | | | | | | | | | | |anyrunning
|
||||
| | | | | | | | | | |allrunning
|
||||
| | | | | | | | | |anyunavail
|
||||
| | | | | | | | |allunavail
|
||||
| | | | | | | |anynonexistent
|
||||
| | | | | | |allnonexistent
|
||||
| | | | | |anyresumeack
|
||||
| | | | |allresumeack
|
||||
| | | |anyhavereset
|
||||
| | |allhavereset
|
||||
| |impebreak
|
||||
| 0 No implicit EBREAK at end of PB
|
||||
| 1 Implicit EBREAK at end of PB
|
||||
|
||||
DM_Addr dm_addr_hartinfo = 'h12;
|
||||
31.30.29.28| 27.26.25.24| 23.22.21.20| 19.18.17.16| 15.14.13.12| 11.10.9.8| 7.6.5.4| 3.2.1.0|
|
||||
0 0 0 0 0 0 0 0 | | 0 0 0 | | | |-----------12-----------|dataaddr
|
||||
| | | |----4---|datasize
|
||||
|----4---|nscratch |dataaccess
|
||||
|
||||
|
||||
DM_Addr dm_addr_haltsum1 = 'h13;
|
||||
DM_Addr dm_addr_hawindowsel = 'h14;
|
||||
DM_Addr dm_addr_hawindow = 'h15;
|
||||
|
||||
// ----------------
|
||||
// Abstract commands (read/write RISC-V registers and RISC-V CSRs)
|
||||
|
||||
DM_Addr dm_addr_abstractcs = 'h16;
|
||||
31.30.29.28| 27.26.25.24| 23.22.21.20| 19.18.17.16| 15.14.13.12| 11.10.9.8| 7.6.5.4| 3.2.1.0|
|
||||
0 0 0 | | 0 0 0 0 0 0 0 0 0 0 0 | 0 | | 0 0 0 0 |--4--|datacount
|
||||
0 0 0 |-----5------|progbufsize |busy |-3-|cmderr
|
||||
|
||||
DM_Addr dm_addr_command = 'h17;
|
||||
31.30.29.28| 27.26.25.24| 23.22.21.20| 19.18.17.16| 15.14.13.12| 11.10.9.8| 7.6.5.4| 3.2.1.0|
|
||||
| 0 | | | | | | |-----------------16------------------|regno
|
||||
| | | | | | | | 0x0000-0x0FFF CSRs (dpc => PC)
|
||||
| | | | | | | | 0x1000-0x101F GPRs
|
||||
| | | | | | | | 0x1020-0x103F Floating Point Regs
|
||||
| | | | | | | | 0xC000-0xFFFF Reserved
|
||||
| | | | | | |write
|
||||
| | | | | | 0: specified reg -> arg0 of data
|
||||
| | | | | | 1: specified reg <- arg0 of data
|
||||
| | | | | |transfer
|
||||
| | | | | 0 Don't do the 'write' op
|
||||
| | | | | 1 Do the 'write' op
|
||||
| | | | | Allows exec of PB without valid vals in 'size' and 'regno'
|
||||
| | | | |postexec
|
||||
| | | | 1 exec Program Buffer exactly once after the xfer
|
||||
| | | |aarpostincrement
|
||||
| |--3--|aarsize
|
||||
| 2 Lowest 32b of reg
|
||||
| 3 Lowest 64b of reg
|
||||
| 4 Lowest 128b of reg
|
||||
|---------8-----------|cmdtype
|
||||
0 ACCESS_REG
|
||||
1 QUICK_ACCESS
|
||||
|
||||
DM_Addr dm_addr_abstractauto = 'h18;
|
||||
DM_Addr dm_addr_confstrptr0 = 'h19;
|
||||
DM_Addr dm_addr_confstrptr1 = 'h1a;
|
||||
DM_Addr dm_addr_confstrptr2 = 'h1b;
|
||||
DM_Addr dm_addr_confstrptr3 = 'h1c;
|
||||
DM_Addr dm_addr_nextdm = 'h1d;
|
||||
|
||||
DM_Addr dm_addr_progbuf0 = 'h20;
|
||||
DM_Addr dm_addr_progbuf1 = 'h21;
|
||||
DM_Addr dm_addr_progbuf2 = 'h22;
|
||||
DM_Addr dm_addr_progbuf3 = 'h23;
|
||||
DM_Addr dm_addr_progbuf4 = 'h24;
|
||||
DM_Addr dm_addr_progbuf5 = 'h25;
|
||||
DM_Addr dm_addr_progbuf6 = 'h26;
|
||||
DM_Addr dm_addr_progbuf7 = 'h27;
|
||||
DM_Addr dm_addr_progbuf8 = 'h28;
|
||||
DM_Addr dm_addr_progbuf9 = 'h29;
|
||||
DM_Addr dm_addr_progbuf10 = 'h2a;
|
||||
DM_Addr dm_addr_progbuf11 = 'h2b;
|
||||
DM_Addr dm_addr_progbuf12 = 'h2c;
|
||||
DM_Addr dm_addr_progbuf13 = 'h2d;
|
||||
DM_Addr dm_addr_progbuf14 = 'h2e;
|
||||
DM_Addr dm_addr_progbuf15 = 'h2f;
|
||||
|
||||
DM_Addr dm_addr_authdata = 'h30;
|
||||
DM_Addr dm_addr_haltsum2 = 'h34;
|
||||
DM_Addr dm_addr_haltsum3 = 'h35;
|
||||
|
||||
DM_Addr dm_addr_sbaddress3 = 'h37;
|
||||
|
||||
// ----------------
|
||||
// System Bus access (read/write RISC-V memory/devices)
|
||||
|
||||
DM_Addr dm_addr_sbcs = 'h38;
|
||||
31.30.29.28| 27.26.25.24| 23.22.21.20| 19.18.17.16| 15.14.13.12| 11.10.9.8| 7.6.5.4| 3.2.1.0|
|
||||
| | 0 0 0 0 0 0 | | | | | | | | | | | | | | | |sbaccess8
|
||||
| | | | | | | | | | | | | | | | |sbaccess16
|
||||
| | | | | | | | | | | | | | | |sbaccess32
|
||||
| | | | | | | | | | | | | | |sbaccess64
|
||||
| | | | | | | | | | | | | |sbaccess128
|
||||
| | | | | | | | | | | |-----7-------|sbasize
|
||||
| | | | | | | | | |--3--|sberror
|
||||
| | | | | | | | | 0: no bus err
|
||||
| | | | | | | | | 1: timeout
|
||||
| | | | | | | | | 2: bad addr
|
||||
| | | | | | | | | 3: alignment err
|
||||
| | | | | | | | | 4: unsupported size
|
||||
| | | | | | | | | 7: other
|
||||
| | | | | | | | |sbreadondata: read on sbdata0 triggers sb read
|
||||
| | | | | | | |sbautoincrement
|
||||
| | | | | |--3--|sbaccess
|
||||
| | | | | 0:8b, 1:16b, 2:32b, 3:64b, 4:128b
|
||||
| | | | |sbreadonaddr
|
||||
| | | | 1 Every write to sbaddress0 triggers sb read at new addr
|
||||
| | | |sbbusy
|
||||
| | |sbbusyerror
|
||||
|--3--|sbversion
|
||||
0: System Bus interface spec version < 2018-01-01
|
||||
1: This System Bus interface spec version
|
||||
|
||||
DM_Addr dm_addr_sbaddress0 = 'h39;
|
||||
DM_Addr dm_addr_sbaddress1 = 'h3a;
|
||||
DM_Addr dm_addr_sbaddress2 = 'h3b;
|
||||
DM_Addr dm_addr_sbdata0 = 'h3c;
|
||||
DM_Addr dm_addr_sbdata1 = 'h3d;
|
||||
DM_Addr dm_addr_sbdata2 = 'h3e;
|
||||
DM_Addr dm_addr_sbdata3 = 'h3f;
|
||||
DM_Addr dm_addr_haltsum0 = 'h40;
|
||||
|
||||
// ================================================================
|
||||
// ================================================================
|
||||
// OLDER VERSIONS OF THE DEBUG MODULE SPEC
|
||||
// ================================================================
|
||||
// ================================================================
|
||||
|
||||
'Debug_Module' implements a Debug Module for RISC-V processors in
|
||||
accordance with the RISC-V standard "External Debug Support" spec:
|
||||
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
// This file is a modified version of: RISCY_OOO/procs/lib/LLCDmaConnect.bsv
|
||||
|
||||
// The original module had, as 2nd parameter, MemLoaderMemClient memLoader
|
||||
// The memLoader assumed only write-transactions (to load memory), and
|
||||
// discarded load responses.
|
||||
|
||||
// Here, the module instead offers an AXI4_Slave interface to be
|
||||
// connected to the AXI4_Master of the Debug Module.
|
||||
// This axi4_slave accepts and responds to both read and write transactions.
|
||||
|
||||
// Copyright (c) 2017 Massachusetts Institute of Technology
|
||||
// Portions Copyright (c) 2019-2020 Bluespec, Inc.
|
||||
//
|
||||
|
||||
// This file is a modified version of: RISCY_OOO/procs/lib/LLCDmaConnect.bsv
|
||||
// Bluespec: this file is has many modifications.
|
||||
|
||||
// The original module had 3 params and had an Empty interface.
|
||||
// The 2nd param was: MemLoaderMemClient memLoader
|
||||
// which issued only write-transactions (to load memory).
|
||||
// The module discarded write responses, and ignored read-requests.
|
||||
|
||||
// Here, that module parameter is removed and, instead, the module has an
|
||||
// AXI4_Slave interface, to be connected to the AXI4_Master of the
|
||||
// Debug Module. This axi4_slave accepts, processes and responds
|
||||
// to both read and write transactions.
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
@@ -87,31 +90,33 @@ typedef union tagged {
|
||||
} LLCDmaReqId deriving(Bits, Eq, FShow);
|
||||
|
||||
// ================================================================
|
||||
// Functions to insert/extract axi4 data into/from a cache line
|
||||
// Help functions for read-modify-writes of 4-Byte values on a 64-Byte Cache Line
|
||||
|
||||
// For writing, position the AXI4 8-byte data and 8-bit byte-enable
|
||||
// into a 64-byte line and 64-bit line-byte-enable
|
||||
function Tuple3 #(Addr,
|
||||
Line,
|
||||
LineByteEn) fn_line_and_line_byteen_from_axi4 (Addr axi4_addr,
|
||||
Bit #(8) axi4_byteen,
|
||||
Bit #(64) axi4_data);
|
||||
Vector #(8, Bit #(64)) line_dwords = replicate (0);
|
||||
Vector #(8, Bit #(8)) line_dword_byteen = replicate (0);
|
||||
Bit #(3) dword_index = axi4_addr [5:3];
|
||||
line_dwords [dword_index] = axi4_data;
|
||||
line_dword_byteen [dword_index] = axi4_byteen;
|
||||
Addr line_addr = { axi4_addr [63:6], 6'b0 };
|
||||
return tuple3 (line_addr,
|
||||
unpack (pack (line_dwords)),
|
||||
unpack (pack (line_dword_byteen)));
|
||||
typedef enum {CACHELINE_CACHE_INVALID,
|
||||
CACHELINE_CACHE_WRITING_BACK,
|
||||
CACHELINE_CACHE_RELOADING,
|
||||
CACHELINE_CACHE_CLEAN,
|
||||
CACHELINE_CACHE_DIRTY
|
||||
} Cacheline_Cache_State
|
||||
deriving (Bits, Eq, FShow);
|
||||
|
||||
function Addr fn_align_addr_to_line (Addr addr);
|
||||
Addr line_addr = { addr [63:6], 6'b0 };
|
||||
return line_addr;
|
||||
endfunction
|
||||
|
||||
// For reading, extract 8-byte AXI4 data from a 64-byte line
|
||||
function Bit #(64) fn_axi4_data_from_line (Line line, Bit #(3) dword_in_line);
|
||||
Vector #(8, Bit #(64)) line_words = unpack (pack (line));
|
||||
Bit #(64) dw = line_words [dword_in_line];
|
||||
return dw;
|
||||
function Bool fn_addr_is_in_line (Addr addr, Addr line_addr);
|
||||
return (fn_align_addr_to_line (addr) == line_addr);
|
||||
endfunction
|
||||
|
||||
function Bit #(64) fn_expand_strb_to_mask (Bit #(8) strb);
|
||||
function Bit #(8) fn_bit_to_byte (Integer j);
|
||||
return ((strb [j] == 1'b1) ? 8'hFF : 8'h00);
|
||||
endfunction
|
||||
|
||||
Vector #(8, Bit #(8)) v = genWith (fn_bit_to_byte);
|
||||
|
||||
return pack (v);
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
@@ -133,6 +138,228 @@ module mkLLCDmaConnect #(
|
||||
// Slave transactor for requests from Debug Module
|
||||
AXI4_Slave_Xactor_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) axi4_slave_xactor <- mkAXI4_Slave_Xactor;
|
||||
|
||||
// ================================================================
|
||||
// These regs are a 1-location local cache for an LLC Cache Line,
|
||||
// to avoid doing a full read-modify-write to the LLC on each transaction.
|
||||
|
||||
Reg #(Cacheline_Cache_State) rg_cacheline_cache_state <- mkReg (CACHELINE_CACHE_CLEAN);
|
||||
Reg #(Addr) rg_cacheline_cache_addr <- mkReg (1); // never matches an LLC line addr
|
||||
Reg #(Line) rg_cacheline_cache_data <- mkRegU;
|
||||
|
||||
// Writeback dirty cacheline_cache if no new store requests within n-cycles
|
||||
Reg #(Bit #(10)) rg_cacheline_cache_dirty_delay <- mkReg (0);
|
||||
|
||||
// ================================================================
|
||||
// Write transactions from the external client (e.g., Debug Module)
|
||||
|
||||
// Respond to store-requests from the external client on store-hit
|
||||
rule rl_handle_MemLoader_st_req ( ( (rg_cacheline_cache_state == CACHELINE_CACHE_CLEAN)
|
||||
|| (rg_cacheline_cache_state == CACHELINE_CACHE_DIRTY))
|
||||
&& (fn_addr_is_in_line (axi4_slave_xactor.o_wr_addr.first.awaddr,
|
||||
rg_cacheline_cache_addr)));
|
||||
let wr_addr <- pop_o (axi4_slave_xactor.o_wr_addr);
|
||||
let wr_data <- pop_o (axi4_slave_xactor.o_wr_data);
|
||||
Addr addr = wr_addr.awaddr;
|
||||
Bit #(64) data = wr_data.wdata;
|
||||
Bit #(64) mask = fn_expand_strb_to_mask (wr_data.wstrb);
|
||||
|
||||
// Read rg_cacheline_cache_data as 64-bit words
|
||||
Vector #(8, Bit #(64)) line_dwords = unpack (pack (rg_cacheline_cache_data));
|
||||
// Modify relevant bytes of relevant dword
|
||||
Bit #(3) dword_in_line = addr [5:3];
|
||||
Bit #(64) old_dword = line_dwords [dword_in_line];
|
||||
Bit #(64) new_dword = ((old_dword & (~ mask)) | (data & mask));
|
||||
line_dwords [dword_in_line] = new_dword;
|
||||
// Save it
|
||||
rg_cacheline_cache_data <= unpack (pack (line_dwords));
|
||||
rg_cacheline_cache_state <= CACHELINE_CACHE_DIRTY;
|
||||
rg_cacheline_cache_dirty_delay <= '1; // start write-back delay countdown
|
||||
|
||||
// Send response to external client
|
||||
AXI4_Wr_Resp #(Wd_Id, Wd_User)
|
||||
wr_resp = AXI4_Wr_Resp {bid: 0, // TODO: change uniformly to Fabric_id
|
||||
bresp: axi4_resp_okay,
|
||||
buser: ?};
|
||||
axi4_slave_xactor.i_wr_resp.enq (wr_resp);
|
||||
|
||||
if (verbosity >= 2) begin
|
||||
$display ("%0d: %m.rl_handle_MemLoader_st_req: addr %0h data %0h strb %0h",
|
||||
cur_cycle, wr_addr.awaddr, wr_data.wdata, wr_data.wstrb);
|
||||
$display (" old_dword: %0h", old_dword);
|
||||
$display (" new_dword: %0h", old_dword);
|
||||
end
|
||||
endrule
|
||||
|
||||
// ================================================================
|
||||
// Read transactions from the external memory client (e.g., Debug Module)
|
||||
|
||||
// Responds to load-requests from the external client on load-hit
|
||||
rule rl_handle_MemLoader_ld_req ( ( (rg_cacheline_cache_state == CACHELINE_CACHE_CLEAN)
|
||||
|| (rg_cacheline_cache_state == CACHELINE_CACHE_DIRTY))
|
||||
&& (fn_addr_is_in_line (axi4_slave_xactor.o_rd_addr.first.araddr,
|
||||
rg_cacheline_cache_addr)));
|
||||
let rd_addr <- pop_o (axi4_slave_xactor.o_rd_addr);
|
||||
Addr addr = rd_addr.araddr;
|
||||
|
||||
// Read rg_cacheline_cache as 64-bit words
|
||||
Vector #(8, Bit #(64)) line_dwords = unpack (pack (rg_cacheline_cache_data));
|
||||
Bit #(3) dword_in_line = addr [5:3];
|
||||
Bit #(64) dword = line_dwords [dword_in_line];
|
||||
|
||||
// Send response to external client
|
||||
AXI4_Rd_Data #(Wd_Id, Wd_Data, Wd_User)
|
||||
rd_data = AXI4_Rd_Data {rid: 0, // TODO: fixup
|
||||
rdata: dword,
|
||||
rresp: axi4_resp_okay,
|
||||
rlast: True,
|
||||
ruser: ?};
|
||||
axi4_slave_xactor.i_rd_data.enq (rd_data);
|
||||
|
||||
if (verbosity >= 2) begin
|
||||
$display ("%0d: %m.rl_handle_MemLoader_ld_req: addr %0h", cur_cycle, rd_addr.araddr);
|
||||
$display (" dword: %0h", dword);
|
||||
end
|
||||
endrule
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Miss and writeback processing
|
||||
|
||||
// Maintain dirty delay countdown
|
||||
rule rl_cacheline_cache_writeback_dirty_delay ( (rg_cacheline_cache_state == CACHELINE_CACHE_DIRTY)
|
||||
&& (rg_cacheline_cache_dirty_delay != 0));
|
||||
rg_cacheline_cache_dirty_delay <= rg_cacheline_cache_dirty_delay - 1;
|
||||
endrule
|
||||
|
||||
function Action fa_writeback;
|
||||
action
|
||||
dmaRqT req = DmaRq {addr: rg_cacheline_cache_addr,
|
||||
byteEn: replicate (True), // Write all bytes
|
||||
data: rg_cacheline_cache_data,
|
||||
id: tagged MemLoader (?) // TODO: use wr_addr.awid?
|
||||
};
|
||||
llc.memReq.enq (req);
|
||||
// $display ("%0d: %m.fa_writeback line at %0h", cur_cycle, rg_cacheline_cache_addr);
|
||||
// $display (" data %0128h", rg_cacheline_cache_data);
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
// Initiate writeback if dirty for full delay
|
||||
rule rl_cacheline_cache_writeback_dirty_aged ( (rg_cacheline_cache_state == CACHELINE_CACHE_DIRTY)
|
||||
&& (rg_cacheline_cache_dirty_delay == 0));
|
||||
if (verbosity >= 2) begin
|
||||
$display ("%0d: %m.rl_cacheline_cache_writeback_dirty_aged.", cur_cycle);
|
||||
$display (" Old line addr %0h", rg_cacheline_cache_addr);
|
||||
end
|
||||
|
||||
fa_writeback;
|
||||
rg_cacheline_cache_state <= CACHELINE_CACHE_WRITING_BACK;
|
||||
endrule
|
||||
|
||||
// Initiate writeback if dirty and next request is store-miss
|
||||
rule rl_cacheline_cache_writeback_st_miss ( (rg_cacheline_cache_state == CACHELINE_CACHE_DIRTY)
|
||||
&& (! fn_addr_is_in_line (axi4_slave_xactor.o_wr_addr.first.awaddr,
|
||||
rg_cacheline_cache_addr)));
|
||||
if (verbosity >= 2) begin
|
||||
$display ("%0d: %m.rl_cacheline_cache_writeback_st_miss.", cur_cycle);
|
||||
$display (" Old line addr %0h", rg_cacheline_cache_addr);
|
||||
$display (" New addr %0h", axi4_slave_xactor.o_wr_addr.first.awaddr);
|
||||
end
|
||||
|
||||
fa_writeback;
|
||||
rg_cacheline_cache_state <= CACHELINE_CACHE_WRITING_BACK;
|
||||
endrule
|
||||
|
||||
// Initiate writeback if dirty and next request is load-miss
|
||||
rule rl_cacheline_cache_writeback_ld_miss ( (rg_cacheline_cache_state == CACHELINE_CACHE_DIRTY)
|
||||
&& (! fn_addr_is_in_line (axi4_slave_xactor.o_rd_addr.first.araddr,
|
||||
rg_cacheline_cache_addr)));
|
||||
if (verbosity >= 2) begin
|
||||
$display ("%0d: %m.rl_cacheline_cache_writeback_ld_miss.", cur_cycle);
|
||||
$display (" Old line addr %0h", rg_cacheline_cache_addr);
|
||||
$display (" New addr %0h", axi4_slave_xactor.o_wr_addr.first.awaddr);
|
||||
end
|
||||
|
||||
fa_writeback;
|
||||
rg_cacheline_cache_state <= CACHELINE_CACHE_WRITING_BACK;
|
||||
endrule
|
||||
|
||||
// Finish writeback
|
||||
rule rl_cacheline_cache_writeback_finish (llc.respSt.first matches tagged MemLoader .id
|
||||
&&& (rg_cacheline_cache_state == CACHELINE_CACHE_WRITING_BACK));
|
||||
let resp = llc.respSt.first;
|
||||
llc.respSt.deq;
|
||||
rg_cacheline_cache_state <= CACHELINE_CACHE_CLEAN;
|
||||
|
||||
if (verbosity >= 2) begin
|
||||
$display ("%0d: %m.rl_cacheline_cache_writeback_finish. Line addr %0h",
|
||||
cur_cycle, rg_cacheline_cache_addr);
|
||||
$display (" Line data %0h", rg_cacheline_cache_data);
|
||||
end
|
||||
endrule
|
||||
|
||||
function Action fa_initiate_reload (Addr addr);
|
||||
action
|
||||
let line_addr = fn_align_addr_to_line (addr);
|
||||
dmaRqT req = DmaRq {addr: line_addr,
|
||||
byteEn: replicate (False), // all False means 'read'
|
||||
data: ?,
|
||||
id: tagged MemLoader (?)}; // TODO: change uniformly to wr_addr.awid
|
||||
llc.memReq.enq (req);
|
||||
rg_cacheline_cache_addr <= line_addr;
|
||||
|
||||
if (verbosity >= 2) begin
|
||||
$display (" fa_initiate_reload: line_addr %0h", line_addr);
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
// Initiate reload when cacheline_cache is clean on store-miss
|
||||
rule rl_cacheline_cache_reload_req_st ( (rg_cacheline_cache_state == CACHELINE_CACHE_CLEAN)
|
||||
&& (! fn_addr_is_in_line (axi4_slave_xactor.o_wr_addr.first.awaddr,
|
||||
rg_cacheline_cache_addr)));
|
||||
let addr = axi4_slave_xactor.o_wr_addr.first.awaddr;
|
||||
|
||||
if (verbosity >= 2) begin
|
||||
$display ("%0d: %m.rl_cacheline_cache_reload_req_st for addr %0h", cur_cycle, addr);
|
||||
end
|
||||
|
||||
fa_initiate_reload (addr);
|
||||
rg_cacheline_cache_state <= CACHELINE_CACHE_RELOADING;
|
||||
endrule
|
||||
|
||||
// Initiate reload when cacheline_cache is clean on load-miss
|
||||
rule rl_cacheline_cache_reload_req_ld ( (rg_cacheline_cache_state == CACHELINE_CACHE_CLEAN)
|
||||
&& (! fn_addr_is_in_line (axi4_slave_xactor.o_rd_addr.first.araddr,
|
||||
rg_cacheline_cache_addr)));
|
||||
let addr = axi4_slave_xactor.o_rd_addr.first.araddr;
|
||||
|
||||
if (verbosity >= 2) begin
|
||||
$display ("%0d: %m.rl_cacheline_cache_reload_req_ld for addr %0h", cur_cycle, addr);
|
||||
end
|
||||
|
||||
fa_initiate_reload (addr);
|
||||
rg_cacheline_cache_state <= CACHELINE_CACHE_RELOADING;
|
||||
endrule
|
||||
|
||||
// Finish reload
|
||||
rule rl_cacheline_cache_reload_finish (llc.respLd.first.id matches tagged MemLoader .id
|
||||
&&& (rg_cacheline_cache_state == CACHELINE_CACHE_RELOADING));
|
||||
let resp = llc.respLd.first;
|
||||
llc.respLd.deq;
|
||||
rg_cacheline_cache_state <= CACHELINE_CACHE_CLEAN;
|
||||
rg_cacheline_cache_data <= resp.data;
|
||||
|
||||
if (verbosity >= 2) begin
|
||||
$display ("%0d: %m.rl_cacheline_cache_reload_finish. Line addr %0h", cur_cycle, rg_cacheline_cache_addr);
|
||||
$display (" Line data %0h", resp.data);
|
||||
end
|
||||
endrule
|
||||
|
||||
// ================================================================
|
||||
// Transactions from the TLB
|
||||
// Expecting only LOAD requests from TLB
|
||||
// This section is unchanged from the original riscy-ooo module.
|
||||
|
||||
// helper functions for cross bar
|
||||
function XBarDstInfo#(Bit#(0), Tuple2#(CoreId, TlbMemReq)) getTlbDst(CoreId core, TlbMemReq r);
|
||||
return XBarDstInfo {idx: 0, data: tuple2(core, r)};
|
||||
@@ -159,84 +386,13 @@ module mkLLCDmaConnect #(
|
||||
};
|
||||
endfunction
|
||||
|
||||
rule sendMemLoaderReqToLLC_wr; // write requests
|
||||
let wr_addr <- pop_o (axi4_slave_xactor.o_wr_addr);
|
||||
let wr_data <- pop_o (axi4_slave_xactor.o_wr_data);
|
||||
// Prioritize external mem client over Tlb
|
||||
(* descending_urgency = "rl_cacheline_cache_writeback_dirty_aged, sendTlbReqToLLC" *)
|
||||
(* descending_urgency = "rl_cacheline_cache_writeback_st_miss, sendTlbReqToLLC" *)
|
||||
(* descending_urgency = "rl_cacheline_cache_writeback_ld_miss, sendTlbReqToLLC" *)
|
||||
(* descending_urgency = "rl_cacheline_cache_reload_req_st, sendTlbReqToLLC" *)
|
||||
(* descending_urgency = "rl_cacheline_cache_reload_req_ld, sendTlbReqToLLC" *)
|
||||
|
||||
if (wr_addr.awlen != 0) begin
|
||||
$display ("%0d: %m.sendMemLoaderReqToLLC_wr: ERROR: awlen is not 0 (burst length is not 1)", cur_cycle);
|
||||
$display (" ", fshow (wr_addr));
|
||||
$display (" ", fshow (wr_data));
|
||||
end
|
||||
else if ( (wr_addr.awsize != axsize_1)
|
||||
&& (wr_addr.awsize != axsize_2)
|
||||
&& (wr_addr.awsize != axsize_4)
|
||||
&& (wr_addr.awsize != axsize_8)) begin
|
||||
$display ("%0d: %m.sendMemLoaderReqToLLC_wr: ERROR: awsize is not code for 1,2,4,8", cur_cycle);
|
||||
$display (" ", fshow (wr_addr));
|
||||
$display (" ", fshow (wr_data));
|
||||
end
|
||||
else if (! wr_data.wlast) begin
|
||||
$display ("%0d: %m.sendMemLoaderReqToLLC_wr: ERROR: wlast is 1", cur_cycle);
|
||||
$display (" ", fshow (wr_addr));
|
||||
$display (" ", fshow (wr_data));
|
||||
end
|
||||
else begin
|
||||
match {.line_addr,
|
||||
.line_data,
|
||||
.line_byteen } = fn_line_and_line_byteen_from_axi4 (wr_addr.awaddr,
|
||||
wr_data.wstrb,
|
||||
wr_data.wdata);
|
||||
dmaRqT req = DmaRq {addr: line_addr,
|
||||
byteEn: line_byteen,
|
||||
data: line_data,
|
||||
id: tagged MemLoader (?) // TODO: change uniformly to wr_addr.awid
|
||||
};
|
||||
llc.memReq.enq(req);
|
||||
if (verbosity != 0) begin
|
||||
$display ("%0d: %m.sendMemLoaderReqToLLC_wr", cur_cycle);
|
||||
$display (" ", fshow (wr_addr));
|
||||
$display (" ", fshow (wr_data));
|
||||
$display (" ", fshow (req));
|
||||
end
|
||||
end
|
||||
endrule
|
||||
|
||||
rule sendMemLoaderReqToLLC_rd; // read requests
|
||||
let rd_addr <- pop_o (axi4_slave_xactor.o_rd_addr);
|
||||
|
||||
if (rd_addr.arlen != 0) begin
|
||||
$display ("%0d: %m.sendMemLoaderReqToLLC_rd: ERROR: arlen is not 0 (burst length is not 1)", cur_cycle);
|
||||
$display (" ", fshow (rd_addr));
|
||||
end
|
||||
else if ( (rd_addr.arsize != axsize_1)
|
||||
&& (rd_addr.arsize != axsize_2)
|
||||
&& (rd_addr.arsize != axsize_4)
|
||||
&& (rd_addr.arsize != axsize_8)) begin
|
||||
$display ("%0d: %m.sendMemLoaderReqToLLC_rd: ERROR: arsize is not code for 1,2,4,8", cur_cycle);
|
||||
$display (" ", fshow (rd_addr));
|
||||
end
|
||||
else begin
|
||||
Addr line_addr = { rd_addr.araddr [63:6], 6'b0 };
|
||||
dmaRqT req = DmaRq {addr: line_addr,
|
||||
byteEn: replicate (False),
|
||||
data: ?,
|
||||
id: MemLoader (?) // TODO: change uniformly to rd_addr.arid
|
||||
};
|
||||
llc.memReq.enq(req);
|
||||
Bit #(3) dword_in_line = rd_addr.araddr [5:3];
|
||||
f_dword_in_line.enq (dword_in_line);
|
||||
|
||||
if (verbosity != 0) begin
|
||||
$display("[LLCDmaConnect sendMemLoaderReqToLLC_rd]");
|
||||
$display (" ", fshow (rd_addr));
|
||||
$display (" ", fshow (req));
|
||||
end
|
||||
end
|
||||
endrule
|
||||
|
||||
(* descending_urgency = "sendMemLoaderReqToLLC_wr, sendTlbReqToLLC" *)
|
||||
(* descending_urgency = "sendMemLoaderReqToLLC_rd, sendTlbReqToLLC" *)
|
||||
rule sendTlbReqToLLC;
|
||||
let {c, r} <- toGet(tlbQ).get;
|
||||
let req = getTlbDmaReq(c, r);
|
||||
@@ -246,26 +402,6 @@ module mkLLCDmaConnect #(
|
||||
end
|
||||
endrule
|
||||
|
||||
// send Ld resp from LLC
|
||||
rule sendLdRespToMemLoader(llc.respLd.first.id matches tagged MemLoader .id);
|
||||
let resp = llc.respLd.first;
|
||||
llc.respLd.deq;
|
||||
let dword_in_line = f_dword_in_line.first;
|
||||
f_dword_in_line.deq;
|
||||
AXI4_Rd_Data #(Wd_Id, Wd_Data, Wd_User)
|
||||
rd_data = AXI4_Rd_Data {rid: 0, // TODO: change uniformly to Fabric_Id
|
||||
rdata: fn_axi4_data_from_line (resp.data, dword_in_line),
|
||||
rresp: axi4_resp_okay,
|
||||
rlast: True,
|
||||
ruser: ?};
|
||||
axi4_slave_xactor.i_rd_data.enq (rd_data);
|
||||
if (verbosity != 0) begin
|
||||
$display ("[LLCDmaConnect sendLdRespToMemLoader]");
|
||||
$display (" ", fshow (resp));
|
||||
$display (" ", fshow (rd_data));
|
||||
end
|
||||
endrule
|
||||
|
||||
rule sendLdRespToTlb(llc.respLd.first.id matches tagged Tlb .id);
|
||||
llc.respLd.deq;
|
||||
let resp = llc.respLd.first;
|
||||
@@ -279,23 +415,6 @@ module mkLLCDmaConnect #(
|
||||
end
|
||||
endrule
|
||||
|
||||
// send St resp from LLC
|
||||
rule sendStRespToMemLoader(llc.respSt.first matches tagged MemLoader .id);
|
||||
let resp = llc.respSt.first;
|
||||
llc.respSt.deq;
|
||||
AXI4_Wr_Resp #(Wd_Id, Wd_User)
|
||||
wr_resp = AXI4_Wr_Resp {bid: 0, // TODO: change uniformly to Fabric_id
|
||||
bresp: axi4_resp_okay,
|
||||
buser: ?};
|
||||
axi4_slave_xactor.i_wr_resp.enq (wr_resp);
|
||||
|
||||
if (verbosity != 0) begin
|
||||
$display ("[LLCDmaConnect sendStRespToMemLoader]");
|
||||
$display (" ", fshow (resp));
|
||||
$display (" ", fshow (wr_resp));
|
||||
end
|
||||
endrule
|
||||
|
||||
rule sendStRespToTlb(llc.respSt.first matches tagged Tlb .id);
|
||||
llc.respSt.deq;
|
||||
if(verbose) begin
|
||||
@@ -304,5 +423,8 @@ module mkLLCDmaConnect #(
|
||||
doAssert(False, "No TLB st");
|
||||
endrule
|
||||
|
||||
// ================================================================
|
||||
// INTERFACE
|
||||
|
||||
return axi4_slave_xactor.axi_side;
|
||||
endmodule
|
||||
|
||||
Reference in New Issue
Block a user