|
@@ -261,6 +261,7 @@ module picorv32 #(
|
|
|
reg [31:0] irq_pending;
|
|
|
reg [31:0] timer;
|
|
|
reg [31:0] buserr_address;
|
|
|
+ wire [31:0] active_irqs = irq_pending & ~irq_mask;
|
|
|
|
|
|
`ifndef PICORV32_REGS
|
|
|
reg [31:0] cpuregs [0:regfile_size-1];
|
|
@@ -1270,7 +1271,6 @@ module picorv32 #(
|
|
|
localparam cpu_state_ldmem = 8'b00000001;
|
|
|
|
|
|
reg [7:0] cpu_state;
|
|
|
- reg [1:0] irq_state;
|
|
|
|
|
|
`FORMAL_KEEP reg [127:0] dbg_ascii_state;
|
|
|
|
|
@@ -1293,6 +1293,7 @@ module picorv32 #(
|
|
|
reg latched_store;
|
|
|
reg latched_stalu;
|
|
|
reg latched_branch;
|
|
|
+ reg latched_irq;
|
|
|
reg latched_compr;
|
|
|
reg latched_trace;
|
|
|
reg latched_is_lu;
|
|
@@ -1389,14 +1390,14 @@ module picorv32 #(
|
|
|
clear_prefetched_high_word = clear_prefetched_high_word_q;
|
|
|
if (!prefetched_high_word)
|
|
|
clear_prefetched_high_word = 0;
|
|
|
- if (latched_branch || irq_state || !resetn)
|
|
|
+ if (latched_branch || latched_irq || !resetn)
|
|
|
clear_prefetched_high_word = COMPRESSED_ISA;
|
|
|
end
|
|
|
|
|
|
- reg cpuregs_write;
|
|
|
- reg [31:0] cpuregs_wrdata;
|
|
|
- reg [31:0] cpuregs_rs1;
|
|
|
- reg [31:0] cpuregs_rs2;
|
|
|
+ (* preserve = 1 *) reg cpuregs_write;
|
|
|
+ (* preserve = 1 *) reg [31:0] cpuregs_wrdata;
|
|
|
+ (* preserve = 1 *) reg [31:0] cpuregs_rs1;
|
|
|
+ (* preserve = 1 *) reg [31:0] cpuregs_rs2;
|
|
|
reg [regfile_bits-1:0] decoded_rs;
|
|
|
|
|
|
always @* begin
|
|
@@ -1414,10 +1415,6 @@ module picorv32 #(
|
|
|
cpuregs_wrdata = latched_stalu ? alu_out_q : reg_out;
|
|
|
cpuregs_write = 1;
|
|
|
end
|
|
|
- ENABLE_IRQ && irq_state[1]: begin
|
|
|
- cpuregs_wrdata = irq_pending & ~irq_mask;
|
|
|
- cpuregs_write = 1;
|
|
|
- end
|
|
|
endcase
|
|
|
end
|
|
|
end
|
|
@@ -1498,7 +1495,7 @@ module picorv32 #(
|
|
|
|
|
|
assign launch_next_insn = cpu_state == cpu_state_fetch &&
|
|
|
decoder_trigger &&
|
|
|
- (!ENABLE_IRQ || irq_delay || irq_active || !(irq_pending & ~irq_mask));
|
|
|
+ (!ENABLE_IRQ || irq_delay || irq_active || !active_irqs);
|
|
|
|
|
|
wire [31:0] csrr_src = instr_funct2[2] ? { 29'b0, decoded_rs1[4:0] } : cpuregs_rs1;
|
|
|
|
|
@@ -1542,7 +1539,6 @@ module picorv32 #(
|
|
|
decoder_trigger_q <= decoder_trigger;
|
|
|
decoder_pseudo_trigger <= 0;
|
|
|
decoder_pseudo_trigger_q <= decoder_pseudo_trigger;
|
|
|
- do_waitirq <= 0;
|
|
|
|
|
|
trace_valid <= 0;
|
|
|
|
|
@@ -1562,6 +1558,7 @@ module picorv32 #(
|
|
|
latched_store <= 0;
|
|
|
latched_stalu <= 0;
|
|
|
latched_branch <= 0;
|
|
|
+ latched_irq <= 0;
|
|
|
latched_trace <= 0;
|
|
|
latched_is_lu <= 0;
|
|
|
latched_is_lh <= 0;
|
|
@@ -1573,9 +1570,9 @@ module picorv32 #(
|
|
|
irq_delay <= 0;
|
|
|
irq_mask <= ~0;
|
|
|
next_irq_pending = 0;
|
|
|
- irq_state <= 0;
|
|
|
eoi <= 0;
|
|
|
- timer <= 0;
|
|
|
+ timer <= 0;
|
|
|
+ do_waitirq <= 0;
|
|
|
if (~STACKADDR) begin
|
|
|
latched_store <= 1;
|
|
|
latched_rd <= (USER_CONTEXTS << xreg_bits) | 2;
|
|
@@ -1590,7 +1587,8 @@ module picorv32 #(
|
|
|
end
|
|
|
|
|
|
cpu_state_fetch: begin
|
|
|
- mem_do_rinst <= !decoder_trigger && !do_waitirq && !(halt && !irq_state);
|
|
|
+ eoi <= 0;
|
|
|
+ mem_do_rinst <= !decoder_trigger && !do_waitirq && !halt;
|
|
|
mem_wordsize <= 0;
|
|
|
|
|
|
current_pc = reg_next_pc;
|
|
@@ -1601,20 +1599,15 @@ module picorv32 #(
|
|
|
current_pc = latched_store ? (latched_stalu ? alu_out_q : reg_out) & ~1 : reg_next_pc;
|
|
|
`debug($display("ST_RD: %2d 0x%08x, BRANCH 0x%08x", latched_rd, reg_pc + (latched_compr ? 2 : 4), current_pc);)
|
|
|
end
|
|
|
- latched_store && !latched_branch: begin
|
|
|
+ latched_store && !latched_branch && !latched_irq: begin
|
|
|
`debug($display("ST_RD: %2d 0x%08x", latched_rd, latched_stalu ? alu_out_q : reg_out);)
|
|
|
end
|
|
|
- ENABLE_IRQ && irq_state[0]: begin
|
|
|
- current_pc = progaddr_irq & ~1;
|
|
|
- irq_active <= 1;
|
|
|
- mem_do_rinst <= 1;
|
|
|
- end
|
|
|
- ENABLE_IRQ && irq_state[1]: begin
|
|
|
- eoi <= irq_pending & ~irq_mask;
|
|
|
- next_irq_pending = next_irq_pending & irq_mask;
|
|
|
- end
|
|
|
endcase
|
|
|
|
|
|
+ if (latched_irq) begin
|
|
|
+ current_pc = progaddr_irq & ~1;
|
|
|
+ mem_do_rinst <= 1'b1;
|
|
|
+ end
|
|
|
if (ENABLE_TRACE && latched_trace) begin
|
|
|
latched_trace <= 0;
|
|
|
trace_valid <= 1;
|
|
@@ -1630,37 +1623,39 @@ module picorv32 #(
|
|
|
latched_store <= 0;
|
|
|
latched_stalu <= 0;
|
|
|
latched_branch <= 0;
|
|
|
+ latched_irq <= 0;
|
|
|
latched_is_lu <= 0;
|
|
|
latched_is_lh <= 0;
|
|
|
latched_is_lb <= 0;
|
|
|
latched_rd <= decoded_rd;
|
|
|
latched_compr <= compressed_instr;
|
|
|
|
|
|
- if (halt && !irq_state) begin
|
|
|
+ if (halt && !latched_irq) begin
|
|
|
// Do nothing, but allow an already started instruction or IRQ to complete
|
|
|
end else
|
|
|
- if (ENABLE_IRQ && ((decoder_trigger && !irq_active && !irq_delay && |(irq_pending & ~irq_mask)) || irq_state)) begin
|
|
|
- irq_state <=
|
|
|
- irq_state == 2'b00 ? 2'b01 :
|
|
|
- irq_state == 2'b01 ? 2'b10 : 2'b00;
|
|
|
- latched_compr <= latched_compr;
|
|
|
- latched_rd <= MASK_IRQ_REG;
|
|
|
- reg_mepc <= reg_next_pc | latched_compr;
|
|
|
+ if (ENABLE_IRQ && do_waitirq &&
|
|
|
+ (&(irq_pending | ~reg_op1) || |(irq_pending & reg_op2))) begin
|
|
|
+ // Waited-for interrupt: wake up and exit waitirq
|
|
|
+ // If this interrupt is enabled, it will be taken on the next cycle
|
|
|
+ latched_store <= 1;
|
|
|
+ reg_out <= irq_pending;
|
|
|
+ reg_next_pc <= current_pc + (compressed_instr ? 2 : 4);
|
|
|
+ do_waitirq <= 0;
|
|
|
+ end else
|
|
|
+ if (ENABLE_IRQ && decoder_trigger && !irq_active && !irq_delay && |active_irqs) begin
|
|
|
+ irq_active <= 1'b1;
|
|
|
+ latched_irq <= 1'b1;
|
|
|
+ latched_rd <= MASK_IRQ_REG;
|
|
|
+ reg_out <= active_irqs;
|
|
|
+ latched_store <= 1'b1;
|
|
|
+ eoi <= active_irqs;
|
|
|
+ next_irq_pending = next_irq_pending & irq_mask;
|
|
|
+ reg_mepc <= reg_next_pc | latched_compr;
|
|
|
+ do_waitirq <= 0; // An unwaited-for interrupt can break waitirq
|
|
|
end else
|
|
|
if (ENABLE_IRQ && do_waitirq) begin
|
|
|
- if (&(irq_pending | ~reg_op1) || |(irq_pending & reg_op2)) begin
|
|
|
- // Waited-for interrupt
|
|
|
- latched_store <= 1;
|
|
|
- reg_out <= irq_pending;
|
|
|
- reg_next_pc <= current_pc + (compressed_instr ? 2 : 4);
|
|
|
- end else if (decoder_trigger && !irq_active && !irq_delay && |(irq_pending & ~irq_mask)) begin
|
|
|
- // Allow non-waited-for interrupt to be taken; in this case
|
|
|
- // PC is *not* advanced so the interrupt routine will return
|
|
|
- // to waitirq.
|
|
|
- do_waitirq <= 0;
|
|
|
- end else begin
|
|
|
- do_waitirq <= 1;
|
|
|
- end
|
|
|
+ // Actually waiting for an IRQ...
|
|
|
+ do_waitirq <= 1; // Keep waiting...
|
|
|
end else
|
|
|
if (decoder_trigger) begin
|
|
|
`debug($display("-- %-0t pc: 0x%08x irq: %x", $time, current_pc, irq_active);)
|
|
@@ -1778,7 +1773,6 @@ module picorv32 #(
|
|
|
cpu_state <= cpu_state_exec;
|
|
|
end
|
|
|
ENABLE_IRQ && instr_retirq: begin
|
|
|
- eoi <= 0;
|
|
|
irq_active <= 0;
|
|
|
latched_branch <= 1;
|
|
|
latched_store <= 1;
|
|
@@ -1803,14 +1797,14 @@ module picorv32 #(
|
|
|
cpu_state <= cpu_state_fetch;
|
|
|
end // case: ENABLE_IRQ && instr_maskirq
|
|
|
ENABLE_IRQ && instr_waitirq: begin
|
|
|
- reg_op1 <= cpuregs_rs1;
|
|
|
- reg_op2 <= cpuregs_rs2;
|
|
|
+ reg_op1 <= cpuregs_rs1;
|
|
|
+ reg_op2 <= cpuregs_rs2;
|
|
|
dbg_rs1val <= cpuregs_rs1;
|
|
|
dbg_rs1val_valid <= 1;
|
|
|
dbg_rs2val <= cpuregs_rs2;
|
|
|
dbg_rs2val_valid <= 1;
|
|
|
do_waitirq <= 1;
|
|
|
- reg_next_pc <= reg_pc;
|
|
|
+ reg_next_pc <= reg_pc; // Stay on this instruction until released
|
|
|
cpu_state <= cpu_state_fetch;
|
|
|
end
|
|
|
ENABLE_IRQ && ENABLE_IRQ_TIMER && instr_timer: begin
|
|
@@ -1824,9 +1818,14 @@ module picorv32 #(
|
|
|
end
|
|
|
ENABLE_IRQ && instr_pollirq: begin
|
|
|
latched_store <= 1;
|
|
|
- reg_out <= (irq_pending & ~irq_mask & ~cpuregs_rs1) | cpuregs_rs2;
|
|
|
- eoi <= irq_pending & ~irq_mask & ~cpuregs_rs1;
|
|
|
+ reg_out <= (active_irqs & ~cpuregs_rs1) | cpuregs_rs2;
|
|
|
+ eoi <= active_irqs & ~cpuregs_rs1;
|
|
|
next_irq_pending = next_irq_pending & (irq_mask | cpuregs_rs1);
|
|
|
+ dbg_rs1val <= cpuregs_rs1;
|
|
|
+ dbg_rs1val_valid <= 1;
|
|
|
+ dbg_rs2val <= cpuregs_rs2;
|
|
|
+ dbg_rs2val_valid <= 1;
|
|
|
+ cpu_state <= cpu_state_fetch;
|
|
|
end
|
|
|
is_lb_lh_lw_lbu_lhu && !instr_trap: begin
|
|
|
`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
|
|
@@ -2140,7 +2139,7 @@ module picorv32 #(
|
|
|
dbg_irq_call <= 0;
|
|
|
dbg_irq_enter <= dbg_irq_call;
|
|
|
end else
|
|
|
- if (irq_state == 1) begin
|
|
|
+ if (latched_irq) begin
|
|
|
dbg_irq_call <= 1;
|
|
|
dbg_irq_ret <= next_pc;
|
|
|
end
|
|
@@ -2149,7 +2148,7 @@ module picorv32 #(
|
|
|
rvfi_rd_addr <= 0;
|
|
|
rvfi_rd_wdata <= 0;
|
|
|
end else
|
|
|
- if (cpuregs_write && !irq_state) begin
|
|
|
+ if (cpuregs_write && !latched_irq) begin
|
|
|
`ifdef PICORV32_TESTBUG_003
|
|
|
rvfi_rd_addr <= latched_rd ^ 1;
|
|
|
`else
|