mirror of https://github.com/YosysHQ/picorv32.git
Refactoring of IRQ handling
This commit is contained in:
parent
9d26ebcf58
commit
9a4a06d981
73
README.md
73
README.md
|
@ -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
|
||||
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
|
||||
software implementations of instructions such as `MUL` and `DIV`.
|
||||
A 1 bit in this bitmask corresponds to a permanently disabled IRQ.
|
||||
|
||||
#### ENABLE_TIMER_IRQ (default = 0)
|
||||
|
||||
Set this to 1 to enable the built-in timer and timer IRQ.
|
||||
|
||||
#### PROGADDR_RESET (default = 0)
|
||||
#### PROGADDR_RESET (default = 32'h 0000_0000)
|
||||
|
||||
The start address of the program.
|
||||
|
||||
#### PROGADDR_IRQ (default = 16)
|
||||
#### PROGADDR_IRQ (default = 32'h 0000_0010)
|
||||
|
||||
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 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
|
||||
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 can be used as temporary storage when saving/restoring register values
|
||||
in the IRQ handler.
|
||||
and `q1` contains a bitmask of all active IRQs. I.e. one call to the interrupt
|
||||
handler might need to service one than more IRQ when more than one bit is set
|
||||
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
|
||||
|
||||
|
@ -182,7 +196,7 @@ Example assembler code using the `custom0` mnemonic:
|
|||
#### retirq
|
||||
|
||||
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:
|
||||
|
||||
0000010 00000 00000 000 00000 0001011
|
||||
|
@ -196,36 +210,26 @@ Example assembler code using the `custom0` mnemonic:
|
|||
|
||||
#### 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
|
||||
`custom0` opcode:
|
||||
|
||||
0000011 XXXXX 00000 000 00000 0001011
|
||||
0000011 00000 XXXXX 000 XXXXX 0001011
|
||||
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:
|
||||
|
||||
| Instruction | Assember Code |
|
||||
| ------------------| --------------------|
|
||||
| maskirq 0 | custom0 0, 0, 0, 3 |
|
||||
| maskirq 1 | custom0 0, 0, 1, 3 |
|
||||
| maskirq x1, x2 | custom0 1, 2, 0, 3 |
|
||||
|
||||
The processor starts with all interrupts disabled.
|
||||
|
||||
An illegal instruction while the illegal instruction interrupt is disabled will
|
||||
cause the processor to halt.
|
||||
An illegal instruction or bus error while the illegal instruction or bus error
|
||||
interrupt is disabled will cause the processor to halt.
|
||||
|
||||
#### waitirq (unimplemented)
|
||||
|
||||
|
@ -243,7 +247,7 @@ Example assembler code using the `custom0` mnemonic:
|
|||
|
||||
#### 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
|
||||
counter to zero disables the timer.
|
||||
|
||||
|
@ -261,6 +265,7 @@ Todos:
|
|||
------
|
||||
|
||||
- Optional FENCE support
|
||||
- Optional Co-Processor Interface
|
||||
- Optional write-through cache
|
||||
- Optional support for compressed ISA
|
||||
- Improved documentation and examples
|
||||
|
|
|
@ -33,7 +33,7 @@ static void print_dec(int val)
|
|||
{
|
||||
char buffer[10];
|
||||
char *p = buffer;
|
||||
while (val) {
|
||||
while (val || p == buffer) {
|
||||
*(p++) = 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;
|
||||
|
||||
if (irqnum == 0) {
|
||||
ext_irq_count++;
|
||||
// print_str("[EXT-IRQ]");
|
||||
return;
|
||||
if ((irqs & (1<<4)) != 0) {
|
||||
ext_irq_4_count++;
|
||||
// print_str("[EXT-IRQ-4]");
|
||||
}
|
||||
|
||||
if (irqnum == 1) {
|
||||
if ((irqs & (1<<5)) != 0) {
|
||||
ext_irq_5_count++;
|
||||
// print_str("[EXT-IRQ-5]");
|
||||
}
|
||||
|
||||
if ((irqs & 1) != 0) {
|
||||
timer_irq_count++;
|
||||
// print_str("[TIMER-IRQ]");
|
||||
return;
|
||||
}
|
||||
|
||||
if (irqnum == 2)
|
||||
if ((irqs & 6) != 0)
|
||||
{
|
||||
int i, k;
|
||||
uint32_t pc = regs[0] - 4;
|
||||
|
@ -114,12 +118,22 @@ void irq(uint32_t *regs, uint32_t irqnum)
|
|||
print_str("\n");
|
||||
print_str("------------------------------------------------------------\n");
|
||||
|
||||
if (instr == 0x00100073) {
|
||||
print_str("SBREAK instruction at 0x");
|
||||
print_hex(pc);
|
||||
print_str("\n");
|
||||
} else {
|
||||
print_str("Illegal Instruction at 0x");
|
||||
if ((irqs & 2) != 0) {
|
||||
if (instr == 0x00100073) {
|
||||
print_str("SBREAK instruction at 0x");
|
||||
print_hex(pc);
|
||||
print_str("\n");
|
||||
} else {
|
||||
print_str("Illegal Instruction at 0x");
|
||||
print_hex(pc);
|
||||
print_str(": 0x");
|
||||
print_hex(instr);
|
||||
print_str("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if ((irqs & 4) != 0) {
|
||||
print_str("Bus error in Instruction at 0x");
|
||||
print_hex(pc);
|
||||
print_str(": 0x");
|
||||
print_hex(instr);
|
||||
|
@ -164,8 +178,12 @@ void irq(uint32_t *regs, uint32_t irqnum)
|
|||
|
||||
print_str("------------------------------------------------------------\n");
|
||||
|
||||
print_str("Number of external IRQs counted: ");
|
||||
print_dec(ext_irq_count);
|
||||
print_str("Number of fast external IRQs counted: ");
|
||||
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("Number of timer IRQs counted: ");
|
||||
|
@ -173,7 +191,8 @@ void irq(uint32_t *regs, uint32_t irqnum)
|
|||
print_str("\n");
|
||||
|
||||
__asm__("sbreak");
|
||||
return;
|
||||
}
|
||||
|
||||
return regs;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
jal zero,n; n ## _ret:
|
||||
|
||||
reset_vec:
|
||||
custom0 0,0,7,3 // maskirq 7
|
||||
custom0 0,0,0,3 // maskirq zero, zero
|
||||
j start
|
||||
nop
|
||||
nop
|
||||
|
|
134
picorv32.v
134
picorv32.v
|
@ -26,17 +26,16 @@
|
|||
***************************************************************/
|
||||
|
||||
module picorv32 #(
|
||||
parameter ENABLE_COUNTERS = 1,
|
||||
parameter ENABLE_REGS_16_31 = 1,
|
||||
parameter ENABLE_REGS_DUALPORT = 1,
|
||||
parameter LATCHED_MEM_RDATA = 0,
|
||||
parameter ENABLE_EXTERNAL_IRQ = 0,
|
||||
parameter ENABLE_ILLINSTR_IRQ = 0,
|
||||
parameter ENABLE_TIMER_IRQ = 0,
|
||||
parameter PROGADDR_RESET = 0,
|
||||
parameter PROGADDR_IRQ = 16
|
||||
parameter [ 0:0] ENABLE_COUNTERS = 1,
|
||||
parameter [ 0:0] ENABLE_REGS_16_31 = 1,
|
||||
parameter [ 0:0] ENABLE_REGS_DUALPORT = 1,
|
||||
parameter [ 0:0] LATCHED_MEM_RDATA = 0,
|
||||
parameter [ 0:0] ENABLE_IRQ = 0,
|
||||
parameter [31:0] MASKED_IRQ = 32'h 0000_0000,
|
||||
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 reg trap,
|
||||
|
||||
output reg mem_valid,
|
||||
|
@ -53,9 +52,15 @@ module picorv32 #(
|
|||
output mem_la_write,
|
||||
output [31:0] mem_la_addr,
|
||||
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 regfile_size = (ENABLE_REGS_16_31 ? 32 : 16) + 4*ENABLE_IRQ;
|
||||
|
@ -69,8 +74,8 @@ module picorv32 #(
|
|||
wire [31:0] next_pc;
|
||||
|
||||
reg irq_active;
|
||||
reg [4:0] irq_mask;
|
||||
reg [4:0] irq_pending;
|
||||
reg [31:0] irq_mask;
|
||||
reg [31:0] irq_pending;
|
||||
reg [31:0] timer;
|
||||
|
||||
// Memory Interface
|
||||
|
@ -185,6 +190,7 @@ module picorv32 #(
|
|||
reg [regindex_bits-1:0] decoded_rd, decoded_rs1, decoded_rs2;
|
||||
reg [31:0] decoded_imm, decoded_imm_uj;
|
||||
reg decoder_trigger;
|
||||
reg decoder_trigger_q;
|
||||
reg decoder_pseudo_trigger;
|
||||
|
||||
reg is_lui_auipc_jal;
|
||||
|
@ -272,7 +278,7 @@ module picorv32 #(
|
|||
if (instr_waitirq) new_instruction = "waitirq";
|
||||
if (instr_timer) new_instruction = "timer";
|
||||
|
||||
if (new_instruction)
|
||||
if (decoder_trigger_q)
|
||||
instruction = new_instruction;
|
||||
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_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_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 && |{
|
||||
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;
|
||||
assign next_pc = latched_store && latched_branch ? reg_out : reg_next_pc;
|
||||
|
||||
reg [31:0] next_irq_pending;
|
||||
|
||||
reg [31:0] alu_out;
|
||||
reg alu_out_0;
|
||||
|
||||
|
@ -484,16 +492,19 @@ module picorv32 #(
|
|||
if (ENABLE_COUNTERS)
|
||||
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)
|
||||
irq_pending[1] <= 1;
|
||||
next_irq_pending[irq_timer] = 1;
|
||||
timer <= timer - 1;
|
||||
end
|
||||
|
||||
if (ENABLE_EXTERNAL_IRQ && irq) begin
|
||||
irq_pending[0] <= 1;
|
||||
if (ENABLE_IRQ) begin
|
||||
next_irq_pending = next_irq_pending | irq;
|
||||
end
|
||||
|
||||
decoder_trigger_q <= decoder_trigger;
|
||||
decoder_trigger <= mem_do_rinst && mem_done;
|
||||
decoder_pseudo_trigger <= 0;
|
||||
|
||||
|
@ -509,9 +520,10 @@ module picorv32 #(
|
|||
latched_is_lh <= 0;
|
||||
latched_is_lb <= 0;
|
||||
irq_active <= 0;
|
||||
irq_mask <= 0;
|
||||
irq_pending <= 0;
|
||||
irq_mask <= ~0;
|
||||
next_irq_pending = 0;
|
||||
irq_state <= 0;
|
||||
eoi <= 0;
|
||||
timer <= 0;
|
||||
cpu_state <= cpu_state_fetch;
|
||||
end else
|
||||
|
@ -546,16 +558,9 @@ module picorv32 #(
|
|||
mem_do_rinst <= 1;
|
||||
end else
|
||||
if (ENABLE_IRQ && irq_state[1]) begin
|
||||
cpuregs[latched_rd] <=
|
||||
irq_pending[0] && irq_mask[0] ? 0 :
|
||||
irq_pending[1] && irq_mask[1] ? 1 :
|
||||
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;
|
||||
eoi <= irq_pending & ~irq_mask;
|
||||
cpuregs[latched_rd] <= irq_pending & ~irq_mask;
|
||||
next_irq_pending = next_irq_pending & irq_mask;
|
||||
end
|
||||
|
||||
reg_pc <= current_pc;
|
||||
|
@ -569,7 +574,7 @@ module picorv32 #(
|
|||
latched_is_lb <= 0;
|
||||
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 == 2'b00 ? 2'b01 :
|
||||
irq_state == 2'b01 ? 2'b10 : 2'b00;
|
||||
|
@ -600,14 +605,14 @@ module picorv32 #(
|
|||
reg_op1 <= 'bx;
|
||||
reg_op2 <= 'bx;
|
||||
`ifdef DEBUG
|
||||
$display("DECODE: 0x%08x %-0s", reg_pc, instruction);
|
||||
$display("DECODE: 0x%08x %-0s", reg_pc, instruction ? instruction : "UNKNOWN");
|
||||
`endif
|
||||
if (instr_trap) begin
|
||||
`ifdef DEBUG
|
||||
$display("SBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);
|
||||
`endif
|
||||
if (ENABLE_ILLINSTR_IRQ && irq_mask[2] && !irq_active) begin
|
||||
irq_pending[2] <= 1;
|
||||
if (ENABLE_IRQ && !irq_mask[irq_sbreak] && !irq_active) begin
|
||||
next_irq_pending[irq_sbreak] = 1;
|
||||
cpu_state <= cpu_state_fetch;
|
||||
end else
|
||||
cpu_state <= cpu_state_trap;
|
||||
|
@ -645,6 +650,7 @@ module picorv32 #(
|
|||
cpu_state <= cpu_state_fetch;
|
||||
end else
|
||||
if (ENABLE_IRQ && instr_retirq) begin
|
||||
eoi <= 0;
|
||||
irq_active <= 0;
|
||||
latched_branch <= 1;
|
||||
latched_store <= 1;
|
||||
|
@ -652,10 +658,12 @@ module picorv32 #(
|
|||
cpu_state <= cpu_state_fetch;
|
||||
end else
|
||||
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;
|
||||
end else
|
||||
if (ENABLE_TIMER_IRQ && instr_timer) begin
|
||||
if (ENABLE_IRQ && instr_timer) begin
|
||||
timer <= cpuregs[decoded_rs1];
|
||||
cpu_state <= cpu_state_fetch;
|
||||
end else begin
|
||||
|
@ -806,20 +814,29 @@ module picorv32 #(
|
|||
`ifdef DEBUG
|
||||
$display("MISALIGNED WORD: 0x%08x", reg_op1);
|
||||
`endif
|
||||
cpu_state <= cpu_state_trap;
|
||||
if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin
|
||||
next_irq_pending[irq_buserror] = 1;
|
||||
end else
|
||||
cpu_state <= cpu_state_trap;
|
||||
end
|
||||
if (mem_wordsize == 1 && reg_op1[0] != 0) begin
|
||||
`ifdef DEBUG
|
||||
$display("MISALIGNED HALFWORD: 0x%08x", reg_op1);
|
||||
`endif
|
||||
cpu_state <= cpu_state_trap;
|
||||
if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin
|
||||
next_irq_pending[irq_buserror] = 1;
|
||||
end else
|
||||
cpu_state <= cpu_state_trap;
|
||||
end
|
||||
end
|
||||
if (resetn && mem_do_rinst && reg_pc[1:0] != 0) begin
|
||||
`ifdef DEBUG
|
||||
$display("MISALIGNED INSTRUCTION: 0x%08x", reg_pc);
|
||||
`endif
|
||||
cpu_state <= cpu_state_trap;
|
||||
if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin
|
||||
next_irq_pending[irq_buserror] = 1;
|
||||
end else
|
||||
cpu_state <= cpu_state_trap;
|
||||
end
|
||||
|
||||
if (!resetn || mem_done) begin
|
||||
|
@ -836,6 +853,8 @@ module picorv32 #(
|
|||
if (set_mem_do_wdata)
|
||||
mem_do_wdata <= 1;
|
||||
|
||||
irq_pending <= next_irq_pending & ~MASKED_IRQ;
|
||||
|
||||
reg_pc[1:0] <= 0;
|
||||
reg_next_pc[1:0] <= 0;
|
||||
current_pc = 'bx;
|
||||
|
@ -848,14 +867,15 @@ endmodule
|
|||
***************************************************************/
|
||||
|
||||
module picorv32_axi #(
|
||||
parameter ENABLE_COUNTERS = 1,
|
||||
parameter ENABLE_REGS_16_31 = 1,
|
||||
parameter ENABLE_REGS_DUALPORT = 1,
|
||||
parameter ENABLE_EXTERNAL_IRQ = 0,
|
||||
parameter ENABLE_ILLINSTR_IRQ = 0,
|
||||
parameter ENABLE_TIMER_IRQ = 0
|
||||
parameter [ 0:0] ENABLE_COUNTERS = 1,
|
||||
parameter [ 0:0] ENABLE_REGS_16_31 = 1,
|
||||
parameter [ 0:0] ENABLE_REGS_DUALPORT = 1,
|
||||
parameter [ 0:0] ENABLE_IRQ = 0,
|
||||
parameter [31:0] MASKED_IRQ = 32'h 0000_0000,
|
||||
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,
|
||||
|
||||
// AXI4-lite master memory interface
|
||||
|
@ -880,7 +900,11 @@ module picorv32_axi #(
|
|||
|
||||
input mem_axi_rvalid,
|
||||
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 [31:0] mem_addr;
|
||||
|
@ -923,13 +947,13 @@ module picorv32_axi #(
|
|||
.ENABLE_COUNTERS (ENABLE_COUNTERS ),
|
||||
.ENABLE_REGS_16_31 (ENABLE_REGS_16_31 ),
|
||||
.ENABLE_REGS_DUALPORT(ENABLE_REGS_DUALPORT),
|
||||
.ENABLE_EXTERNAL_IRQ (ENABLE_EXTERNAL_IRQ ),
|
||||
.ENABLE_ILLINSTR_IRQ (ENABLE_ILLINSTR_IRQ ),
|
||||
.ENABLE_TIMER_IRQ (ENABLE_TIMER_IRQ )
|
||||
.ENABLE_IRQ (ENABLE_IRQ ),
|
||||
.MASKED_IRQ (MASKED_IRQ ),
|
||||
.PROGADDR_RESET (PROGADDR_RESET ),
|
||||
.PROGADDR_IRQ (PROGADDR_IRQ )
|
||||
) picorv32_core (
|
||||
.clk (clk ),
|
||||
.resetn (resetn ),
|
||||
.irq (irq ),
|
||||
.trap (trap ),
|
||||
.mem_valid(mem_valid),
|
||||
.mem_addr (mem_addr ),
|
||||
|
@ -937,7 +961,9 @@ module picorv32_axi #(
|
|||
.mem_wstrb(mem_wstrb),
|
||||
.mem_instr(mem_instr),
|
||||
.mem_ready(mem_ready),
|
||||
.mem_rdata(mem_rdata)
|
||||
.mem_rdata(mem_rdata),
|
||||
.irq (irq ),
|
||||
.eoi (eoi )
|
||||
);
|
||||
endmodule
|
||||
|
||||
|
|
16
testbench.v
16
testbench.v
|
@ -6,9 +6,15 @@ module testbench;
|
|||
|
||||
reg clk = 1;
|
||||
reg resetn = 0;
|
||||
wire irq = &uut.picorv32_core.count_cycle[12:0];
|
||||
reg [31:0] irq;
|
||||
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;
|
||||
|
||||
initial begin
|
||||
|
@ -39,13 +45,10 @@ module testbench;
|
|||
reg [31:0] mem_axi_rdata;
|
||||
|
||||
picorv32_axi #(
|
||||
.ENABLE_EXTERNAL_IRQ (1),
|
||||
.ENABLE_ILLINSTR_IRQ (1),
|
||||
.ENABLE_TIMER_IRQ (1)
|
||||
.ENABLE_IRQ(1)
|
||||
) uut (
|
||||
.clk (clk ),
|
||||
.resetn (resetn ),
|
||||
.irq (irq ),
|
||||
.trap (trap ),
|
||||
.mem_axi_awvalid(mem_axi_awvalid),
|
||||
.mem_axi_awready(mem_axi_awready),
|
||||
|
@ -63,7 +66,8 @@ module testbench;
|
|||
.mem_axi_arprot (mem_axi_arprot ),
|
||||
.mem_axi_rvalid (mem_axi_rvalid ),
|
||||
.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];
|
||||
|
|
Loading…
Reference in New Issue