Skip to content

Commit

Permalink
New: Add testcase interrupt and WFI (priv_sec_testsuite)
Browse files Browse the repository at this point in the history
New: Clear MEIP when external interrupt occurs
Fix: correct interrupt handling when transitioning between modes
Fix: races conditions occured with first interrupt implementation (priv
mode or not)
Change: put in place shared bus between control and CSR
  • Loading branch information
dpretet committed Oct 1, 2023
1 parent 940c908 commit ffb80f7
Show file tree
Hide file tree
Showing 23 changed files with 1,072 additions and 219 deletions.
46 changes: 40 additions & 6 deletions doc/privilege.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Bits [9:8]:
The privilege modes support have been designed based on RISC-V ISA specification version 20211203


# User Mode
## User Mode

- Support U-mode:
- Previous privilege mode interrupt is stored in xPP to support nested trap
Expand All @@ -70,18 +70,52 @@ The privilege modes support have been designed based on RISC-V ISA specification
instruction fetches and data accesses in S and U mode, and data accesses in M-mode when the
MPRV bit in mstatus is set and the MPP field in mstatus contains S or U (page 56 & page 23)
- Study PMA (Physical Memory Attribute) (section 3.6)
- Replace existing IO_MAP by PMP & PMA
- Replace existing IO_MAP by PMP & PMA
- Support cycle registers per mode
- Pass compliance with U-mode
- WFI
- Support MSTATUS.TW
- NOP if interrupts are disabled?
- WFI:
- Support MSTATUS.TW (timeout platform-dependant)
- if MIE/SIE=1, wait for one of them and trap. Resume to mepc=pc+4
- if MIE/SIE=0, wait for any intp and move forward
- mcounteren: accessibility to lower privilege modes
- mcountinhibit: stop a specific counter
- Machine Environment Configuration Registers (menvcfg and menvcfgh)

## Interrupts

- WFI:
- if MIE/SIE, wait for one of them and trap. Resume to mepc=pc+4
- Can be executed evn if MIE/SIE are disabled
- if any MTIE/MEIE/MSIE asserted, wait for them and move to pc+4
- NOP if MTIE/MEIE/MSIE are disabled and move to pc+4

- Bits mip.MEIP and mie.MEIE are the interrupt-pending and interrupt-enable bits for machine-level
external interrupts. MEIP is read-only in mip, and is set and cleared by a platform-specific
interrupt controller.
- Bits mip.MTIP and mie.MTIE are the interrupt-pending and interrupt-enable bits for machine timer
interrupts. MTIP is read-only in mip, and is cleared by writing to the memory-mapped machine-mode
timer compare register.
- Bits mip.MSIP and mie.MSIE are the interrupt-pending and interrupt-enable bits for machine- level
software interrupts. MSIP is read-only in mip, and is written by accesses to memory-mapped control
registers, which are used by remote harts to provide machine-level interprocessor interrupts. A
hart can write its own MSIP bit using the same memory-mapped control register. If a system has
only one hart, or if a platform standard supports the delivery of machine-level interprocessor
interrupts through external interrupts (MEI) instead, then mip.MSIP and mie.MSIE may both be
read-only zeros.

- An interrupt i will trap to M-mode (causing the privilege mode to change to M-mode) if all of the
following are true: (a) either the current privilege mode is M and the MIE bit in the mstatus
register is set, or the current privilege mode has less privilege than M-mode; (b) bit i is set in
both mip and mie; and (c) if register mideleg exists, bit i is not set in mideleg.

- Each individual bit in register mip may be writable or may be read-only. When bit i in mip is
writable, a pending interrupt i can be cleared by writing 0 to this bit. If interrupt i can become
pending but bit i in mip is read-only, the implementation must provide some other mechanism for
clearing the pending interrupt.


## Doc review

Doc review
- mstatus OK
- mtvec NO CHANGES
- mideleg / medeleg NA
Expand Down
103 changes: 71 additions & 32 deletions rtl/friscv_control.sv
Original file line number Diff line number Diff line change
Expand Up @@ -87,18 +87,10 @@ module friscv_control
output logic ctrl_rd_wr,
output logic [5 -1:0] ctrl_rd_addr,
output logic [XLEN -1:0] ctrl_rd_val,
// CSR registers
output logic mepc_wr,
output logic [XLEN -1:0] mepc,
output logic mstatus_wr,
output logic [XLEN -1:0] mstatus,
output logic mcause_wr,
output logic [XLEN -1:0] mcause,
output logic mtval_wr,
output logic [XLEN -1:0] mtval,
output logic [64 -1:0] instret,

// CSR shared bus
input wire [`CSR_SB_W -1:0] csr_sb
input wire [`CSR_SB_W -1:0] csr_sb,
output logic [`CTRL_SB_W -1:0] ctrl_sb
);


Expand Down Expand Up @@ -174,6 +166,7 @@ module friscv_control
// Two flags used intot the FSM to stall the process and control
// the instruction storage
logic cant_jump;
logic cant_trap;
logic cant_process;
logic cant_lui_auipc;
logic cant_sys;
Expand All @@ -187,9 +180,24 @@ module friscv_control
logic fifo_empty;
logic [XLEN -1:0] mtvec;

// Shared bus signals
logic [XLEN -1:0] sb_mepc;
logic [XLEN -1:0] sb_mtvec;
logic [XLEN -1:0] sb_mstatus;
logic sb_mie;
logic sb_mtip;
logic sb_msip;
logic sb_meip;
logic mepc_wr;
logic [XLEN -1:0] mepc;
logic mstatus_wr;
logic [XLEN -1:0] mstatus;
logic mcause_wr;
logic [XLEN -1:0] mcause;
logic mtval_wr;
logic [XLEN -1:0] mtval;
logic [64 -1:0] instret;
logic clr_meip;

logic [XLEN -1:0] mstatus_for_mret;
logic [XLEN -1:0] mstatus_for_trap;
Expand Down Expand Up @@ -308,9 +316,24 @@ module friscv_control
// CSR Shared bus extraction
///////////////////////////////////////////////////////////////////////////

assign sb_mtvec = csr_sb[`MTVEC +: XLEN];
assign sb_mstatus = csr_sb[`MSTATUS +: XLEN];
assign sb_mepc = csr_sb[`MEPC +: XLEN];
assign sb_mtvec = csr_sb[`CSR_SB_MTVEC +: XLEN];
assign sb_mstatus = csr_sb[`CSR_SB_MSTATUS +: XLEN];
assign sb_mepc = csr_sb[`CSR_SB_MEPC +: XLEN];
assign sb_mie = csr_sb[`CSR_SB_MIE];
assign sb_meip = csr_sb[`CSR_SB_MEIP];
assign sb_mtip = csr_sb[`CSR_SB_MTIP];
assign sb_msip = csr_sb[`CSR_SB_MSIP];

assign ctrl_sb = {instret, clr_meip,
mtval_wr, mtval,
mcause_wr, mcause,
mstatus_wr, mstatus,
mepc_wr, mepc};


///////////////////////////////////////////////////////////////////////////
// Input stage
///////////////////////////////////////////////////////////////////////////

assign push_inst = rvalid & (arid == rid);

Expand Down Expand Up @@ -660,14 +683,16 @@ module friscv_control
// interrupt, a wrong instruction, ...
if (trap_occuring) begin

`ifdef USE_SVL
print_mcause("Handling a trap -> MCAUSE=0x", mcause_code);
print_instruction;
`endif
status[3] <= 1'b1;
flush_pipe <= 1'b1;
if (USER_MODE) priv_mode <= `MMODE;
pc_reg <= mtvec;
if (!cant_trap) begin
`ifdef USE_SVL
print_mcause("Handling a trap -> MCAUSE=0x", mcause_code);
print_instruction;
`endif
status[3] <= 1'b1;
flush_pipe <= 1'b1;
if (USER_MODE) priv_mode <= `MMODE;
pc_reg <= mtvec;
end

// Needs to jump or branch thus stop the pipeline
// and reload new instructions
Expand Down Expand Up @@ -814,12 +839,13 @@ module friscv_control
// Wait for Interrupt (software, timer, external)
///////////////////////////////////////////////////////////////
WFI: begin
if (csr_sb[`MSIP] || csr_sb[`MTIP] || csr_sb[`MEIP]) begin
if (sb_msip || sb_mtip || sb_meip) begin
`ifdef USE_SVL
print_mcause("WFI -> MCAUSE=0x", mcause_code);
`endif
status <= 5'b0;
flush_pipe <= 1'b1;
if (USER_MODE) priv_mode <= `MMODE;
arid <= next_id(arid, MAX_ID, AXI_ID_MASK);
araddr <= mtvec;
pc_reg <= mtvec;
Expand All @@ -844,7 +870,7 @@ module friscv_control

// Trace control when jumping/branching for debug purpose
always @ (posedge aclk) begin
if (flush_pipe || (cfsm==WFI && (csr_sb[`MSIP] || csr_sb[`MTIP] || csr_sb[`MEIP]))) begin
if (flush_pipe || (cfsm==WFI && (sb_msip || sb_mtip || sb_meip))) begin
`ifdef TRACE_CONTROL
$fwrite(f, "@ %0t,%x\n", $realtime, sb_mepc);
`endif
Expand All @@ -864,6 +890,7 @@ module friscv_control
mcause <= {XLEN{1'b0}};
mtval_wr <= 1'b0;
mtval <= {XLEN{1'b0}};
clr_meip <= 1'b0;
end else if (srst == 1'b1) begin
mepc_wr <= 1'b0;
mepc <= {XLEN{1'b0}};
Expand All @@ -873,6 +900,7 @@ module friscv_control
mcause <= {XLEN{1'b0}};
mtval_wr <= 1'b0;
mtval <= {XLEN{1'b0}};
clr_meip <= 1'b0;
end else begin

if (cfsm==FETCH) begin
Expand All @@ -884,7 +912,7 @@ module friscv_control

if (inst_ready) begin

if (trap_occuring) begin
if (trap_occuring && !cant_trap) begin

mepc_wr <= 1'b1;
mepc <= pc_reg;
Expand All @@ -894,9 +922,12 @@ module friscv_control
mtval <= mtval_info;
mstatus_wr <= 1'b1;
mstatus <= mstatus_for_trap;
clr_meip <= (mcause_code == 'h8000000B);

end else if (|sys || |fence) begin

clr_meip <= 1'b0;

// Reach an ECALL instruction, jump to trap handler
if (sys[`IS_ECALL] && !proc_busy && csr_ready) begin

Expand Down Expand Up @@ -931,22 +962,30 @@ module friscv_control

end
end
end else begin
clr_meip <= 1'b0;
mepc_wr <= 1'b0;
mcause_wr <= 1'b0;
mstatus_wr <= 1'b0;
mtval_wr <= 1'b0;
end

end else if (cfsm==WFI && (csr_sb[`MSIP] || csr_sb[`MTIP] || csr_sb[`MEIP])) begin
end else if (cfsm==WFI && (sb_msip || sb_mtip || sb_meip)) begin

mcause_wr <= 1'b1;
mcause <= mcause_code;
mtval_wr <= 1'b1;
mtval <= mtval_info;
mstatus_wr <= 1'b1;
mstatus <= mstatus_for_trap;
clr_meip <= (mcause_code == 'h8000000B);

end else begin
mepc_wr <= 1'b0;
mstatus_wr <= 1'b0;
mcause_wr <= 1'b0;
mtval_wr <= 1'b0;
clr_meip <= 1'b0;
end
end
end
Expand All @@ -971,6 +1010,8 @@ module friscv_control

assign cant_sys = |sys & (proc_busy | !csr_ready);

assign cant_trap = (proc_busy | !csr_ready);


///////////////////////////////////////////////////////////////////////////
//
Expand Down Expand Up @@ -1181,9 +1222,9 @@ module friscv_control

// MCAUSE switching logic based on above listed priorities
assign mcause_code = // aync exceptions have highest priority
(csr_sb[`MSIP]) ? {1'b1, {XLEN-5{1'b0}}, 4'h3} :
(csr_sb[`MTIP]) ? {1'b1, {XLEN-5{1'b0}}, 4'h7} :
(csr_sb[`MEIP]) ? {1'b1, {XLEN-5{1'b0}}, 4'hB} :
(sb_msip) ? {1'b1, {XLEN-5{1'b0}}, 4'h3} :
(sb_mtip) ? {1'b1, {XLEN-5{1'b0}}, 4'h7} :
(sb_meip) ? {1'b1, {XLEN-5{1'b0}}, 4'hB} :
// then follow sync exceptions
(illegal_instruction) ? {{XLEN-4{1'b0}}, 4'h2} :
(csr_ro_wr) ? {{XLEN-4{1'b0}}, 4'h2} :
Expand All @@ -1209,9 +1250,7 @@ module friscv_control

// Trigger the trap handling execution in main FSM

assign async_trap_occuring = csr_sb[`MSIP] |
csr_sb[`MTIP] |
csr_sb[`MEIP] ;
assign async_trap_occuring = (sb_mtip | sb_msip | sb_meip ) & sb_mie;

assign sync_trap_occuring = csr_ro_wr |
inst_addr_misaligned |
Expand Down
53 changes: 31 additions & 22 deletions rtl/friscv_csr.sv
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,11 @@ module friscv_csr
output logic rd_wr_en,
output logic [5 -1:0] rd_wr_addr,
output logic [XLEN -1:0] rd_wr_val,
// External source of CSRs
input wire ctrl_mepc_wr,
input wire [XLEN -1:0] ctrl_mepc,
input wire ctrl_mstatus_wr,
input wire [XLEN -1:0] ctrl_mstatus,
input wire ctrl_mcause_wr,
input wire [XLEN -1:0] ctrl_mcause,
input wire ctrl_mtval_wr,
input wire [XLEN -1:0] ctrl_mtval,
input wire [64 -1:0] ctrl_rdinstret,
// Performance registers bus
input wire [PERF_REG_W*3*PERF_NB_BUS -1:0] perfs,
// CSR shared bus
output logic [`CSR_SB_W -1:0] csr_sb
output logic [`CSR_SB_W -1:0] csr_sb,
input logic [`CTRL_SB_W -1:0] ctrl_sb
);

// ------------------------------------------------------------------------
Expand Down Expand Up @@ -99,6 +90,18 @@ module friscv_csr
logic timer_irq_sync;
logic sw_irq_sync;

// External source of CSRs
logic ctrl_mepc_wr;
logic [XLEN -1:0] ctrl_mepc;
logic ctrl_mstatus_wr;
logic [XLEN -1:0] ctrl_mstatus;
logic ctrl_mcause_wr;
logic [XLEN -1:0] ctrl_mcause;
logic ctrl_mtval_wr;
logic [XLEN -1:0] ctrl_mtval;
logic [64 -1:0] ctrl_rdinstret;
logic ctrl_clr_meip;


///////////////////////////////////////////////////////////////////////////
// Build mstatus content
Expand Down Expand Up @@ -719,21 +722,21 @@ module friscv_csr
end else if (srst) begin
mip <= {XLEN{1'b0}};
end else begin
if (ext_irq_sync || timer_irq_sync || sw_irq_sync) begin
if (ext_irq_sync || timer_irq_sync || sw_irq_sync || ctrl_clr_meip) begin
// external interrupt enable && external interrupt pin asserted
if (mstatus[3] && mie[11] && ext_irq_sync) begin
if (mie[11] && ext_irq_sync) begin
mip[11] <= 1'b1;
end else begin
end else if (ctrl_clr_meip) begin
mip[11] <= 1'b0;
end
// software interrupt enable && software interrupt pin asserted
if (mstatus[3] && mie[3] && sw_irq_sync) begin
if (mie[3] && sw_irq_sync) begin
mip[3] <= 1'b1;
end else begin
mip[3] <= 1'b0;
end
// timer interrupt enable && timer interrupt pin asserted
if (mstatus[3] && mie[7] && timer_irq_sync) begin
if (mie[7] && timer_irq_sync) begin
mip[7] <= 1'b1;
end else begin
mip[7] <= 1'b0;
Expand Down Expand Up @@ -791,14 +794,20 @@ module friscv_csr
// CSR Shared bus, for registers used across the processor
//////////////////////////////////////////////////////////////////////////

assign csr_sb[`MTVEC+:XLEN] = mtvec;
assign csr_sb[`MEPC+:XLEN] = mepc;
assign csr_sb[`MSTATUS+:XLEN] = mstatus;
assign csr_sb[`CSR_SB_MTVEC+:XLEN] = mtvec;
assign csr_sb[`CSR_SB_MEPC+:XLEN] = mepc;
assign csr_sb[`CSR_SB_MSTATUS+:XLEN] = mstatus;

assign csr_sb[`MEIP] = mip[11];
assign csr_sb[`MTIP] = mip[7];
assign csr_sb[`MSIP] = mip[3];
assign csr_sb[`CSR_SB_MIE] = mstatus[3];
assign csr_sb[`CSR_SB_MEIP] = mip[11];
assign csr_sb[`CSR_SB_MTIP] = mip[7];
assign csr_sb[`CSR_SB_MSIP] = mip[3];

assign {ctrl_rdinstret, ctrl_clr_meip,
ctrl_mtval_wr, ctrl_mtval,
ctrl_mcause_wr, ctrl_mcause,
ctrl_mstatus_wr, ctrl_mstatus,
ctrl_mepc_wr, ctrl_mepc} = ctrl_sb;
endmodule

`resetall
Loading

0 comments on commit ffb80f7

Please sign in to comment.