Files
Toooba/src_Core/Debug_Module/Debug_Module.bsv
Jessica Clarke 0f65994955 Plumb through a lot more ROB debug state
In particular, the previous set of debug info only looked at one of the
superscalar ways, assuming the 0th was always the next instruction, but
there's a level of indirection to map ports to ways that was missed. But
now we dump out both ways and more. And yes, I fully recognise the
atrocity that is the type in use here... please forgive me. It doesn't
help that bsc is buggy and gets confused about the structure of nested
tuples[1].

Drops the commit debug output to only the low 32 bits of PCC's address
and no instruction bits; as this has been committed it should be (and
has always been observed to be) within bounds and, thus, fit in 32 bits
when running in M-mode, with the instruction bits obtainable from the
binary. I'd much rather know about potentially-dodgy speculative
addresses than things we can reliably infer given the limited number of
DMI registers free (though we could hijack other encodings if
necessary).

[1] https://github.com/B-Lang-org/bsc/issues/199
2020-07-10 15:59:40 +01:00

468 lines
15 KiB
Plaintext

// Copyright (c) 2017-2019 Bluespec, Inc. All Rights Reserved.
//
//-
// RVFI_DII + CHERI modifications:
// Copyright (c) 2020 Alexandre Joannou
// Copyright (c) 2020 Peter Rugg
// Copyright (c) 2020 Jonathan Woodruff
// All rights reserved.
//
// This software was developed by SRI International and the University of
// Cambridge Computer Laboratory (Department of Computer Science and
// Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
// DARPA SSITH research programme.
//
// This work was supported by NCSC programme grant 4212611/RFA 15971 ("SafeBet").
//-
package Debug_Module;
// ================================================================
// This is the top-level package of a collection that implements the
// "Debug Module" specified in:
//
// "RISC-V External Debug Support"
// Version 0.13
// 7c760b0151e43523ab3d2180e7852cd6f27d942c
// Mon Jul 3 17:04:59 2017 -0700
// Note: the spec actually represents three (almost) completely
// independent functionalities:
// Run Control: to start/stop harts, query their start/stop status, etc.
// Abstract Commands: to read/write RISC-V registers and RISC-V CSRs
// System Bus Access: to read/write RISC-V memory/devices
// The only exception to complete independence is that the Run Control
// part has a 'reset' for the Debug Module itself, which includes all
// three parts.
// Unfortunately the spec is not written to make this three-part
// organization clear--aspects of the three parts are completely
// intermingled. Even the address map mixes registers from the three
// parts.
// Here, this top-level package is merely a wrapper that dispatches
// DMI requests to the three packages that implement the three parts:
// DM_Run_Control
// DM_Abstract_Commands
// DM_System_Bus
// DM_Common contains common spec-level (implementation-independent) definitions.
// ================================================================
// Our Debug Module (DM) has a two sides:
// - GDB/Host-facing
// - CPU/Platform-facing
// The GDB/Host-facing side is called DMI (Debug Module Interface) in
// the spec, and is a simple memory-like read/write interface, into a
// debug module address space (unrelated to the RISC-V memory address
// space).
// The CPU/Platform-facing side has request/response interfaces for
// CPU run-control, CPU register/CSR access and RISC-V system memory
// access.
// ================================================================
// BSV library imports
import Memory :: *;
import FIFO :: *;
import GetPut :: *;
import ClientServer :: *;
import SpecialFIFOs :: *;
// ----------------
// Other library imports
import Semi_FIFOF :: *;
import Cur_Cycle :: *;
import AXI4 :: *;
// ================================================================
// Project imports
import ISA_Decls :: *;
import Fabric_Defs :: *;
import DM_Common :: *;
import DM_CPU_Req_Rsp :: *;
import DM_Run_Control :: *;
import DM_Abstract_Commands :: *;
import DM_System_Bus :: *;
`ifdef DEBUG_WEDGE
import ConfigReg :: *;
import CHERICap :: *;
import CHERICC_Fat :: *;
`endif
// ================================================================
export DM_Common :: *;
export Debug_Module_IFC (..);
export mkDebug_Module;
// ================================================================
// Interface to the Debug Module
interface Debug_Module_IFC;
// ----------------
// DMI (Debug Module Interface) facing remote debugger
interface DMI dmi;
// ----------------
// Facing CPU
// This section replicated for additional harts.
// Reset and run-control
interface Client #(Bool, Bool) hart0_reset_client;
interface Client #(Bool, Bool) hart0_client_run_halt;
interface Get #(Bit #(4)) hart0_get_other_req;
// GPR access
interface Client #(DM_CPU_Req #(5, XLEN), DM_CPU_Rsp #(XLEN)) hart0_gpr_mem_client;
// FPR access
`ifdef ISA_F
interface Client #(DM_CPU_Req #(5, FLEN), DM_CPU_Rsp #(FLEN)) hart0_fpr_mem_client;
`endif
// CSR access
interface Client #(DM_CPU_Req #(12, XLEN), DM_CPU_Rsp #(XLEN)) hart0_csr_mem_client;
// Optional debug from commit stage and ROB
`ifdef DEBUG_WEDGE
(* always_enabled *)
method Action hart0_last_inst (Tuple2 #(CapMem, Bit #(32)) pcc_inst);
(* always_enabled *)
method Action hart0_debug_rob (Tuple4 #(Tuple3 #(Bit #(32), Bit #(32), Bit #(32)), Tuple4 #(CapMem, Bit #(32), CapMem, Bit #(32)), Tuple4 #(CapMem, Bit #(32), CapMem, Bit #(32)), void) state);
`endif
// ----------------
// Facing Platform
// Non-Debug-Module Reset (reset all except DM)
// Bool indicates 'running' hart state.
interface Client #(Bool, Bool) ndm_reset_client;
// Read/Write RISC-V memory
interface AXI4_Master_Synth #(Wd_MId_2x3, Wd_Addr, Wd_Data_Periph,
Wd_AW_User, Wd_W_User, Wd_B_User,
Wd_AR_User, Wd_R_User) master;
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;
DM_System_Bus_IFC dm_system_bus <- mkDM_System_Bus;
FIFO#(DM_Addr) f_read_addr <- mkFIFO1;
`ifdef DEBUG_WEDGE
Reg #(CapMem) rg_last_pcc <- mkConfigReg (unpack (0));
Reg #(Bit #(32)) rg_last_inst <- mkConfigReg (0);
Reg #(Bit #(32)) rg_rob_ps_and_ways <- mkConfigReg (0);
Reg #(Bit #(32)) rg_rob_valid0 <- mkConfigReg (0);
Reg #(Bit #(32)) rg_rob_valid1 <- mkConfigReg (0);
Reg #(CapMem) rg_rob_first0_pcc <- mkConfigReg (unpack (0));
Reg #(Bit #(32)) rg_rob_first0_inst <- mkConfigReg (0);
Reg #(CapMem) rg_rob_first1_pcc <- mkConfigReg (unpack (0));
Reg #(Bit #(32)) rg_rob_first1_inst <- mkConfigReg (0);
Reg #(CapMem) rg_rob_last0_pcc <- mkConfigReg (unpack (0));
Reg #(Bit #(32)) rg_rob_last0_inst <- mkConfigReg (0);
Reg #(CapMem) rg_rob_last1_pcc <- mkConfigReg (unpack (0));
Reg #(Bit #(32)) rg_rob_last1_inst <- mkConfigReg (0);
`endif
// ================================================================
// Reset all three parts when dm_run_control.dmactive is low
rule rl_reset (! dm_run_control.dmactive);
$display ("%0d: Debug_Module reset", cur_cycle);
dm_run_control.reset;
dm_abstract_commands.reset;
dm_system_bus.reset;
endrule
// ================================================================
// INTERFACE
// ----------------
// Facing GDB/DMI (Debug Module Interface)
interface DMI dmi;
method Action read_addr (DM_Addr dm_addr) if (dm_run_control.dmactive);
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;
let dm_addr = f_read_addr.first;
f_read_addr.deq;
DM_Word dm_word = ?;
if ( (dm_addr == dm_addr_dmcontrol)
|| (dm_addr == dm_addr_dmstatus)
|| (dm_addr == dm_addr_hartinfo)
|| (dm_addr == dm_addr_haltsum)
|| (dm_addr == dm_addr_hawindowsel)
|| (dm_addr == dm_addr_hawindow)
|| (dm_addr == dm_addr_devtreeaddr0)
|| (dm_addr == dm_addr_authdata)
|| (dm_addr == dm_addr_haltregion0)
|| (dm_addr == dm_addr_haltregion31)
|| (dm_addr == dm_addr_verbosity))
dm_word <- dm_run_control.av_read (dm_addr);
else if ( (dm_addr == dm_addr_abstractcs)
|| (dm_addr == dm_addr_command)
|| (dm_addr == dm_addr_data0)
|| (dm_addr == dm_addr_data1)
|| (dm_addr == dm_addr_data2)
|| (dm_addr == dm_addr_data3)
|| (dm_addr == dm_addr_data4)
|| (dm_addr == dm_addr_data5)
|| (dm_addr == dm_addr_data6)
|| (dm_addr == dm_addr_data7)
|| (dm_addr == dm_addr_data8)
|| (dm_addr == dm_addr_data9)
|| (dm_addr == dm_addr_data10)
|| (dm_addr == dm_addr_data11)
|| (dm_addr == dm_addr_abstractauto)
|| (dm_addr == dm_addr_progbuf0))
dm_word <- dm_abstract_commands.av_read (dm_addr);
else if ( (dm_addr == dm_addr_sbcs)
|| (dm_addr == dm_addr_sbaddress0)
|| (dm_addr == dm_addr_sbaddress1)
|| (dm_addr == dm_addr_sbaddress2)
|| (dm_addr == dm_addr_sbdata0)
|| (dm_addr == dm_addr_sbdata1)
|| (dm_addr == dm_addr_sbdata2)
|| (dm_addr == dm_addr_sbdata3))
dm_word <- dm_system_bus.av_read (dm_addr);
`ifdef DEBUG_WEDGE
else if (dm_addr == dm_addr_custom0)
dm_word = getAddr (rg_last_pcc) [31:0];
else if (dm_addr == dm_addr_custom1)
dm_word = rg_rob_ps_and_ways;
else if (dm_addr == dm_addr_custom2)
dm_word = rg_rob_valid0;
else if (dm_addr == dm_addr_custom3)
dm_word = rg_rob_valid1;
else if (dm_addr == dm_addr_custom4)
dm_word = getAddr (rg_rob_first0_pcc) [31:0];
else if (dm_addr == dm_addr_custom5)
dm_word = getAddr (rg_rob_first0_pcc) [63:32];
else if (dm_addr == dm_addr_custom6)
dm_word = rg_rob_first0_inst;
else if (dm_addr == dm_addr_custom7)
dm_word = getAddr (rg_rob_first1_pcc) [31:0];
else if (dm_addr == dm_addr_custom8)
dm_word = getAddr (rg_rob_first1_pcc) [63:32];
else if (dm_addr == dm_addr_custom9)
dm_word = rg_rob_first1_inst;
else if (dm_addr == dm_addr_custom10)
dm_word = getAddr (rg_rob_last0_pcc) [31:0];
else if (dm_addr == dm_addr_custom11)
dm_word = getAddr (rg_rob_last0_pcc) [63:32];
else if (dm_addr == dm_addr_custom12)
dm_word = rg_rob_last0_inst;
else if (dm_addr == dm_addr_custom13)
dm_word = getAddr (rg_rob_last1_pcc) [31:0];
else if (dm_addr == dm_addr_custom14)
dm_word = getAddr (rg_rob_last1_pcc) [63:32];
else if (dm_addr == dm_addr_custom15)
dm_word = rg_rob_last1_inst;
`endif
else begin
// TODO: set error status?
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
method Action write (DM_Addr dm_addr, DM_Word dm_word) if (dm_run_control.dmactive);
if ( (dm_addr == dm_addr_dmcontrol)
|| (dm_addr == dm_addr_dmstatus)
|| (dm_addr == dm_addr_hartinfo)
|| (dm_addr == dm_addr_haltsum)
|| (dm_addr == dm_addr_hawindowsel)
|| (dm_addr == dm_addr_hawindow)
|| (dm_addr == dm_addr_devtreeaddr0)
|| (dm_addr == dm_addr_authdata)
|| (dm_addr == dm_addr_haltregion0)
|| (dm_addr == dm_addr_haltregion31)
|| (dm_addr == dm_addr_verbosity))
dm_run_control.write (dm_addr, dm_word);
else if ( (dm_addr == dm_addr_abstractcs)
|| (dm_addr == dm_addr_command)
|| (dm_addr == dm_addr_data0)
|| (dm_addr == dm_addr_data1)
|| (dm_addr == dm_addr_data2)
|| (dm_addr == dm_addr_data3)
|| (dm_addr == dm_addr_data4)
|| (dm_addr == dm_addr_data5)
|| (dm_addr == dm_addr_data6)
|| (dm_addr == dm_addr_data7)
|| (dm_addr == dm_addr_data8)
|| (dm_addr == dm_addr_data9)
|| (dm_addr == dm_addr_data10)
|| (dm_addr == dm_addr_data11)
|| (dm_addr == dm_addr_abstractauto)
|| (dm_addr == dm_addr_progbuf0))
dm_abstract_commands.write (dm_addr, dm_word);
else if ( (dm_addr == dm_addr_sbcs)
|| (dm_addr == dm_addr_sbaddress0)
|| (dm_addr == dm_addr_sbaddress1)
|| (dm_addr == dm_addr_sbaddress2)
|| (dm_addr == dm_addr_sbdata0)
|| (dm_addr == dm_addr_sbdata1)
|| (dm_addr == dm_addr_sbdata2)
|| (dm_addr == dm_addr_sbdata3))
dm_system_bus.write (dm_addr, dm_word);
else begin
// 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
// ----------------
// Facing CPU/hart0
// Reset and run-control
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;
// GPR access
interface Client hart0_gpr_mem_client = dm_abstract_commands.hart0_gpr_mem_client;
// FPR access
`ifdef ISA_F
interface Client hart0_fpr_mem_client = dm_abstract_commands.hart0_fpr_mem_client;
`endif
// CSR access
interface Client hart0_csr_mem_client = dm_abstract_commands.hart0_csr_mem_client;
// Optional debug from commit stage
`ifdef DEBUG_WEDGE
method Action hart0_last_inst (Tuple2 #(CapMem, Bit #(32)) pcc_inst);
rg_last_pcc <= tpl_1 (pcc_inst);
rg_last_inst <= tpl_2 (pcc_inst);
endmethod
// XXX: Yes the extra void at the end of the tuple is necessary. Without it,
// bsc seems to inline the last tuple and destroy the programmer-visible
// structure, such that the assignments to rg_rob_lastX_foo need to be
// tpl_[3456] (state), *not* tpl_[1234] (tpl_3 (state)), with the latter
// giving:
//
// The provisos for this expression could not be resolved because there are no
// instances of the form:
// Has_tpl_1#(Bit#(32), Bit#(129))
//
// for the assignment to rg_rob_last0_pcc, and similarly for the others if
// you comment that one out. Just because they're isomorphic doesn't mean
// they're interchangeable :(.
method Action hart0_debug_rob (Tuple4 #(Tuple3 #(Bit #(32), Bit #(32), Bit #(32)), Tuple4 #(CapMem, Bit #(32), CapMem, Bit #(32)), Tuple4 #(CapMem, Bit #(32), CapMem, Bit #(32)), void) state);
rg_rob_ps_and_ways <= tpl_1 (tpl_1 (state));
rg_rob_valid0 <= tpl_2 (tpl_1 (state));
rg_rob_valid1 <= tpl_3 (tpl_1 (state));
rg_rob_first0_pcc <= tpl_1 (tpl_2 (state));
rg_rob_first0_inst <= tpl_2 (tpl_2 (state));
rg_rob_first1_pcc <= tpl_3 (tpl_2 (state));
rg_rob_first1_inst <= tpl_4 (tpl_2 (state));
rg_rob_last0_pcc <= tpl_1 (tpl_3 (state));
rg_rob_last0_inst <= tpl_2 (tpl_3 (state));
rg_rob_last1_pcc <= tpl_3 (tpl_3 (state));
rg_rob_last1_inst <= tpl_4 (tpl_3 (state));
endmethod
`endif
// ----------------
// Facing Platform
// Non-Debug-Module Reset (reset all except DM)
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;
endmodule
// ================================================================
endpackage