summaryrefslogtreecommitdiff
path: root/rvcontroller.lua
diff options
context:
space:
mode:
Diffstat (limited to 'rvcontroller.lua')
-rw-r--r--rvcontroller.lua151
1 files changed, 135 insertions, 16 deletions
diff --git a/rvcontroller.lua b/rvcontroller.lua
index a9bcf3f..831d2d8 100644
--- a/rvcontroller.lua
+++ b/rvcontroller.lua
@@ -171,13 +171,31 @@ a3 - Size of the buffer that the message will be written into
Custom CSRs:
-0x800[0] = Lightweight mode, controls processor clock speed and behavior when mapblock is unloaded:
+0x800[0]: Lightweight mode, controls processor clock speed and behavior when mapblock is unloaded:
0: 10 Hz (adjustable in settings below), processor does not stop when mapblock is unloaded
1: 1 Hz, processor stops when mapblock is unloaded
Note that when set to 0, a digilines message being received will cause the processor to run for one cycle.
This is intended to be used to check if the digilines message needs action to be taken in response,
and the program can then turn lightweight mode off if so.
+0x801: MMIO Base Address (see MMIO section below)
+May be set to any address with no alignment restrictions.
+0 to disable, all other values enable.
+
+MMIO:
+
+Base address is selected by CSR 0x801 above.
+
+Base + 0: Mesecons I/O Direction
+Format: [0000dbca] (WARL)
+0 in the bit corresponding to an I/O pin selects input, 1 selects output.
+Changing a pin from output to input while the output is active may cause unusual behavior due to Luacontroller limitations.
+
+Base + 1: Mesecons I/O Data
+Format: [0000dbca] (Input bits are RO, output bits are RW)
+For inputs: Each bit contains the state of the corresponding input. Writes are ignored.
+For outputs: Each bit contains the state of the corresponding output. Writing to these bits turns the output on/off.
+
]]
--Settings
@@ -277,7 +295,7 @@ end
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
+ if address > RAM_SIZE-1 and not (address >= mem.csr[0x801] and address <= mem.csr[0x801] + 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
return 0
@@ -290,15 +308,37 @@ local function readram(address,bytes,instfetch)
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)
+ if offsetaddr == mem.csr[0x801] and mem.csr[0x801] ~= 0 then
+ --Mesecons I/O Direction
+ local bits = {[0] = mem.meseconsdir.a,mem.meseconsdir.b,mem.meseconsdir.c,mem.meseconsdir.d}
+ out = out + implodebits(bits,4)
+ elseif offsetaddr == mem.csr[0x801]+1 and mem.csr[0x801] ~= 0 then
+ --Mesecons I/O Data
+ local bits = {[0] = pin.a,pin.b,pin.c,pin.d}
+ if mem.meseconsdir.a then
+ bits[0] = mem.meseconsdata.a
+ end
+ if mem.meseconsdir.b then
+ bits[1] = mem.meseconsdata.b
+ end
+ if mem.meseconsdir.c then
+ bits[2] = mem.meseconsdata.c
+ end
+ if mem.meseconsdir.d then
+ bits[3] = mem.meseconsdata.d
+ end
+ out = out + implodebits(bits,4)
+ elseif offsetaddr < RAM_SIZE then
+ 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)
+ end
end
return out
end
-local function writeram(address,data,bytes)
- if address > RAM_SIZE-1 then
+local function writeram(address,data,bytes,fake)
+ if address > RAM_SIZE-1 and not fake and not (address >= mem.csr[0x801] and address <= mem.csr[0x801] + 1) then
digiline_send("monitordisp",string.format("Out-of-bounds\nmemory write\nAddress: %08X\nPC: %08X\nSystem halted",address,mem.registers.pc))
mem.running = false
return
@@ -314,6 +354,7 @@ local function writeram(address,data,bytes)
end
end
end
+ if fake then return end
for i=0,bytes-1 do
local thisbyte = data % (2^((i+1)*8)) / 2^(i*8)
thisbyte = math.floor(thisbyte) % 2^32
@@ -323,9 +364,63 @@ local function writeram(address,data,bytes)
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)
+ if offsetaddr == mem.csr[0x801] and mem.csr[0x801] ~= 0 then
+ --Mesecons I/O Direction
+ local bits = explodebits(data,8)
+ mem.meseconsdir = {
+ a = bits[0],
+ b = bits[1],
+ c = bits[2],
+ d = bits[3],
+ }
+ if not bits[0] then
+ port.a = false
+ mem.meseconsdata.a = pin.a
+ else
+ port.a = mem.meseconsdata.a
+ end
+ if not bits[1] then
+ port.b = false
+ mem.meseconsdata.b = pin.b
+ else
+ port.b = mem.meseconsdata.b
+ end
+ if not bits[2] then
+ port.c = false
+ mem.meseconsdata.c = pin.c
+ else
+ port.c = mem.meseconsdata.c
+ end
+ if not bits[3] then
+ port.d = false
+ mem.meseconsdata.d = pin.d
+ else
+ port.d = mem.meseconsdata.d
+ end
+ elseif offsetaddr == mem.csr[0x801] + 1 and mem.csr[0x801] ~= 0 then
+ --Mesecons I/O Data
+ local bits = explodebits(data,8)
+ if mem.meseconsdir.a then
+ mem.meseconsdata.a = bits[0]
+ port.a = bits[0]
+ end
+ if mem.meseconsdir.b then
+ mem.meseconsdata.b = bits[1]
+ port.b = bits[1]
+ end
+ if mem.meseconsdir.c then
+ mem.meseconsdata.c = bits[2]
+ port.c = bits[2]
+ end
+ if mem.meseconsdir.d then
+ mem.meseconsdata.d = bits[3]
+ port.d = bits[3]
+ end
+ elseif address < RAM_SIZE then
+ 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)
+ end
end
end
@@ -392,6 +487,15 @@ local function writecsr(address,data)
local newbits = {[0] = mem.isa.a,mem.isa.b,mem.isa.c,[4] = not mem.isa.i,[8] = mem.isa.i,[12] = mem.isa.m,[30] = true}
mem.csr[0x301] = implodebits(newbits,32)
return
+ elseif address == 0x801 then
+ --MMIO base address
+ local oldaddr = readcsr(0x801)
+ if oldaddr ~= 0 then writeram(oldaddr,0,1,true) end --Invalidate reservation set at old address
+ mem.csr[0x801] = data
+ if data ~= 0 then
+ writeram(data,0,1,true) --Invalidate reservation set at new address
+ end
+ return
end
if not mem.csr[address] then
digiline_send("monitordisp",string.format("W: Attempted write\nto unknown\nCSR 0x%03X\nPC: %08X",address,mem.registers.pc))
@@ -2440,7 +2544,8 @@ if event.type == "program" or event.iid == "reset" then
[0x300] = 0, --mstatus
[0x301] = 0x40001107, --misa (RV32IMACB)
[0x310] = 0, --mstatush
- [0x800] = 0, --Lightweight Mode
+ [0x800] = 0, --Clock Controls
+ [0x801] = 0, --MMIO Base Address
[0xc00] = 0, --CYCLE
[0xc01] = 0, --TIME
[0xc02] = 0, --INSTRET
@@ -2465,6 +2570,20 @@ if event.type == "program" or event.iid == "reset" then
i = true,
m = true,
}
+ mem.meseconsdir = {}
+ mem.meseconsdata = {}
+ port = {}
+elseif event.type == "on" or event.type == "off" then
+ local pname = string.lower(event.pin.name)
+ local pstate = pin[pname]
+ if not mem.meseconsdir[pname] then
+ --Pin is input
+ mem.meseconsdata[pname] = pstate
+ if readcsr(0x801) ~= 0 then
+ --MMIO is enabled
+ writeram(readcsr(0x801)+1,0,1,true) --Invalidate any existing reservation set
+ end
+ end
elseif event.channel == "reset" then
mem.running = false
digiline_send("monitordisp","\n\n\n\n\n\n\n")
@@ -2489,7 +2608,7 @@ elseif event.channel == "monitorkb" then
end
local argc = #argv
if argv[1] == "peek" then
- local address = validateandclamp(argv[2],0,RAM_SIZE-1)
+ local address = validateandclamp(argv[2],0,0xffffffff)
if not address then
digiline_send("monitordisp","Bad address")
return
@@ -2497,7 +2616,7 @@ elseif event.channel == "monitorkb" then
local data = readram(address,1)
digiline_send("monitordisp",string.format("%08X:%02X",address,data))
elseif argv[1] == "peekw" then
- local address = validateandclamp(argv[2],0,RAM_SIZE-1)
+ local address = validateandclamp(argv[2],0,0xffffffff)
if not address then
digiline_send("monitordisp","Bad address")
return
@@ -2505,7 +2624,7 @@ elseif event.channel == "monitorkb" then
local data = readram(address,4)
digiline_send("monitordisp",string.format("%08X:%08X",address,data))
elseif argv[1] == "poke" then
- local address = validateandclamp(argv[2],0,RAM_SIZE-1)
+ local address = validateandclamp(argv[2],0,0xffffffff)
if not address then
digiline_send("monitordisp","Bad address")
return
@@ -2518,7 +2637,7 @@ elseif event.channel == "monitorkb" then
writeram(address,data,1)
digiline_send("monitordisp",string.format("%08X:%02X",address,data))
elseif argv[1] == "pokew" then
- local address = validateandclamp(argv[2],0,RAM_SIZE-1)
+ local address = validateandclamp(argv[2],0,0xffffffff)
if not address then
digiline_send("monitordisp","Bad address")
return
@@ -2617,7 +2736,7 @@ elseif event.channel == "monitorkb" then
digiline_send("monitordisp","Bad CSR address")
return
end
- local data = validateandclamp(argv[3],0,0xfff)
+ local data = validateandclamp(argv[3],0,0xffffffff)
if not data then
digiline_send("monitordisp","Bad data")
return