Fix DPC write and DCSR Cause

This commit is contained in:
Matthew 2024-06-14 18:27:06 -05:00
parent d0deb1bd7a
commit 60f12a6f60
7 changed files with 74 additions and 51 deletions

View File

@ -143,6 +143,14 @@
`define AAR64 3 `define AAR64 3
`define AAR128 4 `define AAR128 4
// debug mode cause
`define CAUSE_EBREAK 3'h1
`define CAUSE_TRIGGER 3'h2
`define CAUSE_HALTREQ 3'h3
`define CAUSE_STEP 3'h4
`define CAUSE_RESETHALTREQ 3'h5
`define CAUSE_GROUP 3'h6
// Register Numbers (regno) // Register Numbers (regno)
// (Table 3.3) // (Table 3.3)
// 0x0000 0x0fff | CSRs. The “PC” can be accessed here through dpc. // 0x0000 0x0fff | CSRs. The “PC” can be accessed here through dpc.

View File

@ -31,23 +31,26 @@
// 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
input logic ResumeReq, // Initiates core resume input logic ResumeReq, // Initiates core resume
input logic HaltOnReset, // Halts core immediately on hart reset input logic HaltOnReset, // Halts core immediately on hart reset
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 [2:0] DebugCause, // Reason Hart entered debug mode
output logic HaveReset, // Signals Hart has been reset output logic ResumeAck, // Signals Hart has been resumed
output logic DebugStall, // Stall signal goes to hazard unit 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 EnterDebugMode, // Store PCNextF in DPC when entering Debug Mode
output logic ForceDPCNextF, // Updates PCNextF with the current value of DPC output logic ExitDebugMode, // Updates PCNextF with the current value of DPC
output logic ForceNOP // Fills the pipeline with NOP output logic ForceNOP // Fills the pipeline with NOP
); );
enum logic [1:0] {RUNNING, FLUSH, HALTED, RESUME} State; `include "debug.vh"
enum logic [1:0] {RUNNING, FLUSH, HALTED, RESUME} State;
localparam NOP_CYCLE_DURATION = 0; localparam NOP_CYCLE_DURATION = 0;
logic [$clog2(NOP_CYCLE_DURATION+1)-1:0] Counter; logic [$clog2(NOP_CYCLE_DURATION+1)-1:0] Counter;
@ -62,20 +65,24 @@ module dmc (
assign DebugMode = (State != RUNNING); assign DebugMode = (State != RUNNING);
assign DebugStall = (State == HALTED); assign DebugStall = (State == HALTED);
assign CapturePCNextF = (State == FLUSH) & (Counter == 0); assign EnterDebugMode = (State == FLUSH) & (Counter == 0);
assign ForceDPCNextF = (State == HALTED) & ResumeReq; assign ExitDebugMode = (State == HALTED) & ResumeReq;
assign ForceNOP = (State == FLUSH); assign ForceNOP = (State == FLUSH);
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
if (reset) begin if (reset) begin
State <= HaltOnReset ? HALTED : RUNNING; State <= HaltOnReset ? HALTED : RUNNING;
DebugCause <= HaltOnReset ? `CAUSE_RESETHALTREQ : 0;
end else begin end else begin
case (State) case (State)
RUNNING : begin RUNNING : begin
if (HaltReq) begin if (HaltReq) begin
Counter <= 0; Counter <= 0;
State <= FLUSH; State <= FLUSH;
DebugCause <= `CAUSE_HALTREQ;
end end
//else if (eBreak) TODO: halt on ebreak if DCSR bit is set
// DebugCause <= `CAUSE_EBREAK;
end end
// fill the pipe with NOP before halting // fill the pipe with NOP before halting
@ -95,6 +102,7 @@ module dmc (
if (Step) begin if (Step) begin
Counter <= 0; Counter <= 0;
State <= FLUSH; State <= FLUSH;
DebugCause <= `CAUSE_STEP;
end else begin end else begin
State <= RUNNING; State <= RUNNING;
ResumeAck <= 1; ResumeAck <= 1;

View File

@ -98,10 +98,10 @@ 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
(* mark_debug = "true" *)input logic ForceDPCNextF, input logic ExitDebugMode,
(* mark_debug = "true" *)input logic [P.XLEN-1:0] DPC, 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 output logic [P.XLEN-1:0] PCNextF, // Next PCF, selected from Branch predictor, Privilege, or PC+2/4
(* mark_debug = "true" *)input logic ForceNOP, input logic ForceNOP,
// Debug scan chain // Debug scan chain
input logic DebugScanEn, input logic DebugScanEn,
input logic DebugScanIn, input logic DebugScanIn,
@ -327,8 +327,8 @@ module ifu import cvw::*; #(parameter cvw_t P) (
mux3 #(P.XLEN) pcmux3(PC2NextF, EPCM, TrapVectorM, {TrapM, RetM}, UnalignedPCNextF); mux3 #(P.XLEN) pcmux3(PC2NextF, EPCM, TrapVectorM, {TrapM, RetM}, UnalignedPCNextF);
if (P.DEBUG_SUPPORTED) begin 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); 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; assign PCNextF = ExitDebugMode ? DPC : PCNextFM;
flopen #(P.XLEN) pcreg(clk, ~StallF | reset | ForceDPCNextF, PCNextF, PCF); flopen #(P.XLEN) pcreg(clk, ~StallF | reset | ExitDebugMode, PCNextF, PCF);
end else begin end else begin
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

@ -94,10 +94,11 @@ module csr import cvw::*; #(parameter cvw_t P) (
output logic IllegalCSRAccessM, // Illegal CSR access: CSR doesn't exist or is inaccessible at this privilege level output logic IllegalCSRAccessM, // Illegal CSR access: CSR doesn't exist or is inaccessible at this privilege level
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
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 [P.XLEN-1:0] PCNextF, input logic [P.XLEN-1:0] PCNextF,
input logic CapturePCNextF, input logic EnterDebugMode,
// Debug scan chain // Debug scan chain
input logic DebugSel, input logic DebugSel,
input logic [11:0] DebugRegAddr, input logic [11:0] DebugRegAddr,
@ -304,7 +305,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, .DPC, .PCNextF, .CapturePCNextF); .DebugCause, .Step, .DPC, .PCNextF, .EnterDebugMode);
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,10 +34,11 @@ 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 [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 [P.XLEN-1:0] PCNextF, input logic [P.XLEN-1:0] PCNextF,
input logic CapturePCNextF input logic EnterDebugMode
); );
`include "debug.vh" `include "debug.vh"
@ -45,8 +46,8 @@ module csrd import cvw::*; #(parameter cvw_t P) (
localparam DPC_ADDR = 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;
logic [P.XLEN-1:0] DPC_REGW, DPCWriteVal; logic [P.XLEN-1:0] DPCWriteVal;
logic WriteDCSRM; logic WriteDCSRM;
logic WriteDPCM; logic WriteDPCM;
@ -60,7 +61,7 @@ module csrd import cvw::*; #(parameter cvw_t P) (
const logic StepIE = 0; const logic StepIE = 0;
const logic StopCount = 0; const logic StopCount = 0;
const logic StopTime = 0; const logic StopTime = 0;
logic [2:0] Cause; // TODO: give reason for entering debug mode logic [2:0] Cause;
const logic V = 0; const logic V = 0;
const logic MPrvEn = 0; const logic MPrvEn = 0;
logic NMIP; // pending non-maskable interrupt logic NMIP; // pending non-maskable interrupt
@ -68,34 +69,37 @@ module csrd import cvw::*; #(parameter cvw_t P) (
always_ff @(posedge clk) begin
if (reset) begin
Prv <= 3;
Cause <= 0;
end else if (EnterDebugMode) begin
// Prv <= // hart priv mode
Cause <= DebugCause;
end else if (WriteDCSRM) begin
Prv <= CSRWriteValM[`PRV]; // TODO: overwrite hart privilege mode
end
end
assign WriteDCSRM = CSRWriteDM & (CSRAdrM == DCSR_ADDR); assign WriteDCSRM = CSRWriteDM & (CSRAdrM == DCSR_ADDR);
assign WriteDPCM = CSRWriteDM & (CSRAdrM == DPC_ADDR); assign WriteDPCM = CSRWriteDM & (CSRAdrM == DPC_ADDR);
always_ff @(posedge clk) begin
if (reset)
Prv <= 3;
//else if (Halt) // TODO: trigger when hart enters debug mode
// Prv <= // hart priv mode
else if (WriteDCSRM)
Prv <= CSRWriteValM[`PRV]; // TODO: overwrite hart privilege mode
end
flopenr #(4) DCSRreg (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 = {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 DPCWriteVal = CapturePCNextF ? PCNextF : CSRWriteValM; assign DPCWriteVal = EnterDebugMode ? PCNextF : CSRWriteValM;
flopenr #(P.XLEN) DPCreg (clk, reset, WriteDPCM | CapturePCNextF, DPCWriteVal, DPC_REGW); flopenr #(P.XLEN) DPCreg (clk, reset, WriteDPCM | EnterDebugMode, DPCWriteVal, DPC);
always_comb begin always_comb begin
CSRDReadValM = 0; CSRDReadValM = 0;
IllegalCSRDAccessM = 0; IllegalCSRDAccessM = 0;
case (CSRAdrM) case (CSRAdrM)
DCSR_ADDR : CSRDReadValM = DCSR_REGW; DCSR_ADDR : CSRDReadValM = DCSR;
DPC_ADDR : CSRDReadValM = DPC_REGW; DPC_ADDR : CSRDReadValM = DPC;
default: IllegalCSRDAccessM = 1'b1; default: IllegalCSRDAccessM = 1'b1;
endcase endcase
end end

View File

@ -98,10 +98,11 @@ module privileged import cvw::*; #(parameter cvw_t P) (
// Fault outputs // Fault outputs
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
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 [P.XLEN-1:0] PCNextF, input logic [P.XLEN-1:0] PCNextF,
input logic CapturePCNextF, input logic EnterDebugMode,
// Debug scan chain // Debug scan chain
input logic DebugSel, input logic DebugSel,
input logic [11:0] DebugRegAddr, input logic [11:0] DebugRegAddr,
@ -161,7 +162,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,
.Step, .DPC, .PCNextF, .CapturePCNextF, .DebugCause, .Step, .DPC, .PCNextF, .EnterDebugMode,
.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

@ -193,9 +193,10 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
// Debug mode logic // Debug mode logic
logic [P.XLEN-1:0] DPC, PCNextF; logic [P.XLEN-1:0] DPC, PCNextF;
logic ForceDPCNextF; logic ExitDebugMode;
logic CapturePCNextF; logic EnterDebugMode;
logic ForceNOP; logic ForceNOP;
logic [2:0] DebugCause;
// Debug register scan chain interconnects // Debug register scan chain interconnects
logic [2:0] DebugScanReg; logic [2:0] DebugScanReg;
@ -221,7 +222,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, .ExitDebugMode, .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
@ -320,8 +321,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, .DebugCause, .DebugStall,
.CapturePCNextF, .ForceDPCNextF, .ForceNOP); .EnterDebugMode, .ExitDebugMode, .ForceNOP);
end else begin end else begin
assign DebugStall = 1'b0; assign DebugStall = 1'b0;
end end
@ -349,7 +350,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, .FRM_REGW, .ENVCFG_CBE, .ENVCFG_PBMTE, .ENVCFG_ADUE, .wfiM, .IntPendingM, .BigEndianM,
.Step, .DPC, .PCNextF, .CapturePCNextF, .DebugCause, .Step, .DPC, .PCNextF, .EnterDebugMode,
.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]));