Implement progbuf and attempt to halt/resume using existing trap logic (very broken)

This commit is contained in:
Matthew 2024-06-19 23:06:16 -05:00
parent 5c593c3321
commit 9514eab75e
20 changed files with 282 additions and 123 deletions

View File

@ -38,7 +38,13 @@ random_order = False
def prog_buff_test(cvw):
cvw.halt()
cvw.write_dmi("0x20", "0x7ee7beef")
cvw.write_dmi("0x20", "0x00100073")
#cvw.write_dmi("0x21", "0xf00daedd")
#cvw.write_dmi("0x22", "0xdaede105")
#cvw.write_dmi("0x23", "0x00100073") # ebreak
cvw.write_data("DPC", "0x00002000") # Progbuf addr
cvw.resume()
print()
@ -46,10 +52,13 @@ def flow_control_test(cvw):
#time.sleep(70) # wait for OpenSBI
cvw.halt()
cvw.read_data("DCSR")
time.sleep(1)
#cvw.read_data("DCSR")
for _ in range(50):
cvw.step()
print(cvw.read_data("PCM"))
cvw.resume()
cvw.halt()
#cvw.step()
#print(cvw.read_data("PCM"))
cvw.resume()
@ -154,11 +163,11 @@ def random_hex(reg_name):
with OpenOCD() as cvw:
print(cvw.read_dmi("0x16"))
cvw.trst()
#cvw.trst()
cvw.reset_dm()
time.sleep(1)
cvw.reset_hart()
quit()
time.sleep(1)
#register_rw_test(cvw)
flow_control_test(cvw)
#prog_buff_test(cvw)
#flow_control_test(cvw)
prog_buff_test(cvw)

View File

@ -114,6 +114,12 @@ class OpenOCD:
raise Exception("Error: Hart failed to reset")
self.write_dmi("0x10", "0x10000001") # ack HaveReset
def write_progbuf(self, data):
#TODO query progbuf size and error is len(data) is greater
baseaddr = 0x20
for idx, instr in enumerate(data):
self.write_dmi(hex(baseaddr+idx), instr)
def set_haltonreset(self):
self.write_dmi("0x10", "0x9")
@ -139,7 +145,7 @@ class OpenOCD:
dcsr |= 0x4
self.write_data("DCSR", hex(dcsr))
# Resume once
self.resume()
self.write_dmi("0x10", "0x40000001")
# Unset step bit
dcsr &= ~0x4
self.write_data("DCSR", hex(dcsr))
@ -153,7 +159,7 @@ class OpenOCD:
data += int(math.log2(addr_size // 8)) << 20
data += write << 16
data += regno
self.write_dmi("0x17", hex(data))
self.write_dmi("0x17", hex(data))
def write_data(self, register, data):
"""Write data to specified register"""

View File

@ -186,6 +186,9 @@ localparam logic [63:0] SDC_RANGE = 64'h0000007F;
localparam logic SPI_SUPPORTED = 1;
localparam logic [63:0] SPI_BASE = 64'h10040000;
localparam logic [63:0] SPI_RANGE = 64'h00000FFF;
// Debug program buffer support is enabled with DEBUG_SUPPORTED
localparam logic [63:0] PROGBUF_BASE = 64'h00002000;
localparam logic [63:0] PROGBUF_RANGE = 64'h0000000F;
// Bus Interface width
localparam AHBW = (XLEN);

View File

@ -48,6 +48,21 @@
`define ABSTRACTAUTO `ADDR_WIDTH'h18
`define NEXTDM `ADDR_WIDTH'h1d
`define PROGBUF0 `ADDR_WIDTH'h20
`define PROGBUF1 `ADDR_WIDTH'h21
`define PROGBUF2 `ADDR_WIDTH'h22
`define PROGBUF3 `ADDR_WIDTH'h23
`define PROGBUF4 `ADDR_WIDTH'h24
`define PROGBUF5 `ADDR_WIDTH'h25
`define PROGBUF6 `ADDR_WIDTH'h26
`define PROGBUF7 `ADDR_WIDTH'h27
`define PROGBUF8 `ADDR_WIDTH'h28
`define PROGBUF9 `ADDR_WIDTH'h29
`define PROGBUFA `ADDR_WIDTH'h2A
`define PROGBUFB `ADDR_WIDTH'h2B
`define PROGBUFC `ADDR_WIDTH'h2C
`define PROGBUFD `ADDR_WIDTH'h2D
`define PROGBUFE `ADDR_WIDTH'h2E
`define PROGBUFF `ADDR_WIDTH'h2F
//`define dmcs2 `ADDR_WIDTH'h32
`define SBCS `ADDR_WIDTH'h38

View File

@ -85,6 +85,8 @@ localparam cvw_t P = '{
SPI_SUPPORTED : SPI_SUPPORTED,
SPI_BASE : SPI_BASE,
SPI_RANGE : SPI_RANGE,
PROGBUF_BASE : PROGBUF_BASE,
PROGBUF_RANGE : PROGBUF_RANGE,
GPIO_LOOPBACK_TEST : GPIO_LOOPBACK_TEST,
SPI_LOOPBACK_TEST : SPI_LOOPBACK_TEST,
UART_PRESCALE : UART_PRESCALE ,
@ -200,5 +202,5 @@ localparam cvw_t P = '{
DURLEN : DURLEN,
DIVb : DIVb,
DIVBLEN : DIVBLEN,
DEBUG_SUPPORTED : DEBUG_SUPPORTED
DEBUG_SUPPORTED : DEBUG_SUPPORTED
};

View File

@ -140,6 +140,9 @@ typedef struct packed {
logic SPI_SUPPORTED;
logic [63:0] SPI_BASE;
logic [63:0] SPI_RANGE;
// Debug program buffer support is enabled with DEBUG_SUPPORTED
logic [63:0] PROGBUF_BASE;
logic [63:0] PROGBUF_RANGE;
// Test modes

View File

@ -74,12 +74,14 @@ module dm import cvw::*; #(parameter cvw_t P) (
output logic DebugRegUpdate, // writes values from scan register after scanning in
// Program Buffer
output logic [3:0] ProgBufAddr,
output logic ProgBuffScanEn,
output logic ProgBuffScanOut,
output logic ExecProgBuff
);
`include "debug.vh"
localparam PROGBUF_SIZE = (P.PROGBUF_RANGE+1)/4;
// DMI Signals
logic ReqReady;
logic ReqValid;
@ -93,7 +95,7 @@ module dm import cvw::*; #(parameter cvw_t P) (
// JTAG ID for Wally:
// Version [31:28] = 0x1 : 0001
// PartNumber [27:12] = 0x2A : 00000000_00101010
// PartNumber [27:12] = 0x2A : Wally (00000000_00101010)
// JEDEC number [11:1] = 0x602 : Bank 13 (1100) Open HW Group (0000010)
// [0] = 1
localparam JTAG_DEVICE_ID = 32'h1002AC05;
@ -151,7 +153,7 @@ module dm import cvw::*; #(parameter cvw_t P) (
// DMStatus
const logic NdmResetPending = 0;
const logic StickyUnavail = 0;
const logic ImpEBreak = 1;
const logic ImpEBreak = 0;
logic AllHaveReset;
logic AnyHaveReset;
logic AllResumeAck;
@ -170,7 +172,7 @@ module dm import cvw::*; #(parameter cvw_t P) (
const logic ConfStrPtrValid = 0; // Used with SysBusAccess
const logic [3:0] Version = 3; // DM Version
// AbstractCS
const logic [4:0] ProgBufSize = 1;
const logic [4:0] ProgBufSize = PROGBUF_SIZE;
logic Busy;
const logic RelaxedPriv = 1;
logic [2:0] CmdErr;
@ -233,27 +235,27 @@ module dm import cvw::*; #(parameter cvw_t P) (
IDLE : begin
if (ReqValid)
case ({ReqOP, ReqAddress}) inside
{`OP_WRITE,`DATA0} : State <= W_DATA;
{`OP_READ,`DATA0} : State <= R_DATA;
{`OP_WRITE,`DATA1} : State <= (P.LLEN >= 64) ? W_DATA : INVALID;
{`OP_READ,`DATA1} : State <= (P.LLEN >= 64) ? R_DATA : INVALID;
[{`OP_WRITE,`DATA2}:{`OP_WRITE,`DATA3}] : State <= (P.LLEN >= 128) ? W_DATA : INVALID;
[{`OP_READ,`DATA2}:{`OP_READ,`DATA3}] : State <= (P.LLEN >= 128) ? R_DATA : INVALID;
{`OP_WRITE,`DMCONTROL} : State <= W_DMCONTROL;
{`OP_READ,`DMCONTROL} : State <= R_DMCONTROL;
{`OP_READ,`DMSTATUS} : State <= DMSTATUS;
{`OP_WRITE,`ABSTRACTCS} : State <= W_ABSTRACTCS;
{`OP_READ,`ABSTRACTCS} : State <= R_ABSTRACTCS;
{`OP_WRITE,`COMMAND} : State <= ABST_COMMAND;
{`OP_READ,`COMMAND} : State <= READ_ZERO;
{`OP_WRITE,`SBCS} : State <= READ_ZERO;
{`OP_READ,`SBCS} : State <= R_SYSBUSCS;
{`OP_WRITE,`PROGBUF0} : State <= W_PROGBUF;
{`OP_READ,`PROGBUF0},
{`OP_WRITE,`DATA0} : State <= W_DATA;
{`OP_READ,`DATA0} : State <= R_DATA;
{`OP_WRITE,`DATA1} : State <= (P.LLEN >= 64) ? W_DATA : INVALID;
{`OP_READ,`DATA1} : State <= (P.LLEN >= 64) ? R_DATA : INVALID;
[{`OP_WRITE,`DATA2}:{`OP_WRITE,`DATA3}] : State <= (P.LLEN >= 128) ? W_DATA : INVALID;
[{`OP_READ,`DATA2}:{`OP_READ,`DATA3}] : State <= (P.LLEN >= 128) ? R_DATA : INVALID;
{`OP_WRITE,`DMCONTROL} : State <= W_DMCONTROL;
{`OP_READ,`DMCONTROL} : State <= R_DMCONTROL;
{`OP_READ,`DMSTATUS} : State <= DMSTATUS;
{`OP_WRITE,`ABSTRACTCS} : State <= W_ABSTRACTCS;
{`OP_READ,`ABSTRACTCS} : State <= R_ABSTRACTCS;
{`OP_WRITE,`COMMAND} : State <= ABST_COMMAND;
{`OP_READ,`COMMAND} : State <= READ_ZERO;
{`OP_WRITE,`SBCS} : State <= READ_ZERO;
{`OP_READ,`SBCS} : State <= R_SYSBUSCS;
[{`OP_WRITE,`PROGBUF0}:{`OP_WRITE,`PROGBUF3}] : State <= W_PROGBUF; // TODO: update decode range dynamically using PROGBUF_RANGE
[{`OP_READ,`PROGBUF0}:{`OP_READ,`PROGBUFF}],
{2'bx,`HARTINFO},
{2'bx,`ABSTRACTAUTO},
{2'bx,`NEXTDM} : State <= READ_ZERO;
default : State <= READ_ZERO;//INVALID;
{2'bx,`NEXTDM} : State <= READ_ZERO;
default : State <= INVALID;
endcase
end
@ -369,8 +371,10 @@ module dm import cvw::*; #(parameter cvw_t P) (
W_PROGBUF : begin
if (Busy)
CmdErr <= ~|CmdErr ? `CMDERR_BUSY : CmdErr;
else
else begin
NewAcState <= PROGBUFF_WRITE;
ProgBufAddr <= ReqAddress[$clog2(PROGBUF_SIZE)-1:0];
end
RspOP <= `OP_SUCCESS;
State <= ACK;
end
@ -441,7 +445,6 @@ module dm import cvw::*; #(parameter cvw_t P) (
// Program Buffer
assign ProgBuffScanEn = (AcState == PROGBUFF_WRITE);
assign ProgBuffScanOut = ScanReg[0];
// Scan Chain
assign DebugScanOut = ScanReg[0];

View File

@ -27,12 +27,28 @@
// and limitations under the License.
////////////////////////////////////////////////////////////////////////////////////////////////
// Note: This module controls all of the per-hart debug state.
// In a multihart system, this module should be instantiated under wallypipelinedcore
// 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
module dmc (
input logic clk, reset,
input logic Step,
input logic ebreakM, // ebreak instruction
input logic ebreakEn, // DCSR: enter debug mode on ebreak
input logic HaltReq, // Initiates core halt
input logic ResumeReq, // Initiates core resume
input logic HaltOnReset, // Halts core immediately on hart reset
@ -46,14 +62,14 @@ module dmc (
output logic EnterDebugMode, // Store PCNextF in DPC when entering Debug Mode
output logic ExitDebugMode, // Updates PCNextF with the current value of DPC
output logic ForceNOP // Fills the pipeline with NOP
output logic ForceBreakPoint // Causes artificial ebreak that puts core in debug mode
);
`include "debug.vh"
enum logic [1:0] {RUNNING, FLUSH, HALTED, RESUME} State;
enum logic [2:0] {RUNNING, HALTED, RESUME, STEP, PROGBUF} State;
localparam NOP_CYCLE_DURATION = 0;
logic [$clog2(NOP_CYCLE_DURATION+1)-1:0] Counter;
localparam E2M_CYCLE_COUNT = 3;
logic [$clog2(E2M_CYCLE_COUNT+1)-1:0] Counter;
always_ff @(posedge clk) begin
if (reset)
@ -62,12 +78,13 @@ module dmc (
HaveReset <= 0;
end
assign DebugMode = (State != RUNNING);
assign DebugStall = (State == HALTED);
assign ForceBreakPoint = (State == RUNNING) & HaltReq | (State == STEP) & ~|Counter;
assign EnterDebugMode = (State == FLUSH) & ~|Counter;
assign DebugMode = (State != RUNNING);
assign DebugStall = (State == HALTED) | (State == RESUME);
assign EnterDebugMode = (State == RUNNING) & (ebreakM & ebreakEn) | ForceBreakPoint;
assign ExitDebugMode = (State == HALTED) & ResumeReq;
assign ForceNOP = (State == FLUSH);
always_ff @(posedge clk) begin
if (reset) begin
@ -77,34 +94,38 @@ module dmc (
case (State)
RUNNING : begin
if (HaltReq) begin
Counter <= NOP_CYCLE_DURATION;
State <= FLUSH;
DebugCause <= `CAUSE_HALTREQ;
end
//else if (eBreak) TODO: halt on ebreak if DCSR bit is set
// DebugCause <= `CAUSE_EBREAK;
end
// fill the pipe with NOP before halting
FLUSH : begin
if (~|Counter)
State <= HALTED;
else
Counter <= Counter - 1;
DebugCause <= `CAUSE_HALTREQ;
end else if (ebreakM & ebreakEn) begin
State <= HALTED;
DebugCause <= `CAUSE_EBREAK;
end
end
HALTED : begin
if (ResumeReq) begin
if (Step) begin
Counter <= NOP_CYCLE_DURATION;
State <= FLUSH;
DebugCause <= `CAUSE_STEP;
end else begin
State <= RUNNING;
ResumeAck <= 1;
end
if (ResumeReq)
State <= RESUME;
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
State <= RUNNING;
ResumeAck <= 1;
end
end
STEP : begin
if (~|Counter) begin
DebugCause <= `CAUSE_STEP;
State <= HALTED;
end else
Counter <= Counter - 1;
end
endcase
end
end

View File

@ -108,9 +108,8 @@ module hazard import cvw::*; #(parameter cvw_t P) (
assign LatestUnstalledW = ~StallW & StallM;
// Each stage flushes if the previous stage is the last one stalled (for cause) or the system has reason to flush
// Do not flush if halted for Debug
assign FlushD = ~DebugStall & (LatestUnstalledD | FlushDCause);
assign FlushE = ~DebugStall & (LatestUnstalledE | FlushECause);
assign FlushM = ~DebugStall & (LatestUnstalledM | FlushMCause);
assign FlushW = ~DebugStall & (LatestUnstalledW | FlushWCause);
assign FlushD = (LatestUnstalledD | FlushDCause);
assign FlushE = (LatestUnstalledE | FlushECause);
assign FlushM = (LatestUnstalledM | FlushMCause);
assign FlushW = (LatestUnstalledW | FlushWCause);
endmodule

View File

@ -98,11 +98,13 @@ 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 [P.XLEN-1:0] DPC,
output logic [P.XLEN-1:0] PCNextF, // Next PCF, selected from Branch predictor, Privilege, or PC+2/4
input logic ForceNOP,
input logic ProgBuffScanEn,
// Debug scan chain
input logic [3:0] ProgBufAddr,
input logic ProgBufScanIn,
input logic DebugScanEn,
input logic DebugScanIn,
output logic DebugScanOut
@ -111,7 +113,6 @@ 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] 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.
@ -128,6 +129,7 @@ module ifu import cvw::*; #(parameter cvw_t P) (
logic [31:0] IROMInstrF; // Instruction from the IROM
logic [31:0] ICacheInstrF; // Instruction from the I$
logic [31:0] InstrRawF; // Instruction from the IROM, I$, or bus
logic [31:0] ProgBufInstrF; // Instruction from the ProgBuf
logic CompressedF, CompressedE; // The fetched instruction is compressed
logic [31:0] PostSpillInstrRawF; // Fetch instruction after merge two halves of spill
logic [31:0] InstrRawD; // Non-decompressed instruction in the Decode stage
@ -146,6 +148,7 @@ module ifu import cvw::*; #(parameter cvw_t P) (
logic BusCommittedF; // Bus memory operation in flight, delay interrupts
logic CacheCommittedF; // I$ memory operation started, delay interrupts
logic SelIROM; // PMA indicates instruction address is in the IROM
logic SelProgBuf; // PMA indicates instruction address is in Program Buffer
logic [15:0] InstrRawE, InstrRawM;
logic [LINELEN-1:0] FetchBuffer;
logic [31:0] ShiftUncachedInstr;
@ -196,7 +199,7 @@ module ifu import cvw::*; #(parameter cvw_t P) (
.TLBFlush,
.PhysicalAddress(PCPF),
.TLBMiss(ITLBMissF),
.Cacheable(CacheableF), .Idempotent(), .SelTIM(SelIROM),
.Cacheable(CacheableF), .Idempotent(), .SelTIM(SelIROM), .SelProgBuf,
.InstrAccessFaultF, .LoadAccessFaultM(), .StoreAmoAccessFaultM(),
.InstrPageFaultF, .LoadPageFaultM(), .StoreAmoPageFaultM(),
.LoadMisalignedFaultM(), .StoreAmoMisalignedFaultM(),
@ -209,6 +212,7 @@ module ifu import cvw::*; #(parameter cvw_t P) (
assign PCPF = PCFExt[P.PA_BITS-1:0];
assign CacheableF = 1'b1;
assign SelIROM = '0;
assign SelProgBuf = '0;
end
////////////////////////////////////////////////////////////////////////////////////////////////
@ -218,7 +222,7 @@ module ifu import cvw::*; #(parameter cvw_t P) (
// CommittedM tells the CPU's privileged unit the current instruction
// in the memory stage is a memory operaton and that memory operation is either completed
// or is partially executed. Partially completed memory operations need to prevent an interrupts.
// There is not a clean way to restore back to a partial executed instruction. CommiteedM will
// There is not a clean way to restore back to a partial executed instruction. CommittedM will
// delay the interrupt until the LSU is in a clean state.
assign CommittedF = CacheCommittedF | BusCommittedF;
@ -314,7 +318,14 @@ module ifu import cvw::*; #(parameter cvw_t P) (
assign IFUStallF = IFUCacheBusStallF | SelSpillNextF;
assign GatedStallD = StallD & ~SelSpillNextF;
flopenl #(32) AlignedInstrRawDFlop(clk, reset | FlushD, ~StallD, PostSpillInstrRawF, nop, InstrRawD);
if (P.DEBUG_SUPPORTED) begin
logic [31:0] PostSpillInstrRawFM;
progbuf #(P) progbuf(.clk, .reset, .Addr(PCNextF[3:0]), .ProgBufInstrF, .ScanAddr(ProgBufAddr), .Scan(ProgBuffScanEn), .ScanIn(ProgBufScanIn));
assign PostSpillInstrRawFM = SelProgBuf ? ProgBufInstrF : PostSpillInstrRawF;
flopenl #(32) AlignedInstrRawDFlop(clk, reset | FlushD, ~StallD, PostSpillInstrRawFM, nop, InstrRawD);
end else begin
flopenl #(32) AlignedInstrRawDFlop(clk, reset | FlushD, ~StallD, PostSpillInstrRawF, nop, InstrRawD);
end
////////////////////////////////////////////////////////////////////////////////////////////////
// PCNextF logic
@ -324,10 +335,11 @@ module ifu import cvw::*; #(parameter cvw_t P) (
mux2 #(P.XLEN) pcmux2(.d0(PC1NextF), .d1(NextValidPCE), .s(CSRWriteFenceM),.y(PC2NextF));
else assign PC2NextF = PC1NextF;
mux3 #(P.XLEN) pcmux3(PC2NextF, EPCM, TrapVectorM, {TrapM, RetM}, UnalignedPCNextF);
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 = ExitDebugMode ? DPC : PCNextFM;
mux3 #(P.XLEN) pcresetmux(.d2(P.RESET_VECTOR[P.XLEN-1:0]), .d1(DPC), .d0({UnalignedPCNextF[P.XLEN-1:1], 1'b0}), .s({reset,ExitDebugMode}), .y(PCNextF));
flopen #(P.XLEN) pcreg(clk, ~StallF | reset | ExitDebugMode, 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);

69
src/ifu/progbuf.sv Normal file
View File

@ -0,0 +1,69 @@
///////////////////////////////////////////
// progbuf.sv
//
// Written: matthew.n.otto@okstate.edu
// Created: 18 June 2024
//
// Purpose: Holds small programs to be executed in debug mode
// This module acts like a small ROM except it can be written by serial Scanning via the Debug Module
//
// A component of the CORE-V-WALLY configurable RISC-V project.
// https://github.com/openhwgroup/cvw
//
// Copyright (C) 2021-24 Harvey Mudd College & Oklahoma State University
//
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
// except in compliance with the License, or, at your option, the Apache License Version 2.0. You
// may obtain a copy of the License at
//
// https://solderpad.org/licenses/SHL-2.1/
//
// Unless required by applicable law or agreed to in writing, any work distributed under the
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
////////////////////////////////////////////////////////////////////////////////////////////////
module progbuf import cvw::*; #(parameter cvw_t P) (
input logic clk, reset,
input logic [3:0] Addr,
output logic [31:0] ProgBufInstrF,
input logic [3:0] ScanAddr,
input logic Scan,
input logic ScanIn
);
localparam PROGBUF_SIZE = (P.PROGBUF_RANGE+1)/4;
localparam ADDR_WIDTH = $clog2(PROGBUF_SIZE);
bit [31:0] RAM [PROGBUF_SIZE-1:0];
logic EnPrevClk;
logic WriteProgBuf;
logic [32:0] WriteData;
logic [ADDR_WIDTH-1:0] AddrM;
flopr #(1) Scanenhist (.clk, .reset, .d(Scan), .q(EnPrevClk));
assign WriteProgBuf = ~Scan & EnPrevClk;
assign WriteData[32] = ScanIn;
genvar i;
for (i=0; i<32; i=i+1) begin
flopenr #(1) Scanreg (.clk, .reset, .en(Scan), .d(WriteData[i+1]), .q(WriteData[i]));
end
assign AddrM = WriteProgBuf ? ScanAddr[ADDR_WIDTH-1:0] : Addr[ADDR_WIDTH-1:0];
always_ff @(posedge clk) begin
if (WriteProgBuf)
RAM[AddrM] <= WriteData;
if (reset)
ProgBufInstrF <= 0;
else
ProgBufInstrF <= RAM[AddrM];
end
endmodule

View File

@ -33,7 +33,7 @@ module adrdecs import cvw::*; #(parameter cvw_t P) (
input logic [P.PA_BITS-1:0] PhysicalAddress,
input logic AccessRW, AccessRX, AccessRWXC,
input logic [1:0] Size,
output logic [11:0] SelRegions
output logic [12:0] SelRegions
);
localparam logic [3:0] SUPPORTED_SIZE = (P.LLEN == 32 ? 4'b0111 : 4'b1111);
@ -49,6 +49,7 @@ module adrdecs import cvw::*; #(parameter cvw_t P) (
adrdec #(P.PA_BITS) plicdec(PhysicalAddress, P.PLIC_BASE[P.PA_BITS-1:0], P.PLIC_RANGE[P.PA_BITS-1:0], P.PLIC_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[9]);
adrdec #(P.PA_BITS) sdcdec(PhysicalAddress, P.SDC_BASE[P.PA_BITS-1:0], P.SDC_RANGE[P.PA_BITS-1:0], P.SDC_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE & 4'b1100, SelRegions[10]);
adrdec #(P.PA_BITS) spidec(PhysicalAddress, P.SPI_BASE[P.PA_BITS-1:0], P.SPI_RANGE[P.PA_BITS-1:0], P.SPI_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[11]);
adrdec #(P.PA_BITS) progbufdec(PhysicalAddress, P.PROGBUF_BASE[P.PA_BITS-1:0], P.PROGBUF_RANGE[P.PA_BITS-1:0], P.DEBUG_SUPPORTED, AccessRX, Size, SUPPORTED_SIZE, SelRegions[12]);
assign SelRegions[0] = ~|(SelRegions[11:1]); // none of the regions are selected
endmodule

View File

@ -50,6 +50,7 @@ module mmu import cvw::*; #(parameter cvw_t P,
output logic Cacheable, // PMA indicates memory address is cachable
output logic Idempotent, // PMA indicates memory address is idempotent
output logic SelTIM, // Select a tightly integrated memory
output logic SelProgBuf, // Select ProgBuf
// Faults
output logic InstrAccessFaultF, LoadAccessFaultM, StoreAmoAccessFaultM, // access fault sources
output logic InstrPageFaultF, LoadPageFaultM, StoreAmoPageFaultM, // page fault sources
@ -112,7 +113,7 @@ module mmu import cvw::*; #(parameter cvw_t P,
pmachecker #(P) pmachecker(.PhysicalAddress, .Size, .CMOpM,
.AtomicAccessM, .ExecuteAccessF, .WriteAccessM, .ReadAccessM, .PBMemoryType,
.Cacheable, .Idempotent, .SelTIM,
.Cacheable, .Idempotent, .SelTIM, .SelProgBuf,
.PMAInstrAccessFaultF, .PMALoadAccessFaultM, .PMAStoreAmoAccessFaultM);
if (P.PMP_ENTRIES > 0) begin : pmp

View File

@ -38,7 +38,7 @@ module pmachecker import cvw::*; #(parameter cvw_t P) (
input logic WriteAccessM, // Write access
input logic ReadAccessM, // Read access
input logic [1:0] PBMemoryType, // PBMT field of PTE during TLB hit, or 00 otherwise
output logic Cacheable, Idempotent, SelTIM,
output logic Cacheable, Idempotent, SelTIM, SelProgBuf,
output logic PMAInstrAccessFaultF,
output logic PMALoadAccessFaultM,
output logic PMAStoreAmoAccessFaultM
@ -46,7 +46,7 @@ module pmachecker import cvw::*; #(parameter cvw_t P) (
logic PMAAccessFault;
logic AccessRW, AccessRWXC, AccessRX;
logic [11:0] SelRegions;
logic [12:0] SelRegions;
logic AtomicAllowed;
logic CacheableRegion, IdempotentRegion;
@ -72,6 +72,9 @@ module pmachecker import cvw::*; #(parameter cvw_t P) (
// Check if tightly integrated memories are selected
assign SelTIM = SelRegions[1] | SelRegions[2]; // exclusion-tag: unused-tim
// Debug program buffer
assign SelProgBuf = SelRegions[12];
// Detect access faults
assign PMAAccessFault = SelRegions[0] & AccessRWXC | AtomicAccessM & ~AtomicAllowed;
assign PMAInstrAccessFaultF = ExecuteAccessF & PMAAccessFault;

View File

@ -96,9 +96,9 @@ module csr import cvw::*; #(parameter cvw_t P) (
// Debug Mode output
input logic DebugMode,
input logic [2:0] DebugCause,
output logic ebreakEn,
output logic Step,
output logic [P.XLEN-1:0] DPC,
input logic [P.XLEN-1:0] PCNextF,
input logic EnterDebugMode,
// Debug scan chain
input logic DebugSel,
@ -215,10 +215,10 @@ module csr import cvw::*; #(parameter cvw_t P) (
///////////////////////////////////////////
assign CSRAdrM = InstrM[31:20];
assign UnalignedNextEPCM = TrapM ? PCM : CSRWriteValDM;
assign UnalignedNextEPCM = TrapM ? PCM : CSRWriteValM;
assign NextEPCM = P.ZCA_SUPPORTED ? {UnalignedNextEPCM[P.XLEN-1:1], 1'b0} : {UnalignedNextEPCM[P.XLEN-1:2], 2'b00}; // 3.1.15 alignment
assign NextCauseM = TrapM ? {InterruptM, CauseM}: {CSRWriteValDM[P.XLEN-1], CSRWriteValDM[3:0]};
assign NextMtvalM = TrapM ? NextFaultMtvalM : CSRWriteValDM;
assign NextCauseM = TrapM ? {InterruptM, CauseM}: {CSRWriteValM[P.XLEN-1], CSRWriteValM[3:0]};
assign NextMtvalM = TrapM ? NextFaultMtvalM : CSRWriteValM;
assign UngatedCSRMWriteM = CSRWriteDM & (PrivilegeModeW == P.M_MODE);
assign CSRMWriteM = UngatedCSRMWriteM & InstrValidNotFlushedM;
assign CSRSWriteM = CSRWriteDM & (|PrivilegeModeW) & InstrValidNotFlushedM;
@ -305,7 +305,7 @@ module csr import cvw::*; #(parameter cvw_t P) (
if (P.DEBUG_SUPPORTED) begin:csrd
csrd #(P) csrd(.clk, .reset, .DebugMode, .PrivilegeModeW,
.CSRWriteDM, .CSRAdrM(CSRAdrDM), .CSRWriteValM(CSRWriteValDM), .CSRDReadValM, .IllegalCSRDAccessM,
.DebugCause, .Step, .DPC, .PCNextF, .EnterDebugMode);
.DebugCause, .ebreakEn, .Step, .DPC, .PCM, .EnterDebugMode);
end else begin
assign CSRDReadValM = '0;
assign IllegalCSRDAccessM = 1'b1; // Debug isn't supported

View File

@ -35,12 +35,12 @@ module csrd import cvw::*; #(parameter cvw_t P) (
input logic [P.XLEN-1:0] CSRWriteValM,
output logic [P.XLEN-1:0] CSRDReadValM,
output logic IllegalCSRDAccessM,
input logic [P.XLEN-1:0] PCM,
input logic EnterDebugMode,
input logic [2:0] DebugCause,
output logic ebreakEn,
output logic Step,
output logic [P.XLEN-1:0] DPC,
input logic [P.XLEN-1:0] PCNextF,
input logic EnterDebugMode
output logic [P.XLEN-1:0] DPC
);
`include "debug.vh"
@ -58,8 +58,8 @@ module csrd import cvw::*; #(parameter cvw_t P) (
const logic ebreakVS = 0;
const logic ebreakVU = 0;
logic ebreakM;
logic ebreakS;
logic ebreakU;
const logic ebreakS = 0;
const logic ebreakU = 0;
const logic StepIE = 0;
const logic StopCount = 0;
const logic StopTime = 0;
@ -69,7 +69,8 @@ module csrd import cvw::*; #(parameter cvw_t P) (
logic NMIP; // pending non-maskable interrupt
logic [1:0] Prv;
assign ebreakEn = ebreakM; // Only support ebreak from M mode
assign CSRDWriteM = CSRWriteDM & (PrivilegeModeW == P.M_MODE) & DebugMode;
assign WriteDCSRM = CSRDWriteM & (CSRAdrM == DCSR_ADDR);
@ -85,15 +86,13 @@ module csrd import cvw::*; #(parameter cvw_t P) (
end
end
flopenr #(4) DCSRreg (clk, reset, WriteDCSRM,
{CSRWriteValM[`EBREAKM], CSRWriteValM[`EBREAKS], CSRWriteValM[`EBREAKU], CSRWriteValM[`STEP]},
{ebreakM, ebreakS, ebreakU, Step});
flopenr #(4) DCSRreg (clk, reset, WriteDCSRM, {CSRWriteValM[`EBREAKM], CSRWriteValM[`STEP]}, {ebreakM, Step});
assign DCSR = {DebugVer, 10'b0, ebreakVS, ebreakVU, ebreakM, 1'b0, ebreakS, ebreakU, StepIE,
StopCount, StopTime, Cause, V, MPrvEn, NMIP, Step, Prv};
assign DPCWriteVal = EnterDebugMode ? PCNextF : CSRWriteValM;
flopenr #(P.XLEN) DPCreg (clk, reset, WriteDPCM | EnterDebugMode, DPCWriteVal, DPC);
assign DPCWriteVal = EnterDebugMode ? PCM : CSRWriteValM;
flopenr #(P.XLEN) DPCreg (clk, reset, WriteDPCM | EnterDebugMode, DPCWriteVal, DPC); // TODO: reset to something sane (0x80000000?)
always_comb begin
CSRDReadValM = '0;

View File

@ -30,7 +30,8 @@
module privdec import cvw::*; #(parameter cvw_t P) (
input logic clk, reset,
input logic StallW, FlushW,
input logic StallW, FlushW,
input logic ForceBreakPoint, // Debug Module initiated break to debug mode
input logic [31:15] InstrM, // privileged instruction function field
input logic PrivilegedM, // is this a privileged instruction (from IEU controller)
input logic IllegalIEUFPUInstrM, // Not a legal IEU instruction
@ -40,13 +41,14 @@ module privdec import cvw::*; #(parameter cvw_t P) (
output logic IllegalInstrFaultM, // Illegal instruction
output logic EcallFaultM, BreakpointFaultM, // Ecall or breakpoint; must retire, so don't flush it when the trap occurs
output logic sretM, mretM, RetM, // return instructions
output logic wfiM, wfiW, sfencevmaM // wfi / sfence.vma / sinval.vma instructions
output logic wfiM, wfiW, sfencevmaM, // wfi / sfence.vma / sinval.vma instructions
output logic ebreakM // ebreak instruction
);
logic rs1zeroM; // rs1 field = 0
logic IllegalPrivilegedInstrM; // privileged instruction isn't a legal one or in legal mode
logic WFITimeoutM; // WFI reaches timeout threshold
logic ebreakM, ecallM; // ebreak / ecall instructions
logic ecallM; // ecall instructions
logic sinvalvmaM; // sinval.vma
logic sfencewinvalM, sfenceinvalirM; // sfence.w.inval, sfence.inval.ir
logic invalM; // any of the svinval instructions
@ -94,7 +96,10 @@ module privdec import cvw::*; #(parameter cvw_t P) (
// Extract exceptions by name and handle them
///////////////////////////////////////////
assign BreakpointFaultM = ebreakM; // could have other causes from a debugger
if (P.DEBUG_SUPPORTED)
assign BreakpointFaultM = ebreakM | ForceBreakPoint;
else
assign BreakpointFaultM = ebreakM;
assign EcallFaultM = ecallM;
///////////////////////////////////////////

View File

@ -97,12 +97,14 @@ module privileged import cvw::*; #(parameter cvw_t P) (
output logic BigEndianM, // Use big endian in current privilege mode
// Fault outputs
output logic wfiM, IntPendingM, // Stall in Memory stage for WFI until interrupt pending or timeout
output logic ebreakM, // Notifies DM to enter debug mode
// Debuge Mode
output logic ebreakEn,
input logic ForceBreakPoint,
input logic DebugMode,
input logic [2:0] DebugCause,
output logic Step,
output logic [P.XLEN-1:0] DPC,
input logic [P.XLEN-1:0] PCNextF,
input logic EnterDebugMode,
// Debug scan chain
input logic DebugSel,
@ -142,9 +144,9 @@ module privileged import cvw::*; #(parameter cvw_t P) (
// decode privileged instructions
privdec #(P) pmd(.clk, .reset, .StallW, .FlushW, .InstrM(InstrM[31:15]),
.PrivilegedM, .IllegalIEUFPUInstrM, .IllegalCSRAccessM,
.PrivilegedM, .IllegalIEUFPUInstrM, .IllegalCSRAccessM, .ForceBreakPoint,
.PrivilegeModeW, .STATUS_TSR, .STATUS_TVM, .STATUS_TW, .IllegalInstrFaultM,
.EcallFaultM, .BreakpointFaultM, .sretM, .mretM, .RetM, .wfiM, .wfiW, .sfencevmaM);
.EcallFaultM, .BreakpointFaultM, .sretM, .mretM, .RetM, .wfiM, .wfiW, .sfencevmaM, .ebreakM);
// Control and Status Registers
csr #(P) csr(.clk, .reset, .FlushM, .FlushW, .StallE, .StallM, .StallW,
@ -163,7 +165,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, .Step, .DPC, .PCNextF, .EnterDebugMode,
.DebugMode, .DebugCause, .ebreakEn, .Step, .DPC, .EnterDebugMode,
.DebugSel, .DebugRegAddr, .DebugCapture, .DebugRegUpdate, .DebugScanEn, .DebugScanIn, .DebugScanOut);
// pipeline early-arriving trap sources

View File

@ -53,6 +53,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
output logic ResumeAck,
output logic HaveReset,
output logic DebugStall,
input logic ExecProgBuff,
// Debug scan chain
input logic DebugScanEn, // puts scannable flops into scan mode
output logic DebugScanOut, // (misc) scan chain data out
@ -66,13 +67,16 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
input logic CSRSel, // selects CSR scan chain
input logic [11:0] DebugRegAddr, // address for scanable regfiles (GPR, FPR, CSR)
input logic DebugCapture, // latches values into scan register before scanning out
input logic DebugRegUpdate // writes values from scan register after scanning in
input logic DebugRegUpdate, // writes values from scan register after scanning in
input logic [3:0] ProgBufAddr,
input logic ProgBuffScanEn
);
logic StallF, StallD, StallE, StallM, StallW;
logic FlushD, FlushE, FlushM, FlushW;
logic TrapM, RetM;
logic DebugMode, Step;
logic ebreakEn;
// signals that must connect through DP
logic IntDivE, W64E;
@ -190,13 +194,14 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
logic BranchD, BranchE, JumpD, JumpE;
logic DCacheStallM, ICacheStallF;
logic wfiM, IntPendingM;
logic ebreakM;
// Debug mode logic
logic [P.XLEN-1:0] DPC, PCNextF;
logic ExitDebugMode;
logic EnterDebugMode;
logic [2:0] DebugCause;
logic ForceNOP;
logic ForceBreakPoint;
// Debug register scan chain interconnects
logic [2:0] DebugScanReg;
@ -222,7 +227,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,
.ExitDebugMode, .DPC, .PCNextF, .ForceNOP,
.ExitDebugMode, .DPC, .PCNextF, .ProgBuffScanEn, .ProgBufAddr, .ProgBufScanIn(DebugScanIn),
.DebugScanEn(DebugScanEn & MiscSel), .DebugScanIn(DebugScanReg[0]), .DebugScanOut(DebugScanReg[1]));
// integer execution unit: integer register file, datapath and controller
@ -320,9 +325,9 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
if (P.DEBUG_SUPPORTED) begin
dmc debugcontrol(
.clk, .reset,
.Step, .HaltReq, .ResumeReq, .HaltOnReset, .AckHaveReset,
.Step, .ebreakM, .ebreakEn, .HaltReq, .ResumeReq, .HaltOnReset, .AckHaveReset,
.ResumeAck, .HaveReset, .DebugMode, .DebugCause, .DebugStall,
.EnterDebugMode, .ExitDebugMode, .ForceNOP);
.EnterDebugMode, .ExitDebugMode, .ForceBreakPoint);
end else begin
assign DebugStall = 1'b0;
end
@ -349,8 +354,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,
.DebugMode, .DebugCause, .Step, .DPC, .PCNextF, .EnterDebugMode,
.FRM_REGW, .ENVCFG_CBE, .ENVCFG_PBMTE, .ENVCFG_ADUE, .wfiM, .IntPendingM, .BigEndianM, .ebreakM,
.ebreakEn, .ForceBreakPoint, .DebugMode, .DebugCause, .Step, .DPC, .EnterDebugMode,
.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,6 +82,7 @@ module wallypipelinedsoc import cvw::*; #(parameter cvw_t P) (
logic ResumeAck;
logic HaveReset;
logic DebugStall;
logic ExecProgBuff;
// Debug Module signals
logic DebugScanEn;
logic DebugScanIn;
@ -96,9 +97,8 @@ module wallypipelinedsoc import cvw::*; #(parameter cvw_t P) (
logic [11:0] DebugRegAddr;
logic DebugCapture;
logic DebugRegUpdate;
logic [3:0] ProgBufAddr;
logic ProgBuffScanEn;
logic ProgBuffScanOut;
logic ExecProgBuff;
// synchronize reset to SOC clock domain
synchronizer resetsync(.clk, .d(reset_ext), .q(reset));
@ -108,9 +108,10 @@ 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,
.HaltReq, .ResumeReq, .HaltOnReset, .AckHaveReset, .ResumeAck, .HaveReset, .DebugStall, .ExecProgBuff,
.DebugScanEn, .DebugScanOut(DebugScanIn), .GPRScanOut(GPRScanIn), .FPRScanOut(FPRScanIn), .CSRScanOut(CSRScanIn),
.DebugScanIn(DebugScanOut), .MiscSel, .GPRSel, .FPRSel, .CSRSel, .DebugRegAddr, .DebugCapture, .DebugRegUpdate);
.DebugScanIn(DebugScanOut), .MiscSel, .GPRSel, .FPRSel, .CSRSel, .DebugRegAddr, .DebugCapture, .DebugRegUpdate,
.ProgBufAddr, .ProgBuffScanEn);
// instantiate uncore if a bus interface exists
if (P.BUS_SUPPORTED) begin : uncoregen // Hack to work around Verilator bug https://github.com/verilator/verilator/issues/4769
@ -130,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,
.ProgBuffScanEn, .ProgBuffScanOut, .ExecProgBuff);
.ProgBufAddr, .ProgBuffScanEn, .ExecProgBuff);
end
endmodule