summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--assembly/meseconsio/Makefile24
-rw-r--r--assembly/meseconsio/meseconsio.S30
-rwxr-xr-xassembly/meseconsio/meseconsio.elfbin0 -> 5348 bytes
-rw-r--r--assembly/meseconsio/meseconsio.hex7
-rw-r--r--assembly/meseconsio/meseconsio.obin0 -> 1192 bytes
l---------assembly/meseconsio/rvcontroller.ld1
-rw-r--r--rvcontroller.lua151
7 files changed, 197 insertions, 16 deletions
diff --git a/assembly/meseconsio/Makefile b/assembly/meseconsio/Makefile
new file mode 100644
index 0000000..786418a
--- /dev/null
+++ b/assembly/meseconsio/Makefile
@@ -0,0 +1,24 @@
+MARCH ?= rv32imacbzicntr_zicond_zicsr_zifencei_zihintpause_zilsd_zclsd_zabha_zacas_zawrs_zbkb_zbkx_zcb_zcmp_zcmt
+
+.PHONY: all dump load clean
+
+all: meseconsio.hex
+
+meseconsio.o: meseconsio.S
+ riscv32-none-elf-as -I../rvcontroller-libraries -march=${MARCH} -o meseconsio.o meseconsio.S
+
+meseconsio.elf: meseconsio.o
+ riscv32-none-elf-ld -T rvcontroller.ld --no-warn-rwx-segments -o meseconsio.elf meseconsio.o
+
+dump: meseconsio.elf
+ riscv32-none-elf-objdump -d meseconsio.elf
+
+meseconsio.hex: meseconsio.elf
+ riscv32-none-elf-objcopy -O ihex meseconsio.elf meseconsio.hex
+
+load: meseconsio.hex
+ bash -c "wl-copy < meseconsio.hex"
+
+clean:
+ rm -f meseconsio.bin meseconsio.elf meseconsio.o
+
diff --git a/assembly/meseconsio/meseconsio.S b/assembly/meseconsio/meseconsio.S
new file mode 100644
index 0000000..f2a441f
--- /dev/null
+++ b/assembly/meseconsio/meseconsio.S
@@ -0,0 +1,30 @@
+ li s0,0xffff0000
+ csrw 0x801,s0 # Set MMIO base address
+
+ li t0,0x7 # Pin D input, others output
+ sb t0,0(s0) # Write to mesecons I/O direction register
+
+start: lr.w x0,0(s0) # Establish a reservation set on the mesecons I/O region
+ wrs.nto # Wait for it to become invalid
+ lb t0,1(s0) # Read the mesecons I/O data
+ andi t1,t0,0x8 # Is pin D on?
+ beqz t1,start # If not, go wait again
+
+ li t0,1 # only A on
+ sb t0,1(s0)
+ pause
+ pause
+ pause
+ li t0,2 # only B on
+ sb t0,1(s0)
+ pause
+ pause
+ pause
+ li t0,4 # only C on
+ sb t0,1(s0)
+ pause
+ pause
+ pause
+ li t0,0 # all off
+ sb t0,1(s0)
+ j start
diff --git a/assembly/meseconsio/meseconsio.elf b/assembly/meseconsio/meseconsio.elf
new file mode 100755
index 0000000..09468fe
--- /dev/null
+++ b/assembly/meseconsio/meseconsio.elf
Binary files differ
diff --git a/assembly/meseconsio/meseconsio.hex b/assembly/meseconsio/meseconsio.hex
new file mode 100644
index 0000000..5feb581
--- /dev/null
+++ b/assembly/meseconsio/meseconsio.hex
@@ -0,0 +1,7 @@
+:100000004174731014809D42230054002F2004106B
+:100010007300D0008302140013F38200E30803FE90
+:100020008542A30054000F0000010F0000010F00E3
+:1000300000018942A30054000F0000010F000001DD
+:100040000F0000019142A30054000F0000010F00B7
+:0E00500000010F0000018142A300540045BFD3
+:00000001FF
diff --git a/assembly/meseconsio/meseconsio.o b/assembly/meseconsio/meseconsio.o
new file mode 100644
index 0000000..33ce2df
--- /dev/null
+++ b/assembly/meseconsio/meseconsio.o
Binary files differ
diff --git a/assembly/meseconsio/rvcontroller.ld b/assembly/meseconsio/rvcontroller.ld
new file mode 120000
index 0000000..bc01402
--- /dev/null
+++ b/assembly/meseconsio/rvcontroller.ld
@@ -0,0 +1 @@
+../../rvcontroller.ld \ No newline at end of file
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