2021-05-21 09:34:16 +08:00
|
|
|
/******************************************************************************
|
|
|
|
* DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE *
|
|
|
|
* Version 3, April 2008 *
|
|
|
|
* *
|
2021-05-30 01:00:43 +08:00
|
|
|
* Copyright (C) 2021 Luke Wren *
|
2021-05-21 09:34:16 +08:00
|
|
|
* *
|
|
|
|
* Everyone is permitted to copy and distribute verbatim or modified *
|
|
|
|
* copies of this license document and accompanying software, and *
|
|
|
|
* changing either is allowed. *
|
|
|
|
* *
|
|
|
|
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION *
|
|
|
|
* *
|
|
|
|
* 0. You just DO WHAT THE FUCK YOU WANT TO. *
|
|
|
|
* 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. *
|
|
|
|
* *
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2021-05-30 01:00:43 +08:00
|
|
|
`default_nettype none
|
|
|
|
|
2021-05-21 09:34:16 +08:00
|
|
|
// Control and Status Registers (CSRs)
|
|
|
|
// Also includes CSR-related logic like interrupt enable/masking,
|
|
|
|
// trap vector calculation.
|
|
|
|
|
2021-05-21 10:46:29 +08:00
|
|
|
module hazard3_csr #(
|
2021-05-21 09:34:16 +08:00
|
|
|
parameter XLEN = 32, // Must be 32
|
2021-05-21 10:23:44 +08:00
|
|
|
parameter W_COUNTER = 64, // This *should* be 64, but can be reduced to save gates.
|
2021-05-21 09:34:16 +08:00
|
|
|
// The full 64 bits is writeable, so high-word increment can
|
|
|
|
// be implemented in software, and a narrower hw counter used
|
2021-05-21 10:46:29 +08:00
|
|
|
`include "hazard3_config.vh"
|
2021-05-23 18:59:46 +08:00
|
|
|
,
|
|
|
|
`include "hazard3_width_const.vh"
|
2021-05-21 09:34:16 +08:00
|
|
|
) (
|
|
|
|
input wire clk,
|
|
|
|
input wire rst_n,
|
|
|
|
|
|
|
|
// Read port is combinatorial.
|
|
|
|
// Write port is synchronous, and write effects will be observed on the next clock cycle.
|
|
|
|
// The *_soon strobes are versions which the core does not gate with its stall signal.
|
|
|
|
// These are needed because:
|
|
|
|
// - Core stall is a function of bus stall
|
|
|
|
// - Illegal CSR accesses produce trap entry
|
|
|
|
// - Trap entry (not necessarily caused by CSR access) gates outgoing bus accesses
|
|
|
|
// - Through-paths from e.g. hready to htrans are problematic for timing/implementation
|
2021-05-23 18:59:46 +08:00
|
|
|
input wire [11:0] addr,
|
|
|
|
input wire [XLEN-1:0] wdata,
|
|
|
|
input wire wen,
|
|
|
|
input wire wen_soon, // wen will be asserted once some stall condition clears
|
|
|
|
input wire [1:0] wtype,
|
|
|
|
output reg [XLEN-1:0] rdata,
|
|
|
|
input wire ren,
|
|
|
|
input wire ren_soon, // ren will be asserted once some stall condition clears
|
|
|
|
output wire illegal,
|
2021-05-21 09:34:16 +08:00
|
|
|
|
|
|
|
// Trap signalling
|
|
|
|
// *We* tell the core that we are taking a trap, and where to, based on:
|
|
|
|
// - Synchronous exception inputs from the core
|
|
|
|
// - External IRQ signals
|
|
|
|
// - Masking etc based on the state of CSRs like mie
|
|
|
|
//
|
|
|
|
// We do this by raising trap_enter_vld, and keeping it raised until trap_enter_rdy
|
|
|
|
// goes high. trap_addr has the absolute value of trap target address.
|
|
|
|
// Once trap_enter_vld && _rdy, mepc_in is copied to mepc, and other trap state is set.
|
|
|
|
//
|
|
|
|
// Note that an exception input can go away, e.g. if the pipe gets flushed. In this
|
|
|
|
// case we lower trap_enter_vld.
|
2021-05-23 18:59:46 +08:00
|
|
|
output wire [XLEN-1:0] trap_addr,
|
2021-05-30 01:00:43 +08:00
|
|
|
output wire trap_is_irq,
|
2021-05-23 18:59:46 +08:00
|
|
|
output wire trap_enter_vld,
|
|
|
|
input wire trap_enter_rdy,
|
|
|
|
input wire [XLEN-1:0] mepc_in,
|
2021-05-21 09:34:16 +08:00
|
|
|
|
|
|
|
// Exceptions must *not* be a function of bus stall.
|
2021-05-23 18:59:46 +08:00
|
|
|
input wire [W_EXCEPT-1:0] except,
|
2021-05-21 09:34:16 +08:00
|
|
|
|
2021-06-01 00:54:12 +08:00
|
|
|
// Level-sensitive interrupt sources
|
|
|
|
input wire delay_irq_entry,
|
|
|
|
input wire [NUM_IRQ-1:0] irq,
|
|
|
|
input wire irq_software,
|
|
|
|
input wire irq_timer,
|
|
|
|
|
2021-05-21 09:34:16 +08:00
|
|
|
// Other CSR-specific signalling
|
2021-05-23 18:59:46 +08:00
|
|
|
input wire instr_ret
|
2021-05-21 09:34:16 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
// TODO block CSR access when entering trap?
|
|
|
|
|
2021-05-21 10:46:29 +08:00
|
|
|
`include "hazard3_ops.vh"
|
2021-05-21 09:34:16 +08:00
|
|
|
|
|
|
|
localparam X0 = {XLEN{1'b0}};
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// List of M-mode CSRs (we implement a configurable subset of M-mode).
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// The CSR block is the only piece of hardware which needs to know this mapping.
|
|
|
|
|
|
|
|
// Machine Information Registers (RO)
|
|
|
|
localparam MVENDORID = 12'hf11; // Vendor ID.
|
|
|
|
localparam MARCHID = 12'hf12; // Architecture ID.
|
|
|
|
localparam MIMPID = 12'hf13; // Implementation ID.
|
|
|
|
localparam MHARTID = 12'hf14; // Hardware thread ID.
|
|
|
|
|
|
|
|
// Machine Trap Setup (RW)
|
|
|
|
localparam MSTATUS = 12'h300; // Machine status register.
|
|
|
|
localparam MISA = 12'h301; // ISA and extensions
|
|
|
|
localparam MEDELEG = 12'h302; // Machine exception delegation register.
|
|
|
|
localparam MIDELEG = 12'h303; // Machine interrupt delegation register.
|
|
|
|
localparam MIE = 12'h304; // Machine interrupt-enable register.
|
|
|
|
localparam MTVEC = 12'h305; // Machine trap-handler base address.
|
|
|
|
localparam MCOUNTEREN = 12'h306; // Machine counter enable.
|
|
|
|
|
|
|
|
// Machine Trap Handling (RW)
|
|
|
|
localparam MSCRATCH = 12'h340; // Scratch register for machine trap handlers.
|
|
|
|
localparam MEPC = 12'h341; // Machine exception program counter.
|
|
|
|
localparam MCAUSE = 12'h342; // Machine trap cause.
|
|
|
|
localparam MTVAL = 12'h343; // Machine bad address or instruction.
|
|
|
|
localparam MIP = 12'h344; // Machine interrupt pending.
|
|
|
|
|
|
|
|
// Machine Memory Protection (RW)
|
|
|
|
localparam PMPCFG0 = 12'h3a0; // Physical memory protection configuration.
|
|
|
|
localparam PMPCFG1 = 12'h3a1; // Physical memory protection configuration, RV32 only.
|
|
|
|
localparam PMPCFG2 = 12'h3a2; // Physical memory protection configuration.
|
|
|
|
localparam PMPCFG3 = 12'h3a3; // Physical memory protection configuration, RV32 only.
|
|
|
|
localparam PMPADDR0 = 12'h3b0; // Physical memory protection address register.
|
|
|
|
localparam PMPADDR1 = 12'h3b1; // Physical memory protection address register.
|
|
|
|
|
|
|
|
// Performance counters (RW)
|
|
|
|
localparam MCYCLE = 12'hb00; // Raw cycles since start of day
|
|
|
|
localparam MINSTRET = 12'hb02; // Instruction retire count since start of day
|
|
|
|
localparam MHPMCOUNTER3 = 12'hb03; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER4 = 12'hb04; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER5 = 12'hb05; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER6 = 12'hb06; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER7 = 12'hb07; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER8 = 12'hb08; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER9 = 12'hb09; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER10 = 12'hb0a; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER11 = 12'hb0b; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER12 = 12'hb0c; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER13 = 12'hb0d; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER14 = 12'hb0e; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER15 = 12'hb0f; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER16 = 12'hb10; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER17 = 12'hb11; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER18 = 12'hb12; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER19 = 12'hb13; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER20 = 12'hb14; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER21 = 12'hb15; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER22 = 12'hb16; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER23 = 12'hb17; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER24 = 12'hb18; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER25 = 12'hb19; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER26 = 12'hb1a; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER27 = 12'hb1b; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER28 = 12'hb1c; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER29 = 12'hb1d; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER30 = 12'hb1e; // WARL (we tie to 0)
|
|
|
|
localparam MHPMCOUNTER31 = 12'hb1f; // WARL (we tie to 0)
|
|
|
|
|
|
|
|
localparam MCYCLEH = 12'hb80; // High halves of each counter
|
|
|
|
localparam MINSTRETH = 12'hb82;
|
|
|
|
localparam MHPMCOUNTER3H = 12'hb83;
|
|
|
|
localparam MHPMCOUNTER4H = 12'hb84;
|
|
|
|
localparam MHPMCOUNTER5H = 12'hb85;
|
|
|
|
localparam MHPMCOUNTER6H = 12'hb86;
|
|
|
|
localparam MHPMCOUNTER7H = 12'hb87;
|
|
|
|
localparam MHPMCOUNTER8H = 12'hb88;
|
|
|
|
localparam MHPMCOUNTER9H = 12'hb89;
|
|
|
|
localparam MHPMCOUNTER10H = 12'hb8a;
|
|
|
|
localparam MHPMCOUNTER11H = 12'hb8b;
|
|
|
|
localparam MHPMCOUNTER12H = 12'hb8c;
|
|
|
|
localparam MHPMCOUNTER13H = 12'hb8d;
|
|
|
|
localparam MHPMCOUNTER14H = 12'hb8e;
|
|
|
|
localparam MHPMCOUNTER15H = 12'hb8f;
|
|
|
|
localparam MHPMCOUNTER16H = 12'hb90;
|
|
|
|
localparam MHPMCOUNTER17H = 12'hb91;
|
|
|
|
localparam MHPMCOUNTER18H = 12'hb92;
|
|
|
|
localparam MHPMCOUNTER19H = 12'hb93;
|
|
|
|
localparam MHPMCOUNTER20H = 12'hb94;
|
|
|
|
localparam MHPMCOUNTER21H = 12'hb95;
|
|
|
|
localparam MHPMCOUNTER22H = 12'hb96;
|
|
|
|
localparam MHPMCOUNTER23H = 12'hb97;
|
|
|
|
localparam MHPMCOUNTER24H = 12'hb98;
|
|
|
|
localparam MHPMCOUNTER25H = 12'hb99;
|
|
|
|
localparam MHPMCOUNTER26H = 12'hb9a;
|
|
|
|
localparam MHPMCOUNTER27H = 12'hb9b;
|
|
|
|
localparam MHPMCOUNTER28H = 12'hb9c;
|
|
|
|
localparam MHPMCOUNTER29H = 12'hb9d;
|
|
|
|
localparam MHPMCOUNTER30H = 12'hb9e;
|
|
|
|
localparam MHPMCOUNTER31H = 12'hb9f;
|
|
|
|
|
2021-05-31 02:20:53 +08:00
|
|
|
localparam MCOUNTINHIBIT = 12'h302; // Count inhibit register for mcycle/minstret
|
2021-05-21 09:34:16 +08:00
|
|
|
localparam MHPMEVENT3 = 12'h323; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT4 = 12'h324; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT5 = 12'h325; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT6 = 12'h326; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT7 = 12'h327; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT8 = 12'h328; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT9 = 12'h329; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT10 = 12'h32a; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT11 = 12'h32b; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT12 = 12'h32c; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT13 = 12'h32d; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT14 = 12'h32e; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT15 = 12'h32f; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT16 = 12'h330; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT17 = 12'h331; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT18 = 12'h332; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT19 = 12'h333; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT20 = 12'h334; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT21 = 12'h335; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT22 = 12'h336; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT23 = 12'h337; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT24 = 12'h338; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT25 = 12'h339; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT26 = 12'h33a; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT27 = 12'h33b; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT28 = 12'h33c; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT29 = 12'h33d; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT30 = 12'h33e; // WARL (we tie to 0)
|
|
|
|
localparam MHPMEVENT31 = 12'h33f; // WARL (we tie to 0)
|
|
|
|
|
2021-06-01 00:54:12 +08:00
|
|
|
// Custom M-mode CSRs:
|
|
|
|
localparam MIDCR = 12'hbc0; // Implementation-defined control register (bag of bits)
|
|
|
|
localparam MEIE0 = 12'hbe0; // External interrupt enable register 0
|
|
|
|
localparam MEIP0 = 12'hfe0; // External interrupt pending register 0
|
|
|
|
localparam MLEI = 12'hfe4; // Lowest external interrupt number
|
|
|
|
|
2021-05-21 09:34:16 +08:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// CSR state + update logic
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Names are (reg)_(field)
|
|
|
|
|
|
|
|
// Generic update logic for write/set/clear of an entire CSR:
|
|
|
|
function [XLEN-1:0] update;
|
|
|
|
input [XLEN-1:0] prev;
|
|
|
|
begin
|
|
|
|
update =
|
|
|
|
wtype == CSR_WTYPE_C ? prev & ~wdata :
|
|
|
|
wtype == CSR_WTYPE_S ? prev | wdata :
|
|
|
|
wdata;
|
|
|
|
end
|
|
|
|
endfunction
|
|
|
|
|
2021-06-01 00:54:12 +08:00
|
|
|
function [XLEN-1:0] update_nonconst;
|
|
|
|
input [XLEN-1:0] prev;
|
|
|
|
input [XLEN-1:0] nonconst;
|
|
|
|
begin
|
|
|
|
update_nonconst = ((
|
|
|
|
wtype == CSR_WTYPE_C ? prev & ~wdata :
|
|
|
|
wtype == CSR_WTYPE_S ? prev | wdata :
|
|
|
|
wdata) & nonconst) | (prev & ~nonconst) ;
|
|
|
|
end
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Implementation-defined control register
|
|
|
|
|
|
|
|
localparam MIDCR_INIT = X0;
|
|
|
|
localparam MIDCR_WMASK = 32'h00000001;
|
|
|
|
|
|
|
|
reg [XLEN-1:0] midcr;
|
|
|
|
|
|
|
|
always @ (posedge clk or negedge rst_n) begin
|
|
|
|
if (!rst_n) begin
|
|
|
|
midcr <= MIDCR_INIT;
|
|
|
|
end else if (wen && addr == MIDCR) begin
|
|
|
|
midcr <= update_nonconst(midcr, MIDCR_WMASK);
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
// Modified external interrupt vectoring
|
|
|
|
wire midcr_eivect = midcr[0];
|
|
|
|
|
2021-05-21 09:34:16 +08:00
|
|
|
// ----------------------------------------------------------------------------
|
2021-06-01 00:54:12 +08:00
|
|
|
// Trap-handling CSRs
|
2021-05-21 09:34:16 +08:00
|
|
|
|
|
|
|
// Two-level interrupt enable stack, shuffled on entry/exit:
|
|
|
|
reg mstatus_mpie;
|
|
|
|
reg mstatus_mie;
|
|
|
|
|
|
|
|
always @ (posedge clk or negedge rst_n) begin
|
|
|
|
if (!rst_n) begin
|
|
|
|
mstatus_mpie <= 1'b0;
|
|
|
|
mstatus_mie <= 1'b0;
|
|
|
|
end else if (CSR_M_TRAP) begin
|
|
|
|
if (trap_enter_vld && trap_enter_rdy) begin
|
2021-05-23 18:59:46 +08:00
|
|
|
if (except == EXCEPT_MRET) begin
|
|
|
|
mstatus_mpie <= 1'b1;
|
|
|
|
mstatus_mie <= mstatus_mpie;
|
|
|
|
end else begin
|
|
|
|
mstatus_mpie <= mstatus_mie;
|
|
|
|
mstatus_mie <= 1'b0;
|
|
|
|
end
|
2021-05-21 09:34:16 +08:00
|
|
|
end else if (wen && addr == MSTATUS) begin
|
|
|
|
{mstatus_mpie, mstatus_mie} <=
|
|
|
|
wtype == CSR_WTYPE_C ? {mstatus_mpie, mstatus_mie} & ~{wdata[7], wdata[3]} :
|
|
|
|
wtype == CSR_WTYPE_S ? {mstatus_mpie, mstatus_mie} | {wdata[7], wdata[3]} :
|
|
|
|
{wdata[7], wdata[3]} ;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
reg [XLEN-1:0] mscratch;
|
|
|
|
|
|
|
|
always @ (posedge clk or negedge rst_n) begin
|
|
|
|
if (!rst_n) begin
|
|
|
|
mscratch <= X0;
|
|
|
|
end else if (CSR_M_TRAP) begin
|
|
|
|
if (wen && addr == MSCRATCH)
|
|
|
|
mscratch <= update(mscratch);
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
// Trap vector base
|
|
|
|
reg [XLEN-1:0] mtvec_reg;
|
2021-06-01 00:54:12 +08:00
|
|
|
wire [XLEN-1:0] mtvec = mtvec_reg & ({XLEN{1'b1}} << 2);
|
2021-05-31 02:52:46 +08:00
|
|
|
wire irq_vector_enable = mtvec_reg[0];
|
2021-05-21 09:34:16 +08:00
|
|
|
|
|
|
|
always @ (posedge clk or negedge rst_n) begin
|
|
|
|
if (!rst_n) begin
|
|
|
|
mtvec_reg <= MTVEC_INIT;
|
|
|
|
end else if (CSR_M_TRAP) begin
|
|
|
|
if (wen && addr == MTVEC)
|
2021-06-01 00:54:12 +08:00
|
|
|
mtvec_reg <= update_nonconst(mtvec_reg, MTVEC_WMASK);
|
2021-05-21 09:34:16 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
// Exception program counter
|
|
|
|
reg [XLEN-1:0] mepc;
|
|
|
|
// LSB is always 0
|
|
|
|
localparam MEPC_MASK = {{XLEN-1{1'b1}}, 1'b0};
|
|
|
|
|
|
|
|
always @ (posedge clk or negedge rst_n) begin
|
|
|
|
if (!rst_n) begin
|
|
|
|
mepc <= X0;
|
|
|
|
end else if (CSR_M_TRAP) begin
|
2021-05-23 18:59:46 +08:00
|
|
|
if (trap_enter_vld && trap_enter_rdy && except != EXCEPT_MRET) begin
|
2021-05-21 09:34:16 +08:00
|
|
|
mepc <= mepc_in & MEPC_MASK;
|
|
|
|
end else if (wen && addr == MEPC) begin
|
|
|
|
mepc <= update(mepc) & MEPC_MASK;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
// Interrupt enable (reserved bits are tied to 0)
|
|
|
|
reg [XLEN-1:0] mie;
|
2021-06-01 00:54:12 +08:00
|
|
|
localparam MIE_WMASK = 32'h00000888; // meie, mtip, msip
|
2021-05-21 09:34:16 +08:00
|
|
|
|
|
|
|
always @ (posedge clk or negedge rst_n) begin
|
|
|
|
if (!rst_n) begin
|
|
|
|
mie <= X0;
|
|
|
|
end else if (CSR_M_TRAP) begin
|
|
|
|
if (wen && addr == MIE)
|
2021-06-01 00:54:12 +08:00
|
|
|
mie <= update_nonconst(mie, MIE_WMASK);
|
2021-05-21 09:34:16 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-06-01 00:54:12 +08:00
|
|
|
wire mie_meie = mie[11];
|
2021-05-21 09:34:16 +08:00
|
|
|
|
|
|
|
// Interrupt status ("pending") register, handled later
|
|
|
|
wire [XLEN-1:0] mip;
|
|
|
|
// None of the bits we implement are directly writeable.
|
|
|
|
// MSIP is only writeable by a "platform-defined" mechanism, and we don't implement
|
|
|
|
// one!
|
|
|
|
|
|
|
|
// Trap cause registers. The non-constant bits can be written by software,
|
|
|
|
// and update automatically on trap entry. (bits 30:0 are WLRL, so we tie most off)
|
|
|
|
reg mcause_irq;
|
2021-06-01 00:54:12 +08:00
|
|
|
reg [5:0] mcause_code;
|
2021-05-21 09:34:16 +08:00
|
|
|
wire mcause_irq_next;
|
2021-06-01 00:54:12 +08:00
|
|
|
wire [5:0] mcause_code_next;
|
2021-05-21 09:34:16 +08:00
|
|
|
|
|
|
|
always @ (posedge clk or negedge rst_n) begin
|
|
|
|
if (!rst_n) begin
|
|
|
|
mcause_irq <= 1'b0;
|
2021-06-01 00:54:12 +08:00
|
|
|
mcause_code <= 6'h0;
|
2021-05-21 09:34:16 +08:00
|
|
|
end else if (CSR_M_TRAP) begin
|
2021-05-23 18:59:46 +08:00
|
|
|
if (trap_enter_vld && trap_enter_rdy && except != EXCEPT_MRET) begin
|
2021-05-21 09:34:16 +08:00
|
|
|
mcause_irq <= mcause_irq_next;
|
|
|
|
mcause_code <= mcause_code_next;
|
|
|
|
end else if (wen && addr == MCAUSE) begin
|
|
|
|
{mcause_irq, mcause_code} <=
|
2021-06-01 00:54:12 +08:00
|
|
|
wtype == CSR_WTYPE_C ? {mcause_irq, mcause_code} & ~{wdata[31], wdata[5:0]} :
|
|
|
|
wtype == CSR_WTYPE_S ? {mcause_irq, mcause_code} | {wdata[31], wdata[5:0]} :
|
|
|
|
{wdata[31], wdata[5:0]} ;
|
2021-05-21 09:34:16 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-06-01 00:54:12 +08:00
|
|
|
// Custom external interrupt enable register (would be at top of mie, but that
|
|
|
|
// only leaves room for 16 external interrupts)
|
|
|
|
|
|
|
|
localparam MEIE0_WMASK = ~({XLEN{1'b1}} << NUM_IRQ);
|
|
|
|
|
|
|
|
reg [XLEN-1:0] meie0;
|
|
|
|
|
|
|
|
always @ (posedge clk or negedge rst_n) begin
|
|
|
|
if (!rst_n) begin
|
|
|
|
// All-ones for implemented IRQs
|
2021-06-04 14:37:02 +08:00
|
|
|
meie0 <= X0;
|
2021-06-01 00:54:12 +08:00
|
|
|
end else if (wen && addr == MEIE0) begin
|
|
|
|
meie0 <= update_nonconst(meie0, MEIE0_WMASK);
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
// Assigned later:
|
|
|
|
wire [XLEN-1:0] meip0;
|
|
|
|
wire [4:0] mlei;
|
|
|
|
|
2021-05-21 09:34:16 +08:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Counters
|
2021-05-31 02:20:53 +08:00
|
|
|
|
|
|
|
reg mcountinhibit_cy;
|
|
|
|
reg mcountinhibit_ir;
|
|
|
|
|
2021-05-21 09:34:16 +08:00
|
|
|
reg [XLEN-1:0] mcycleh;
|
|
|
|
reg [XLEN-1:0] mcycle;
|
|
|
|
reg [XLEN-1:0] minstreth;
|
|
|
|
reg [XLEN-1:0] minstret;
|
|
|
|
|
|
|
|
wire [XLEN-1:0] ctr_update = update(
|
|
|
|
{addr[7], addr[1]} == 2'b00 ? mcycle :
|
|
|
|
{addr[7], addr[1]} == 2'b01 ? minstret :
|
|
|
|
{addr[7], addr[1]} == 2'b10 ? mcycleh :
|
|
|
|
minstreth
|
|
|
|
);
|
|
|
|
|
|
|
|
always @ (posedge clk or negedge rst_n) begin
|
|
|
|
if (!rst_n) begin
|
|
|
|
mcycleh <= X0;
|
|
|
|
mcycle <= X0;
|
|
|
|
minstreth <= X0;
|
|
|
|
minstret <= X0;
|
2021-05-31 02:20:53 +08:00
|
|
|
// Counters inhibited by default to save energy
|
|
|
|
mcountinhibit_cy <= 1'b0;
|
|
|
|
mcountinhibit_ir <= 1'b0;
|
2021-05-21 09:34:16 +08:00
|
|
|
end else if (CSR_COUNTER) begin
|
2021-05-31 02:20:53 +08:00
|
|
|
// Optionally hold the top (2 * XLEN - W_COUNTER) bits constant to
|
|
|
|
// save gates (noncompliant if enabled)
|
|
|
|
if (!mcountinhibit_cy)
|
|
|
|
{mcycleh, mcycle} <= (({mcycleh, mcycle} + 1'b1) & ~({2*XLEN{1'b1}} << W_COUNTER))
|
|
|
|
| ({mcycleh, mcycle} & ({2*XLEN{1'b1}} << W_COUNTER));
|
|
|
|
if (!mcountinhibit_ir && instr_ret)
|
2021-05-21 09:34:16 +08:00
|
|
|
{minstreth, minstret} <= (({minstreth, minstret} + 1'b1) & ~({2*XLEN{1'b1}} << W_COUNTER))
|
|
|
|
| ({minstreth, minstret} & ({2*XLEN{1'b1}} << W_COUNTER));
|
|
|
|
if (wen) begin
|
|
|
|
if (addr == MCYCLEH)
|
|
|
|
mcycleh <= ctr_update;
|
|
|
|
if (addr == MCYCLE)
|
|
|
|
mcycle <= ctr_update;
|
|
|
|
if (addr == MINSTRETH)
|
|
|
|
minstreth <= ctr_update;
|
|
|
|
if (addr == MINSTRET)
|
|
|
|
minstret <= ctr_update;
|
2021-05-31 02:20:53 +08:00
|
|
|
if (addr == MCOUNTINHIBIT) begin
|
|
|
|
{mcountinhibit_ir, mcountinhibit_cy} <=
|
|
|
|
wtype == CSR_WTYPE_C ? {mcountinhibit_ir, mcountinhibit_cy} & ~{wdata[2], wdata[0]} :
|
|
|
|
wtype == CSR_WTYPE_S ? {mcountinhibit_ir, mcountinhibit_cy} | {wdata[2], wdata[0]} :
|
|
|
|
{wdata[2], wdata[0]} ;
|
|
|
|
end
|
2021-05-21 09:34:16 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Read port + detect addressing of unmapped CSRs
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
reg decode_match;
|
|
|
|
|
|
|
|
always @ (*) begin
|
|
|
|
decode_match = 1'b0;
|
|
|
|
rdata = {XLEN{1'b0}};
|
|
|
|
case (addr)
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
// Mandatory CSRs
|
|
|
|
|
|
|
|
MISA: if (CSR_M_MANDATORY) begin
|
|
|
|
// WARL, so it is legal to be tied constant
|
|
|
|
decode_match = 1'b1;
|
|
|
|
rdata = {
|
|
|
|
2'h1, // MXL: 32-bit
|
2021-05-31 01:42:43 +08:00
|
|
|
{XLEN-28{1'b0}}, // WLRL
|
2021-05-21 09:34:16 +08:00
|
|
|
|
|
|
|
13'd0, // Z...N, no
|
|
|
|
|EXTENSION_M,
|
|
|
|
3'd0, // L...J, no
|
|
|
|
1'b1, // Integer ISA
|
|
|
|
5'd0, // H...D, no
|
|
|
|
|EXTENSION_C,
|
|
|
|
2'b0
|
|
|
|
};
|
|
|
|
end
|
|
|
|
MVENDORID: if (CSR_M_MANDATORY) begin
|
|
|
|
decode_match = !wen_soon; // MRO
|
2021-05-31 01:42:43 +08:00
|
|
|
rdata = MVENDORID_VAL;
|
2021-05-21 09:34:16 +08:00
|
|
|
end
|
|
|
|
MARCHID: if (CSR_M_MANDATORY) begin
|
|
|
|
decode_match = !wen_soon; // MRO
|
2021-05-31 01:42:43 +08:00
|
|
|
rdata = MARCHID_VAL;
|
2021-05-21 09:34:16 +08:00
|
|
|
end
|
|
|
|
MIMPID: if (CSR_M_MANDATORY) begin
|
|
|
|
decode_match = !wen_soon; // MRO
|
2021-05-31 01:42:43 +08:00
|
|
|
rdata = MIMPID_VAL;
|
2021-05-21 09:34:16 +08:00
|
|
|
end
|
|
|
|
MHARTID: if (CSR_M_MANDATORY) begin
|
|
|
|
decode_match = !wen_soon; // MRO
|
|
|
|
// There is only one hart, and spec says this must be numbered 0.
|
|
|
|
rdata = {XLEN{1'b0}};
|
|
|
|
end
|
|
|
|
|
|
|
|
MSTATUS: if (CSR_M_MANDATORY || CSR_M_TRAP) begin
|
|
|
|
decode_match = 1'b1;
|
|
|
|
rdata = {
|
|
|
|
1'b0, // Never any dirty state besides GPRs
|
|
|
|
8'd0, // (WPRI)
|
|
|
|
1'b0, // TSR (Trap SRET), tied 0 if no S mode.
|
|
|
|
1'b0, // TW (Timeout Wait), tied 0 if only M mode.
|
|
|
|
1'b0, // TVM (trap virtual memory), tied 0 if no S mode.
|
|
|
|
1'b0, // MXR (Make eXecutable Readable), tied 0 if not S mode.
|
|
|
|
1'b0, // SUM, tied 0, we have no S or U mode
|
|
|
|
1'b0, // MPRV (modify privilege), tied 0 if no U mode
|
|
|
|
4'd0, // XS, FS always "off" (no extension state to clear!)
|
|
|
|
2'b11, // MPP (M-mode previous privilege), we are always M-mode
|
|
|
|
2'd0, // (WPRI)
|
|
|
|
1'b0, // SPP, tied 0 if S mode not supported
|
|
|
|
mstatus_mpie,
|
|
|
|
3'd0, // No S, U
|
|
|
|
mstatus_mie,
|
|
|
|
3'd0 // No S, U
|
|
|
|
};
|
|
|
|
end
|
|
|
|
|
2021-05-31 01:42:43 +08:00
|
|
|
// MSTATUSH is not implemented (permitted when all fields would be tied to
|
|
|
|
// zero -- those fields being MBE and SBE, which are zero because we are
|
|
|
|
// pure little-endian.)
|
|
|
|
|
2021-05-21 09:34:16 +08:00
|
|
|
// MEDELEG, MIDELEG should not exist for M-only implementations. Will raise
|
|
|
|
// illegal instruction exception if accessed.
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
// Trap-handling CSRs
|
|
|
|
|
|
|
|
// TODO bit of a hack but this is a 32 bit synthesised register with
|
|
|
|
// set/clear/write/read, don't turn it on unless we really have to
|
|
|
|
MSCRATCH: if (CSR_M_TRAP && CSR_M_MANDATORY) begin
|
|
|
|
decode_match = 1'b1;
|
|
|
|
rdata = mscratch;
|
|
|
|
end
|
|
|
|
|
|
|
|
MEPC: if (CSR_M_TRAP) begin
|
|
|
|
decode_match = 1'b1;
|
|
|
|
rdata = mepc;
|
|
|
|
end
|
|
|
|
|
|
|
|
MCAUSE: if (CSR_M_TRAP) begin
|
|
|
|
decode_match = 1'b1;
|
|
|
|
rdata = {
|
|
|
|
mcause_irq, // Sign bit is 1 for IRQ, 0 for exception
|
|
|
|
{26{1'b0}}, // Padding
|
|
|
|
mcause_code[4:0] // Enough for 16 external IRQs, which is all we have room for in mip/mie
|
|
|
|
};
|
|
|
|
end
|
|
|
|
|
|
|
|
MTVAL: if (CSR_M_TRAP) begin
|
|
|
|
decode_match = 1'b1;
|
|
|
|
// Hardwired to 0
|
|
|
|
end
|
|
|
|
|
|
|
|
MIE: if (CSR_M_TRAP) begin
|
|
|
|
decode_match = 1'b1;
|
|
|
|
rdata = mie;
|
|
|
|
end
|
|
|
|
|
|
|
|
MIP: if (CSR_M_TRAP) begin
|
2021-06-01 00:54:12 +08:00
|
|
|
// Writes are permitted, but ignored.
|
2021-05-21 09:34:16 +08:00
|
|
|
decode_match = 1'b1;
|
|
|
|
rdata = mip;
|
|
|
|
end
|
|
|
|
|
|
|
|
MTVEC: if (CSR_M_TRAP) begin
|
|
|
|
decode_match = 1'b1;
|
|
|
|
rdata = {
|
|
|
|
mtvec[XLEN-1:2], // BASE
|
2021-05-31 02:52:46 +08:00
|
|
|
1'b0, // Reserved mode bit gets WARL'd to 0
|
|
|
|
irq_vector_enable // MODE is vectored (2'h1) or direct (2'h0)
|
2021-05-21 09:34:16 +08:00
|
|
|
};
|
|
|
|
end
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
// Counter CSRs
|
|
|
|
|
|
|
|
// Get the tied WARLs out the way first
|
2021-05-31 02:20:53 +08:00
|
|
|
MHPMCOUNTER3: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER4: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER5: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER6: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER7: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER8: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER9: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER10: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER11: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER12: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER13: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER14: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER15: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER16: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER17: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER18: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER19: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER20: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER21: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER22: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER23: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER24: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER25: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER26: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER27: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER28: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER29: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER30: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER31: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
|
|
|
|
MHPMCOUNTER3H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER4H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER5H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER6H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER7H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER8H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER9H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER10H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER11H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER12H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER13H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER14H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER15H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER16H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER17H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER18H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER19H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER20H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER21H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER22H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER23H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER24H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER25H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER26H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER27H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER28H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER29H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER30H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMCOUNTER31H: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
|
|
|
|
MHPMEVENT3: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT4: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT5: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT6: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT7: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT8: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT9: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT10: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT11: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT12: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT13: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT14: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT15: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT16: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT17: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT18: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT19: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT20: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT21: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT22: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT23: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT24: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT25: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT26: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT27: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT28: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT29: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT30: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
MHPMEVENT31: if (CSR_COUNTER) begin decode_match = 1'b1; end
|
|
|
|
|
|
|
|
MCOUNTINHIBIT: if (CSR_COUNTER) begin
|
|
|
|
decode_match = 1'b1;
|
|
|
|
rdata = {
|
|
|
|
29'd0,
|
|
|
|
mcountinhibit_ir,
|
|
|
|
1'b0,
|
|
|
|
mcountinhibit_cy
|
|
|
|
};
|
|
|
|
end
|
2021-05-21 09:34:16 +08:00
|
|
|
|
|
|
|
MCYCLE: if (CSR_COUNTER) begin
|
|
|
|
decode_match = 1'b1;
|
|
|
|
rdata = mcycle;
|
|
|
|
end
|
|
|
|
MINSTRET: if (CSR_COUNTER) begin
|
|
|
|
decode_match = 1'b1;
|
|
|
|
rdata = minstret;
|
|
|
|
end
|
|
|
|
|
|
|
|
MCYCLEH: if (CSR_COUNTER) begin
|
|
|
|
decode_match = 1'b1;
|
|
|
|
rdata = mcycleh;
|
|
|
|
end
|
|
|
|
MINSTRETH: if (CSR_COUNTER) begin
|
|
|
|
decode_match = 1'b1;
|
|
|
|
rdata = minstreth;
|
|
|
|
end
|
|
|
|
|
2021-06-01 00:54:12 +08:00
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
// Custom CSRs
|
|
|
|
|
|
|
|
MIDCR: if (CSR_M_TRAP) begin
|
|
|
|
decode_match = 1'b1;
|
|
|
|
rdata = midcr;
|
|
|
|
end
|
|
|
|
|
|
|
|
MEIE0: if (CSR_M_TRAP) begin
|
|
|
|
decode_match = 1'b1;
|
|
|
|
rdata = meie0;
|
|
|
|
end
|
|
|
|
|
|
|
|
MEIP0: if (CSR_M_TRAP) begin
|
|
|
|
decode_match = !wen_soon;
|
|
|
|
rdata = meip0;
|
|
|
|
end
|
|
|
|
|
|
|
|
MLEI: if (CSR_M_TRAP) begin
|
|
|
|
decode_match = !wen_soon;
|
|
|
|
rdata = {{XLEN-5{1'b0}}, mlei};
|
|
|
|
end
|
|
|
|
|
2021-05-21 09:34:16 +08:00
|
|
|
default: begin end
|
|
|
|
endcase
|
|
|
|
end
|
|
|
|
|
2021-05-23 18:59:46 +08:00
|
|
|
assign illegal = (wen_soon || ren_soon) && !decode_match;
|
2021-05-21 09:34:16 +08:00
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Trap request generation
|
|
|
|
|
2021-06-01 00:54:12 +08:00
|
|
|
reg [NUM_IRQ-1:0] irq_r;
|
|
|
|
reg irq_software_r;
|
|
|
|
reg irq_timer_r;
|
2021-05-21 09:34:16 +08:00
|
|
|
|
2021-06-01 00:54:12 +08:00
|
|
|
always @ (posedge clk or negedge rst_n) begin
|
|
|
|
if (!rst_n) begin
|
|
|
|
irq_r <= {NUM_IRQ{1'b0}};
|
|
|
|
irq_software_r <= 1'b0;
|
|
|
|
irq_timer_r <= 1'b0;
|
|
|
|
end else begin
|
2021-05-21 09:34:16 +08:00
|
|
|
irq_r <= irq;
|
2021-06-01 00:54:12 +08:00
|
|
|
irq_software_r <= irq_software;
|
|
|
|
irq_timer_r <= irq_timer;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
assign meip0 = {{XLEN-NUM_IRQ{1'b0}}, irq_r};
|
|
|
|
wire external_irq_pending = |(meie0 & meip0);
|
2021-05-21 09:34:16 +08:00
|
|
|
|
|
|
|
assign mip = {
|
2021-06-01 00:54:12 +08:00
|
|
|
20'h0, // Reserved
|
|
|
|
external_irq_pending, // meip, Global pending bit for external IRQs
|
|
|
|
3'h0, // Reserved
|
|
|
|
irq_timer_r, // mtip, interrupt from memory-mapped timer peripheral
|
|
|
|
3'h0, // Reserved
|
|
|
|
irq_software_r, // msip, software interrupt from memory-mapped register
|
|
|
|
3'h0 // Reserved
|
2021-05-21 09:34:16 +08:00
|
|
|
};
|
|
|
|
|
2021-06-01 00:54:12 +08:00
|
|
|
// When eivect = 1, mip.meip is masked from the standard IRQs, so that the
|
|
|
|
// platform-specific causes and vectors are used instead.
|
|
|
|
wire [31:0] mip_no_global = mip & ~(32'h800 & ~{XLEN{midcr_eivect}});
|
|
|
|
wire standard_irq_active = |(mip_no_global & mie) && mstatus_mie;
|
|
|
|
wire external_irq_active = external_irq_pending && mstatus_mie && mie_meie;
|
|
|
|
|
|
|
|
wire [4:0] external_irq_num;
|
|
|
|
wire [3:0] standard_irq_num;
|
|
|
|
assign mlei = external_irq_num;
|
2021-05-21 09:34:16 +08:00
|
|
|
|
2021-05-21 10:46:29 +08:00
|
|
|
hazard3_priority_encode #(
|
2021-06-01 00:54:12 +08:00
|
|
|
.W_REQ (32)
|
|
|
|
) mlei_priority_encode (
|
|
|
|
.req (meie0 & meip0),
|
|
|
|
.gnt (external_irq_num)
|
|
|
|
);
|
|
|
|
|
|
|
|
hazard3_priority_encode #(
|
|
|
|
.W_REQ (16)
|
2021-05-21 09:34:16 +08:00
|
|
|
) irq_priority (
|
2021-06-01 00:54:12 +08:00
|
|
|
.req (mip_no_global[15:0] & mie[15:0]),
|
|
|
|
.gnt (standard_irq_num)
|
2021-05-21 09:34:16 +08:00
|
|
|
);
|
|
|
|
|
2021-06-01 00:54:12 +08:00
|
|
|
wire exception_req_any = except != EXCEPT_NONE;
|
|
|
|
|
|
|
|
wire [5:0] vector_sel =
|
2021-06-04 03:03:43 +08:00
|
|
|
exception_req_any || !irq_vector_enable ? 6'd0 :
|
|
|
|
standard_irq_active ? {2'h0, standard_irq_num} :
|
|
|
|
external_irq_active ? {1'h0, external_irq_num} + 6'd16 : 6'd0;
|
2021-05-21 09:34:16 +08:00
|
|
|
|
2021-06-01 00:54:12 +08:00
|
|
|
assign trap_addr = except == EXCEPT_MRET ? mepc : mtvec | {24'h0, vector_sel, 2'h0};
|
2021-05-30 01:00:43 +08:00
|
|
|
assign trap_is_irq = !exception_req_any;
|
2021-06-01 00:54:12 +08:00
|
|
|
assign trap_enter_vld = CSR_M_TRAP && (exception_req_any ||
|
|
|
|
!delay_irq_entry && (standard_irq_active || external_irq_active));
|
2021-05-21 09:34:16 +08:00
|
|
|
|
|
|
|
assign mcause_irq_next = !exception_req_any;
|
2021-06-01 00:54:12 +08:00
|
|
|
assign mcause_code_next = exception_req_any ? {2'h0, except} : vector_sel;
|
2021-05-21 09:34:16 +08:00
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
`ifdef RISCV_FORMAL
|
2021-05-23 18:59:46 +08:00
|
|
|
|
|
|
|
// Keep track of whether we are in a trap (only for formal property purposes)
|
|
|
|
reg in_trap;
|
|
|
|
|
|
|
|
always @ (posedge clk or negedge rst_n)
|
|
|
|
if (!rst_n)
|
|
|
|
in_trap <= 1'b0;
|
|
|
|
else
|
|
|
|
in_trap <= (in_trap || (trap_enter_vld && trap_enter_rdy))
|
|
|
|
&& !(trap_enter_vld && trap_enter_rdy && except == EXCEPT_MRET);
|
|
|
|
|
2021-05-21 09:34:16 +08:00
|
|
|
always @ (posedge clk) begin
|
2021-05-31 02:52:46 +08:00
|
|
|
// Assume there are no nested exceptions, to stop riscv-formal from doing
|
2021-05-23 18:59:46 +08:00
|
|
|
// annoying things like stopping instructions from retiring by repeatedly
|
|
|
|
// feeding in invalid instructions
|
|
|
|
|
2021-05-21 09:34:16 +08:00
|
|
|
if (in_trap)
|
2021-05-23 18:59:46 +08:00
|
|
|
assume(except == EXCEPT_NONE);
|
2021-05-21 09:34:16 +08:00
|
|
|
|
2021-05-30 01:57:43 +08:00
|
|
|
// Assume IRQs are not deasserted on cycles where exception entry does not
|
|
|
|
// take place
|
|
|
|
|
|
|
|
if (!trap_enter_rdy)
|
|
|
|
assume(~|(irq_r & ~irq));
|
|
|
|
|
2021-06-01 00:54:12 +08:00
|
|
|
// Make sure CSR accesses are flushed
|
|
|
|
if (trap_enter_vld && trap_enter_rdy)
|
|
|
|
assert(!(wen || ren));
|
2021-05-21 09:34:16 +08:00
|
|
|
// Something is screwed up if this happens
|
|
|
|
if ($past(trap_enter_vld && trap_enter_rdy))
|
|
|
|
assert(!wen);
|
|
|
|
// Should be impossible to get into the trap and exit it so quickly:
|
|
|
|
if (in_trap && !$past(in_trap))
|
2021-05-23 18:59:46 +08:00
|
|
|
assert(except != EXCEPT_MRET);
|
2021-05-21 09:34:16 +08:00
|
|
|
// Should be impossible to get to another mret so soon after exiting:
|
2021-05-23 18:59:46 +08:00
|
|
|
assert(!(except == EXCEPT_MRET && $past(except == EXCEPT_MRET)));
|
2021-05-30 01:57:43 +08:00
|
|
|
|
2021-05-21 09:34:16 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
`endif
|
|
|
|
|
|
|
|
endmodule
|