summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcheapie <no-email-for-you@example.com>2026-05-25 13:24:01 -0500
committercheapie <no-email-for-you@example.com>2026-05-25 13:35:04 -0500
commit6ecdb461c1a823f9c2ff007457ee9963d7e1f681 (patch)
treebed9437c9e3e7cb17368c742c0fac5a544e3cb18
parentb319dda192819bf079d314441469787908d97606 (diff)
downloadrvcontroller-6ecdb461c1a823f9c2ff007457ee9963d7e1f681.tar
rvcontroller-6ecdb461c1a823f9c2ff007457ee9963d7e1f681.tar.gz
rvcontroller-6ecdb461c1a823f9c2ff007457ee9963d7e1f681.tar.bz2
rvcontroller-6ecdb461c1a823f9c2ff007457ee9963d7e1f681.tar.xz
rvcontroller-6ecdb461c1a823f9c2ff007457ee9963d7e1f681.zip
Add experimental big-endian support (via MBE bit in mstatush)
-rw-r--r--rvcontroller.lua29
1 files changed, 23 insertions, 6 deletions
diff --git a/rvcontroller.lua b/rvcontroller.lua
index a8d8915..d804f75 100644
--- a/rvcontroller.lua
+++ b/rvcontroller.lua
@@ -7,7 +7,7 @@
Emulated system specifications:
-Single RISC-V core, RV32IMACB_Zicntr_Zicond_Zicsr_Zifencei_Zihintpause_Zilsd_Zimop_Zabha_Zacas_Zalasr_Zawrs_Zcb_Zclsd_Zcmop_Zcmp_Zcmt_Zbkb_Zbkx instruction set, little-endian
+Single RISC-V core, RV32IMACBZicntr_Zicond_Zicsr_Zifencei_Zihintpause_Zilsd_Zimop_Zabha_Zacas_Zalasr_Zawrs_Zcb_Zclsd_Zcmop_Zcmp_Zcmt_Zbkb_Zbkx instruction set, switchable endianness (little-endian default)
65536 bytes of RAM (configurable in settings below) starting at base address 0
Intended to be compliant with the following specifications:
@@ -262,7 +262,8 @@ local function setreg(reg,val)
if reg ~= 0 then mem.registers[reg] = math.floor(val%(2^32)) end
end
-local function readram(address,bytes)
+local function readram(address,bytes,instfetch)
+ local bigendian = mem.bigendian and not instfetch --Instruction fetches must always be little-endian
if address > RAM_SIZE-1 then
digiline_send("monitordisp",string.format("Out-of-bounds\nmemory read\nAddress: %08X\nPC: %08X\nSystem halted",address,mem.registers.pc))
mem.running = false
@@ -270,7 +271,12 @@ local function readram(address,bytes)
end
local out = 0
for i=0,bytes-1 do
- local offsetaddr = address+i
+ local offsetaddr
+ if bigendian then
+ offsetaddr = address+bytes-1-i
+ else
+ offsetaddr = address+i
+ end
local segment = math.floor(offsetaddr/256)
local offset = offsetaddr%256
out = out + (string.byte(string.sub(mem.ram[segment],offset+1,offset+1)) or 0) * 2^(8*i)
@@ -298,7 +304,12 @@ local function writeram(address,data,bytes)
for i=0,bytes-1 do
local thisbyte = data % (2^((i+1)*8)) / 2^(i*8)
thisbyte = math.floor(thisbyte) % 2^32
- local offsetaddr = address+i
+ local offsetaddr
+ if mem.bigendian then
+ offsetaddr = address+bytes-1-i
+ else
+ offsetaddr = address+i
+ end
local segment = math.floor(offsetaddr/256)
local offset = offsetaddr%256
mem.ram[segment] = string.sub(mem.ram[segment],0,offset)..string.char(thisbyte)..string.sub(mem.ram[segment],offset+2,-1)
@@ -345,8 +356,13 @@ local function writecsr(address,data)
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
return
- elseif address == 0xf11 or address == 0xf12 or address == 0xf13 or address == 0xf14 or address == 0xf15 or address == 0x300 or address == 0x301 or address == 0x310 then
+ elseif address == 0xf11 or address == 0xf12 or address == 0xf13 or address == 0xf14 or address == 0xf15 or address == 0x300 or address == 0x301 then
--Read-only machine information register, ignore write
+ elseif address == 0x310 then
+ --mstatush
+ local bits = explodebits(data,32)
+ mem.bigendian = bits[5]
+ mem.csr[0x310] = mem.bigendian and 0x20 or 0
return
end
if not mem.csr[address] then
@@ -2310,7 +2326,7 @@ local function run(limit)
break
end
first = false
- local instruction = readram(mem.registers.pc,4)
+ local instruction = readram(mem.registers.pc,4,true)
if instruction%4 == 3 then
local jumped,stop = runinst(instruction)
if not jumped then mem.registers.pc = (mem.registers.pc + 4) % 2^32 end
@@ -2407,6 +2423,7 @@ if event.type == "program" or event.iid == "reset" then
mem.breakpoint = -1
mem.hexloading = false
mem.reservationset = nil
+ mem.bigendian = false
elseif event.channel == "reset" then
mem.running = false
digiline_send("monitordisp","\n\n\n\n\n\n\n")