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
214217main:
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
370403trap:
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:
24152451modify_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
24462482modify_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
24732509modify_csr__sstatus:
24742510#% do reset_locals(modify_csr_start)
0 commit comments