Block traps in debug mode

This commit is contained in:
Matthew 2024-06-25 12:33:32 -05:00
parent 372904c6d9
commit bf4bdd46af
9 changed files with 50 additions and 39 deletions

View File

@ -23,7 +23,7 @@
`define OP_FAILED 2'b10 `define OP_FAILED 2'b10
`define OP_BUSY 2'b11 `define OP_BUSY 2'b11
// DMI register Address Width // DMI Bus Address Width
`define DMI_ADDR_WIDTH 7 `define DMI_ADDR_WIDTH 7
// Debug Module Debug Bus Register Addresses // Debug Module Debug Bus Register Addresses

View File

@ -43,22 +43,21 @@ module dmc (
input logic AckHaveReset, // Clears HaveReset status input logic AckHaveReset, // Clears HaveReset status
input logic ExecProgBuf, // Updates PC to progbuf and resumes core 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 [2:0] DebugCause, // Reason Hart entered debug mode
output logic ResumeAck, // Signals Hart has been resumed output logic ResumeAck, // Signals Hart has been resumed
output logic HaveReset, // Signals Hart has been reset output logic HaveReset, // Signals Hart has been reset
output logic DebugStall, // Stall signal goes to hazard unit output logic DebugStall, // Stall signal goes to hazard unit
output logic EnterDebugMode, // Store PCNextF in DPC when entering Debug Mode output logic DCall, // Store PCNextF in DPC when entering Debug Mode
output logic ExitDebugMode, // Updates PCNextF with the current value of DPC output logic DRet, // Updates PCNextF with the current value of DPC
output logic ForceBreakPoint // Causes artificial ebreak that puts core in debug mode output logic ForceBreakPoint // Causes artificial ebreak that puts core in debug mode
); );
`include "debug.vh" `include "debug.vh"
enum logic [1:0] {RUNNING, EXECPROGBUF, HALTED, STEP} State;
enum logic [1:0] {RUNNING, HALTED, STEP} State; localparam E2M_CYCLE_COUNT = 4;
localparam E2M_CYCLE_COUNT = 3;
logic [$clog2(E2M_CYCLE_COUNT+1)-1:0] Counter; logic [$clog2(E2M_CYCLE_COUNT+1)-1:0] Counter;
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
@ -73,8 +72,8 @@ module dmc (
assign DebugMode = (State != RUNNING); assign DebugMode = (State != RUNNING);
assign DebugStall = (State == HALTED); assign DebugStall = (State == HALTED);
assign EnterDebugMode = (State == RUNNING) & (ebreakM & ebreakEn) | ForceBreakPoint; assign DCall = ((State == RUNNING) | (State == EXECPROGBUF)) & ((ebreakM & ebreakEn) | ForceBreakPoint);
assign ExitDebugMode = (State == HALTED) & (ResumeReq | ExecProgBuf); assign DRet = (State == HALTED) & (ResumeReq | ExecProgBuf);
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
if (reset) begin if (reset) begin
@ -92,6 +91,14 @@ module dmc (
end end
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 HALTED : begin
if (ResumeReq) begin if (ResumeReq) begin
if (Step) begin if (Step) begin
@ -102,7 +109,7 @@ module dmc (
ResumeAck <= 1; ResumeAck <= 1;
end end
end else if (ExecProgBuf) begin end else if (ExecProgBuf) begin
State <= RUNNING; State <= EXECPROGBUF;
ResumeAck <= 1; ResumeAck <= 1;
end end
end end

View File

@ -29,7 +29,7 @@
module hazard import cvw::*; #(parameter cvw_t P) ( module hazard import cvw::*; #(parameter cvw_t P) (
input logic BPWrongE, CSRWriteFenceM, RetM, TrapM, input logic BPWrongE, CSRWriteFenceM, RetM, TrapM,
input logic ExitDebugMode, input logic DRet,
input logic StructuralStallD, input logic StructuralStallD,
input logic LSUStallM, IFUStallF, input logic LSUStallM, IFUStallF,
input logic FPUStallD, 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. // 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 // 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 // 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 FlushDCause = TrapM | RetM | DRet | CSRWriteFenceM | BPWrongE;
assign FlushECause = TrapM | RetM | ExitDebugMode | CSRWriteFenceM |(BPWrongE & ~(DivBusyE | FDivBusyE)); assign FlushECause = TrapM | RetM | DRet | CSRWriteFenceM |(BPWrongE & ~(DivBusyE | FDivBusyE));
assign FlushMCause = TrapM | RetM | ExitDebugMode | CSRWriteFenceM; assign FlushMCause = TrapM | RetM | DRet | CSRWriteFenceM;
assign FlushWCause = TrapM & ~WFIInterruptedM; assign FlushWCause = TrapM & ~WFIInterruptedM;
// Stall causes // Stall causes
@ -91,7 +91,7 @@ module hazard import cvw::*; #(parameter cvw_t P) (
// Need to gate IFUStallF when the equivalent FlushFCause = FlushDCause = 1. // Need to gate IFUStallF when the equivalent FlushFCause = FlushDCause = 1.
// assign StallWCause = ((IFUStallF & ~FlushDCause) | LSUStallM) & ~FlushWCause; // assign StallWCause = ((IFUStallF & ~FlushDCause) | LSUStallM) & ~FlushWCause;
// Because FlushWCause is a strict subset of FlushDCause, FlushWCause is factored out. // 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 // Stall each stage for cause or if the next stage is stalled
// coverage off: StallFCause is always 0 // coverage off: StallFCause is always 0

View File

@ -97,7 +97,7 @@ module ifu import cvw::*; #(parameter cvw_t P) (
output logic ICacheAccess, // Report I$ read to performance counters output logic ICacheAccess, // Report I$ read to performance counters
output logic ICacheMiss, // Report I$ miss to performance counters output logic ICacheMiss, // Report I$ miss to performance counters
// Debug Mode logic // Debug Mode logic
input logic ExitDebugMode, input logic DRet,
input logic ProgBuffScanEn, input logic ProgBuffScanEn,
// Debug scan chain // Debug scan chain
input logic [3:0] ProgBufAddr, input logic [3:0] ProgBufAddr,
@ -336,7 +336,7 @@ module ifu import cvw::*; #(parameter cvw_t P) (
else assign PC2NextF = PC1NextF; 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); 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); flopen #(P.XLEN) pcreg(clk, ~StallF | reset, PCNextF, PCF);

View File

@ -99,8 +99,8 @@ module csr import cvw::*; #(parameter cvw_t P) (
output logic ebreakEn, output logic ebreakEn,
output logic Step, output logic Step,
output logic [P.XLEN-1:0] DPC, output logic [P.XLEN-1:0] DPC,
input logic EnterDebugMode, input logic DCall,
input logic ExitDebugMode, input logic DRet,
input logic ExecProgBuf, input logic ExecProgBuf,
// Debug scan chain // Debug scan chain
input logic DebugSel, input logic DebugSel,
@ -189,7 +189,7 @@ module csr import cvw::*; #(parameter cvw_t P) (
if (P.DEBUG_SUPPORTED) begin if (P.DEBUG_SUPPORTED) begin
always_comb always_comb
if (ExecProgBuf) EPCM = P.PROGBUF_BASE; if (ExecProgBuf) EPCM = P.PROGBUF_BASE;
else if (ExitDebugMode) EPCM = DPC; else if (DRet) EPCM = DPC;
else if (mretM) EPCM = MEPC_REGW; else if (mretM) EPCM = MEPC_REGW;
else EPCM = SEPC_REGW; else EPCM = SEPC_REGW;
end else begin end else begin
@ -318,7 +318,7 @@ module csr import cvw::*; #(parameter cvw_t P) (
if (P.DEBUG_SUPPORTED) begin:csrd if (P.DEBUG_SUPPORTED) begin:csrd
csrd #(P) csrd(.clk, .reset, .DebugMode, .PrivilegeModeW, csrd #(P) csrd(.clk, .reset, .DebugMode, .PrivilegeModeW,
.CSRWriteDM, .CSRAdrM(CSRAdrDM), .CSRWriteValM(CSRWriteValDM), .CSRDReadValM, .IllegalCSRDAccessM, .CSRWriteDM, .CSRAdrM(CSRAdrDM), .CSRWriteValM(CSRWriteValDM), .CSRDReadValM, .IllegalCSRDAccessM,
.DebugCause, .ebreakEn, .Step, .DPC, .PCM, .EnterDebugMode); .DebugCause, .ebreakEn, .Step, .DPC, .PCM, .DCall);
end else begin end else begin
assign CSRDReadValM = '0; assign CSRDReadValM = '0;
assign IllegalCSRDAccessM = 1'b1; // Debug isn't supported assign IllegalCSRDAccessM = 1'b1; // Debug isn't supported

View File

@ -36,7 +36,7 @@ module csrd import cvw::*; #(parameter cvw_t P) (
output logic [P.XLEN-1:0] CSRDReadValM, output logic [P.XLEN-1:0] CSRDReadValM,
output logic IllegalCSRDAccessM, output logic IllegalCSRDAccessM,
input logic [P.XLEN-1:0] PCM, input logic [P.XLEN-1:0] PCM,
input logic EnterDebugMode, input logic DCall,
input logic [2:0] DebugCause, input logic [2:0] DebugCause,
output logic ebreakEn, output logic ebreakEn,
output logic Step, output logic Step,
@ -70,7 +70,8 @@ module csrd import cvw::*; #(parameter cvw_t P) (
logic [1:0] Prv; 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 CSRDWriteM = CSRWriteDM & (PrivilegeModeW == P.M_MODE) & DebugMode;
assign WriteDCSRM = CSRDWriteM & (CSRAdrM == DCSR_ADDR); assign WriteDCSRM = CSRDWriteM & (CSRAdrM == DCSR_ADDR);
@ -80,7 +81,7 @@ module csrd import cvw::*; #(parameter cvw_t P) (
if (reset) begin if (reset) begin
Prv <= 2'h3; Prv <= 2'h3;
Cause <= 3'h0; Cause <= 3'h0;
end else if (EnterDebugMode) begin end else if (DCall) begin
Prv <= PrivilegeModeW; Prv <= PrivilegeModeW;
Cause <= DebugCause; Cause <= DebugCause;
end 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, assign DCSR = {DebugVer, 10'b0, ebreakVS, ebreakVU, ebreakM, 1'b0, ebreakS, ebreakU, StepIE,
StopCount, StopTime, Cause, V, MPrvEn, NMIP, Step, Prv}; StopCount, StopTime, Cause, V, MPrvEn, NMIP, Step, Prv};
assign DPCWriteVal = EnterDebugMode ? PCM : CSRWriteValM; assign DPCWriteVal = DCall ? PCM : CSRWriteValM;
flopenr #(P.XLEN) DPCreg (clk, reset, WriteDPCM | EnterDebugMode, DPCWriteVal, DPC); // TODO: reset to something sane (0x80000000?) flopenr #(P.XLEN) DPCreg (clk, reset, WriteDPCM | DCall, DPCWriteVal, DPC);
always_comb begin always_comb begin
CSRDReadValM = '0; CSRDReadValM = '0;

View File

@ -105,8 +105,8 @@ module privileged import cvw::*; #(parameter cvw_t P) (
input logic [2:0] DebugCause, input logic [2:0] DebugCause,
output logic Step, output logic Step,
output logic [P.XLEN-1:0] DPC, output logic [P.XLEN-1:0] DPC,
input logic EnterDebugMode, input logic DCall,
input logic ExitDebugMode, input logic DRet,
input logic ExecProgBuf, input logic ExecProgBuf,
// Debug scan chain // Debug scan chain
input logic DebugSel, input logic DebugSel,
@ -167,7 +167,7 @@ module privileged import cvw::*; #(parameter cvw_t P) (
.SetFflagsM, .FRM_REGW, .ENVCFG_CBE, .ENVCFG_PBMTE, .ENVCFG_ADUE, .SetFflagsM, .FRM_REGW, .ENVCFG_CBE, .ENVCFG_PBMTE, .ENVCFG_ADUE,
.EPCM, .TrapVectorM, .EPCM, .TrapVectorM,
.CSRReadValW, .IllegalCSRAccessM, .BigEndianM, .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); .DebugSel, .DebugRegAddr, .DebugCapture, .DebugRegUpdate, .DebugScanEn, .DebugScanIn, .DebugScanOut);
// pipeline early-arriving trap sources // pipeline early-arriving trap sources
@ -182,6 +182,6 @@ module privileged import cvw::*; #(parameter cvw_t P) (
.LoadAccessFaultM, .StoreAmoAccessFaultM, .EcallFaultM, .InstrPageFaultM, .LoadAccessFaultM, .StoreAmoAccessFaultM, .EcallFaultM, .InstrPageFaultM,
.LoadPageFaultM, .StoreAmoPageFaultM, .PrivilegeModeW, .LoadPageFaultM, .StoreAmoPageFaultM, .PrivilegeModeW,
.MIP_REGW, .MIE_REGW, .MIDELEG_REGW, .MEDELEG_REGW, .STATUS_MIE, .STATUS_SIE, .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); .TrapM, .wfiM, .wfiW, .InterruptM, .ExceptionM, .IntPendingM, .DelegateM, .CauseM);
endmodule endmodule

View File

@ -40,6 +40,7 @@ module trap import cvw::*; #(parameter cvw_t P) (
input logic STATUS_MIE, STATUS_SIE, // machine/supervisor interrupt enables input logic STATUS_MIE, STATUS_SIE, // machine/supervisor interrupt enables
input logic InstrValidM, // current instruction is valid, not flushed 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 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 TrapM, // Trap is occurring
output logic InterruptM, // Interrupt is occurring output logic InterruptM, // Interrupt is occurring
output logic ExceptionM, // exception is occurring output logic ExceptionM, // exception is occurring
@ -88,7 +89,9 @@ module trap import cvw::*; #(parameter cvw_t P) (
BreakpointFaultM | EcallFaultM | BreakpointFaultM | EcallFaultM |
LoadAccessFaultM | StoreAmoAccessFaultM; LoadAccessFaultM | StoreAmoAccessFaultM;
// coverage on // 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 // Cause priority defined in privileged spec

View File

@ -199,8 +199,8 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
// Debug mode logic // Debug mode logic
logic [P.XLEN-1:0] DPC; logic [P.XLEN-1:0] DPC;
logic ExitDebugMode; logic DRet;
logic EnterDebugMode; logic DCall;
logic [2:0] DebugCause; logic [2:0] DebugCause;
logic ForceBreakPoint; logic ForceBreakPoint;
// Debug register scan chain interconnects // 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, .STATUS_MPP, .ENVCFG_PBMTE, .ENVCFG_ADUE, .ITLBWriteF, .sfencevmaM, .ITLBMissOrUpdateAF,
// pmp/pma (inside mmu) signals. // pmp/pma (inside mmu) signals.
.PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW, .InstrAccessFaultF, .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])); .DebugScanEn(DebugScanEn & MiscSel), .DebugScanIn(DebugScanReg[0]), .DebugScanOut(DebugScanReg[1]));
// integer execution unit: integer register file, datapath and controller // 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 // global stall and flush control
hazard #(P) hzu( hazard #(P) hzu(
.BPWrongE, .CSRWriteFenceM, .RetM, .TrapM, .ExitDebugMode, .BPWrongE, .CSRWriteFenceM, .RetM, .TrapM, .DRet,
.StructuralStallD, .StructuralStallD,
.LSUStallM, .IFUStallF, .LSUStallM, .IFUStallF,
.FPUStallD, .FPUStallD,
@ -327,7 +327,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
.clk, .reset, .clk, .reset,
.Step, .ebreakM, .ebreakEn, .HaltReq, .ResumeReq, .HaltOnReset, .AckHaveReset, .Step, .ebreakM, .ebreakEn, .HaltReq, .ResumeReq, .HaltOnReset, .AckHaveReset,
.ResumeAck, .HaveReset, .DebugMode, .DebugCause, .DebugStall, .ExecProgBuf, .ResumeAck, .HaveReset, .DebugMode, .DebugCause, .DebugStall, .ExecProgBuf,
.EnterDebugMode, .ExitDebugMode, .ForceBreakPoint); .DCall, .DRet, .ForceBreakPoint);
end else begin end else begin
assign DebugStall = 1'b0; assign DebugStall = 1'b0;
end end
@ -355,7 +355,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
.STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .STATUS_FS, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .STATUS_FS,
.PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW, .PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW,
.FRM_REGW, .ENVCFG_CBE, .ENVCFG_PBMTE, .ENVCFG_ADUE, .wfiM, .IntPendingM, .BigEndianM, .ebreakM, .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)); .DebugSel(CSRSel), .DebugRegAddr, .DebugCapture, .DebugRegUpdate, .DebugScanEn(DebugScanEn & CSRSel), .DebugScanIn, .DebugScanOut(CSRScanOut));
if (P.DEBUG_SUPPORTED) begin if (P.DEBUG_SUPPORTED) begin
flopenrs #(1) scantrapm (.clk, .reset, .en(DebugCapture), .d(TrapM), .q(), .scan(DebugScanEn), .scanin(DebugScanIn), .scanout(DebugScanReg[0])); flopenrs #(1) scantrapm (.clk, .reset, .en(DebugCapture), .d(TrapM), .q(), .scan(DebugScanEn), .scanin(DebugScanIn), .scanout(DebugScanReg[0]));