From d0deb1bd7a72d106b3ef5b943f49f7819e3368b2 Mon Sep 17 00:00:00 2001 From: Matthew <106996253+Matthew-Otto@users.noreply.github.com> Date: Fri, 14 Jun 2024 14:21:38 -0500 Subject: [PATCH] Add DPC support (does not write on resume) --- src/debug/dm.sv | 2 +- src/debug/dmc.sv | 54 ++++++++++++++++++++++++++------- src/ifu/ifu.sv | 19 +++++++++--- src/privileged/csr.sv | 6 ++-- src/privileged/csrd.sv | 26 +++++++++------- src/privileged/privileged.sv | 6 +++- src/wally/wallypipelinedcore.sv | 13 ++++++-- 7 files changed, 93 insertions(+), 33 deletions(-) diff --git a/src/debug/dm.sv b/src/debug/dm.sv index 8423683e7..77f142b89 100644 --- a/src/debug/dm.sv +++ b/src/debug/dm.sv @@ -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; diff --git a/src/debug/dmc.sv b/src/debug/dmc.sv index 4d29b99e8..1a7d8404d 100644 --- a/src/debug/dmc.sv +++ b/src/debug/dmc.sv @@ -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 diff --git a/src/ifu/ifu.sv b/src/ifu/ifu.sv index 4a9ead7ad..c7cfe7403 100644 --- a/src/ifu/ifu.sv +++ b/src/ifu/ifu.sv @@ -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 diff --git a/src/privileged/csr.sv b/src/privileged/csr.sv index 9973e5dfd..9f64c4dc4 100644 --- a/src/privileged/csr.sv +++ b/src/privileged/csr.sv @@ -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 diff --git a/src/privileged/csrd.sv b/src/privileged/csrd.sv index c405fdd5e..1263b7fdc 100644 --- a/src/privileged/csrd.sv +++ b/src/privileged/csrd.sv @@ -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 diff --git a/src/privileged/privileged.sv b/src/privileged/privileged.sv index 7b1706fe9..458f63ab2 100644 --- a/src/privileged/privileged.sv +++ b/src/privileged/privileged.sv @@ -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 diff --git a/src/wally/wallypipelinedcore.sv b/src/wally/wallypipelinedcore.sv index 5a75f5770..473c8f5f6 100644 --- a/src/wally/wallypipelinedcore.sv +++ b/src/wally/wallypipelinedcore.sv @@ -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]));