mirror of
https://github.com/olofk/serv.git
synced 2026-03-01 09:20:58 +00:00
Fix IRQ
This contains a lot of fixes as IRQ support was broken on both RTL and zephyr side * Interrupts are now synced to instruction lifetimes * Interrupts are disabled on traps and mie is pushed to mpie * Zephyr applications regenerated from rewritten Zephyr port * Timer is 32-bit to avoid wrapping around too often * MEPC was not read properly from CSR storage
This commit is contained in:
@@ -15,12 +15,14 @@ module serv_csr
|
||||
output wire o_csr_in,
|
||||
//Stuff
|
||||
input wire i_mtip,
|
||||
output reg o_new_irq,
|
||||
output wire o_new_irq,
|
||||
input wire i_pending_irq,
|
||||
input wire i_trap_taken,
|
||||
input wire i_mstatus_en,
|
||||
input wire i_mie_en,
|
||||
input wire i_mcause_en,
|
||||
input wire [1:0] i_csr_source,
|
||||
input wire i_trap,
|
||||
input wire i_mret,
|
||||
input wire i_d,
|
||||
output wire o_q);
|
||||
|
||||
@@ -28,6 +30,7 @@ module serv_csr
|
||||
|
||||
reg mstatus;
|
||||
reg mstatus_mie;
|
||||
reg mstatus_mpie;
|
||||
reg mie_mtie;
|
||||
|
||||
reg mcause31;
|
||||
@@ -37,6 +40,8 @@ module serv_csr
|
||||
wire csr_in;
|
||||
wire csr_out;
|
||||
|
||||
reg timer_irq_r;
|
||||
|
||||
assign csr_in = (i_csr_source == CSR_SOURCE_EXT) ? i_d :
|
||||
(i_csr_source == CSR_SOURCE_SET) ? csr_out | i_d :
|
||||
(i_csr_source == CSR_SOURCE_CLR) ? csr_out & ~i_d :
|
||||
@@ -57,9 +62,14 @@ module serv_csr
|
||||
|
||||
assign o_csr_in = csr_in;
|
||||
|
||||
reg mtip_r;
|
||||
assign o_new_irq = !timer_irq_r & timer_irq;
|
||||
|
||||
|
||||
always @(posedge i_clk) begin
|
||||
/*
|
||||
Note: To save resources mstatus_mpie (mstatus bit 7) is not
|
||||
readable or writable from sw
|
||||
*/
|
||||
if (i_mstatus_en & (i_cnt[4:2] == 3'd0) & i_cnt_r[3])
|
||||
mstatus_mie <= csr_in;
|
||||
|
||||
@@ -68,12 +78,17 @@ module serv_csr
|
||||
|
||||
mstatus <= (i_cnt[4:2] == 0) & i_cnt_r[2] & mstatus_mie;
|
||||
|
||||
mtip_r <= i_mtip;
|
||||
o_new_irq <= !mtip_r & timer_irq;
|
||||
timer_irq_r <= timer_irq;
|
||||
|
||||
if (i_trap) begin
|
||||
mcause31 <= timer_irq;
|
||||
mcause3_0 <= timer_irq ? 4'd7 :
|
||||
if (i_mret) begin
|
||||
mstatus_mie <= mstatus_mpie;
|
||||
end
|
||||
|
||||
if (i_trap_taken) begin
|
||||
mstatus_mpie <= mstatus_mie;
|
||||
mstatus_mie <= 1'b0;
|
||||
mcause31 <= i_pending_irq;
|
||||
mcause3_0 <= i_pending_irq ? 4'd7 :
|
||||
i_e_op ? {!i_ebreak, 3'b011} :
|
||||
i_mem_misalign ? {2'b01, i_mem_cmd, 1'b0} :
|
||||
4'd0;
|
||||
|
||||
@@ -3,6 +3,8 @@ module serv_state
|
||||
input wire i_clk,
|
||||
input wire i_rst,
|
||||
input wire i_new_irq,
|
||||
output wire o_trap_taken,
|
||||
output reg o_pending_irq,
|
||||
input wire i_dbus_ack,
|
||||
input wire i_ibus_ack,
|
||||
output wire o_rf_rreq,
|
||||
@@ -49,7 +51,7 @@ module serv_state
|
||||
assign o_cnt_done = cnt_done;
|
||||
|
||||
//Update PC in RUN or TRAP states
|
||||
assign o_ctrl_pc_en = running | o_ctrl_trap;
|
||||
assign o_ctrl_pc_en = running | (state == TRAP);
|
||||
|
||||
assign o_csr_imm = (o_cnt < 5) ? i_rs1_addr[o_cnt[2:0]] : 1'b0;
|
||||
assign o_alu_shamt_en = (o_cnt < 5) & (state == INIT);
|
||||
@@ -64,14 +66,13 @@ module serv_state
|
||||
assign running = (state == RUN);
|
||||
assign o_run = running;
|
||||
|
||||
assign o_ctrl_trap = (state == TRAP);
|
||||
|
||||
//slt*, branch/jump, shift, load/store
|
||||
wire two_stage_op = i_slt_op | i_mem_op | i_branch_op | i_shift_op;
|
||||
|
||||
reg stage_two_pending;
|
||||
|
||||
reg pending_irq;
|
||||
reg irq_sync;
|
||||
reg misalign_trap_sync;
|
||||
|
||||
assign o_dbus_cyc = (state == IDLE) & stage_two_pending & i_mem_op & !i_mem_misalign;
|
||||
|
||||
@@ -87,6 +88,10 @@ module serv_state
|
||||
//Shift operations require bufreg to hold for one cycle between INIT and RUN before shifting
|
||||
assign o_bufreg_hold = !cnt_en & (stage_two_req | ~i_shift_op);
|
||||
|
||||
assign o_ctrl_trap = i_e_op | o_pending_irq | misalign_trap_sync;
|
||||
assign o_trap_taken = i_ibus_ack & o_ctrl_trap;
|
||||
|
||||
|
||||
always @(posedge i_clk) begin
|
||||
if (cnt_done)
|
||||
o_ctrl_jump <= (state == INIT) & i_take_branch;
|
||||
@@ -94,14 +99,24 @@ module serv_state
|
||||
if (cnt_en)
|
||||
stage_two_pending <= o_init;
|
||||
|
||||
if (i_ibus_ack)
|
||||
irq_sync <= 1'b0;
|
||||
if (i_new_irq)
|
||||
pending_irq <= 1'b1;
|
||||
irq_sync <= 1'b1;
|
||||
|
||||
if (i_ibus_ack)
|
||||
o_pending_irq <= irq_sync;
|
||||
|
||||
cnt_done <= (o_cnt[4:2] == 3'b111) & o_cnt_r[2];
|
||||
|
||||
//Need a strobe for the first cycle in the IDLE state after INIT
|
||||
stage_two_req <= cnt_done & (state == INIT);
|
||||
|
||||
if (stage_two_req)
|
||||
misalign_trap_sync <= trap_pending;
|
||||
if (i_ibus_ack)
|
||||
misalign_trap_sync <= 1'b0;
|
||||
|
||||
case (state)
|
||||
IDLE : begin
|
||||
if (stage_two_pending) begin
|
||||
@@ -111,7 +126,7 @@ module serv_state
|
||||
state <= TRAP;
|
||||
end else begin
|
||||
if (i_rf_ready)
|
||||
if (i_e_op | pending_irq)
|
||||
if (i_e_op | o_pending_irq)
|
||||
state <= TRAP;
|
||||
else if (two_stage_op)
|
||||
state <= INIT;
|
||||
@@ -124,7 +139,6 @@ module serv_state
|
||||
RUN : begin
|
||||
end
|
||||
TRAP : begin
|
||||
pending_irq <= 1'b0;
|
||||
end
|
||||
default : state <= IDLE;
|
||||
endcase
|
||||
@@ -138,7 +152,6 @@ module serv_state
|
||||
if (i_rst) begin
|
||||
state <= IDLE;
|
||||
o_cnt <= 5'd0;
|
||||
pending_irq <= 1'b0;
|
||||
stage_two_pending <= 1'b0;
|
||||
o_ctrl_jump <= 1'b0;
|
||||
o_cnt_r <= 4'b0001;
|
||||
|
||||
@@ -128,6 +128,8 @@ module serv_top
|
||||
parameter RESET_PC = 32'd8;
|
||||
|
||||
wire new_irq;
|
||||
wire trap_taken;
|
||||
wire pending_irq;
|
||||
|
||||
wire [1:0] lsb;
|
||||
wire [31:0] bufreg_out;
|
||||
@@ -137,6 +139,8 @@ module serv_top
|
||||
.i_clk (clk),
|
||||
.i_rst (i_rst),
|
||||
.i_new_irq (new_irq),
|
||||
.o_trap_taken (trap_taken),
|
||||
.o_pending_irq (pending_irq),
|
||||
.i_dbus_ack (i_dbus_ack),
|
||||
.i_ibus_ack (i_ibus_ack),
|
||||
.o_rf_rreq (rf_rreq),
|
||||
@@ -375,11 +379,13 @@ module serv_top
|
||||
.o_csr_in (csr_in),
|
||||
.i_mtip (i_timer_irq),
|
||||
.o_new_irq (new_irq),
|
||||
.i_trap_taken (trap_taken),
|
||||
.i_pending_irq (pending_irq),
|
||||
.i_mstatus_en (csr_mstatus_en),
|
||||
.i_mie_en (csr_mie_en ),
|
||||
.i_mcause_en (csr_mcause_en ),
|
||||
.i_csr_source (csr_source),
|
||||
.i_trap (trap),
|
||||
.i_mret (mret),
|
||||
.i_d (csr_d_sel ? csr_imm : rs1),
|
||||
.o_q (csr_rd));
|
||||
|
||||
|
||||
@@ -135,7 +135,9 @@ servant_arbiter servant_arbiter
|
||||
.o_wb_rdt (wb_mem_rdt),
|
||||
.o_wb_ack (wb_mem_ack));
|
||||
|
||||
servant_timer timer
|
||||
servant_timer
|
||||
#(.WIDTH (32))
|
||||
timer
|
||||
(.i_clk (wb_clk),
|
||||
.i_rst (wb_rst),
|
||||
.o_irq (timer_irq),
|
||||
|
||||
2568
sw/zephyr_hello.hex
2568
sw/zephyr_hello.hex
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
4602
sw/zephyr_phil.hex
4602
sw/zephyr_phil.hex
File diff suppressed because it is too large
Load Diff
3896
sw/zephyr_sync.hex
3896
sw/zephyr_sync.hex
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user