summaryrefslogtreecommitdiff
path: root/rvcontroller.lua
diff options
context:
space:
mode:
authorcheapie <cheapiephp@gmail.com>2026-06-19 12:50:05 -0500
committercheapie <cheapiephp@gmail.com>2026-06-19 12:50:05 -0500
commitff0878bcd2744eeef0e875851ac9a98b9b067c7b (patch)
tree18c1daf1bdeea2a9b7538fcee55a27e09c657360 /rvcontroller.lua
parent9ae1b986e8461eabe43291fec51abbd4153f8e30 (diff)
downloadrvcontroller-ff0878bcd2744eeef0e875851ac9a98b9b067c7b.tar
rvcontroller-ff0878bcd2744eeef0e875851ac9a98b9b067c7b.tar.gz
rvcontroller-ff0878bcd2744eeef0e875851ac9a98b9b067c7b.tar.bz2
rvcontroller-ff0878bcd2744eeef0e875851ac9a98b9b067c7b.tar.xz
rvcontroller-ff0878bcd2744eeef0e875851ac9a98b9b067c7b.zip
Assorted trap improvements and add Smdbltrp extension
Diffstat (limited to 'rvcontroller.lua')
-rw-r--r--rvcontroller.lua79
1 files changed, 60 insertions, 19 deletions
diff --git a/rvcontroller.lua b/rvcontroller.lua
index 1acb1f1..37b09f5 100644
--- a/rvcontroller.lua
+++ b/rvcontroller.lua
@@ -50,6 +50,8 @@ Intended to be compliant with the following specifications:
* Zbkx: Extension for Crossbar permutations, Version 1.0.0
* Xh3bextm: Hazard3 bit extract multiple
- 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
+* "Smdbltrp" Double Trap Extension, Version 1.0
See https://docs.riscv.org/reference/isa/unpriv/unpriv-index.html for full specifications.
@@ -338,7 +340,7 @@ local function setreg(reg,val)
end
local function readram(address,bytes,instfetch)
- local bigendian = mem.bigendian and not instfetch --Instruction fetches must always be little-endian
+ local bigendian = mem.mbe and not instfetch --Instruction fetches must always be little-endian
if address > RAM_SIZE-1 and not (address >= mem.csr[0x801] and address <= mem.csr[0x801] + 1) then
fault = instfetch and 1 or 5
return instfetch and 0x13 or 0 --0x13 = addi x0,x0,0
@@ -401,7 +403,7 @@ local function writeram(address,data,bytes,fake)
local thisbyte = data % (2^((i+1)*8)) / 2^(i*8)
thisbyte = math.floor(thisbyte) % 2^32
local offsetaddr
- if mem.bigendian then
+ if mem.mbe then
offsetaddr = address+bytes-1-i
else
offsetaddr = address+i
@@ -492,7 +494,28 @@ local function stdout(text)
end
local function readcsr(address)
- if not mem.csr[address] then
+ if address == 0x341 then --mepc
+ local ret = mem.csr[0x341]
+ --mepc[0] must be 0
+ if ret%2 == 1 then ret = ret-1 end
+ --mepc[1] must be 0 if IALIGN=32
+ if not mem.isa.c and ret%4 >= 2 then
+ ret = ret - 2
+ end
+ return ret
+ elseif address == 0x300 then --mstatus
+ local bits = {}
+ bits[3] = mem.mie
+ bits[7] = mem.mpie
+ bits[11] = mem.mpp%2 == 1
+ bits[12] = mem.mpp >= 2
+ return implodebits(bits,32)
+ elseif address == 0x310 then --mstatush
+ local bits = {}
+ bits[5] = mem.mbe
+ bits[10] = mem.mdt
+ return implodebits(bits,32)
+ elseif not mem.csr[address] then
digiline_send("monitordisp",string.format("Attempted read\nfrom unknown\nCSR 0x%03X\nPC: %08X",address,mem.registers.pc))
fault = 2
return 0
@@ -505,16 +528,24 @@ local function writecsr(address,data)
--jvt
data = math.floor(data/2^6)*2^6 --WARL, and mode is required to be 0
elseif address == 0xc00 or address == 0xc01 or address == 0xc02 or address == 0xc80 or address == 0xc81 or address == 0xc82 then
- --One of the read-only CSRs from Zicntr, just ignore the write
+ --One of the read-only CSRs from Zicntr
+ fault = 2
return
- elseif address == 0xf11 or address == 0xf12 or address == 0xf13 or address == 0xf14 or address == 0xf15 or address == 0x300 then
- --Read-only machine information register, ignore write
+ elseif address == 0xf11 or address == 0xf12 or address == 0xf13 or address == 0xf14 or address == 0xf15 then
+ --Read-only machine information register
+ fault = 2
+ return
+ elseif address == 0x300 then
+ --mstatus
+ local bits = explodebits(data,32)
+ mem.mie = bits[3] and not mem.mdt
+ mem.mpie = bits[7]
return
elseif address == 0x310 then
--mstatush
local bits = explodebits(data,32)
- mem.bigendian = bits[5]
- mem.csr[0x310] = mem.bigendian and 0x20 or 0
+ mem.mbe = bits[5]
+ mem.mdt = bits[10]
return
elseif address == 0x301 then
--misa
@@ -556,7 +587,10 @@ local function trap(reason)
writecsr(0x342,reason) --mcause
writecsr(0x341,mem.registers.pc) --mepc
writecsr(0x343,0) --mtval
- if mem.trapbase then
+ mem.mpie = mem.mie
+ mem.mie = false
+ if not mem.mdt then
+ mem.mdt = 1
if mem.trapmode == 1 then
--vectored mode
local int = reason >= 0x8000000
@@ -569,7 +603,7 @@ local function trap(reason)
return true,false
end
else
- digiline_send("monitordisp","Unhandled trap!")
+ digiline_send("monitordisp","Unexpected trap!")
digiline_send("monitordisp",traptypes[reason] or "Unknown reason")
digiline_send("monitordisp",string.format("PC: %08X",mem.registers.pc))
digiline_send("monitordisp","System halted")
@@ -859,8 +893,8 @@ local operations = {
if rd == 0 or rd == 31 then return end
if imm >= 2^11 then imm = imm - 2^12 end
local address = getreg(rs1)+imm
- setreg(rd,readram(address+(mem.bigendian and 4 or 0),4))
- setreg(rd+1,readram(address+(mem.bigendian and 0 or 4),4))
+ setreg(rd,readram(address+(mem.mbe and 4 or 0),4))
+ setreg(rd+1,readram(address+(mem.mbe and 0 or 4),4))
end,
lhu = function(rd,rs1,imm)
if imm >= 2^11 then imm = imm - 2^12 end
@@ -888,8 +922,8 @@ local operations = {
if rs2 == 31 then return end
if imm >= 2^11 then imm = imm - 2^12 end
local address = getreg(rs1)+imm
- writeram(address+(mem.bigendian and 4 or 0),getreg(rs2),4)
- writeram(address+(mem.bigendian and 0 or 4),getreg(rs2+1),4)
+ writeram(address+(mem.mbe and 4 or 0),getreg(rs2),4)
+ writeram(address+(mem.mbe and 0 or 4),getreg(rs2+1),4)
end,
ecall = function()
local func = mem.isa.i and getreg(17) or getreg(15)
@@ -1787,6 +1821,10 @@ local operations = {
end,
mret = function()
mem.registers.pc = readcsr(0x341)
+ mem.mie = mem.mpie
+ mem.mpie = true
+ mem.mpp = 3
+ mem.mdt = false
return true
end,
}
@@ -2714,7 +2752,6 @@ if event.type == "program" or event.iid == "reset" then
[0x300] = 0, --mstatus
[0x301] = 0x40001107, --misa (RV32IMACB)
[0x305] = 0, --mtvec
- [0x310] = 0, --mstatush
[0x340] = 0, --mscratch
[0x341] = 0, --mepc
[0x342] = 0, --mcause
@@ -2737,7 +2774,7 @@ if event.type == "program" or event.iid == "reset" then
mem.breakpoint = -1
mem.hexloading = false
mem.reservationset = nil
- mem.bigendian = false
+ mem.mbe = false
mem.isa = {
a = true,
b = true,
@@ -2748,8 +2785,12 @@ if event.type == "program" or event.iid == "reset" then
mem.meseconsdir = {}
mem.meseconsdata = {}
port = {}
- mem.trapbase = nil
- mem.trapmode = nil
+ mem.trapbase = 0
+ mem.trapmode = 0
+ mem.mie = false
+ mem.mpie = true
+ mem.mpp = 3
+ mem.mdt = true
elseif event.type == "on" or event.type == "off" then
local pname = string.lower(event.pin.name)
local pstate = pin[pname]
@@ -2923,7 +2964,7 @@ elseif event.channel == "monitorkb" then
digiline_send("monitordisp",string.format("%03X: %08X",address,readcsr(address)))
elseif argv[1] == "endian" then
if argc == 1 then
- digiline_send("monitordisp",mem.bigendian and "Big-endian" or "Little-endian")
+ digiline_send("monitordisp",mem.mbe and "Big-endian" or "Little-endian")
elseif argv[2] == "b" or argv[2] == "big" then
local bits = explodebits(readcsr(0x310),32) --mstatush
bits[5] = true --MBE