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 //// DM register fields
// DMControl // DMControl
logic AckUnavail; 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 // DMStatus
logic StickyUnavail; logic StickyUnavail;
logic ImpEBreak; logic ImpEBreak;

View File

@ -30,7 +30,7 @@
// Note: This module controls all of the per-hart debug state. // Note: This module controls all of the per-hart debug state.
// In a multihart system, this module should be instantiated under wallypipelinedcore // In a multihart system, this module should be instantiated under wallypipelinedcore
module dmc( module dmc (
input logic clk, reset, input logic clk, reset,
input logic Step, input logic Step,
input logic HaltReq, // Initiates core halt input logic HaltReq, // Initiates core halt
@ -39,11 +39,18 @@ module dmc(
input logic AckHaveReset, // Clears HaveReset status input logic AckHaveReset, // Clears HaveReset status
output logic DebugMode, output logic DebugMode,
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 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 always_ff @(posedge clk) begin
if (reset) if (reset)
@ -52,21 +59,46 @@ module dmc(
HaveReset <= 0; HaveReset <= 0;
end end
assign DebugMode = (State != RUNNING); // TODO: update this assign DebugMode = (State != RUNNING);
assign DebugStall = (State == HALTED); assign DebugStall = (State == HALTED);
assign CapturePCNextF = (State == FLUSH) & (Counter == 0);
assign ForceDPCNextF = (State == HALTED) & ResumeReq;
assign ForceNOP = (State == FLUSH);
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
if (reset) if (reset) begin
State <= HaltOnReset ? HALTED : RUNNING; State <= HaltOnReset ? HALTED : RUNNING;
else begin end else begin
case (State) case (State)
RUNNING : begin 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 end
HALTED : begin HALTED : begin
State <= ResumeReq ? RUNNING : HALTED; if (ResumeReq)
ResumeAck <= ResumeReq ? 1 : ResumeAck; State <= RESUME;
end
RESUME : begin
if (Step) begin
Counter <= 0;
State <= FLUSH;
end else begin
State <= RUNNING;
ResumeAck <= 1;
end
end end
endcase endcase
end end

View File

@ -97,6 +97,11 @@ module ifu import cvw::*; #(parameter cvw_t P) (
output logic InstrAccessFaultF, // Instruction access fault output logic InstrAccessFaultF, // Instruction access fault
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
(* 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 // Debug scan chain
input logic DebugScanEn, input logic DebugScanEn,
input logic DebugScanIn, 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 [31:0] nop = 32'h00000013; // instruction for NOP
localparam LINELEN = P.ICACHE_SUPPORTED ? P.ICACHE_LINELENINBITS : P.XLEN; 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] 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] 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. 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 [LINELEN-1:0] FetchBuffer;
logic [31:0] ShiftUncachedInstr; logic [31:0] ShiftUncachedInstr;
// Debug scan chain // Debug scan chain
logic DebugScanChainReg; // Debug Scan Chain Register logic DebugScanChainReg; // Debug Scan Chain Register
assign PCFExt = {2'b00, PCSpillF}; assign PCFExt = {2'b00, PCSpillF};
@ -320,8 +325,14 @@ 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}, UnalignedPCNextF); 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); if (P.DEBUG_SUPPORTED) begin
flopen #(P.XLEN) pcreg(clk, ~StallF | reset, PCNextF, PCF); 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 // pcadder
// add 2 or 4 to the PC, based on whether the instruction is 16 bits or 32 // 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 output logic BigEndianM, // memory access is big-endian based on privilege mode and STATUS register endian fields
// Debug Mode output // Debug Mode output
output logic Step, output logic Step,
output logic [P.XLEN-1:0] DPC,
input logic [P.XLEN-1:0] PCNextF,
input logic CapturePCNextF,
// Debug scan chain // Debug scan chain
input logic DebugSel, input logic DebugSel,
input logic [11:0] DebugRegAddr, input logic [11:0] DebugRegAddr,
@ -301,8 +304,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, csrd #(P) csrd(.clk, .reset,
.CSRWriteDM, .CSRAdrM(CSRAdrDM), .CSRWriteValM(CSRWriteValDM), .CSRDReadValM, .IllegalCSRDAccessM, .CSRWriteDM, .CSRAdrM(CSRAdrDM), .CSRWriteValM(CSRWriteValDM), .CSRDReadValM, .IllegalCSRDAccessM,
.Step .Step, .DPC, .PCNextF, .CapturePCNextF);
);
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

@ -34,16 +34,19 @@ 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,
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" `include "debug.vh"
localparam DCSR = 12'h7B0; // Debug Control and Status Register localparam DCSR_ADDR = 12'h7B0; // Debug Control and Status Register
localparam DPC = 12'h7B1; // Debug PC localparam DPC_ADDR = 12'h7B1; // Debug PC
// TODO: these registers are only accessible from Debug Mode. // TODO: these registers are only accessible from Debug Mode.
logic [31:0] DCSR_REGW; logic [31:0] DCSR_REGW;
logic [31:0] DPC_REGW; logic [P.XLEN-1:0] DPC_REGW, DPCWriteVal;
logic WriteDCSRM; logic WriteDCSRM;
logic WriteDPCM; logic WriteDPCM;
@ -65,8 +68,8 @@ module csrd import cvw::*; #(parameter cvw_t P) (
assign WriteDCSRM = CSRWriteDM & (CSRAdrM == DCSR); assign WriteDCSRM = CSRWriteDM & (CSRAdrM == DCSR_ADDR);
assign WriteDPCM = CSRWriteDM & (CSRAdrM == DPC); assign WriteDPCM = CSRWriteDM & (CSRAdrM == DPC_ADDR);
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
if (reset) if (reset)
@ -77,21 +80,22 @@ module csrd import cvw::*; #(parameter cvw_t P) (
Prv <= CSRWriteValM[`PRV]; // TODO: overwrite hart privilege mode Prv <= CSRWriteValM[`PRV]; // TODO: overwrite hart privilege mode
end end
flopenr ebreakreg(clk, reset, WriteDCSRM, flopenr #(4) DCSRreg (clk, reset, WriteDCSRM,
{CSRWriteValM[`EBREAKM], CSRWriteValM[`EBREAKS], CSRWriteValM[`EBREAKU], CSRWriteValM[`STEP]}, {CSRWriteValM[`EBREAKM], CSRWriteValM[`EBREAKS], CSRWriteValM[`EBREAKU], CSRWriteValM[`STEP]},
{ebreakM, ebreakS, ebreakU, Step}); {ebreakM, ebreakS, ebreakU, Step});
assign DCSR_REGW = {4'b0100, 10'b0, ebreakVS, ebreakVU, ebreakM, 1'b0, ebreakS, ebreakU, StepIE, assign DCSR_REGW = {4'b0100, 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 DPC_REGW = {32'hd099f00d};
assign DPCWriteVal = CapturePCNextF ? PCNextF : CSRWriteValM;
flopenr #(P.XLEN) DPCreg (clk, reset, WriteDPCM | CapturePCNextF, DPCWriteVal, DPC_REGW);
always_comb begin always_comb begin
CSRDReadValM = 0; CSRDReadValM = 0;
IllegalCSRDAccessM = 0; IllegalCSRDAccessM = 0;
case (CSRAdrM) case (CSRAdrM)
DCSR : CSRDReadValM = DCSR_REGW; DCSR_ADDR : CSRDReadValM = DCSR_REGW;
DPC : CSRDReadValM = DPC_REGW; DPC_ADDR : CSRDReadValM = DPC_REGW;
default: IllegalCSRDAccessM = 1'b1; default: IllegalCSRDAccessM = 1'b1;
endcase endcase
end 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 output logic wfiM, IntPendingM, // Stall in Memory stage for WFI until interrupt pending or timeout
// Debuge Mode // Debuge Mode
output logic Step, output logic Step,
output logic [P.XLEN-1:0] DPC,
input logic [P.XLEN-1:0] PCNextF,
input logic CapturePCNextF,
// Debug scan chain // Debug scan chain
input logic DebugSel, input logic DebugSel,
input logic [11:0] DebugRegAddr, 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, .SATP_REGW, .PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW,
.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, .Step, .CSRReadValW, .IllegalCSRAccessM, .BigEndianM,
.Step, .DPC, .PCNextF, .CapturePCNextF,
.DebugSel, .DebugRegAddr, .DebugCapture, .DebugRegUpdate, .DebugScanEn, .DebugScanIn, .DebugScanOut); .DebugSel, .DebugRegAddr, .DebugCapture, .DebugRegUpdate, .DebugScanEn, .DebugScanIn, .DebugScanOut);
// pipeline early-arriving trap sources // pipeline early-arriving trap sources

View File

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