diff options
| author | cheapie <cheapiephp@gmail.com> | 2026-11-08 07:38:17 -0600 |
|---|---|---|
| committer | cheapie <cheapiephp@gmail.com> | 2026-11-08 07:38:17 -0600 |
| commit | f8cc0d73afe12cc1c8dd1600a28ff4634decf617 (patch) | |
| tree | 035cc4c5b466c98fb2940c48af79389d43ab4994 | |
| parent | 71729845170cdb4380f1ae42708638fdaee997cb (diff) | |
| download | rvcontroller-f8cc0d73afe12cc1c8dd1600a28ff4634decf617.tar rvcontroller-f8cc0d73afe12cc1c8dd1600a28ff4634decf617.tar.gz rvcontroller-f8cc0d73afe12cc1c8dd1600a28ff4634decf617.tar.bz2 rvcontroller-f8cc0d73afe12cc1c8dd1600a28ff4634decf617.tar.xz rvcontroller-f8cc0d73afe12cc1c8dd1600a28ff4634decf617.zip | |
Add Smrnmi
| -rw-r--r-- | assembly/crosswalk/crosswalk.S | 1 | ||||
| -rw-r--r-- | assembly/multitask/multitask.S | 1 | ||||
| -rw-r--r-- | assembly/rrxing2/rrxing2.S | 19 | ||||
| -rw-r--r-- | doc/_start_here.txt | 1 | ||||
| -rw-r--r-- | doc/csr.txt | 8 | ||||
| -rw-r--r-- | rvcontroller.lua | 58 |
6 files changed, 84 insertions, 4 deletions
diff --git a/assembly/crosswalk/crosswalk.S b/assembly/crosswalk/crosswalk.S index 86a0813..4baeaa8 100644 --- a/assembly/crosswalk/crosswalk.S +++ b/assembly/crosswalk/crosswalk.S @@ -1,3 +1,4 @@ +csrsi mnstatus,8 # Set NMIE so that interrupts can work (not actually setting up a real NMI handler) la t0,handler csrw mtvec,t0 # Set up trap handler li t0,0x400 diff --git a/assembly/multitask/multitask.S b/assembly/multitask/multitask.S index e46dd81..29df46c 100644 --- a/assembly/multitask/multitask.S +++ b/assembly/multitask/multitask.S @@ -1,3 +1,4 @@ +csrsi mnstatus,8 # Set NMIE so that interrupts can work (not actually setting up a real NMI handler) la t0,handler csrw mtvec,t0 # Set trap handler address and mode (0/direct) li t0,0x400 diff --git a/assembly/rrxing2/rrxing2.S b/assembly/rrxing2/rrxing2.S index c94edc0..bb2c4dc 100644 --- a/assembly/rrxing2/rrxing2.S +++ b/assembly/rrxing2/rrxing2.S @@ -8,6 +8,9 @@ j _start .include "util.S" _start: +la t0,nmihandler +csrw 0xbc0,t0 # Set up RNMI handler +csrsi mnstatus,8 # Turn on NMIE li t0,0x400 csrs mseccfg,t0 # Turn on MLPE (enable Zicfilp) li sp,0x10000 # Set up stack pointer @@ -187,6 +190,19 @@ ecall # Tell the user li a7,10 ecall # Then halt +.align 2 +nmihandler: +li a7,4 +la a0,uinmi +ecall # Display NMI message + +csrr a0,mncause # Read what the cause was +li a7,1 +ecall # Tell the user + +li a7,10 +ecall # Then halt + states: .word destate0,destate1,destate2,destate3,destate4,destate5,destate6,0,0,0,0,0,0,0,0,0 .word ukstate0,ukstate1,ukstate2,ukstate3,ukstate4,ukstate5,ukstate6,ukstate7,0,0,0,0,0,0,0,0 .word usstate0,usstate1,usstate2,usstate3,usstate4,0,0,0,0,0,0,0,0,0,0,0 @@ -364,7 +380,8 @@ activetime: .byte 15 extensiontime: .byte 25 traincounter: .word 0 -uiunimplementedtrap: .asciz "Unimplemented trap!\nmcause: " +uiunimplementedtrap: .asciz "\nUnimplemented trap!\nmcause: " +uinmi: .asciz "\nUnexpected NMI!\nmncause: " channelbuf: .skip 16 msgbuf: .skip 16 lightchannel: .asciz "light" diff --git a/doc/_start_here.txt b/doc/_start_here.txt index b9dc6d0..bf83857 100644 --- a/doc/_start_here.txt +++ b/doc/_start_here.txt @@ -89,6 +89,7 @@ RVController is intended to be compliant with the following specifications: - Note: Defined in the Hazard3 reference manual, available at https://github.com/Wren6991/Hazard3/releases/download/v1.1/hazard3.pdf * Machine-Level ISA, Version 1.13 * "Smcntrpmf" Cycle and Instret Privilege Mode Filtering, Version 1.0 +* "Smrnmi" Extension for Resumable Non-Maskable Interrupts, Version 1.0 * "Smdbltrp" Double Trap Extension, Version 1.0 For full specification text, visit https://docs.riscv.org/reference/home/index.html diff --git a/doc/csr.txt b/doc/csr.txt index 2e88f67..cb129b2 100644 --- a/doc/csr.txt +++ b/doc/csr.txt @@ -21,6 +21,10 @@ The following standard CSRs are available: * 0x34b: mtval2 * 0x721: mcyclecfgh * 0x722: minstretcfgh +* 0x740: mnscratch +* 0x741: mnepc +* 0x742: mncause +* 0x744: mnstatus * 0x747: mseccfg * 0xb00: mcycle * 0xb02: minstret @@ -76,6 +80,10 @@ the Address field selects the base address of the 256-byte MMIO region. When set to 0x00000000, MMIO is disabled. See mmio.txt for MMIO region contents. +0xbc0 - mnvec (RNMI Handler Address) + +Contains the address of the RNMI handler (see Smrnmi extension). Default is 0x8000. + 0xbf1 - h3.misa Stores enhanced ISA identification information, see the Hazard3 reference manual for more information: https://wren.wtf/hazard3/doc/#reg-h3.misa diff --git a/rvcontroller.lua b/rvcontroller.lua index c4e27d6..bf9877f 100644 --- a/rvcontroller.lua +++ b/rvcontroller.lua @@ -640,6 +640,13 @@ local function writecsr(address,data) elseif address == 0x722 then --minstretcfgh mem.instretminh = explodebits(data,32)[30] return + elseif address == 0x744 then --mnstatus + local oldbits = explodebits(mem.csr[0x744],32) + local newbits = explodebits(data,32) + oldbits[9] = newbits[9] + oldbits[3] = oldbits[3] or newbits[3] + mem.csr[0x744] = implodebits(oldbits,32) + return elseif address == 0xb00 or address == 0xb02 or address == 0xb80 or address == 0xb82 then --mcycle(h)/minstret(h) --Transform into cycle(h)/instret(h) (but allow the write) address = address + 0x100 @@ -710,6 +717,20 @@ local function writecsr(address,data) mem.csr[address] = data end +local function rnmi(reason) + mem.rnmi = true + local mnstatusbits = explodebits(mem.csr[0x744],32) + writecsr(0x741,mem.registers.pc) --mnepc + writecsr(0x742,reason) --mncause + mnstatusbits[11] = 1 --mnpp[0] + mnstatusbits[12] = 1 --mnpp[1] + mnstatusbits[9] = mem.elp --mnpelp + mem.elp = false + mnstatusbits[3] = false --nmie + mem.registers.pc = mem.csr[0xbc0] --mnvec + mem.csr[0x744] = implodebits(mnstatusbits,32) +end + local function trap(reason,val) if reason >= 0x8000000 then --Interrupt @@ -725,7 +746,7 @@ local function trap(reason,val) end end local oldreason = reason - if mem.mdt then + if mem.mdt and not mem.rnmi then writecsr(0x34b,reason) --mtval2 reason = 0x10 end @@ -753,8 +774,15 @@ local function trap(reason,val) mem.registers.pc = mem.trapbase return true,false end + elseif mem.csr[0x744]%16 >= 8 and not mem.rnmi then + rnmi(oldreason) + return true,false else - digiline_send("monitordisp","Unexpected trap!") + if mem.rnmi then + digiline_send("monitordisp","Trap during NMI!") + else + digiline_send("monitordisp","Unexpected trap!") + end if not mem.mtvecwritten then digiline_send("monitordisp",traptypes[oldreason] or "Unknown reason") if oldreason == 18 then @@ -783,6 +811,7 @@ local function trap(reason,val) end local function checkinterrupts() + local mnstatusbits = explodebits(mem.csr[0x744],32) local miebits = explodebits(mem.csr[0x304],32) local mipbits = explodebits(mem.csr[0x344],32) if mem.mtimecmphigh == mem.csr[0xc81] and (os.time() - mem.starttime) >= mem.mtimecmplow then @@ -794,6 +823,7 @@ local function checkinterrupts() end mem.csr[0x344] = implodebits(mipbits,32) if not mem.mie then return end + if not mnstatusbits[3] then return end --nmie local order = {11,3,7,9,1,5,13,16,17,18} for _,i in ipairs(order) do if miebits[i] and mipbits[i] then @@ -2062,6 +2092,15 @@ local operations = { checkinterrupts() return true end, + mnret = function() + mem.registers.pc = readcsr(0x741) + local mnstatusbits = explodebits(mem.csr[0x744],32) + mnstatusbits[3] = 1 --nmie + mem.elp = mem.mlpe and mnstatusbits[9] --mnpelp + mem.csr[0x741] = implodebits(mnstatusbits,32) + mem.rnmi = false + return true + end, wfi = function() mem.interruptwaiting = true mem.running = false @@ -2524,6 +2563,8 @@ local function runinst(instruction) return operations.wrssto() elseif imm == 0x302 and rd == 0 and rs1 == 0 then return operations.mret() + elseif imm == 0x702 and rd == 0 and rs1 == 0 then + return operations.mnret() elseif imm == 0x105 and rd == 0 and rs1 == 0 then return operations.wfi() else @@ -2820,7 +2861,7 @@ local function runinst(instruction) return trap(2,instruction) end else - trap(2,instruction) + return trap(2,instruction) end end @@ -3405,6 +3446,11 @@ local csraliases = { minstretcfg = 0x322, mcyclecfgh = 0x721, minstretcfgh = 0x722, + mnscratch = 0x740, + mnepc = 0x741, + mncause = 0x742, + mnstatus = 0x744, + mnvec = 0xbc0, } if event.type == "program" or event.iid == "reset" then @@ -3458,6 +3504,11 @@ if event.type == "program" or event.iid == "reset" then [0xc84] = 0, --hpmcounter4h [0xc85] = 0, --hpmcounter5h [0xc86] = 0, --hpmcounter6h + [0x740] = 0, --mnscratch + [0x741] = 0, --mnepc + [0x742] = 0, --mncause + [0x744] = 0, --mnstatus + [0xbc0] = 0x8000, --mnvec } for i=1,6 do mem.stdout[i] = "" end local mdisp = event.type == "program" and "\nReset: Cold" or "\nReset: Warm" @@ -3497,6 +3548,7 @@ if event.type == "program" or event.iid == "reset" then mem.mcountinhibit = {} mem.cycleminh = false mem.instretminh = false + mem.rnmi = false elseif event.type == "on" or event.type == "off" then local pname = string.lower(event.pin.name) local pstate = pin[pname] |
