Refactoring of IRQ handling

This commit is contained in:
Clifford Wolf 2015-06-26 10:03:37 +02:00
parent 9d26ebcf58
commit 9a4a06d981
5 changed files with 168 additions and 114 deletions

View File

@ -83,24 +83,19 @@ transaction. In the default configuration the PicoRV32 core only expects the
`mem_rdata` input to be valid in the cycle with `mem_valid && mem_ready` and `mem_rdata` input to be valid in the cycle with `mem_valid && mem_ready` and
latches the value internally. latches the value internally.
#### ENABLE_EXTERNAL_IRQ (default = 0) #### ENABLE_IRQ (default = 0)
Set this to 1 to enable external IRQs. Set this to 1 to enable IRQs.
#### ENABLE_ILLINSTR_IRQ (default = 0) #### MASKED_IRQ (default = 32'h 0000_0000)
Set this to 1 to enable the illegal instruction IRQ. This can be used for A 1 bit in this bitmask corresponds to a permanently disabled IRQ.
software implementations of instructions such as `MUL` and `DIV`.
#### ENABLE_TIMER_IRQ (default = 0) #### PROGADDR_RESET (default = 32'h 0000_0000)
Set this to 1 to enable the built-in timer and timer IRQ.
#### PROGADDR_RESET (default = 0)
The start address of the program. The start address of the program.
#### PROGADDR_IRQ (default = 16) #### PROGADDR_IRQ (default = 32'h 0000_0010)
The start address of the interrupt handler. The start address of the interrupt handler.
@ -141,11 +136,30 @@ Custom Instructions for IRQ Handling
The following custom instructions are supported when IRQs are enabled. The following custom instructions are supported when IRQs are enabled.
The PicoRV32 core has a built-in interrupt controller with 32 interrupts. An
interrupt can be triggered by asserting the corresponding bit in the `irq`
input of the core.
When the interrupt handler is started, the `eoi` End Of Interrupt (EOI) signals
for the handled interrupts goes high. The `eoi` signal goes low again when the
interrupt handler returns.
The IRQs 0-2 can be triggered internally and have the following meaning:
| IRQ | Interrupt Source |
| ---:| -----------------------------------|
| 0 | Timer Interrupt |
| 1 | SBREAK or Illegal Instruction |
| 2 | BUS Error (Unalign Memory Access) |
The core has 4 additional 32-bit registers `q0 .. q3` that are used for IRQ The core has 4 additional 32-bit registers `q0 .. q3` that are used for IRQ
handling. When an IRQ triggers, the register `q0` contains the return address handling. When an IRQ triggers, the register `q0` contains the return address
and `q1` contains the IRQ number. Registers `q2` and `q3` are uninitialized and `q1` contains a bitmask of all active IRQs. I.e. one call to the interrupt
and can be used as temporary storage when saving/restoring register values handler might need to service one than more IRQ when more than one bit is set
in the IRQ handler. in `q1`.
Registers `q2` and `q3` are uninitialized and can be used as temporary storage
when saving/restoring register values in the IRQ handler.
#### getq rd, qs #### getq rd, qs
@ -182,7 +196,7 @@ Example assembler code using the `custom0` mnemonic:
#### retirq #### retirq
Return from interrupt. This instruction copies the value from `q0` Return from interrupt. This instruction copies the value from `q0`
to the program counter and enables interrupts. The Instruction is to the program counter and re-enables interrupts. The Instruction is
encoded under the `custom0` opcode: encoded under the `custom0` opcode:
0000010 00000 00000 000 00000 0001011 0000010 00000 00000 000 00000 0001011
@ -196,36 +210,26 @@ Example assembler code using the `custom0` mnemonic:
#### maskirq #### maskirq
The "IRQ Mask" register contains a birtmask of masked (disabled) interrupts.
This opcodes writes a new value to the irq mask register and reads the old
value.
Enable/disable interrupt sources. The Instruction is encoded under the Enable/disable interrupt sources. The Instruction is encoded under the
`custom0` opcode: `custom0` opcode:
0000011 XXXXX 00000 000 00000 0001011 0000011 00000 XXXXX 000 XXXXX 0001011
f7 f5 rs f3 rd opcode f7 f5 rs f3 rd opcode
The following interrupt sources occupy the following bits
in the `f5` field:
| Bit | Interrupt Source |
| ------| ---------------------|
| f5[0] | External IRQ |
| f5[1] | Timer Interrupt |
| f5[2] | Illegal Instruction |
| f5[3] | Reserved |
| f5[4] | Reserved |
Set bits in the IRQ mask correspond to enabled interrupt sources.
Example assembler code using the `custom0` mnemonic: Example assembler code using the `custom0` mnemonic:
| Instruction | Assember Code | | Instruction | Assember Code |
| ------------------| --------------------| | ------------------| --------------------|
| maskirq 0 | custom0 0, 0, 0, 3 | | maskirq x1, x2 | custom0 1, 2, 0, 3 |
| maskirq 1 | custom0 0, 0, 1, 3 |
The processor starts with all interrupts disabled. The processor starts with all interrupts disabled.
An illegal instruction while the illegal instruction interrupt is disabled will An illegal instruction or bus error while the illegal instruction or bus error
cause the processor to halt. interrupt is disabled will cause the processor to halt.
#### waitirq (unimplemented) #### waitirq (unimplemented)
@ -243,7 +247,7 @@ Example assembler code using the `custom0` mnemonic:
#### timer #### timer
Reset the timer counter to a new value. The counter counts down cycles and Reset the timer counter to a new value. The counter counts down clock cycles and
triggers the timer interrupt when transitioning from 1 to 0. Setting the triggers the timer interrupt when transitioning from 1 to 0. Setting the
counter to zero disables the timer. counter to zero disables the timer.
@ -261,6 +265,7 @@ Todos:
------ ------
- Optional FENCE support - Optional FENCE support
- Optional Co-Processor Interface
- Optional write-through cache - Optional write-through cache
- Optional support for compressed ISA - Optional support for compressed ISA
- Improved documentation and examples - Improved documentation and examples

View File

@ -33,7 +33,7 @@ static void print_dec(int val)
{ {
char buffer[10]; char buffer[10];
char *p = buffer; char *p = buffer;
while (val) { while (val || p == buffer) {
*(p++) = val % 10; *(p++) = val % 10;
val = val / 10; val = val / 10;
} }
@ -88,24 +88,28 @@ void sieve()
} }
} }
void irq(uint32_t *regs, uint32_t irqnum) uint32_t *irq(uint32_t *regs, uint32_t irqs)
{ {
static int ext_irq_count = 0; static int ext_irq_4_count = 0;
static int ext_irq_5_count = 0;
static int timer_irq_count = 0; static int timer_irq_count = 0;
if (irqnum == 0) { if ((irqs & (1<<4)) != 0) {
ext_irq_count++; ext_irq_4_count++;
// print_str("[EXT-IRQ]"); // print_str("[EXT-IRQ-4]");
return;
} }
if (irqnum == 1) { if ((irqs & (1<<5)) != 0) {
ext_irq_5_count++;
// print_str("[EXT-IRQ-5]");
}
if ((irqs & 1) != 0) {
timer_irq_count++; timer_irq_count++;
// print_str("[TIMER-IRQ]"); // print_str("[TIMER-IRQ]");
return;
} }
if (irqnum == 2) if ((irqs & 6) != 0)
{ {
int i, k; int i, k;
uint32_t pc = regs[0] - 4; uint32_t pc = regs[0] - 4;
@ -114,6 +118,7 @@ void irq(uint32_t *regs, uint32_t irqnum)
print_str("\n"); print_str("\n");
print_str("------------------------------------------------------------\n"); print_str("------------------------------------------------------------\n");
if ((irqs & 2) != 0) {
if (instr == 0x00100073) { if (instr == 0x00100073) {
print_str("SBREAK instruction at 0x"); print_str("SBREAK instruction at 0x");
print_hex(pc); print_hex(pc);
@ -125,6 +130,15 @@ void irq(uint32_t *regs, uint32_t irqnum)
print_hex(instr); print_hex(instr);
print_str("\n"); print_str("\n");
} }
}
if ((irqs & 4) != 0) {
print_str("Bus error in Instruction at 0x");
print_hex(pc);
print_str(": 0x");
print_hex(instr);
print_str("\n");
}
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
for (k = 0; k < 4; k++) for (k = 0; k < 4; k++)
@ -164,8 +178,12 @@ void irq(uint32_t *regs, uint32_t irqnum)
print_str("------------------------------------------------------------\n"); print_str("------------------------------------------------------------\n");
print_str("Number of external IRQs counted: "); print_str("Number of fast external IRQs counted: ");
print_dec(ext_irq_count); print_dec(ext_irq_4_count);
print_str("\n");
print_str("Number of slow external IRQs counted: ");
print_dec(ext_irq_5_count);
print_str("\n"); print_str("\n");
print_str("Number of timer IRQs counted: "); print_str("Number of timer IRQs counted: ");
@ -173,7 +191,8 @@ void irq(uint32_t *regs, uint32_t irqnum)
print_str("\n"); print_str("\n");
__asm__("sbreak"); __asm__("sbreak");
return;
} }
return regs;
} }

View File

@ -10,7 +10,7 @@
jal zero,n; n ## _ret: jal zero,n; n ## _ret:
reset_vec: reset_vec:
custom0 0,0,7,3 // maskirq 7 custom0 0,0,0,3 // maskirq zero, zero
j start j start
nop nop
nop nop

View File

@ -26,17 +26,16 @@
***************************************************************/ ***************************************************************/
module picorv32 #( module picorv32 #(
parameter ENABLE_COUNTERS = 1, parameter [ 0:0] ENABLE_COUNTERS = 1,
parameter ENABLE_REGS_16_31 = 1, parameter [ 0:0] ENABLE_REGS_16_31 = 1,
parameter ENABLE_REGS_DUALPORT = 1, parameter [ 0:0] ENABLE_REGS_DUALPORT = 1,
parameter LATCHED_MEM_RDATA = 0, parameter [ 0:0] LATCHED_MEM_RDATA = 0,
parameter ENABLE_EXTERNAL_IRQ = 0, parameter [ 0:0] ENABLE_IRQ = 0,
parameter ENABLE_ILLINSTR_IRQ = 0, parameter [31:0] MASKED_IRQ = 32'h 0000_0000,
parameter ENABLE_TIMER_IRQ = 0, parameter [31:0] PROGADDR_RESET = 32'h 0000_0000,
parameter PROGADDR_RESET = 0, parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010
parameter PROGADDR_IRQ = 16
) ( ) (
input clk, resetn, irq, input clk, resetn,
output reg trap, output reg trap,
output reg mem_valid, output reg mem_valid,
@ -53,9 +52,15 @@ module picorv32 #(
output mem_la_write, output mem_la_write,
output [31:0] mem_la_addr, output [31:0] mem_la_addr,
output reg [31:0] mem_la_wdata, output reg [31:0] mem_la_wdata,
output reg [ 3:0] mem_la_wstrb output reg [ 3:0] mem_la_wstrb,
// IRQ interface
input [31:0] irq,
output reg [31:0] eoi
); );
localparam ENABLE_IRQ = ENABLE_EXTERNAL_IRQ || ENABLE_ILLINSTR_IRQ || ENABLE_TIMER_IRQ; localparam integer irq_timer = 0;
localparam integer irq_sbreak = 1;
localparam integer irq_buserror = 2;
localparam integer irqregs_offset = ENABLE_REGS_16_31 ? 32 : 16; localparam integer irqregs_offset = ENABLE_REGS_16_31 ? 32 : 16;
localparam integer regfile_size = (ENABLE_REGS_16_31 ? 32 : 16) + 4*ENABLE_IRQ; localparam integer regfile_size = (ENABLE_REGS_16_31 ? 32 : 16) + 4*ENABLE_IRQ;
@ -69,8 +74,8 @@ module picorv32 #(
wire [31:0] next_pc; wire [31:0] next_pc;
reg irq_active; reg irq_active;
reg [4:0] irq_mask; reg [31:0] irq_mask;
reg [4:0] irq_pending; reg [31:0] irq_pending;
reg [31:0] timer; reg [31:0] timer;
// Memory Interface // Memory Interface
@ -185,6 +190,7 @@ module picorv32 #(
reg [regindex_bits-1:0] decoded_rd, decoded_rs1, decoded_rs2; reg [regindex_bits-1:0] decoded_rd, decoded_rs1, decoded_rs2;
reg [31:0] decoded_imm, decoded_imm_uj; reg [31:0] decoded_imm, decoded_imm_uj;
reg decoder_trigger; reg decoder_trigger;
reg decoder_trigger_q;
reg decoder_pseudo_trigger; reg decoder_pseudo_trigger;
reg is_lui_auipc_jal; reg is_lui_auipc_jal;
@ -272,7 +278,7 @@ module picorv32 #(
if (instr_waitirq) new_instruction = "waitirq"; if (instr_waitirq) new_instruction = "waitirq";
if (instr_timer) new_instruction = "timer"; if (instr_timer) new_instruction = "timer";
if (new_instruction) if (decoder_trigger_q)
instruction = new_instruction; instruction = new_instruction;
end end
@ -362,7 +368,7 @@ module picorv32 #(
instr_setq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000001 && ENABLE_IRQ; instr_setq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000001 && ENABLE_IRQ;
instr_maskirq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000011 && ENABLE_IRQ; instr_maskirq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000011 && ENABLE_IRQ;
instr_waitirq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000100 && ENABLE_IRQ; instr_waitirq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000100 && ENABLE_IRQ;
instr_timer <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000101 && ENABLE_TIMER_IRQ; instr_timer <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000101 && ENABLE_IRQ;
is_slli_srli_srai <= is_alu_reg_imm && |{ is_slli_srli_srai <= is_alu_reg_imm && |{
mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000, mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000,
@ -432,6 +438,8 @@ module picorv32 #(
reg [31:0] current_pc; reg [31:0] current_pc;
assign next_pc = latched_store && latched_branch ? reg_out : reg_next_pc; assign next_pc = latched_store && latched_branch ? reg_out : reg_next_pc;
reg [31:0] next_irq_pending;
reg [31:0] alu_out; reg [31:0] alu_out;
reg alu_out_0; reg alu_out_0;
@ -484,16 +492,19 @@ module picorv32 #(
if (ENABLE_COUNTERS) if (ENABLE_COUNTERS)
count_cycle <= resetn ? count_cycle + 1 : 0; count_cycle <= resetn ? count_cycle + 1 : 0;
if (ENABLE_TIMER_IRQ && timer) begin next_irq_pending = irq_pending;
if (ENABLE_IRQ && timer) begin
if (timer - 1 == 0) if (timer - 1 == 0)
irq_pending[1] <= 1; next_irq_pending[irq_timer] = 1;
timer <= timer - 1; timer <= timer - 1;
end end
if (ENABLE_EXTERNAL_IRQ && irq) begin if (ENABLE_IRQ) begin
irq_pending[0] <= 1; next_irq_pending = next_irq_pending | irq;
end end
decoder_trigger_q <= decoder_trigger;
decoder_trigger <= mem_do_rinst && mem_done; decoder_trigger <= mem_do_rinst && mem_done;
decoder_pseudo_trigger <= 0; decoder_pseudo_trigger <= 0;
@ -509,9 +520,10 @@ module picorv32 #(
latched_is_lh <= 0; latched_is_lh <= 0;
latched_is_lb <= 0; latched_is_lb <= 0;
irq_active <= 0; irq_active <= 0;
irq_mask <= 0; irq_mask <= ~0;
irq_pending <= 0; next_irq_pending = 0;
irq_state <= 0; irq_state <= 0;
eoi <= 0;
timer <= 0; timer <= 0;
cpu_state <= cpu_state_fetch; cpu_state <= cpu_state_fetch;
end else end else
@ -546,16 +558,9 @@ module picorv32 #(
mem_do_rinst <= 1; mem_do_rinst <= 1;
end else end else
if (ENABLE_IRQ && irq_state[1]) begin if (ENABLE_IRQ && irq_state[1]) begin
cpuregs[latched_rd] <= eoi <= irq_pending & ~irq_mask;
irq_pending[0] && irq_mask[0] ? 0 : cpuregs[latched_rd] <= irq_pending & ~irq_mask;
irq_pending[1] && irq_mask[1] ? 1 : next_irq_pending = next_irq_pending & irq_mask;
irq_pending[2] && irq_mask[2] ? 2 :
irq_pending[3] && irq_mask[3] ? 3 : 4;
irq_pending <=
irq_pending[0] && irq_mask[0] ? irq_pending & 5'b11110 :
irq_pending[1] && irq_mask[1] ? irq_pending & 5'b11101 :
irq_pending[2] && irq_mask[2] ? irq_pending & 5'b11011 :
irq_pending[3] && irq_mask[3] ? irq_pending & 5'b10111 : irq_pending & 5'b01111;
end end
reg_pc <= current_pc; reg_pc <= current_pc;
@ -569,7 +574,7 @@ module picorv32 #(
latched_is_lb <= 0; latched_is_lb <= 0;
latched_rd <= decoded_rd; latched_rd <= decoded_rd;
if (ENABLE_IRQ && ((decoder_trigger && !irq_active && |(irq_pending & irq_mask)) || irq_state)) begin if (ENABLE_IRQ && ((decoder_trigger && !irq_active && |(irq_pending & ~irq_mask)) || irq_state)) begin
irq_state <= irq_state <=
irq_state == 2'b00 ? 2'b01 : irq_state == 2'b00 ? 2'b01 :
irq_state == 2'b01 ? 2'b10 : 2'b00; irq_state == 2'b01 ? 2'b10 : 2'b00;
@ -600,14 +605,14 @@ module picorv32 #(
reg_op1 <= 'bx; reg_op1 <= 'bx;
reg_op2 <= 'bx; reg_op2 <= 'bx;
`ifdef DEBUG `ifdef DEBUG
$display("DECODE: 0x%08x %-0s", reg_pc, instruction); $display("DECODE: 0x%08x %-0s", reg_pc, instruction ? instruction : "UNKNOWN");
`endif `endif
if (instr_trap) begin if (instr_trap) begin
`ifdef DEBUG `ifdef DEBUG
$display("SBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc); $display("SBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);
`endif `endif
if (ENABLE_ILLINSTR_IRQ && irq_mask[2] && !irq_active) begin if (ENABLE_IRQ && !irq_mask[irq_sbreak] && !irq_active) begin
irq_pending[2] <= 1; next_irq_pending[irq_sbreak] = 1;
cpu_state <= cpu_state_fetch; cpu_state <= cpu_state_fetch;
end else end else
cpu_state <= cpu_state_trap; cpu_state <= cpu_state_trap;
@ -645,6 +650,7 @@ module picorv32 #(
cpu_state <= cpu_state_fetch; cpu_state <= cpu_state_fetch;
end else end else
if (ENABLE_IRQ && instr_retirq) begin if (ENABLE_IRQ && instr_retirq) begin
eoi <= 0;
irq_active <= 0; irq_active <= 0;
latched_branch <= 1; latched_branch <= 1;
latched_store <= 1; latched_store <= 1;
@ -652,10 +658,12 @@ module picorv32 #(
cpu_state <= cpu_state_fetch; cpu_state <= cpu_state_fetch;
end else end else
if (ENABLE_IRQ && instr_maskirq) begin if (ENABLE_IRQ && instr_maskirq) begin
irq_mask = decoded_rs2; latched_store <= 1;
reg_out <= irq_mask;
irq_mask <= (decoded_rs1 ? cpuregs[decoded_rs1] : 0) | MASKED_IRQ;
cpu_state <= cpu_state_fetch; cpu_state <= cpu_state_fetch;
end else end else
if (ENABLE_TIMER_IRQ && instr_timer) begin if (ENABLE_IRQ && instr_timer) begin
timer <= cpuregs[decoded_rs1]; timer <= cpuregs[decoded_rs1];
cpu_state <= cpu_state_fetch; cpu_state <= cpu_state_fetch;
end else begin end else begin
@ -806,12 +814,18 @@ module picorv32 #(
`ifdef DEBUG `ifdef DEBUG
$display("MISALIGNED WORD: 0x%08x", reg_op1); $display("MISALIGNED WORD: 0x%08x", reg_op1);
`endif `endif
if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin
next_irq_pending[irq_buserror] = 1;
end else
cpu_state <= cpu_state_trap; cpu_state <= cpu_state_trap;
end end
if (mem_wordsize == 1 && reg_op1[0] != 0) begin if (mem_wordsize == 1 && reg_op1[0] != 0) begin
`ifdef DEBUG `ifdef DEBUG
$display("MISALIGNED HALFWORD: 0x%08x", reg_op1); $display("MISALIGNED HALFWORD: 0x%08x", reg_op1);
`endif `endif
if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin
next_irq_pending[irq_buserror] = 1;
end else
cpu_state <= cpu_state_trap; cpu_state <= cpu_state_trap;
end end
end end
@ -819,6 +833,9 @@ module picorv32 #(
`ifdef DEBUG `ifdef DEBUG
$display("MISALIGNED INSTRUCTION: 0x%08x", reg_pc); $display("MISALIGNED INSTRUCTION: 0x%08x", reg_pc);
`endif `endif
if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin
next_irq_pending[irq_buserror] = 1;
end else
cpu_state <= cpu_state_trap; cpu_state <= cpu_state_trap;
end end
@ -836,6 +853,8 @@ module picorv32 #(
if (set_mem_do_wdata) if (set_mem_do_wdata)
mem_do_wdata <= 1; mem_do_wdata <= 1;
irq_pending <= next_irq_pending & ~MASKED_IRQ;
reg_pc[1:0] <= 0; reg_pc[1:0] <= 0;
reg_next_pc[1:0] <= 0; reg_next_pc[1:0] <= 0;
current_pc = 'bx; current_pc = 'bx;
@ -848,14 +867,15 @@ endmodule
***************************************************************/ ***************************************************************/
module picorv32_axi #( module picorv32_axi #(
parameter ENABLE_COUNTERS = 1, parameter [ 0:0] ENABLE_COUNTERS = 1,
parameter ENABLE_REGS_16_31 = 1, parameter [ 0:0] ENABLE_REGS_16_31 = 1,
parameter ENABLE_REGS_DUALPORT = 1, parameter [ 0:0] ENABLE_REGS_DUALPORT = 1,
parameter ENABLE_EXTERNAL_IRQ = 0, parameter [ 0:0] ENABLE_IRQ = 0,
parameter ENABLE_ILLINSTR_IRQ = 0, parameter [31:0] MASKED_IRQ = 32'h 0000_0000,
parameter ENABLE_TIMER_IRQ = 0 parameter [31:0] PROGADDR_RESET = 32'h 0000_0000,
parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010
) ( ) (
input clk, resetn, irq, input clk, resetn,
output trap, output trap,
// AXI4-lite master memory interface // AXI4-lite master memory interface
@ -880,7 +900,11 @@ module picorv32_axi #(
input mem_axi_rvalid, input mem_axi_rvalid,
output mem_axi_rready, output mem_axi_rready,
input [31:0] mem_axi_rdata input [31:0] mem_axi_rdata,
// IRQ interface
input [31:0] irq,
output [31:0] eoi
); );
wire mem_valid; wire mem_valid;
wire [31:0] mem_addr; wire [31:0] mem_addr;
@ -923,13 +947,13 @@ module picorv32_axi #(
.ENABLE_COUNTERS (ENABLE_COUNTERS ), .ENABLE_COUNTERS (ENABLE_COUNTERS ),
.ENABLE_REGS_16_31 (ENABLE_REGS_16_31 ), .ENABLE_REGS_16_31 (ENABLE_REGS_16_31 ),
.ENABLE_REGS_DUALPORT(ENABLE_REGS_DUALPORT), .ENABLE_REGS_DUALPORT(ENABLE_REGS_DUALPORT),
.ENABLE_EXTERNAL_IRQ (ENABLE_EXTERNAL_IRQ ), .ENABLE_IRQ (ENABLE_IRQ ),
.ENABLE_ILLINSTR_IRQ (ENABLE_ILLINSTR_IRQ ), .MASKED_IRQ (MASKED_IRQ ),
.ENABLE_TIMER_IRQ (ENABLE_TIMER_IRQ ) .PROGADDR_RESET (PROGADDR_RESET ),
.PROGADDR_IRQ (PROGADDR_IRQ )
) picorv32_core ( ) picorv32_core (
.clk (clk ), .clk (clk ),
.resetn (resetn ), .resetn (resetn ),
.irq (irq ),
.trap (trap ), .trap (trap ),
.mem_valid(mem_valid), .mem_valid(mem_valid),
.mem_addr (mem_addr ), .mem_addr (mem_addr ),
@ -937,7 +961,9 @@ module picorv32_axi #(
.mem_wstrb(mem_wstrb), .mem_wstrb(mem_wstrb),
.mem_instr(mem_instr), .mem_instr(mem_instr),
.mem_ready(mem_ready), .mem_ready(mem_ready),
.mem_rdata(mem_rdata) .mem_rdata(mem_rdata),
.irq (irq ),
.eoi (eoi )
); );
endmodule endmodule

View File

@ -6,9 +6,15 @@ module testbench;
reg clk = 1; reg clk = 1;
reg resetn = 0; reg resetn = 0;
wire irq = &uut.picorv32_core.count_cycle[12:0]; reg [31:0] irq;
wire trap; wire trap;
always @* begin
irq = 0;
irq[4] = &uut.picorv32_core.count_cycle[12:0];
irq[5] = &uut.picorv32_core.count_cycle[15:0];
end
always #5 clk = ~clk; always #5 clk = ~clk;
initial begin initial begin
@ -39,13 +45,10 @@ module testbench;
reg [31:0] mem_axi_rdata; reg [31:0] mem_axi_rdata;
picorv32_axi #( picorv32_axi #(
.ENABLE_EXTERNAL_IRQ (1), .ENABLE_IRQ(1)
.ENABLE_ILLINSTR_IRQ (1),
.ENABLE_TIMER_IRQ (1)
) uut ( ) uut (
.clk (clk ), .clk (clk ),
.resetn (resetn ), .resetn (resetn ),
.irq (irq ),
.trap (trap ), .trap (trap ),
.mem_axi_awvalid(mem_axi_awvalid), .mem_axi_awvalid(mem_axi_awvalid),
.mem_axi_awready(mem_axi_awready), .mem_axi_awready(mem_axi_awready),
@ -63,7 +66,8 @@ module testbench;
.mem_axi_arprot (mem_axi_arprot ), .mem_axi_arprot (mem_axi_arprot ),
.mem_axi_rvalid (mem_axi_rvalid ), .mem_axi_rvalid (mem_axi_rvalid ),
.mem_axi_rready (mem_axi_rready ), .mem_axi_rready (mem_axi_rready ),
.mem_axi_rdata (mem_axi_rdata ) .mem_axi_rdata (mem_axi_rdata ),
.irq (irq )
); );
reg [31:0] memory [0:64*1024/4-1]; reg [31:0] memory [0:64*1024/4-1];