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_BUSY 2'b11
// DMI register Address Width
// DMI Bus Address Width
`define DMI_ADDR_WIDTH 7
// Debug Module Debug Bus Register Addresses

View File

@ -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

View File

@ -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

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 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);

View File

@ -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

View File

@ -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,
@ -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;

View File

@ -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

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 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

View File

@ -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]));