Skip to content

Commit 45a4683

Browse files
committed
Implement S-mode interrupt delegation
1 parent f1ff4a1 commit 45a4683

File tree

2 files changed

+72
-36
lines changed

2 files changed

+72
-36
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ CSR values are stored either in a RAM processor (CSRS) or in a variable in the C
164164
| `misa` | CSRS | Read-only. |
165165
| `medeleg` | CSRS | Read-only zero. |
166166
| `medelegh` | CSRS | Read-only zero. |
167-
| `mideleg` | CSRS | Read-only zero. |
167+
| `mideleg` | CSRS | Read-only. Supervisor-level interrupts are always delegated to S-mode. |
168168
| `mie` | CPU | |
169169
| `mtvec` | CSRS | Bits 1:0 read-only zero. |
170170
| `mcounteren` | CSRS | |

src/cpu/worker.mlog.jinja

Lines changed: 71 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292

9393
#% set labels.next_tick = 14
9494

95-
#% set labels.end_instruction_with_rd_and_poll_interrupts = 147
95+
#% set labels.end_instruction_with_rd_and_poll_interrupts = 148
9696
#% set labels.end_instruction_with_rd_and_fire_interrupts = _labels_vals|last + 1
9797
#% set labels.end_instruction_with_rd = _labels_vals|last + 1
9898
#% set labels.end_instruction = _labels_vals|last + 2
@@ -173,13 +173,16 @@ fire_interrupts:
173173
#% do reset_locals()
174174
op and csr_mip csr_mip 0b10111111111111111111111111111111 # clear interrupt_flags.fire
175175

176-
# if privilege_mode < M, machine interrupts are globally enabled
177-
jump fire_interrupts__machine lessThan privilege_mode 0b11
178-
# if privilege_mode = M, machine interrupts are enabled if mstatus.MIE is 1
179-
op and $mstatus.mie csr_mstatus 0b1000
180-
jump main equal $mstatus.mie 0
176+
# in U-mode, interrupts are always enabled
177+
jump fire_interrupts__ok lessThan privilege_mode 0b01
181178

182-
fire_interrupts__machine:
179+
# in S-mode or M-mode, interrupts are enabled if mstatus.xIE is 1
180+
# conveniently, SIE is bit 1 and MIE is bit 3
181+
op shl $mstatus.xie 1 privilege_mode
182+
op and $mstatus.xie $mstatus.xie csr_mstatus
183+
jump main equal $mstatus.xie 0
184+
185+
fire_interrupts__ok:
183186
#% do reset_locals()
184187
# interrupt priority order: MEI, MSI*, MTI, SEI, SSI, STI, LCOFI*
185188
# * not implemented
@@ -199,17 +202,17 @@ fire_interrupts__machine:
199202
# supervisor external interrupt
200203
set mcause 0x80000009
201204
op and $enabled $interrupts 0b1000000000 # SEIP
202-
jump trap_without_mtval notEqual $enabled 0
205+
jump supervisor_trap_without_mtval notEqual $enabled 0
203206

204207
# supervisor software interrupt
205208
set mcause 0x80000001
206209
op and $enabled $interrupts 0b10 # SSIP
207-
jump trap_without_mtval notEqual $enabled 0
210+
jump supervisor_trap_without_mtval notEqual $enabled 0
208211

209212
# supervisor timer interrupt
210213
set mcause 0x80000005
211214
op and $enabled $interrupts 0b100000 # STIP
212-
jump trap_without_mtval notEqual $enabled 0
215+
jump supervisor_trap_without_mtval notEqual $enabled 0
213216

214217
main:
215218
# store the pc for the following instruction in a separate variable, so jumps and traps don't need to account for the pc being incremented at the end of an instruction
@@ -357,8 +360,38 @@ state->reset:
357360
set state "reset"
358361
jump reset always
359362

360-
ILLEGAL_OP:
363+
supervisor_trap_without_mtval:
361364
#% do reset_locals()
365+
set mtval 0
366+
367+
# don't trap from M-mode to S-mode
368+
jump trap greaterThan privilege_mode 0b01
369+
370+
# set sstatus.SPIE to sstatus.SIE, set sstatus.SIE to 0, and set sstatus.SPP to privilege_mode
371+
op and $mstatus.xpie csr_mstatus 0b10
372+
373+
op shl $mstatus.xpp privilege_mode 8
374+
375+
op and csr_mstatus csr_mstatus 0b11111111111111111111111011011101
376+
377+
# set scause
378+
write mcause {{CSRS}} "{{ 'scause'|csr }}"
379+
380+
# set stval
381+
write mtval {{CSRS}} "{{ 'stval'|csr }}"
382+
383+
# set sepc to current pc
384+
write pc {{CSRS}} "{{ 'sepc'|csr }}"
385+
386+
# we only support direct mode, so set next_pc to mtvec
387+
read next_pc {{CSRS}} "{{ 'stvec'|csr }}"
388+
389+
# trap into S-mode
390+
set privilege_mode 0b01
391+
392+
jump common_trap always
393+
394+
ILLEGAL_OP:
362395
set mcause 2
363396
# TODO: return faulting instruction bits?
364397
# continue into trap_without_mtval
@@ -368,22 +401,12 @@ trap_without_mtval:
368401
# continue into trap
369402

370403
trap:
371-
jump trap__breakpoint strictEqual pc breakpoint_address
372-
jump trap__no_breakpoint notEqual single_step_enabled true
373-
trap__breakpoint:
374-
set state "trap_breakpoint"
375-
stop
376-
trap__no_breakpoint:
377-
378404
# set mstatus.MPIE to mstatus.MIE, set mstatus.MIE to 0, and set mstatus.MPP to privilege_mode
379-
op and $mstatus.mpie csr_mstatus 0b1000
380-
op shl $mstatus.mpie $mstatus.mpie 4
405+
op and $mstatus.xpie csr_mstatus 0b1000
381406

382-
op shl $mstatus.mpp privilege_mode 11
407+
op shl $mstatus.xpp privilege_mode 11
383408

384409
op and csr_mstatus csr_mstatus 0b11111111111111111110011101110111
385-
op or csr_mstatus csr_mstatus $mstatus.mpie
386-
op or csr_mstatus csr_mstatus $mstatus.mpp
387410

388411
# set mcause
389412
write mcause {{CSRS}} "{{ 'mcause'|csr }}"
@@ -397,9 +420,22 @@ trap__no_breakpoint:
397420
# we only support direct mode, so set next_pc to mtvec
398421
read next_pc {{CSRS}} "{{ 'mtvec'|csr }}"
399422

400-
# medeleg and mideleg are not implemented, so always trap into M-mode
423+
# trap into M-mode
401424
set privilege_mode 0b11
402425

426+
common_trap:
427+
op shl $mstatus.xpie $mstatus.xpie 4
428+
op or csr_mstatus csr_mstatus $mstatus.xpie
429+
op or csr_mstatus csr_mstatus $mstatus.xpp
430+
431+
# check for breakpoints
432+
jump trap__breakpoint strictEqual pc breakpoint_address
433+
jump trap__no_breakpoint notEqual single_step_enabled true
434+
trap__breakpoint:
435+
set state "trap_breakpoint"
436+
stop
437+
trap__no_breakpoint:
438+
403439
# update effective_privilege_mode
404440
# tail call into end_instruction_trap so we don't update instret
405441
set ret {{# labels.end_instruction_trap }}
@@ -2385,11 +2421,11 @@ modify_csr__read__machine:
23852421
jump modify_csr__mstatus equal imm 0x300 # mstatus
23862422
jump modify_csr__readonly equal imm 0x301 # misa
23872423
jump modify_csr__readonly_zero equal imm 0x302 # medeleg
2388-
jump modify_csr__readonly_zero equal imm 0x303 # mideleg
2424+
jump modify_csr__mideleg equal imm 0x303 # mideleg
23892425
jump modify_csr__mie equal imm 0x304 # mie
23902426
jump modify_csr__readonly_zero equal imm 0x310 # mstatush
23912427
jump modify_csr__readonly_zero equal imm 0x312 # medelegh
2392-
jump modify_csr__xenvcfg equal imm 0x31a # menvcfgh
2428+
jump modify_csr__readonly_zero equal imm 0x31a # menvcfgh
23932429
jump modify_csr__readonly_zero equal imm 0x320 # mcountinhibit
23942430
jump ILLEGAL_OP equal imm 0x321 # mcyclecfg
23952431
jump modify_csr__mip equal imm 0x344 # mip
@@ -2415,7 +2451,7 @@ modify_csr__read__supervisor:
24152451
modify_csr__read__privileged:
24162452
# CSRs that use the same handler for supervisor- and machine-level
24172453
jump modify_csr__align_4B equal $csr_7_0 0x05 # xtvec
2418-
jump modify_csr__xenvcfg equal $csr_7_0 0x0a # xenvcfg
2454+
jump modify_csr__readonly_zero equal $csr_7_0 0x0a # xenvcfg
24192455
jump ILLEGAL_OP equal $csr_7_0 0x0c # xstateen0
24202456
jump modify_csr__align_4B equal $csr_7_0 0x41 # xepc
24212457

@@ -2441,7 +2477,7 @@ modify_csr__read__timers:
24412477
jump modify_csr__minstreth equal $csr_7_0 0x82 # minstreth
24422478

24432479
# hardwire all of the hpmcounter registers to 0
2444-
jump modify_csr__readonly_zero always
2480+
# continue into modify_csr__readonly_zero
24452481

24462482
modify_csr__readonly_zero:
24472483
#% do reset_locals(modify_csr_start)
@@ -2460,15 +2496,15 @@ modify_csr__align_4B:
24602496
op and $$new_value $$new_value 0xfffffffc
24612497
jump modify_csr__write always
24622498

2463-
modify_csr__xenvcfg:
2499+
modify_csr__mideleg:
24642500
#% do reset_locals(modify_csr_start)
24652501
#% do declare_locals(modify_csr_locals)
2466-
op add $$modify_csr_write @counter 1
2467-
set @counter $$modify_csr_op
2468-
2469-
# clear all bits except FIOM
2470-
op and $$new_value $$new_value 0b1
2471-
jump modify_csr__write always
2502+
# we always delegate supervisor interrupts to S-mode, so reflect that in mideleg
2503+
# SEIE -
2504+
# STIE -
2505+
# SSIE -
2506+
set rd 0b00000000000000000000001000100010
2507+
jump modify_csr__readonly always
24722508

24732509
modify_csr__sstatus:
24742510
#% do reset_locals(modify_csr_start)

0 commit comments

Comments
 (0)