Implement new IRQ behaviour, and change mip.meip to be masked by individual enables in meip0
This commit is contained in:
parent
4053458485
commit
5f8d217395
|
@ -1 +0,0 @@
|
||||||
*.pdf
|
|
File diff suppressed because it is too large
Load Diff
|
@ -72,9 +72,9 @@ External IRQ pending register 0. Contains a read-only bit for each external inte
|
||||||
|
|
||||||
Addresses `0xfe1` through `0xfe3` are reserved for further `meip` registers, supporting up to 128 external interrupts.
|
Addresses `0xfe1` through `0xfe3` are reserved for further `meip` registers, supporting up to 128 external interrupts.
|
||||||
|
|
||||||
When any bit is set in `meip0`, the standard external interrupt pending bit `mip.meip` is also set. An external interrupt is taken when all of the following are true:
|
When any bit is set in both `meip0` and `meie0`, the standard external interrupt pending bit `mip.meip` is also set. In other words, `meip0` is filtered by `meie0` to generate the standard `mip.meip` flag. So, an external interrupt is taken when _all_ of the following are true:
|
||||||
|
|
||||||
* The interrupt is currently asserted in `meip0`
|
* An interrupt is currently asserted in `meip0`
|
||||||
* The matching interrupt enable bit is set in `meie0`
|
* The matching interrupt enable bit is set in `meie0`
|
||||||
* The standard M-mode interrupt enable `mstatus.mie` is set
|
* The standard M-mode interrupt enable `mstatus.mie` is set
|
||||||
* The standard M-mode global external interrupt enable `mie.meie` is set
|
* The standard M-mode global external interrupt enable `mie.meie` is set
|
||||||
|
@ -84,7 +84,7 @@ In this case, the processor jumps to either:
|
||||||
* `mtvec` directly, if vectoring is disabled (`mtvec[0]` is 0)
|
* `mtvec` directly, if vectoring is disabled (`mtvec[0]` is 0)
|
||||||
* `mtvec + 0x2c`, if vectoring is enabled (`mtvec[0]` is 1) and modified external IRQ vectoring is disabled (`midcr.eivect` is 0)
|
* `mtvec + 0x2c`, if vectoring is enabled (`mtvec[0]` is 1) and modified external IRQ vectoring is disabled (`midcr.eivect` is 0)
|
||||||
* `mtvect + (mlei + 16) * 4`, if vectoring is enabled (`mtvec[0]` is 1) and modified external IRQ vectoring is enabled (`midcr.eivect` is 1). `
|
* `mtvect + (mlei + 16) * 4`, if vectoring is enabled (`mtvec[0]` is 1) and modified external IRQ vectoring is enabled (`midcr.eivect` is 1). `
|
||||||
** `mlei` is a read-only CSR containing the lowest-numbered
|
** `mlei` is a read-only CSR containing the lowest-numbered pending-and-enabled external interrupt.
|
||||||
|
|
||||||
==== mlei
|
==== mlei
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
// your top-level instantiation, it's up to you. These parameters are all
|
// your top-level instantiation, it's up to you. These parameters are all
|
||||||
// plumbed through Hazard3's internal hierarchy to the appropriate places.
|
// plumbed through Hazard3's internal hierarchy to the appropriate places.
|
||||||
|
|
||||||
|
// If you add a parameter here, you should add a matching line to
|
||||||
|
// hazard3_config_inst.vh to propagate the parameter through module
|
||||||
|
// instantiations.
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Reset state configuration
|
// Reset state configuration
|
||||||
|
|
||||||
|
@ -41,7 +45,11 @@ parameter CSR_M_MANDATORY = 1,
|
||||||
parameter CSR_M_TRAP = 1,
|
parameter CSR_M_TRAP = 1,
|
||||||
|
|
||||||
// CSR_COUNTER: Include performance counters and relevant M-mode CSRs
|
// CSR_COUNTER: Include performance counters and relevant M-mode CSRs
|
||||||
parameter CSR_COUNTER = 0,
|
parameter CSR_COUNTER = 1,
|
||||||
|
|
||||||
|
// NUM_IRQ: Number of external IRQs implemented in meie0 and meip0.
|
||||||
|
// Minimum 1 (if CSR_M_TRAP = 1), maximum 32.
|
||||||
|
parameter NUM_IRQ = 32,
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// ID registers
|
// ID registers
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
.CSR_M_MANDATORY (CSR_M_MANDATORY),
|
.CSR_M_MANDATORY (CSR_M_MANDATORY),
|
||||||
.CSR_M_TRAP (CSR_M_TRAP),
|
.CSR_M_TRAP (CSR_M_TRAP),
|
||||||
.CSR_COUNTER (CSR_COUNTER),
|
.CSR_COUNTER (CSR_COUNTER),
|
||||||
|
.NUM_IRQ (NUM_IRQ),
|
||||||
|
.MVENDORID_VAL (MVENDORID_VAL),
|
||||||
|
.MARCHID_VAL (MARCHID_VAL),
|
||||||
|
.MIMPID_VAL (MIMPID_VAL),
|
||||||
.REDUCED_BYPASS (REDUCED_BYPASS),
|
.REDUCED_BYPASS (REDUCED_BYPASS),
|
||||||
.MULDIV_UNROLL (MULDIV_UNROLL),
|
.MULDIV_UNROLL (MULDIV_UNROLL),
|
||||||
.MUL_FAST (MUL_FAST),
|
.MUL_FAST (MUL_FAST),
|
||||||
|
|
|
@ -53,8 +53,10 @@ module hazard3_core #(
|
||||||
output reg [W_DATA-1:0] bus_wdata_d,
|
output reg [W_DATA-1:0] bus_wdata_d,
|
||||||
input wire [W_DATA-1:0] bus_rdata_d,
|
input wire [W_DATA-1:0] bus_rdata_d,
|
||||||
|
|
||||||
// External level-sensitive interrupt sources (tie 0 if unused)
|
// Level-sensitive interrupt sources
|
||||||
input wire [15:0] irq
|
input wire [NUM_IRQ-1:0] irq, // -> mip.meip
|
||||||
|
input wire soft_irq, // -> mip.msip
|
||||||
|
input wire timer_irq // -> mip.mtip
|
||||||
);
|
);
|
||||||
|
|
||||||
`include "hazard3_ops.vh"
|
`include "hazard3_ops.vh"
|
||||||
|
@ -493,6 +495,8 @@ hazard3_csr #(
|
||||||
// IRQ and exception requests
|
// IRQ and exception requests
|
||||||
.delay_irq_entry (xm_delay_irq_entry),
|
.delay_irq_entry (xm_delay_irq_entry),
|
||||||
.irq (irq),
|
.irq (irq),
|
||||||
|
.irq_software (soft_irq),
|
||||||
|
.irq_timer (timer_irq),
|
||||||
.except (xm_except),
|
.except (xm_except),
|
||||||
|
|
||||||
// Other CSR-specific signalling
|
// Other CSR-specific signalling
|
||||||
|
|
|
@ -43,8 +43,10 @@ module hazard3_cpu_1port #(
|
||||||
output wire [W_DATA-1:0] ahblm_hwdata,
|
output wire [W_DATA-1:0] ahblm_hwdata,
|
||||||
input wire [W_DATA-1:0] ahblm_hrdata,
|
input wire [W_DATA-1:0] ahblm_hrdata,
|
||||||
|
|
||||||
// External level-sensitive interrupt sources (tie 0 if unused)
|
// Level-sensitive interrupt sources
|
||||||
input wire [15:0] irq
|
input wire [NUM_IRQ-1:0] irq, // -> mip.meip
|
||||||
|
input wire irq_software, // -> mip.msip
|
||||||
|
input wire irq_timer // -> mip.mtip
|
||||||
);
|
);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -104,7 +106,9 @@ hazard3_core #(
|
||||||
.bus_wdata_d (core_wdata_d),
|
.bus_wdata_d (core_wdata_d),
|
||||||
.bus_rdata_d (core_rdata_d),
|
.bus_rdata_d (core_rdata_d),
|
||||||
|
|
||||||
.irq (irq)
|
.irq (irq),
|
||||||
|
.soft_irq (soft_irq),
|
||||||
|
.timer_irq (timer_irq)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -56,8 +56,10 @@ module hazard3_cpu_2port #(
|
||||||
output wire [W_DATA-1:0] d_hwdata,
|
output wire [W_DATA-1:0] d_hwdata,
|
||||||
input wire [W_DATA-1:0] d_hrdata,
|
input wire [W_DATA-1:0] d_hrdata,
|
||||||
|
|
||||||
// External level-sensitive interrupt sources (tie 0 if unused)
|
// Level-sensitive interrupt sources
|
||||||
input wire [15:0] irq
|
input wire [NUM_IRQ-1:0] irq, // -> mip.meip
|
||||||
|
input wire soft_irq, // -> mip.msip
|
||||||
|
input wire timer_irq // -> mip.mtip
|
||||||
);
|
);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -117,7 +119,9 @@ hazard3_core #(
|
||||||
.bus_wdata_d (core_wdata_d),
|
.bus_wdata_d (core_wdata_d),
|
||||||
.bus_rdata_d (core_rdata_d),
|
.bus_rdata_d (core_rdata_d),
|
||||||
|
|
||||||
.irq (irq)
|
.irq (irq),
|
||||||
|
.soft_irq (soft_irq),
|
||||||
|
.timer_irq (timer_irq)
|
||||||
);
|
);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
|
@ -70,10 +70,14 @@ module hazard3_csr #(
|
||||||
input wire [XLEN-1:0] mepc_in,
|
input wire [XLEN-1:0] mepc_in,
|
||||||
|
|
||||||
// Exceptions must *not* be a function of bus stall.
|
// Exceptions must *not* be a function of bus stall.
|
||||||
input wire delay_irq_entry,
|
|
||||||
input wire [15:0] irq,
|
|
||||||
input wire [W_EXCEPT-1:0] except,
|
input wire [W_EXCEPT-1:0] except,
|
||||||
|
|
||||||
|
// Level-sensitive interrupt sources
|
||||||
|
input wire delay_irq_entry,
|
||||||
|
input wire [NUM_IRQ-1:0] irq,
|
||||||
|
input wire irq_software,
|
||||||
|
input wire irq_timer,
|
||||||
|
|
||||||
// Other CSR-specific signalling
|
// Other CSR-specific signalling
|
||||||
input wire instr_ret
|
input wire instr_ret
|
||||||
);
|
);
|
||||||
|
@ -215,6 +219,12 @@ localparam MHPMEVENT29 = 12'h33d; // WARL (we tie to 0)
|
||||||
localparam MHPMEVENT30 = 12'h33e; // WARL (we tie to 0)
|
localparam MHPMEVENT30 = 12'h33e; // WARL (we tie to 0)
|
||||||
localparam MHPMEVENT31 = 12'h33f; // WARL (we tie to 0)
|
localparam MHPMEVENT31 = 12'h33f; // WARL (we tie to 0)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// CSR state + update logic
|
// CSR state + update logic
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -231,8 +241,38 @@ begin
|
||||||
end
|
end
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Trap-handling
|
// 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];
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Trap-handling CSRs
|
||||||
|
|
||||||
// Two-level interrupt enable stack, shuffled on entry/exit:
|
// Two-level interrupt enable stack, shuffled on entry/exit:
|
||||||
reg mstatus_mpie;
|
reg mstatus_mpie;
|
||||||
|
@ -273,7 +313,7 @@ end
|
||||||
|
|
||||||
// Trap vector base
|
// Trap vector base
|
||||||
reg [XLEN-1:0] mtvec_reg;
|
reg [XLEN-1:0] mtvec_reg;
|
||||||
wire [XLEN-1:0] mtvec = ((mtvec_reg & MTVEC_WMASK) | (MTVEC_INIT & ~MTVEC_WMASK)) & ({XLEN{1'b1}} << 2);
|
wire [XLEN-1:0] mtvec = mtvec_reg & ({XLEN{1'b1}} << 2);
|
||||||
wire irq_vector_enable = mtvec_reg[0];
|
wire irq_vector_enable = mtvec_reg[0];
|
||||||
|
|
||||||
always @ (posedge clk or negedge rst_n) begin
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
|
@ -281,7 +321,7 @@ always @ (posedge clk or negedge rst_n) begin
|
||||||
mtvec_reg <= MTVEC_INIT;
|
mtvec_reg <= MTVEC_INIT;
|
||||||
end else if (CSR_M_TRAP) begin
|
end else if (CSR_M_TRAP) begin
|
||||||
if (wen && addr == MTVEC)
|
if (wen && addr == MTVEC)
|
||||||
mtvec_reg <= update(mtvec_reg);
|
mtvec_reg <= update_nonconst(mtvec_reg, MTVEC_WMASK);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -304,21 +344,18 @@ end
|
||||||
|
|
||||||
// Interrupt enable (reserved bits are tied to 0)
|
// Interrupt enable (reserved bits are tied to 0)
|
||||||
reg [XLEN-1:0] mie;
|
reg [XLEN-1:0] mie;
|
||||||
localparam MIE_CONST_MASK = 32'h0000f777;
|
localparam MIE_WMASK = 32'h00000888; // meie, mtip, msip
|
||||||
|
|
||||||
always @ (posedge clk or negedge rst_n) begin
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
if (!rst_n) begin
|
if (!rst_n) begin
|
||||||
mie <= X0;
|
mie <= X0;
|
||||||
end else if (CSR_M_TRAP) begin
|
end else if (CSR_M_TRAP) begin
|
||||||
if (wen && addr == MIE)
|
if (wen && addr == MIE)
|
||||||
mie <= update(mie) & ~MIE_CONST_MASK;
|
mie <= update_nonconst(mie, MIE_WMASK);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
wire [15:0] mie_irq = mie[31:16]; // Per-IRQ mask. Nonstandard, but legal.
|
wire mie_meie = mie[11];
|
||||||
wire mie_meie = mie[11]; // Global external IRQ enable. This is ANDed over our per-IRQ mask
|
|
||||||
wire mie_mtie = mie[7]; // Timer interrupt enable
|
|
||||||
wire mie_msie = mie[3]; // Software interrupt enable
|
|
||||||
|
|
||||||
// Interrupt status ("pending") register, handled later
|
// Interrupt status ("pending") register, handled later
|
||||||
wire [XLEN-1:0] mip;
|
wire [XLEN-1:0] mip;
|
||||||
|
@ -329,27 +366,47 @@ wire [XLEN-1:0] mip;
|
||||||
// Trap cause registers. The non-constant bits can be written by software,
|
// 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)
|
// and update automatically on trap entry. (bits 30:0 are WLRL, so we tie most off)
|
||||||
reg mcause_irq;
|
reg mcause_irq;
|
||||||
reg [4:0] mcause_code;
|
reg [5:0] mcause_code;
|
||||||
wire mcause_irq_next;
|
wire mcause_irq_next;
|
||||||
wire [4:0] mcause_code_next;
|
wire [5:0] mcause_code_next;
|
||||||
|
|
||||||
always @ (posedge clk or negedge rst_n) begin
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
if (!rst_n) begin
|
if (!rst_n) begin
|
||||||
mcause_irq <= 1'b0;
|
mcause_irq <= 1'b0;
|
||||||
mcause_code <= 5'h0;
|
mcause_code <= 6'h0;
|
||||||
end else if (CSR_M_TRAP) begin
|
end else if (CSR_M_TRAP) begin
|
||||||
if (trap_enter_vld && trap_enter_rdy && except != EXCEPT_MRET) begin
|
if (trap_enter_vld && trap_enter_rdy && except != EXCEPT_MRET) begin
|
||||||
mcause_irq <= mcause_irq_next;
|
mcause_irq <= mcause_irq_next;
|
||||||
mcause_code <= mcause_code_next;
|
mcause_code <= mcause_code_next;
|
||||||
end else if (wen && addr == MCAUSE) begin
|
end else if (wen && addr == MCAUSE) begin
|
||||||
{mcause_irq, mcause_code} <=
|
{mcause_irq, mcause_code} <=
|
||||||
wtype == CSR_WTYPE_C ? {mcause_irq, mcause_code} & ~{wdata[31], wdata[4:0]} :
|
wtype == CSR_WTYPE_C ? {mcause_irq, mcause_code} & ~{wdata[31], wdata[5:0]} :
|
||||||
wtype == CSR_WTYPE_S ? {mcause_irq, mcause_code} | {wdata[31], wdata[4:0]} :
|
wtype == CSR_WTYPE_S ? {mcause_irq, mcause_code} | {wdata[31], wdata[5:0]} :
|
||||||
{wdata[31], wdata[4:0]} ;
|
{wdata[31], wdata[5:0]} ;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
// 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
|
||||||
|
meie0 <= MEIE0_WMASK;
|
||||||
|
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;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Counters
|
// Counters
|
||||||
|
|
||||||
|
@ -517,6 +574,7 @@ always @ (*) begin
|
||||||
end
|
end
|
||||||
|
|
||||||
MIP: if (CSR_M_TRAP) begin
|
MIP: if (CSR_M_TRAP) begin
|
||||||
|
// Writes are permitted, but ignored.
|
||||||
decode_match = 1'b1;
|
decode_match = 1'b1;
|
||||||
rdata = mip;
|
rdata = mip;
|
||||||
end
|
end
|
||||||
|
@ -652,6 +710,29 @@ always @ (*) begin
|
||||||
rdata = minstreth;
|
rdata = minstreth;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// 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
|
||||||
|
|
||||||
default: begin end
|
default: begin end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
@ -660,53 +741,74 @@ assign illegal = (wen_soon || ren_soon) && !decode_match;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Trap request generation
|
// Trap request generation
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
wire exception_req_any = except != EXCEPT_NONE;
|
reg [NUM_IRQ-1:0] irq_r;
|
||||||
|
reg irq_software_r;
|
||||||
|
reg irq_timer_r;
|
||||||
|
|
||||||
// Interrupt masking and selection
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
|
if (!rst_n) begin
|
||||||
reg [15:0] irq_r;
|
irq_r <= {NUM_IRQ{1'b0}};
|
||||||
|
irq_software_r <= 1'b0;
|
||||||
always @ (posedge clk or negedge rst_n)
|
irq_timer_r <= 1'b0;
|
||||||
if (!rst_n)
|
end else begin
|
||||||
irq_r <= 16'h0;
|
|
||||||
else
|
|
||||||
irq_r <= irq;
|
irq_r <= irq;
|
||||||
|
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);
|
||||||
|
|
||||||
assign mip = {
|
assign mip = {
|
||||||
irq_r, // Our nonstandard bits for per-IRQ status
|
20'h0, // Reserved
|
||||||
4'h0, // Reserved
|
external_irq_pending, // meip, Global pending bit for external IRQs
|
||||||
|irq_r, // Global pending bit for external IRQs
|
|
||||||
3'h0, // Reserved
|
3'h0, // Reserved
|
||||||
1'b0, // Timer (FIXME)
|
irq_timer_r, // mtip, interrupt from memory-mapped timer peripheral
|
||||||
3'h0, // Reserved
|
3'h0, // Reserved
|
||||||
1'b0, // Software interrupt (FIXME)
|
irq_software_r, // msip, software interrupt from memory-mapped register
|
||||||
3'h0 // Reserved
|
3'h0 // Reserved
|
||||||
};
|
};
|
||||||
|
|
||||||
// We don't actually trap the aggregate IRQ, just provide it for software info
|
// When eivect = 1, mip.meip is masked from the standard IRQs, so that the
|
||||||
wire [31:0] mip_no_global = mip & 32'hffff_f7ff;
|
// platform-specific causes and vectors are used instead.
|
||||||
wire irq_any = |(mip_no_global & {{16{mie_meie}}, {16{1'b1}}}) && mstatus_mie && !delay_irq_entry;
|
wire [31:0] mip_no_global = mip & ~(32'h800 & ~{XLEN{midcr_eivect}});
|
||||||
wire [4:0] irq_num;
|
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;
|
||||||
|
|
||||||
hazard3_priority_encode #(
|
hazard3_priority_encode #(
|
||||||
.W_REQ(32)
|
.W_REQ (32)
|
||||||
) irq_priority (
|
) mlei_priority_encode (
|
||||||
.req (mip_no_global),
|
.req (meie0 & meip0),
|
||||||
.gnt (irq_num)
|
.gnt (external_irq_num)
|
||||||
);
|
);
|
||||||
|
|
||||||
wire [11:0] mtvec_offs = (
|
hazard3_priority_encode #(
|
||||||
exception_req_any || !irq_vector_enable ? 12'h0 : {7'h0, irq_num}
|
.W_REQ (16)
|
||||||
) << 2;
|
) irq_priority (
|
||||||
|
.req (mip_no_global[15:0] & mie[15:0]),
|
||||||
|
.gnt (standard_irq_num)
|
||||||
|
);
|
||||||
|
|
||||||
assign trap_addr = except == EXCEPT_MRET ? mepc : mtvec | {20'h0, mtvec_offs};
|
wire exception_req_any = except != EXCEPT_NONE;
|
||||||
|
|
||||||
|
wire [5:0] vector_sel =
|
||||||
|
exception_req_any || !irq_vector_enable ? 6'd0 :
|
||||||
|
standard_irq_active ? standard_irq_num :
|
||||||
|
external_irq_active ? 6'd16 + external_irq_num : 6'd0;
|
||||||
|
|
||||||
|
assign trap_addr = except == EXCEPT_MRET ? mepc : mtvec | {24'h0, vector_sel, 2'h0};
|
||||||
assign trap_is_irq = !exception_req_any;
|
assign trap_is_irq = !exception_req_any;
|
||||||
assign trap_enter_vld = CSR_M_TRAP && (exception_req_any || irq_any);
|
assign trap_enter_vld = CSR_M_TRAP && (exception_req_any ||
|
||||||
|
!delay_irq_entry && (standard_irq_active || external_irq_active));
|
||||||
|
|
||||||
assign mcause_irq_next = !exception_req_any;
|
assign mcause_irq_next = !exception_req_any;
|
||||||
assign mcause_code_next = exception_req_any ? except : {1'b0, irq_num};
|
assign mcause_code_next = exception_req_any ? {2'h0, except} : vector_sel;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -736,6 +838,9 @@ always @ (posedge clk) begin
|
||||||
if (!trap_enter_rdy)
|
if (!trap_enter_rdy)
|
||||||
assume(~|(irq_r & ~irq));
|
assume(~|(irq_r & ~irq));
|
||||||
|
|
||||||
|
// Make sure CSR accesses are flushed
|
||||||
|
if (trap_enter_vld && trap_enter_rdy)
|
||||||
|
assert(!(wen || ren));
|
||||||
// Something is screwed up if this happens
|
// Something is screwed up if this happens
|
||||||
if ($past(trap_enter_vld && trap_enter_rdy))
|
if ($past(trap_enter_vld && trap_enter_rdy))
|
||||||
assert(!wen);
|
assert(!wen);
|
||||||
|
|
Loading…
Reference in New Issue