From f8cc0d73afe12cc1c8dd1600a28ff4634decf617 Mon Sep 17 00:00:00 2001 From: cheapie Date: Sun, 8 Nov 2026 07:38:17 -0600 Subject: Add Smrnmi --- rvcontroller.lua | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-) (limited to 'rvcontroller.lua') 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] -- cgit v1.2.3