diff --git a/config/shared/debug.vh b/config/shared/debug.vh index e2ecf49cd..24091620b 100755 --- a/config/shared/debug.vh +++ b/config/shared/debug.vh @@ -23,7 +23,7 @@ `define OP_FAILED 2'b10 `define OP_BUSY 2'b11 -// DMI register Address Width +// DMI Bus Address Width `define DMI_ADDR_WIDTH 7 // Debug Module Debug Bus Register Addresses diff --git a/src/debug/dmc.sv b/src/debug/dmc.sv index 852b77585..f01c051dd 100644 --- a/src/debug/dmc.sv +++ b/src/debug/dmc.sv @@ -43,22 +43,21 @@ module dmc ( input logic AckHaveReset, // Clears HaveReset status input logic ExecProgBuf, // Updates PC to progbuf and resumes core - output logic DebugMode, + output logic DebugMode, // Sets state in DM and controls masking of interrupts output logic [2:0] DebugCause, // Reason Hart entered debug mode output logic ResumeAck, // Signals Hart has been resumed output logic HaveReset, // Signals Hart has been reset output logic DebugStall, // Stall signal goes to hazard unit - output logic EnterDebugMode, // Store PCNextF in DPC when entering Debug Mode - output logic ExitDebugMode, // Updates PCNextF with the current value of DPC + output logic DCall, // Store PCNextF in DPC when entering Debug Mode + output logic DRet, // Updates PCNextF with the current value of DPC output logic ForceBreakPoint // Causes artificial ebreak that puts core in debug mode ); `include "debug.vh" + enum logic [1:0] {RUNNING, EXECPROGBUF, HALTED, STEP} State; - enum logic [1:0] {RUNNING, HALTED, STEP} State; - - localparam E2M_CYCLE_COUNT = 3; + localparam E2M_CYCLE_COUNT = 4; logic [$clog2(E2M_CYCLE_COUNT+1)-1:0] Counter; always_ff @(posedge clk) begin @@ -73,8 +72,8 @@ module dmc ( assign DebugMode = (State != RUNNING); assign DebugStall = (State == HALTED); - assign EnterDebugMode = (State == RUNNING) & (ebreakM & ebreakEn) | ForceBreakPoint; - assign ExitDebugMode = (State == HALTED) & (ResumeReq | ExecProgBuf); + assign DCall = ((State == RUNNING) | (State == EXECPROGBUF)) & ((ebreakM & ebreakEn) | ForceBreakPoint); + assign DRet = (State == HALTED) & (ResumeReq | ExecProgBuf); always_ff @(posedge clk) begin if (reset) begin @@ -92,6 +91,14 @@ module dmc ( end end + // Similar to RUNNING, but DebugMode isn't deasserted + EXECPROGBUF : begin + if (ebreakM & ebreakEn) begin + State <= HALTED; + DebugCause <= `CAUSE_EBREAK; + end + end + HALTED : begin if (ResumeReq) begin if (Step) begin @@ -102,7 +109,7 @@ module dmc ( ResumeAck <= 1; end end else if (ExecProgBuf) begin - State <= RUNNING; + State <= EXECPROGBUF; ResumeAck <= 1; end end diff --git a/src/hazard/hazard.sv b/src/hazard/hazard.sv index 7c2133420..f7361246f 100644 --- a/src/hazard/hazard.sv +++ b/src/hazard/hazard.sv @@ -29,7 +29,7 @@ module hazard import cvw::*; #(parameter cvw_t P) ( input logic BPWrongE, CSRWriteFenceM, RetM, TrapM, - input logic ExitDebugMode, + input logic DRet, input logic StructuralStallD, input logic LSUStallM, IFUStallF, input logic FPUStallD, @@ -71,9 +71,9 @@ module hazard import cvw::*; #(parameter cvw_t P) ( // Branch misprediction is found in the Execute stage and must flush the next two instructions. // However, an active division operation resides in the Execute stage, and when the BP incorrectly mispredicts the divide as a taken branch, the divde must still complete // When a WFI is interrupted and causes a trap, it flushes the rest of the pipeline but not the W stage, because the WFI needs to commit - assign FlushDCause = TrapM | RetM | ExitDebugMode | CSRWriteFenceM | BPWrongE; - assign FlushECause = TrapM | RetM | ExitDebugMode | CSRWriteFenceM |(BPWrongE & ~(DivBusyE | FDivBusyE)); - assign FlushMCause = TrapM | RetM | ExitDebugMode | CSRWriteFenceM; + assign FlushDCause = TrapM | RetM | DRet | CSRWriteFenceM | BPWrongE; + assign FlushECause = TrapM | RetM | DRet | CSRWriteFenceM |(BPWrongE & ~(DivBusyE | FDivBusyE)); + assign FlushMCause = TrapM | RetM | DRet | CSRWriteFenceM; assign FlushWCause = TrapM & ~WFIInterruptedM; // Stall causes @@ -91,7 +91,7 @@ module hazard import cvw::*; #(parameter cvw_t P) ( // Need to gate IFUStallF when the equivalent FlushFCause = FlushDCause = 1. // assign StallWCause = ((IFUStallF & ~FlushDCause) | LSUStallM) & ~FlushWCause; // Because FlushWCause is a strict subset of FlushDCause, FlushWCause is factored out. - assign StallWCause = (IFUStallF & ~FlushDCause) | (LSUStallM & ~FlushWCause) | (DebugStall & ~ExitDebugMode); + assign StallWCause = (IFUStallF & ~FlushDCause) | (LSUStallM & ~FlushWCause) | (DebugStall & ~DRet); // Stall each stage for cause or if the next stage is stalled // coverage off: StallFCause is always 0 diff --git a/src/ifu/ifu.sv b/src/ifu/ifu.sv index 81586d7ab..261536643 100644 --- a/src/ifu/ifu.sv +++ b/src/ifu/ifu.sv @@ -97,7 +97,7 @@ module ifu import cvw::*; #(parameter cvw_t P) ( output logic ICacheAccess, // Report I$ read to performance counters output logic ICacheMiss, // Report I$ miss to performance counters // Debug Mode logic - input logic ExitDebugMode, + input logic DRet, input logic ProgBuffScanEn, // Debug scan chain input logic [3:0] ProgBufAddr, @@ -336,7 +336,7 @@ module ifu import cvw::*; #(parameter cvw_t P) ( else assign PC2NextF = PC1NextF; - mux3 #(P.XLEN) pcmux3(PC2NextF, EPCM, TrapVectorM, {TrapM, (RetM | ExitDebugMode)}, UnalignedPCNextF); + mux3 #(P.XLEN) pcmux3(PC2NextF, EPCM, TrapVectorM, {TrapM, (RetM | DRet)}, UnalignedPCNextF); mux2 #(P.XLEN) pcresetmux({UnalignedPCNextF[P.XLEN-1:1], 1'b0}, P.RESET_VECTOR[P.XLEN-1:0], reset, PCNextF); flopen #(P.XLEN) pcreg(clk, ~StallF | reset, PCNextF, PCF); diff --git a/src/privileged/csr.sv b/src/privileged/csr.sv index d4ea6f18e..98582ad00 100644 --- a/src/privileged/csr.sv +++ b/src/privileged/csr.sv @@ -99,8 +99,8 @@ module csr import cvw::*; #(parameter cvw_t P) ( output logic ebreakEn, output logic Step, output logic [P.XLEN-1:0] DPC, - input logic EnterDebugMode, - input logic ExitDebugMode, + input logic DCall, + input logic DRet, input logic ExecProgBuf, // Debug scan chain input logic DebugSel, @@ -189,7 +189,7 @@ module csr import cvw::*; #(parameter cvw_t P) ( if (P.DEBUG_SUPPORTED) begin always_comb if (ExecProgBuf) EPCM = P.PROGBUF_BASE; - else if (ExitDebugMode) EPCM = DPC; + else if (DRet) EPCM = DPC; else if (mretM) EPCM = MEPC_REGW; else EPCM = SEPC_REGW; end else begin @@ -318,7 +318,7 @@ module csr import cvw::*; #(parameter cvw_t P) ( if (P.DEBUG_SUPPORTED) begin:csrd csrd #(P) csrd(.clk, .reset, .DebugMode, .PrivilegeModeW, .CSRWriteDM, .CSRAdrM(CSRAdrDM), .CSRWriteValM(CSRWriteValDM), .CSRDReadValM, .IllegalCSRDAccessM, - .DebugCause, .ebreakEn, .Step, .DPC, .PCM, .EnterDebugMode); + .DebugCause, .ebreakEn, .Step, .DPC, .PCM, .DCall); end else begin assign CSRDReadValM = '0; assign IllegalCSRDAccessM = 1'b1; // Debug isn't supported diff --git a/src/privileged/csrd.sv b/src/privileged/csrd.sv index 6d7432a72..293c59eac 100644 --- a/src/privileged/csrd.sv +++ b/src/privileged/csrd.sv @@ -36,7 +36,7 @@ module csrd import cvw::*; #(parameter cvw_t P) ( output logic [P.XLEN-1:0] CSRDReadValM, output logic IllegalCSRDAccessM, input logic [P.XLEN-1:0] PCM, - input logic EnterDebugMode, + input logic DCall, input logic [2:0] DebugCause, output logic ebreakEn, output logic Step, @@ -44,8 +44,8 @@ module csrd import cvw::*; #(parameter cvw_t P) ( ); `include "debug.vh" - localparam DCSR_ADDR = 12'h7B0; // Debug Control and Status Register - localparam DPC_ADDR = 12'h7B1; // Debug PC + localparam DCSR_ADDR = 12'h7B0; // Debug Control and Status Register + localparam DPC_ADDR = 12'h7B1; // Debug PC logic CSRDWriteM; logic [31:0] DCSR; @@ -70,7 +70,8 @@ module csrd import cvw::*; #(parameter cvw_t P) ( logic [1:0] Prv; - assign ebreakEn = ebreakM; // Only support ebreak from M mode + //assign ebreakEn = ebreakM; // Only support ebreak from M mode + assign ebreakEn = 1'b1; // OpenOCD doesn't set ebreakM???? ebreakM; // Only support ebreak from M mode assign CSRDWriteM = CSRWriteDM & (PrivilegeModeW == P.M_MODE) & DebugMode; assign WriteDCSRM = CSRDWriteM & (CSRAdrM == DCSR_ADDR); @@ -80,7 +81,7 @@ module csrd import cvw::*; #(parameter cvw_t P) ( if (reset) begin Prv <= 2'h3; Cause <= 3'h0; - end else if (EnterDebugMode) begin + end else if (DCall) begin Prv <= PrivilegeModeW; Cause <= DebugCause; end @@ -91,8 +92,8 @@ module csrd import cvw::*; #(parameter cvw_t P) ( assign DCSR = {DebugVer, 10'b0, ebreakVS, ebreakVU, ebreakM, 1'b0, ebreakS, ebreakU, StepIE, StopCount, StopTime, Cause, V, MPrvEn, NMIP, Step, Prv}; - assign DPCWriteVal = EnterDebugMode ? PCM : CSRWriteValM; - flopenr #(P.XLEN) DPCreg (clk, reset, WriteDPCM | EnterDebugMode, DPCWriteVal, DPC); // TODO: reset to something sane (0x80000000?) + assign DPCWriteVal = DCall ? PCM : CSRWriteValM; + flopenr #(P.XLEN) DPCreg (clk, reset, WriteDPCM | DCall, DPCWriteVal, DPC); always_comb begin CSRDReadValM = '0; diff --git a/src/privileged/privileged.sv b/src/privileged/privileged.sv index febdacd2e..ed4cbfa1b 100644 --- a/src/privileged/privileged.sv +++ b/src/privileged/privileged.sv @@ -105,8 +105,8 @@ module privileged import cvw::*; #(parameter cvw_t P) ( input logic [2:0] DebugCause, output logic Step, output logic [P.XLEN-1:0] DPC, - input logic EnterDebugMode, - input logic ExitDebugMode, + input logic DCall, + input logic DRet, input logic ExecProgBuf, // Debug scan chain input logic DebugSel, @@ -167,7 +167,7 @@ module privileged import cvw::*; #(parameter cvw_t P) ( .SetFflagsM, .FRM_REGW, .ENVCFG_CBE, .ENVCFG_PBMTE, .ENVCFG_ADUE, .EPCM, .TrapVectorM, .CSRReadValW, .IllegalCSRAccessM, .BigEndianM, - .DebugMode, .DebugCause, .ebreakEn, .Step, .DPC, .EnterDebugMode, .ExitDebugMode, .ExecProgBuf, + .DebugMode, .DebugCause, .ebreakEn, .Step, .DPC, .DCall, .DRet, .ExecProgBuf, .DebugSel, .DebugRegAddr, .DebugCapture, .DebugRegUpdate, .DebugScanEn, .DebugScanIn, .DebugScanOut); // pipeline early-arriving trap sources @@ -182,6 +182,6 @@ module privileged import cvw::*; #(parameter cvw_t P) ( .LoadAccessFaultM, .StoreAmoAccessFaultM, .EcallFaultM, .InstrPageFaultM, .LoadPageFaultM, .StoreAmoPageFaultM, .PrivilegeModeW, .MIP_REGW, .MIE_REGW, .MIDELEG_REGW, .MEDELEG_REGW, .STATUS_MIE, .STATUS_SIE, - .InstrValidM, .CommittedM, .CommittedF, + .InstrValidM, .CommittedM, .CommittedF, .DebugMode, .TrapM, .wfiM, .wfiW, .InterruptM, .ExceptionM, .IntPendingM, .DelegateM, .CauseM); endmodule diff --git a/src/privileged/trap.sv b/src/privileged/trap.sv index 95ae26e1a..a1f84260e 100644 --- a/src/privileged/trap.sv +++ b/src/privileged/trap.sv @@ -40,6 +40,7 @@ module trap import cvw::*; #(parameter cvw_t P) ( input logic STATUS_MIE, STATUS_SIE, // machine/supervisor interrupt enables input logic InstrValidM, // current instruction is valid, not flushed input logic CommittedM, CommittedF, // LSU/IFU has committed to a bus operation that can't be interrupted + input logic DebugMode, // Ignore all interrupts in debug mode output logic TrapM, // Trap is occurring output logic InterruptM, // Interrupt is occurring output logic ExceptionM, // exception is occurring @@ -88,7 +89,9 @@ module trap import cvw::*; #(parameter cvw_t P) ( BreakpointFaultM | EcallFaultM | LoadAccessFaultM | StoreAmoAccessFaultM; // coverage on - assign TrapM = (ExceptionM & ~CommittedF) | InterruptM; + //assign TrapM = (ExceptionM & ~CommittedF) | InterruptM; + // Debug Test + assign TrapM = DebugMode ? BreakpointFaultM : (ExceptionM & ~CommittedF) | InterruptM; /////////////////////////////////////////// // Cause priority defined in privileged spec diff --git a/src/wally/wallypipelinedcore.sv b/src/wally/wallypipelinedcore.sv index 7858a13fe..f91af1b98 100644 --- a/src/wally/wallypipelinedcore.sv +++ b/src/wally/wallypipelinedcore.sv @@ -199,8 +199,8 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( // Debug mode logic logic [P.XLEN-1:0] DPC; - logic ExitDebugMode; - logic EnterDebugMode; + logic DRet; + logic DCall; logic [2:0] DebugCause; logic ForceBreakPoint; // Debug register scan chain interconnects @@ -228,7 +228,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( .STATUS_MPP, .ENVCFG_PBMTE, .ENVCFG_ADUE, .ITLBWriteF, .sfencevmaM, .ITLBMissOrUpdateAF, // pmp/pma (inside mmu) signals. .PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW, .InstrAccessFaultF, - .ExitDebugMode, .ProgBuffScanEn, .ProgBufAddr, .ProgBufScanIn(DebugScanIn), + .DRet, .ProgBuffScanEn, .ProgBufAddr, .ProgBufScanIn(DebugScanIn), .DebugScanEn(DebugScanEn & MiscSel), .DebugScanIn(DebugScanReg[0]), .DebugScanOut(DebugScanReg[1])); // integer execution unit: integer register file, datapath and controller @@ -312,7 +312,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( // global stall and flush control hazard #(P) hzu( - .BPWrongE, .CSRWriteFenceM, .RetM, .TrapM, .ExitDebugMode, + .BPWrongE, .CSRWriteFenceM, .RetM, .TrapM, .DRet, .StructuralStallD, .LSUStallM, .IFUStallF, .FPUStallD, @@ -327,7 +327,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( .clk, .reset, .Step, .ebreakM, .ebreakEn, .HaltReq, .ResumeReq, .HaltOnReset, .AckHaveReset, .ResumeAck, .HaveReset, .DebugMode, .DebugCause, .DebugStall, .ExecProgBuf, - .EnterDebugMode, .ExitDebugMode, .ForceBreakPoint); + .DCall, .DRet, .ForceBreakPoint); end else begin assign DebugStall = 1'b0; end @@ -355,7 +355,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .STATUS_FS, .PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW, .FRM_REGW, .ENVCFG_CBE, .ENVCFG_PBMTE, .ENVCFG_ADUE, .wfiM, .IntPendingM, .BigEndianM, .ebreakM, - .ebreakEn, .ForceBreakPoint, .DebugMode, .DebugCause, .Step, .DPC, .EnterDebugMode, .ExitDebugMode, .ExecProgBuf, + .ebreakEn, .ForceBreakPoint, .DebugMode, .DebugCause, .Step, .DPC, .DCall, .DRet, .ExecProgBuf, .DebugSel(CSRSel), .DebugRegAddr, .DebugCapture, .DebugRegUpdate, .DebugScanEn(DebugScanEn & CSRSel), .DebugScanIn, .DebugScanOut(CSRScanOut)); if (P.DEBUG_SUPPORTED) begin flopenrs #(1) scantrapm (.clk, .reset, .en(DebugCapture), .d(TrapM), .q(), .scan(DebugScanEn), .scanin(DebugScanIn), .scanout(DebugScanReg[0]));