From 68d3bd484e85d2a49ab5e9a78ddbb85ace0dfec1 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Tue, 7 Jul 2020 23:59:35 +0100 Subject: [PATCH] Provide opt-in wedge debugging info 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. --- src_Core/CPU/Core.bsv | 12 ++++ src_Core/CPU/Proc.bsv | 10 +++ src_Core/CPU/Proc_IFC.bsv | 12 ++++ src_Core/Core/CoreW.bsv | 5 ++ src_Core/Debug_Module/DM_Common.bsv | 22 ++++++- src_Core/Debug_Module/Debug_Module.bsv | 61 +++++++++++++++++++ .../RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv | 38 ++++++++++++ .../RISCY_OOO/procs/lib/ReorderBuffer.bsv | 11 ++++ src_SSITH_P3/Makefile | 3 + src_SSITH_P3/src_BSV/JtagTap.bsv | 2 +- 10 files changed, 174 insertions(+), 2 deletions(-) diff --git a/src_Core/CPU/Core.bsv b/src_Core/CPU/Core.bsv index 1f77235..071c975 100644 --- a/src_Core/CPU/Core.bsv +++ b/src_Core/CPU/Core.bsv @@ -201,6 +201,13 @@ interface Core; interface Vector #(SupSize, Get #(Trace_Data2)) v_to_TV; `endif +`ifdef DEBUG_WEDGE + (* always_enabled *) + method Tuple2#(CapMem, Bit#(32)) debugLastInst; + (* always_enabled *) + method Tuple2#(CapMem, Bit#(32)) debugNextInst; +`endif + endinterface // fixpoint to instantiate modules @@ -1446,4 +1453,9 @@ module mkCore#(CoreId coreId)(Core); interface v_to_TV = map (toGet, v_f_to_TV); `endif +`ifdef DEBUG_WEDGE + method Tuple2#(CapMem, Bit#(32)) debugLastInst = commitStage.debugLastInst; + method Tuple2#(CapMem, Bit#(32)) debugNextInst = rob.debugNextInst; +`endif + endmodule diff --git a/src_Core/CPU/Proc.bsv b/src_Core/CPU/Proc.bsv index 219bad9..740a52c 100644 --- a/src_Core/CPU/Proc.bsv +++ b/src_Core/CPU/Proc.bsv @@ -103,6 +103,11 @@ import ProcTypes :: *; import Trace_Data2 :: *; `endif +`ifdef DEBUG_WEDGE +import CHERICap :: *; +import CHERICC_Fat :: *; +`endif + // ================================================================ (* synthesize *) @@ -328,6 +333,11 @@ module mkProc (Proc_IFC); interface v_to_TV = core [0].v_to_TV; `endif +`ifdef DEBUG_WEDGE + method Tuple2#(CapMem, Bit#(32)) hart0_last_inst = core[0].debugLastInst; + method Tuple2#(CapMem, Bit#(32)) hart0_next_inst = core[0].debugNextInst; +`endif + endmodule: mkProc // ================================================================ diff --git a/src_Core/CPU/Proc_IFC.bsv b/src_Core/CPU/Proc_IFC.bsv index 7c4a263..dca743b 100644 --- a/src_Core/CPU/Proc_IFC.bsv +++ b/src_Core/CPU/Proc_IFC.bsv @@ -46,6 +46,11 @@ import Trace_Data2 :: *; import Types :: *; `endif +`ifdef DEBUG_WEDGE +import CHERICap :: *; +import CHERICC_Fat :: *; +`endif + // ================================================================ // CPU interface @@ -128,6 +133,13 @@ interface Proc_IFC; interface Vector #(SupSize, Get #(Trace_Data2)) v_to_TV; `endif +`ifdef DEBUG_WEDGE + (* always_enabled *) + method Tuple2#(CapMem, Bit#(32)) hart0_last_inst; + (* always_enabled *) + method Tuple2#(CapMem, Bit#(32)) hart0_next_inst; +`endif + endinterface // ================================================================ diff --git a/src_Core/Core/CoreW.bsv b/src_Core/Core/CoreW.bsv index 7bbbff7..d573715 100644 --- a/src_Core/Core/CoreW.bsv +++ b/src_Core/Core/CoreW.bsv @@ -231,6 +231,11 @@ module mkCoreW #(Reset dm_power_on_reset) mkConnection (debug_module.hart0_client_run_halt, proc.hart0_run_halt_server); mkConnection (debug_module.hart0_get_other_req, proc.hart0_put_other_req); + +`ifdef DEBUG_WEDGE + mkConnection (proc.hart0_last_inst, debug_module.hart0_last_inst); + mkConnection (proc.hart0_next_inst, debug_module.hart0_next_inst); +`endif `endif `ifdef INCLUDE_TANDEM_VERIF diff --git a/src_Core/Debug_Module/DM_Common.bsv b/src_Core/Debug_Module/DM_Common.bsv index 45049f2..cbb1a67 100644 --- a/src_Core/Debug_Module/DM_Common.bsv +++ b/src_Core/Debug_Module/DM_Common.bsv @@ -22,7 +22,7 @@ package DM_Common; typedef Bit #(7) DM_Addr; -DM_Addr max_DM_Addr = 'h5F; +DM_Addr max_DM_Addr = 'h7F; typedef Bit #(32) DM_Word; @@ -79,6 +79,26 @@ DM_Addr dm_addr_sbdata1 = 'h3d; DM_Addr dm_addr_sbdata2 = 'h3e; DM_Addr dm_addr_sbdata3 = 'h3f; +// ---------------- +// Custom registers + +DM_Addr dm_addr_custom0 = 'h70; +DM_Addr dm_addr_custom1 = 'h71; +DM_Addr dm_addr_custom2 = 'h72; +DM_Addr dm_addr_custom3 = 'h73; +DM_Addr dm_addr_custom4 = 'h74; +DM_Addr dm_addr_custom5 = 'h75; +DM_Addr dm_addr_custom6 = 'h76; +DM_Addr dm_addr_custom7 = 'h77; +DM_Addr dm_addr_custom8 = 'h78; +DM_Addr dm_addr_custom9 = 'h79; +DM_Addr dm_addr_custom10 = 'h7a; +DM_Addr dm_addr_custom11 = 'h7b; +DM_Addr dm_addr_custom12 = 'h7c; +DM_Addr dm_addr_custom13 = 'h7d; +DM_Addr dm_addr_custom14 = 'h7e; +DM_Addr dm_addr_custom15 = 'h7f; + // ================================================================ function Fmt fshow_dm_addr (DM_Addr dm_addr); diff --git a/src_Core/Debug_Module/Debug_Module.bsv b/src_Core/Debug_Module/Debug_Module.bsv index afe53be..1d3043a 100644 --- a/src_Core/Debug_Module/Debug_Module.bsv +++ b/src_Core/Debug_Module/Debug_Module.bsv @@ -91,6 +91,12 @@ 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 :: *; @@ -126,6 +132,15 @@ interface Debug_Module_IFC; // 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 @@ -154,6 +169,13 @@ module mkDebug_Module (Debug_Module_IFC); 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 @@ -228,6 +250,32 @@ module mkDebug_Module (Debug_Module_IFC); 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; @@ -315,6 +363,19 @@ module mkDebug_Module (Debug_Module_IFC); // 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 diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv index b3cc5b3..6531543 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv @@ -161,6 +161,10 @@ interface CommitStage; method Bool is_debug_halted; method Action debug_resume; `endif +`ifdef DEBUG_WEDGE + (* always_enabled *) + method Tuple2#(CapMem, Bit#(32)) debugLastInst; +`endif endinterface // we apply actions the end of commit rule @@ -620,6 +624,11 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); endfunction `endif +`ifdef DEBUG_WEDGE + Reg#(CapMem) rg_last_pcc <- mkReg(unpack(0)); + Reg#(Bit#(32)) rg_last_inst <- mkReg(0); +`endif + // TODO Currently we don't check spec bits == 0 when we commit an // instruction. This is because killings of wrong path instructions are // done in a single cycle. However, when we make killings distributed or @@ -779,6 +788,13 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); x, no_fflags, no_mstatus, tagged Valid trap_updates, no_ret_updates); `endif rg_serial_num <= rg_serial_num + 1; +`ifdef DEBUG_WEDGE + Bool is_exception = trap.trap matches tagged Interrupt .i ? False : True; + if (is_exception) begin + rg_last_pcc <= trap.pc; + rg_last_inst <= trap.orig_inst; + end +`endif // system consistency // TODO spike flushes TLB here, but perhaps it is because spike's TLB @@ -945,6 +961,10 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); x, no_fflags, new_mstatus, no_trap_updates, m_ret_updates); `endif rg_serial_num <= rg_serial_num + 1; +`ifdef DEBUG_WEDGE + rg_last_pcc <= x.pc; + rg_last_inst <= x.orig_inst; +`endif // rename stage only sends out system inst when ROB is empty, so no // need to flush ROB again @@ -1068,6 +1088,10 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); // (whereas the 'fflags' variable does just one update after superscalar retirement). Bit #(5) po_fflags = ?; Data po_mstatus = ?; +`endif +`ifdef DEBUG_WEDGE + CapMem last_pcc = rg_last_pcc; + Bit#(32) last_inst = rg_last_inst; `endif // compute what actions to take for(Integer i = 0; i < valueof(SupSize); i = i+1) begin @@ -1110,6 +1134,10 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); no_trap_updates, no_ret_updates); `endif instret = instret + 1; +`ifdef DEBUG_WEDGE + last_pcc = x.pc; + last_inst = x.orig_inst; +`endif // inst can be committed, deq it rob.deqPort[i].deq; @@ -1163,6 +1191,10 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); end end rg_serial_num <= rg_serial_num + instret; +`ifdef DEBUG_WEDGE + rg_last_pcc <= last_pcc; + rg_last_inst <= last_inst; +`endif // write FPU csr if(csrf.fpuInstNeedWr(fflags, will_dirty_fpu_state)) begin @@ -1281,4 +1313,10 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); endmethod `endif +`ifdef DEBUG_WEDGE + method Tuple2#(CapMem, Bit#(32)) debugLastInst; + return tuple2(rg_last_pcc, rg_last_inst); + endmethod +`endif + endmodule diff --git a/src_Core/RISCY_OOO/procs/lib/ReorderBuffer.bsv b/src_Core/RISCY_OOO/procs/lib/ReorderBuffer.bsv index 8425be9..1609f8d 100755 --- a/src_Core/RISCY_OOO/procs/lib/ReorderBuffer.bsv +++ b/src_Core/RISCY_OOO/procs/lib/ReorderBuffer.bsv @@ -661,6 +661,11 @@ interface SupReorderBuffer#(numeric type aluExeNum, numeric type fpuMulDivExeNum method Bool isFull_ehrPort0; interface ROB_SpeculationUpdate specUpdate; + +`ifdef DEBUG_WEDGE + (* always_enabled *) + method Tuple2#(CapMem, Bit#(32)) debugNextInst; +`endif endinterface typedef struct { @@ -1305,4 +1310,10 @@ module mkSupReorderBuffer#( end endmethod endinterface + +`ifdef DEBUG_WEDGE + method Tuple2#(CapMem, Bit#(32)) debugNextInst; + return tuple2(fifo_first[0].pc, fifo_first[0].orig_inst); + endmethod +`endif endmodule diff --git a/src_SSITH_P3/Makefile b/src_SSITH_P3/Makefile index 19bd37c..740c1f3 100644 --- a/src_SSITH_P3/Makefile +++ b/src_SSITH_P3/Makefile @@ -40,6 +40,9 @@ BSC_COMPILATION_FLAGS += \ -D BRVF_TRACE \ -D XILINX_BSCAN -D JTAG_TAP +# Enable to expose last and next instruction info as DMI registers +#BSC_COMPILATION_FLAGS += -D DEBUG_WEDGE + # Synth only BSC_COMPILATION_FLAGS SYNTH_BSC_OPTIONS = -D XILINX_XCVU9P diff --git a/src_SSITH_P3/src_BSV/JtagTap.bsv b/src_SSITH_P3/src_BSV/JtagTap.bsv index 1efe670..e094651 100644 --- a/src_SSITH_P3/src_BSV/JtagTap.bsv +++ b/src_SSITH_P3/src_BSV/JtagTap.bsv @@ -13,7 +13,7 @@ import PowerOnReset ::*; import ClockHacks ::*; import Giraffe_IFC ::*; -typedef 6 ABITS; +typedef 7 ABITS; `ifdef XILINX_BSCAN `ifdef XILINX_XCVU095 typedef 6 IR_LENGTH;