Add DPC support (does not write on resume)

This commit is contained in:
Matthew 2024-06-14 14:21:38 -05:00
parent be7d657f71
commit d0deb1bd7a
7 changed files with 93 additions and 33 deletions

View File

@ -139,7 +139,7 @@ module dm import cvw::*; #(parameter cvw_t P) (
//// DM register fields
// DMControl
logic AckUnavail;
logic DmActive; // This bit is used to (de)activate the DM. Toggling off/on acts as reset
logic DmActive; // This bit is used to (de)activate the DM. Toggling off-on acts as reset
// DMStatus
logic StickyUnavail;
logic ImpEBreak;

View File

@ -30,7 +30,7 @@
// Note: This module controls all of the per-hart debug state.
// In a multihart system, this module should be instantiated under wallypipelinedcore
module dmc(
module dmc (
input logic clk, reset,
input logic Step,
input logic HaltReq, // Initiates core halt
@ -39,11 +39,18 @@ module dmc(
input logic AckHaveReset, // Clears HaveReset status
output logic DebugMode,
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 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 CapturePCNextF, // Store PCNextF in DPC when entering Debug Mode
output logic ForceDPCNextF, // Updates PCNextF with the current value of DPC
output logic ForceNOP // Fills the pipeline with NOP
);
enum logic {RUNNING, HALTED} State;
enum logic [1:0] {RUNNING, FLUSH, HALTED, RESUME} State;
localparam NOP_CYCLE_DURATION = 0;
logic [$clog2(NOP_CYCLE_DURATION+1)-1:0] Counter;
always_ff @(posedge clk) begin
if (reset)
@ -52,21 +59,46 @@ module dmc(
HaveReset <= 0;
end
assign DebugMode = (State != RUNNING); // TODO: update this
assign DebugMode = (State != RUNNING);
assign DebugStall = (State == HALTED);
assign CapturePCNextF = (State == FLUSH) & (Counter == 0);
assign ForceDPCNextF = (State == HALTED) & ResumeReq;
assign ForceNOP = (State == FLUSH);
always_ff @(posedge clk) begin
if (reset)
if (reset) begin
State <= HaltOnReset ? HALTED : RUNNING;
else begin
end else begin
case (State)
RUNNING : begin
State <= Step | HaltReq ? HALTED : RUNNING;
if (HaltReq) begin
Counter <= 0;
State <= FLUSH;
end
end
// fill the pipe with NOP before halting
FLUSH : begin
if (Counter == NOP_CYCLE_DURATION)
State <= HALTED;
else
Counter <= Counter + 1;
end
HALTED : begin
State <= ResumeReq ? RUNNING : HALTED;
ResumeAck <= ResumeReq ? 1 : ResumeAck;
if (ResumeReq)
State <= RESUME;
end
RESUME : begin
if (Step) begin
Counter <= 0;
State <= FLUSH;
end else begin
State <= RUNNING;
ResumeAck <= 1;
end
end
endcase
end

View File

@ -97,6 +97,11 @@ module ifu import cvw::*; #(parameter cvw_t P) (
output logic InstrAccessFaultF, // Instruction access fault
output logic ICacheAccess, // Report I$ read to performance counters
output logic ICacheMiss, // Report I$ miss to performance counters
// Debug Mode logic
(* mark_debug = "true" *)input logic ForceDPCNextF,
(* mark_debug = "true" *)input logic [P.XLEN-1:0] DPC,
(* mark_debug = "true" *)output logic [P.XLEN-1:0] PCNextF, // Next PCF, selected from Branch predictor, Privilege, or PC+2/4
(* mark_debug = "true" *)input logic ForceNOP,
// Debug scan chain
input logic DebugScanEn,
input logic DebugScanIn,
@ -106,7 +111,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] PCNextFM; // (muxed for debug) 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.
@ -145,7 +150,7 @@ module ifu import cvw::*; #(parameter cvw_t P) (
logic [LINELEN-1:0] FetchBuffer;
logic [31:0] ShiftUncachedInstr;
// Debug scan chain
logic DebugScanChainReg; // Debug Scan Chain Register
logic DebugScanChainReg; // Debug Scan Chain Register
assign PCFExt = {2'b00, PCSpillF};
@ -320,8 +325,14 @@ module ifu import cvw::*; #(parameter cvw_t P) (
else assign PC2NextF = PC1NextF;
mux3 #(P.XLEN) pcmux3(PC2NextF, EPCM, TrapVectorM, {TrapM, RetM}, 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);
if (P.DEBUG_SUPPORTED) begin
mux2 #(P.XLEN) pcresetmux({UnalignedPCNextF[P.XLEN-1:1], 1'b0}, P.RESET_VECTOR[P.XLEN-1:0], reset, PCNextFM);
assign PCNextF = ForceDPCNextF ? DPC : PCNextFM;
flopen #(P.XLEN) pcreg(clk, ~StallF | reset | ForceDPCNextF, PCNextF, PCF);
end else begin
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);
end
// pcadder
// add 2 or 4 to the PC, based on whether the instruction is 16 bits or 32

View File

@ -95,6 +95,9 @@ module csr import cvw::*; #(parameter cvw_t P) (
output logic BigEndianM, // memory access is big-endian based on privilege mode and STATUS register endian fields
// Debug Mode output
output logic Step,
output logic [P.XLEN-1:0] DPC,
input logic [P.XLEN-1:0] PCNextF,
input logic CapturePCNextF,
// Debug scan chain
input logic DebugSel,
input logic [11:0] DebugRegAddr,
@ -301,8 +304,7 @@ module csr import cvw::*; #(parameter cvw_t P) (
if (P.DEBUG_SUPPORTED) begin:csrd
csrd #(P) csrd(.clk, .reset,
.CSRWriteDM, .CSRAdrM(CSRAdrDM), .CSRWriteValM(CSRWriteValDM), .CSRDReadValM, .IllegalCSRDAccessM,
.Step
);
.Step, .DPC, .PCNextF, .CapturePCNextF);
end else begin
assign CSRDReadValM = '0;
assign IllegalCSRDAccessM = 1'b1; // Debug isn't supported

View File

@ -34,16 +34,19 @@ module csrd import cvw::*; #(parameter cvw_t P) (
output logic [P.XLEN-1:0] CSRDReadValM,
output logic IllegalCSRDAccessM,
output logic Step
output logic Step,
output logic [P.XLEN-1:0] DPC,
input logic [P.XLEN-1:0] PCNextF,
input logic CapturePCNextF
);
`include "debug.vh"
localparam DCSR = 12'h7B0; // Debug Control and Status Register
localparam DPC = 12'h7B1; // Debug PC
localparam DCSR_ADDR = 12'h7B0; // Debug Control and Status Register
localparam DPC_ADDR = 12'h7B1; // Debug PC
// TODO: these registers are only accessible from Debug Mode.
logic [31:0] DCSR_REGW;
logic [31:0] DPC_REGW;
logic [P.XLEN-1:0] DPC_REGW, DPCWriteVal;
logic WriteDCSRM;
logic WriteDPCM;
@ -65,8 +68,8 @@ module csrd import cvw::*; #(parameter cvw_t P) (
assign WriteDCSRM = CSRWriteDM & (CSRAdrM == DCSR);
assign WriteDPCM = CSRWriteDM & (CSRAdrM == DPC);
assign WriteDCSRM = CSRWriteDM & (CSRAdrM == DCSR_ADDR);
assign WriteDPCM = CSRWriteDM & (CSRAdrM == DPC_ADDR);
always_ff @(posedge clk) begin
if (reset)
@ -77,21 +80,22 @@ module csrd import cvw::*; #(parameter cvw_t P) (
Prv <= CSRWriteValM[`PRV]; // TODO: overwrite hart privilege mode
end
flopenr ebreakreg(clk, reset, WriteDCSRM,
flopenr #(4) DCSRreg (clk, reset, WriteDCSRM,
{CSRWriteValM[`EBREAKM], CSRWriteValM[`EBREAKS], CSRWriteValM[`EBREAKU], CSRWriteValM[`STEP]},
{ebreakM, ebreakS, ebreakU, Step});
assign DCSR_REGW = {4'b0100, 10'b0, ebreakVS, ebreakVU, ebreakM, 1'b0, ebreakS, ebreakU, StepIE,
StopCount, StopTime, Cause, V, MPrvEn, NMIP, Step, Prv};
assign DPC_REGW = {32'hd099f00d};
assign DPCWriteVal = CapturePCNextF ? PCNextF : CSRWriteValM;
flopenr #(P.XLEN) DPCreg (clk, reset, WriteDPCM | CapturePCNextF, DPCWriteVal, DPC_REGW);
always_comb begin
CSRDReadValM = 0;
IllegalCSRDAccessM = 0;
case (CSRAdrM)
DCSR : CSRDReadValM = DCSR_REGW;
DPC : CSRDReadValM = DPC_REGW;
DCSR_ADDR : CSRDReadValM = DCSR_REGW;
DPC_ADDR : CSRDReadValM = DPC_REGW;
default: IllegalCSRDAccessM = 1'b1;
endcase
end

View File

@ -99,6 +99,9 @@ module privileged import cvw::*; #(parameter cvw_t P) (
output logic wfiM, IntPendingM, // Stall in Memory stage for WFI until interrupt pending or timeout
// Debuge Mode
output logic Step,
output logic [P.XLEN-1:0] DPC,
input logic [P.XLEN-1:0] PCNextF,
input logic CapturePCNextF,
// Debug scan chain
input logic DebugSel,
input logic [11:0] DebugRegAddr,
@ -157,7 +160,8 @@ module privileged import cvw::*; #(parameter cvw_t P) (
.SATP_REGW, .PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW,
.SetFflagsM, .FRM_REGW, .ENVCFG_CBE, .ENVCFG_PBMTE, .ENVCFG_ADUE,
.EPCM, .TrapVectorM,
.CSRReadValW, .IllegalCSRAccessM, .BigEndianM, .Step,
.CSRReadValW, .IllegalCSRAccessM, .BigEndianM,
.Step, .DPC, .PCNextF, .CapturePCNextF,
.DebugSel, .DebugRegAddr, .DebugCapture, .DebugRegUpdate, .DebugScanEn, .DebugScanIn, .DebugScanOut);
// pipeline early-arriving trap sources

View File

@ -191,6 +191,11 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
logic DCacheStallM, ICacheStallF;
logic wfiM, IntPendingM;
// Debug mode logic
logic [P.XLEN-1:0] DPC, PCNextF;
logic ForceDPCNextF;
logic CapturePCNextF;
logic ForceNOP;
// Debug register scan chain interconnects
logic [2:0] DebugScanReg;
@ -216,6 +221,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
.STATUS_MPP, .ENVCFG_PBMTE, .ENVCFG_ADUE, .ITLBWriteF, .sfencevmaM, .ITLBMissF,
// pmp/pma (inside mmu) signals.
.PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW, .InstrAccessFaultF, .InstrUpdateDAF,
.ForceDPCNextF, .DPC, .PCNextF, .ForceNOP,
.DebugScanEn(DebugScanEn & MiscSel), .DebugScanIn(DebugScanReg[0]), .DebugScanOut(DebugScanReg[1]));
// integer execution unit: integer register file, datapath and controller
@ -314,8 +320,8 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
dmc debugcontrol(
.clk, .reset,
.Step, .HaltReq, .ResumeReq, .HaltOnReset, .AckHaveReset,
.ResumeAck, .HaveReset, .DebugMode, .DebugStall
);
.ResumeAck, .HaveReset, .DebugMode, .DebugStall,
.CapturePCNextF, .ForceDPCNextF, .ForceNOP);
end else begin
assign DebugStall = 1'b0;
end
@ -342,7 +348,8 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
.PrivilegeModeW, .SATP_REGW,
.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, .Step,
.FRM_REGW, .ENVCFG_CBE, .ENVCFG_PBMTE, .ENVCFG_ADUE, .wfiM, .IntPendingM, .BigEndianM,
.Step, .DPC, .PCNextF, .CapturePCNextF,
.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]));