When DEBUG_WEDGE is defined, expose the last committed and next in the reorder buffer PC and corresponding instruction via DMI registers, since even when the core is wedged and we can't read GPRs etc we can still interact with the debug module itself. Hopefully this proves useful for debugging wedges.
392 lines
12 KiB
Plaintext
392 lines
12 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_next_inst (Tuple2 #(CapMem, Bit #(32)) pcc_inst);
|
|
`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 #(CapMem) rg_next_pcc <- mkConfigReg (unpack (0));
|
|
Reg #(Bit #(32)) rg_next_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 = getAddr (rg_last_pcc) [63:32];
|
|
|
|
else if (dm_addr == dm_addr_custom2)
|
|
|
|
dm_word = rg_last_inst;
|
|
|
|
else if (dm_addr == dm_addr_custom3)
|
|
|
|
dm_word = getAddr (rg_next_pcc) [31:0];
|
|
|
|
else if (dm_addr == dm_addr_custom4)
|
|
|
|
dm_word = getAddr (rg_next_pcc) [63:32];
|
|
|
|
else if (dm_addr == dm_addr_custom5)
|
|
|
|
dm_word = rg_next_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
|
|
|
|
method Action hart0_next_inst (Tuple2 #(CapMem, Bit #(32)) pcc_inst);
|
|
rg_next_pcc <= tpl_1 (pcc_inst);
|
|
rg_next_inst <= tpl_2 (pcc_inst);
|
|
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
|