diff options
| author | cheapie <cheapiephp@gmail.com> | 2026-06-06 12:42:38 -0500 |
|---|---|---|
| committer | cheapie <cheapiephp@gmail.com> | 2026-06-06 12:42:38 -0500 |
| commit | 95311ab84fb8ea6a5509aaa909be825c74e691ca (patch) | |
| tree | 35f4753c0961fe223a352f07662244e548bea059 /rvcontroller.lua | |
| parent | 2b1c27b2b6ae78a043ecae25603939c76d63956e (diff) | |
| download | rvcontroller-95311ab84fb8ea6a5509aaa909be825c74e691ca.tar rvcontroller-95311ab84fb8ea6a5509aaa909be825c74e691ca.tar.gz rvcontroller-95311ab84fb8ea6a5509aaa909be825c74e691ca.tar.bz2 rvcontroller-95311ab84fb8ea6a5509aaa909be825c74e691ca.tar.xz rvcontroller-95311ab84fb8ea6a5509aaa909be825c74e691ca.zip | |
Add (experimental for now) mesecons I/O support
Diffstat (limited to 'rvcontroller.lua')
| -rw-r--r-- | rvcontroller.lua | 151 |
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 |
