fix bug with resuming from debug mode

This commit is contained in:
Matthew 2024-06-23 08:34:55 -05:00
parent 636501e06c
commit 21a51a1c9e
13 changed files with 74 additions and 78 deletions

View File

@ -51,15 +51,17 @@ def prog_buff_test(cvw):
def flow_control_test(cvw):
#time.sleep(70) # wait for OpenSBI
cvw.halt()
#cvw.halt()
time.sleep(1)
#cvw.read_data("DCSR")
for _ in range(50):
cvw.resume()
for _ in range(100):
time.sleep(random.randint(5,10))
print("Halting")
cvw.halt()
cvw.resume()
#cvw.step()
#print(cvw.read_data("PCM"))
cvw.resume()
#cvw.resume()
def register_rw_test(cvw):

View File

@ -26,16 +26,10 @@
////////////////////////////////////////////////////////////////////////////////////////////////
// TODO List:
// add "progbuff" register to overwrite instrF
// overwrite wfi instructions with NOP during DebugMode
// mask all interrupts in debug mode (even NMI)
// Ignore traps in debug mode
// Ignore wfi instructions in debug mode (overwrite with NOP?)
// mask all interrupts/ignore all traps (except ebreak) in debug mode
// capture CSR read/write failures as convert them to cmderr
// Flush pipe with NOPs during halt?
module dm import cvw::*; #(parameter cvw_t P) (
input logic clk,
@ -52,7 +46,7 @@ module dm import cvw::*; #(parameter cvw_t P) (
// Core control signals
input logic ResumeAck, // Signals Hart has been resumed
input logic HaveReset, // Signals Hart has been reset
input logic DebugStall, // Signals core is halted
input logic DebugStall, // Signals core is halted
output logic HaltReq, // Initiates core halt
output logic ResumeReq, // Initiates core resume
output logic HaltOnReset, // Halts core immediately on hart reset
@ -76,7 +70,7 @@ module dm import cvw::*; #(parameter cvw_t P) (
// Program Buffer
output logic [3:0] ProgBufAddr,
output logic ProgBuffScanEn,
output logic ExecProgBuff
output logic ExecProgBuf
);
`include "debug.vh"
@ -106,7 +100,7 @@ module dm import cvw::*; #(parameter cvw_t P) (
enum logic [3:0] {INACTIVE, IDLE, ACK, R_DATA, W_DATA, DMSTATUS, W_DMCONTROL, R_DMCONTROL,
W_ABSTRACTCS, R_ABSTRACTCS, ABST_COMMAND, R_SYSBUSCS, W_PROGBUF, READ_ZERO,
INVALID} State;
INVALID, EXEC_PROGBUF} State;
enum logic [2:0] {AC_IDLE, AC_UPDATE, AC_SCAN, AC_CAPTURE, PROGBUFF_WRITE} AcState, NewAcState;
@ -186,7 +180,7 @@ module dm import cvw::*; #(parameter cvw_t P) (
assign AnyRunning = ~DebugStall;
assign AllRunning = ~DebugStall;
// I believe resumeack is used to determine when a resume is requested but never completes
// It's pretty worthless in this implementation (complain to the debug working group)
// It's pretty worthless in this implementation (complain to the riscv debug working group)
assign AllResumeAck = ResumeAck;
assign AnyResumeAck = ResumeAck;
@ -339,6 +333,9 @@ module dm import cvw::*; #(parameter cvw_t P) (
end
ABST_COMMAND : begin
RspOP <= `OP_SUCCESS;
State <= ACK;
if (CmdErr != `CMDERR_NONE); // If CmdErr, do nothing
else if (Busy)
CmdErr <= `CMDERR_BUSY; // If Busy, set CmdErr, do nothing
@ -347,16 +344,18 @@ module dm import cvw::*; #(parameter cvw_t P) (
else begin
case (ReqData[`CMDTYPE])
`ACCESS_REGISTER : begin
if (ReqData[`AARSIZE] > $clog2(P.LLEN/8)) // if AARSIZE (encoded) is greater than P.LLEN, set CmdErr, do nothing
CmdErr <= `CMDERR_BUS;
else if (~ReqData[`TRANSFER]); // If not TRANSFER, do nothing
if (ReqData[`AARSIZE] > $clog2(P.LLEN/8))
CmdErr <= `CMDERR_BUS; // if AARSIZE (encoded) is greater than P.LLEN, set CmdErr, do nothing
else if (InvalidRegNo)
CmdErr <= `CMDERR_EXCEPTION; // If InvalidRegNo, set CmdErr, do nothing
CmdErr <= `CMDERR_EXCEPTION; // If InvalidRegNo, set CmdErr, do nothing
else if (ReqData[`AARWRITE] & RegReadOnly)
CmdErr <= `CMDERR_NOT_SUPPORTED; // If writing to a read only register, set CmdErr, do nothing
CmdErr <= `CMDERR_NOT_SUPPORTED; // If writing to a read only register, set CmdErr, do nothing
else begin
AcWrite <= ReqData[`AARWRITE];
NewAcState <= ~ReqData[`AARWRITE] ? AC_CAPTURE : AC_SCAN;
if (ReqData[`TRANSFER]) begin
AcWrite <= ReqData[`AARWRITE];
NewAcState <= ~ReqData[`AARWRITE] ? AC_CAPTURE : AC_SCAN;
end
State <= ReqData[`POSTEXEC] ? EXEC_PROGBUF : ACK;
end
end
//`QUICK_ACCESS : State <= QUICK_ACCESS;
@ -364,8 +363,6 @@ module dm import cvw::*; #(parameter cvw_t P) (
default : CmdErr <= `CMDERR_NOT_SUPPORTED;
endcase
end
RspOP <= `OP_SUCCESS;
State <= ACK;
end
W_PROGBUF : begin
@ -392,9 +389,15 @@ module dm import cvw::*; #(parameter cvw_t P) (
end
INVALID : begin
RspOP <= `OP_SUCCESS;//`OP_FAILED;
RspOP <= `OP_SUCCESS; // openocd cannot recover from `OP_FAILED;
State <= ACK;
end
EXEC_PROGBUF : begin
NewAcState <= AC_IDLE;
if (~Busy)
State <= ACK;
end
endcase
end
end
@ -442,6 +445,7 @@ module dm import cvw::*; #(parameter cvw_t P) (
end
assign Busy = ~(AcState == AC_IDLE);
assign ExecProgBuf = (State == EXEC_PROGBUF) & ~Busy;
// Program Buffer
assign ProgBuffScanEn = (AcState == PROGBUFF_WRITE);

View File

@ -27,22 +27,11 @@
// and limitations under the License.
////////////////////////////////////////////////////////////////////////////////////////////////
// On HaltReq/eBreak:
// store value of NextPC in DPC
// trigger trap (flush pipe)
// stall pipe
// On Step:
// unstall pipe until instruction receaches M stage
// goto: HaltReq/eBreak
// On exec_progbuf
// change NextPC to progbuf_address (using DPC?)
// goto: resume (implicic ebreak will return to debug mode)
// On Resume:
// update NextPC from DPC
// Unstall pipe
// TODO:
// Figure out what is causing resumes from stalls to error out
// Calculate correct cycle timing for step
// Test progbuf
module dmc (
input logic clk, reset,
@ -53,6 +42,7 @@ module dmc (
input logic ResumeReq, // Initiates core resume
input logic HaltOnReset, // Halts core immediately on hart reset
input logic AckHaveReset, // Clears HaveReset status
input logic ExecProgBuf, // Updates PC to progbuf and resumes core
output logic DebugMode,
output logic [2:0] DebugCause, // Reason Hart entered debug mode
@ -66,7 +56,8 @@ module dmc (
);
`include "debug.vh"
enum logic [2:0] {RUNNING, HALTED, RESUME, STEP, PROGBUF} State;
enum logic [1:0] {RUNNING, HALTED, STEP} State;
localparam E2M_CYCLE_COUNT = 3;
logic [$clog2(E2M_CYCLE_COUNT+1)-1:0] Counter;
@ -81,10 +72,10 @@ module dmc (
assign ForceBreakPoint = (State == RUNNING) & HaltReq | (State == STEP) & ~|Counter;
assign DebugMode = (State != RUNNING);
assign DebugStall = (State == HALTED) | (State == RESUME);
assign DebugStall = (State == HALTED);
assign EnterDebugMode = (State == RUNNING) & (ebreakM & ebreakEn) | ForceBreakPoint;
assign ExitDebugMode = (State == HALTED) & ResumeReq;
assign ExitDebugMode = (State == HALTED) & (ResumeReq | ExecProgBuf);
always_ff @(posedge clk) begin
if (reset) begin
@ -104,7 +95,6 @@ module dmc (
HALTED : begin
if (ResumeReq) begin
//State <= RESUME;
if (Step) begin
Counter <= E2M_CYCLE_COUNT;
State <= STEP;
@ -112,21 +102,13 @@ module dmc (
State <= RUNNING;
ResumeAck <= 1;
end
end
end
// Wait a cycle to load PCF from DPC before resuming
// TODO: test without resume stage
RESUME : begin
if (Step) begin
Counter <= E2M_CYCLE_COUNT;
State <= STEP;
end else begin
end else if (ExecProgBuf) begin
State <= RUNNING;
ResumeAck <= 1;
end
end
STEP : begin
if (~|Counter) begin
DebugCause <= `CAUSE_STEP;

View File

@ -45,4 +45,4 @@ module flopenrcs #(parameter WIDTH = 8) (
flopenrc #(WIDTH) flop (.clk, .reset, .clear, .en(en | scan), .d(dmux), .q(q));
endmodule
endmodule

View File

@ -45,4 +45,4 @@ module flopenrs #(parameter WIDTH = 8) (
flopenr #(WIDTH) flop (.clk, .reset, .en(en | scan), .d(dmux), .q(q));
endmodule
endmodule

View File

@ -28,7 +28,8 @@
////////////////////////////////////////////////////////////////////////////////////////////////
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 StructuralStallD,
input logic LSUStallM, IFUStallF,
input logic FPUStallD,
@ -70,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 | CSRWriteFenceM | BPWrongE;
assign FlushECause = TrapM | RetM | CSRWriteFenceM |(BPWrongE & ~(DivBusyE | FDivBusyE));
assign FlushMCause = TrapM | RetM | CSRWriteFenceM;
assign FlushDCause = TrapM | RetM | ExitDebugMode | CSRWriteFenceM | BPWrongE;
assign FlushECause = TrapM | RetM | ExitDebugMode | CSRWriteFenceM |(BPWrongE & ~(DivBusyE | FDivBusyE));
assign FlushMCause = TrapM | RetM | ExitDebugMode | CSRWriteFenceM;
assign FlushWCause = TrapM & ~WFIInterruptedM;
// Stall causes
@ -90,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;
assign StallWCause = (IFUStallF & ~FlushDCause) | (LSUStallM & ~FlushWCause) | (DebugStall & ~ExitDebugMode);
// 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
output logic [P.XLEN-1:0] PCNextF, // Next PCF, selected from Branch predictor, Privilege, or PC+2/4
input logic ExitDebugMode,
input logic ProgBuffScanEn,
// Debug scan chain
input logic [3:0] ProgBufAddr,
@ -110,6 +110,7 @@ module ifu import cvw::*; #(parameter cvw_t P) (
localparam [31:0] nop = 32'h00000013; // instruction for NOP
localparam LINELEN = P.ICACHE_SUPPORTED ? P.ICACHE_LINELENINBITS : P.XLEN;
logic [P.XLEN-1:0] PCNextF; // Next PCF, selected from Branch predictor, Privilege, or PC+2/4
logic [P.XLEN-1:0] PC1NextF; // Branch predictor next PCF
logic [P.XLEN-1:0] PC2NextF; // Selected PC between branch prediction and next valid PC if CSRWriteFence
logic [P.XLEN-1:0] UnalignedPCNextF; // The next PCF, but not aligned to 2 bytes.
@ -332,7 +333,7 @@ module ifu import cvw::*; #(parameter cvw_t P) (
else assign PC2NextF = PC1NextF;
mux3 #(P.XLEN) pcmux3(PC2NextF, EPCM, TrapVectorM, {TrapM, RetM}, UnalignedPCNextF);
mux3 #(P.XLEN) pcmux3(PC2NextF, EPCM, TrapVectorM, {TrapM, (RetM | ExitDebugMode)}, 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

@ -66,4 +66,4 @@ module progbuf import cvw::*; #(parameter cvw_t P) (
ProgBufInstrF <= RAM[AddrM];
end
endmodule
endmodule

View File

@ -99,8 +99,9 @@ module csr import cvw::*; #(parameter cvw_t P) (
output logic ebreakEn,
output logic Step,
output logic [P.XLEN-1:0] DPC,
input logic ExitDebugMode,
input logic EnterDebugMode,
input logic ExitDebugMode,
input logic ExecProgBuf,
// Debug scan chain
input logic DebugSel,
input logic [11:0] DebugRegAddr,
@ -186,7 +187,11 @@ module csr import cvw::*; #(parameter cvw_t P) (
// A trap sets the PC to TrapVector
// A return sets the PC to MEPC or SEPC
if (P.DEBUG_SUPPORTED) begin
mux3 #(P.XLEN) epcmux(SEPC_REGW, MEPC_REGW, DPC, {ExitDebugMode,mretM}, EPCM);
always_comb
if (ExecProgBuf) EPCM = P.PROGBUF_BASE;
else if (ExitDebugMode) EPCM = DPC;
else if (mretM) EPCM = MEPC_REGW;
else EPCM = SEPC_REGW;
end else begin
mux2 #(P.XLEN) epcmux(SEPC_REGW, MEPC_REGW, mretM, EPCM);
end

View File

@ -107,4 +107,4 @@ module csrd import cvw::*; #(parameter cvw_t P) (
endcase
end
endmodule
endmodule

View File

@ -107,6 +107,7 @@ module privileged import cvw::*; #(parameter cvw_t P) (
output logic [P.XLEN-1:0] DPC,
input logic EnterDebugMode,
input logic ExitDebugMode,
input logic ExecProgBuf,
// Debug scan chain
input logic DebugSel,
input logic [11:0] DebugRegAddr,
@ -166,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,
.DebugMode, .DebugCause, .ebreakEn, .Step, .DPC, .EnterDebugMode, .ExitDebugMode, .ExecProgBuf,
.DebugSel, .DebugRegAddr, .DebugCapture, .DebugRegUpdate, .DebugScanEn, .DebugScanIn, .DebugScanOut);
// pipeline early-arriving trap sources

View File

@ -53,7 +53,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
output logic ResumeAck,
output logic HaveReset,
output logic DebugStall,
input logic ExecProgBuff,
input logic ExecProgBuf,
// Debug scan chain
input logic DebugScanEn, // puts scannable flops into scan mode
output logic DebugScanOut, // (misc) scan chain data out
@ -198,7 +198,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
logic ebreakM;
// Debug mode logic
logic [P.XLEN-1:0] DPC, PCNextF;
logic [P.XLEN-1:0] DPC;
logic ExitDebugMode;
logic EnterDebugMode;
logic [2:0] DebugCause;
@ -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,
.PCNextF, .ProgBuffScanEn, .ProgBufAddr, .ProgBufScanIn(DebugScanIn),
.ExitDebugMode, .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,
.BPWrongE, .CSRWriteFenceM, .RetM, .TrapM, .ExitDebugMode,
.StructuralStallD,
.LSUStallM, .IFUStallF,
.FPUStallD,
@ -326,7 +326,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
dmc debugcontrol(
.clk, .reset,
.Step, .ebreakM, .ebreakEn, .HaltReq, .ResumeReq, .HaltOnReset, .AckHaveReset,
.ResumeAck, .HaveReset, .DebugMode, .DebugCause, .DebugStall,
.ResumeAck, .HaveReset, .DebugMode, .DebugCause, .DebugStall, .ExecProgBuf,
.EnterDebugMode, .ExitDebugMode, .ForceBreakPoint);
end else begin
assign DebugStall = 1'b0;
@ -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,
.ebreakEn, .ForceBreakPoint, .DebugMode, .DebugCause, .Step, .DPC, .EnterDebugMode, .ExitDebugMode, .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]));

View File

@ -82,7 +82,7 @@ module wallypipelinedsoc import cvw::*; #(parameter cvw_t P) (
logic ResumeAck;
logic HaveReset;
logic DebugStall;
logic ExecProgBuff;
logic ExecProgBuf;
// Debug Module signals
logic DebugScanEn;
logic DebugScanIn;
@ -108,7 +108,7 @@ module wallypipelinedsoc import cvw::*; #(parameter cvw_t P) (
.MTimerInt, .MExtInt, .SExtInt, .MSwInt, .MTIME_CLINT,
.HRDATA, .HREADY, .HRESP, .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB,
.HWRITE, .HSIZE, .HBURST, .HPROT, .HTRANS, .HMASTLOCK,
.HaltReq, .ResumeReq, .HaltOnReset, .AckHaveReset, .ResumeAck, .HaveReset, .DebugStall, .ExecProgBuff,
.HaltReq, .ResumeReq, .HaltOnReset, .AckHaveReset, .ResumeAck, .HaveReset, .DebugStall, .ExecProgBuf,
.DebugScanEn, .DebugScanOut(DebugScanIn), .GPRScanOut(GPRScanIn), .FPRScanOut(FPRScanIn), .CSRScanOut(CSRScanIn),
.DebugScanIn(DebugScanOut), .MiscSel, .GPRSel, .FPRSel, .CSRSel, .DebugRegAddr, .DebugCapture, .DebugRegUpdate,
.ProgBufAddr, .ProgBuffScanEn);
@ -131,7 +131,7 @@ module wallypipelinedsoc import cvw::*; #(parameter cvw_t P) (
.HaltReq, .ResumeReq, .HaltOnReset, .AckHaveReset, .ResumeAck, .HaveReset, .DebugStall,
.DebugScanEn, .DebugScanIn, .GPRScanIn, .FPRScanIn, .CSRScanIn, .DebugScanOut,
.MiscSel, .GPRSel, .FPRSel, .CSRSel, .RegAddr(DebugRegAddr), .DebugCapture, .DebugRegUpdate,
.ProgBufAddr, .ProgBuffScanEn, .ExecProgBuff);
.ProgBufAddr, .ProgBuffScanEn, .ExecProgBuf);
end
endmodule