summaryrefslogtreecommitdiff
path: root/rvcontroller.lua
diff options
context:
space:
mode:
Diffstat (limited to 'rvcontroller.lua')
-rw-r--r--rvcontroller.lua58
1 files changed, 55 insertions, 3 deletions
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]