--RVController
--A product of Advanced Mesecons Devices, a Cheapie Systems company
--This is free and unencumbered software released into the public domain.
--See http://unlicense.org/ for more information
--[[
Emulated system specifications:
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:
* RV32I Base Integer Instruction Set, Version 2.1
* "Zifencei" Extension for Instruction-Fetch Fence, Version 2.0
- Note: Implemented as a 'nop' instruction as memory is always consistent (see note on RVWMO below)
* "Zicsr" Extension for Control and Status Register (CSR) Instructions, Version 2.0
* "Zicond" Extension for Integer Conditional Operations, Version 1.0.0
* "Zicntr" Extension for Counters, Version 2.0
* "Zimop" Extension for May-Be-Operations, Version 1.0
* "M" Extension for Integer Multiplication and Division, Version 2.0
- Note: This implies the following:
- * Zmmul Extension, Version 1.0
* "A" Extension for Atomic Instructions, Version 2.1
- Note: This implies the following:
- * "Zalrsc" Extension for Load-Reserved/Store-Conditional Instructions
- * "Zaamo" Extension for Atomic Memory Operations
* RVWMO Memory Consistency Model, Version 2.0
- Note: The actual implemented memory model is significantly more strict (memory is always consistent, there is no cache)
* "Ztso" Extension for Total Store Ordering, Version 1.0
* "C" Extension for Compressed Instructions, Version 2.0
- Note: This implies the following:
- * "Zca" Extension for Code Size Reduction, Version 1.0.0
* Zcb: Extension for Code Size Reduction, Version 1.0.0
* "Zcmop" Compressed May-Be-Operations Extension, Version 1.0
* Zcmp: Extension for Code Size Reduction, Version 1.0.0
* Zcmt: Extension for Code Size Reduction, Version 1.0.0
* "B" Extension for Bit Manipulation, Version 1.0.0
- Note: This implies the following:
- * Zba: Extension for Address generation, Version 1.0.0
- * Zbb: Extension for Basic bit-manipulation, Version 1.0.0
- * Zbs: Extension for Single-bit instructions, Version 1.0.0
* "Zihintpause" Extension for Pause Hint, Version 2.0
* Zilsd, Zclsd: Extensions for Load/Store pair for RV32, Version 1.0
* "Zabha" Extension for Byte and Halfword Atomic Memory Operations, Version 1.0
* "Zacas" Extension for Atomic Compare-and-Swap (CAS) Instructions, Version 1.0.0
* "Zalasr" Atomic Load-Acquire and Store-Release Instructions, Version 1.0
* "Zawrs" Extension for Wait-on-Reservation-Set instructions, Version 1.01
* Zbkb: Extension for Bit-manipulation for Cryptography, Version 1.0.0
* Zbkx: Extension for Crossbar permutations, Version 1.0.0
See https://docs.riscv.org/reference/isa/unpriv/unpriv-index.html for full specifications.
Monitor commands:
peek
Reads and displays the byte (8 bits) value from RAM at the specified address
poke
Writes the specified byte (8 bits) value to RAM at the specified address
peekw
Reads and displays the word (32 bits) value from RAM starting at the specified address
pokew
Writes the specified word (32 bits) value to RAM starting at the specified address
getreg
Displays the current value of the specified register number (0-31)
setreg
Sets the specified register (0-31) to the specified value
getpc
Displays the current value of the program counter
setpc
Sets the program counter to the specified value
reset
Stops the CPU, resets all registers to zero, and clears all RAM
step
Allows the CPU to run for one instruction, then halts
run
Allows the CPU to run indefinitely
stop
Halts the CPU
setbreak
Sets a breakpoint on the specified address.
Note that the breakpoint triggers just *before* the instruction fetch,
as in the instruction with the breakpoint on it will not have executed yet.
There can only be one breakpoint at a time. If one is already set, the new one will replace it.
clearbreak
Clears any set breakpoint. Note that an ebreak instruction will still cause a break.
help [command]
Shows information on a monitor command, or a list of commands if none is specified
ecall operations:
a7 = 1
Prints the integer value from register a0
a7 = 4
Prints the null-terminated string from the address specified by register a0
a7 = 5
Reads an integer from the console and stores it into register a0
This will block until the user enters a valid number
a7 = 8
Reads a string from the console and stores it (with a null terminator) into the address pointed to by register a0
Will not read more than the length specified in register a1, anything more is discarded
This will block until the user types something
a7 = 10
Exits the program (halts the CPU)
a7 = 11
Prints the character stored in the register a0
a7 = 12
Reads one character from the console (any more characters on the line are discarded) and stores it into register a0
a7 = 128
Gets a random integer (between the values in registers a0 and a1) and stores it into register a0
a7 = 129
Sends a digilines string message:
* channel is specified by the null-terminated string at the address specified by register a0
* message is specified by the null-terminated string at the address specified by register a1
a7 = 130
Gets the number of characters available to read from the console input buffer
Result is stored in register a0
a7 = 131
Clears the console input buffer
a7 = 132
Reads one character from the console input buffer and stores it into register a0
This will not block - if no data is available to read, a NUL character (0) is returned
The input buffer can store up to 256 characters - if full, incoming characters are dropped
a7 = 133
Gets the number of messages in the digilines receive buffer
Result is stored in register a0
a7 = 134
Clears the digilines receive buffer
a7 = 135
Reads one message from the digilines receive buffer, returns channel and message as null-terminated strings
This will not block - if no data is available to read, zero-length strings will be returned
Arguments:
a0 - Address that the channel string will be written to
a1 - Size of the buffer that the channel string will be written into
a2 - Address that the message will be written to
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:
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.
]]
--Settings
local RAM_SIZE = 0x10000 --RAM size in bytes, must be a multiple of 256
local CLOCK_SPEED = 20 --Clock speed in Hz when not in lightweight mode
local INSTRUCTIONS_PER_CLOCK = 50 --Maximum number of instructions that will be run on each clock cycle
local STDOUT_TO_TERMINAL = false --Whether to show standard output on the Luacontroller terminal in addition to the screen
local function implodebits(bits,count,signed)
local negative = false
if signed then
negative = bits[count-1]
end
local out = 0
for i=0,count-1 do
if bits[i] then out = out + (2^i) end
end
if negative then out = out - (2^count) end
return out
end
local function explodebits(num,count)
num = num%(2^count)
if num < 0 then
num = num + (2^count)
end
local out = {}
for i=0,count-1 do
out[i] = num%(2^(i+1)) >= 2^i
end
return out
end
local function signextend(bits,fromcount,tocount)
for i=fromcount,tocount-1 do
bits[i] = bits[fromcount-1]
end
end
local function mul64(a,b,asigned,bsigned)
--If in signed mode and the number is too big to be positive, make it negative
if asigned and a >= 2^31 then a = a - 2^32 end
if bsigned and b >= 2^31 then b = b - 2^32 end
--Break 32-bit arguments into 16-bit pieces
local alow = a%2^16
local ahigh = math.floor(a/2^16)
local blow = b%2^16
local bhigh = math.floor(b/2^16)
--Multiply 16x16-bit numbers to get 32-bit partial products
local pp1 = alow*blow
local pp2 = alow*bhigh
local pp3 = ahigh*blow
local pp4 = ahigh*bhigh
--Split the two partial products that will straddle the 32-bit boundary
local pp2low = pp2%2^16
local pp2high = math.floor(pp2/2^16)
local pp3low = pp3%2^16
local pp3high = math.floor(pp3/2^16)
--And give them the proper 16-bit shift
pp2low = pp2low*2^16
pp3low = pp3low*2^16
--Sum the lower partial products into a 34-bit value
local lowresult = pp1+pp2low+pp3low
--Split the upper 2 bits off into a carry value
local carry = math.floor(lowresult/2^32)
lowresult = lowresult%2^32
--Sum the upper partial products and carry
local highresult = carry+pp2high+pp3high+pp4
return lowresult,highresult
end
local function getreg(reg)
return reg == 0 and 0 or mem.registers[reg]
end
local function setreg(reg,val)
if val < 0 then val = val + (2^32) end
if reg ~= 0 then mem.registers[reg] = math.floor(val%(2^32)) end
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
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
end
local out = 0
for i=0,bytes-1 do
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)
end
return out
end
local function writeram(address,data,bytes)
if address > RAM_SIZE-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
end
if mem.reservationset then
if mem.reservationset + 4 >= address and mem.reservationset <= address+bytes-1 then
mem.reservationset = nil
if mem.rswaiting then
if mem.rswaiting == "nto" then digiline_send("monitordisp","CPU started") end
mem.rswaiting = false
mem.running = true
interrupt(0,"tick")
end
end
end
for i=0,bytes-1 do
local thisbyte = data % (2^((i+1)*8)) / 2^(i*8)
thisbyte = math.floor(thisbyte) % 2^32
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)
end
end
local stdoutdirty = false
local function scrollstdout(lines)
lines = lines or 1
for i=1,lines do
table.remove(mem.stdout,1)
mem.stdout[6] = ""
end
end
local function stdout(text)
if string.len(text) == 0 then return end
if STDOUT_TO_TERMINAL then print(text) end
stdoutdirty = true
for i=1,string.len(text) do
local thischar = string.sub(text,i,i)
if string.len(mem.stdout[6]) == 20 or thischar == "\n" then
scrollstdout(1)
if thischar ~= "\n" then mem.stdout[6] = mem.stdout[6]..thischar end
elseif thischar ~= string.char(0) then
mem.stdout[6] = mem.stdout[6]..thischar
end
end
end
local function readcsr(address)
if not mem.csr[address] then
digiline_send("monitordisp",string.format("W: Attempted read\nfrom unknown\nCSR 0x%03X\nPC: %08X",address,mem.registers.pc))
return 0
end
return mem.csr[address]
end
local function writecsr(address,data)
if address == 0x17 then
--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
return
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
digiline_send("monitordisp",string.format("W: Attempted write\nto unknown\nCSR 0x%03X\nPC: %08X",address,mem.registers.pc))
return
end
mem.csr[address] = data
end
local cmpushpopreglists = {
[4] = {registers = {1},stack = 16},
[5] = {registers = {1,8},stack = 16},
[6] = {registers = {1,8,9},stack = 16},
[7] = {registers = {1,8,9,18},stack = 16},
[8] = {registers = {1,8,9,18,19},stack = 32},
[9] = {registers = {1,8,9,18,19,20},stack = 32},
[10] = {registers = {1,8,9,18,19,20,21},stack = 32},
[11] = {registers = {1,8,9,18,19,20,21,22},stack = 32},
[12] = {registers = {1,8,9,18,19,20,21,22,23},stack = 48},
[13] = {registers = {1,8,9,18,19,20,21,22,23,24},stack = 48},
[14] = {registers = {1,8,9,18,19,20,21,22,23,24,25},stack = 48},
[15] = {registers = {1,8,9,18,19,20,21,22,23,24,25,26,27},stack = 64},
}
local operations = {
add = function(rd,rs1,rs2)
setreg(rd,getreg(rs1)+getreg(rs2))
end,
sub = function(rd,rs1,rs2)
setreg(rd,getreg(rs1)-getreg(rs2))
end,
xor = function(rd,rs1,rs2)
local rs1bits = explodebits(getreg(rs1),32)
local rs2bits = explodebits(getreg(rs2),32)
local rdbits = {}
for i=0,31 do rdbits[i] = rs1bits[i] ~= rs2bits[i] end
setreg(rd,implodebits(rdbits,32,false))
end,
orr = function(rd,rs1,rs2) --instruction is "or" but that's a reserved word
local rs1bits = explodebits(getreg(rs1),32)
local rs2bits = explodebits(getreg(rs2),32)
local rdbits = {}
for i=0,31 do rdbits[i] = rs1bits[i] or rs2bits[i] end
setreg(rd,implodebits(rdbits,32,false))
end,
andr = function(rd,rs1,rs2) --instruction is "and" but that's a reserved word
local rs1bits = explodebits(getreg(rs1),32)
local rs2bits = explodebits(getreg(rs2),32)
local rdbits = {}
for i=0,31 do rdbits[i] = rs1bits[i] and rs2bits[i] end
setreg(rd,implodebits(rdbits,32,false))
end,
xnor = function(rd,rs1,rs2)
local rs1bits = explodebits(getreg(rs1),32)
local rs2bits = explodebits(getreg(rs2),32)
local rdbits = {}
for i=0,31 do rdbits[i] = rs1bits[i] == rs2bits[i] end
setreg(rd,implodebits(rdbits,32,false))
end,
orn = function(rd,rs1,rs2)
local rs1bits = explodebits(getreg(rs1),32)
local rs2bits = explodebits(getreg(rs2),32)
local rdbits = {}
for i=0,31 do rdbits[i] = rs1bits[i] or not rs2bits[i] end
setreg(rd,implodebits(rdbits,32,false))
end,
andn = function(rd,rs1,rs2)
local rs1bits = explodebits(getreg(rs1),32)
local rs2bits = explodebits(getreg(rs2),32)
local rdbits = {}
for i=0,31 do rdbits[i] = rs1bits[i] and not rs2bits[i] end
setreg(rd,implodebits(rdbits,32,false))
end,
sll = function(rd,rs1,rs2)
setreg(rd,getreg(rs1)*(2^(getreg(rs2)%2^5)))
end,
srl = function(rd,rs1,rs2)
setreg(rd,getreg(rs1)/(2^(getreg(rs2)%2^5)))
end,
sra = function(rd,rs1,rs2)
local num = getreg(rs1)
local amount = getreg(rs2)%2^5
local sign = num>=(2^31)
if amount == 0 then return end
for _=1,amount do
num = num/2
if sign then num = num+(2^31) end
end
setreg(rd,num)
end,
slt = function(rd,rs1,rs2)
local num1 = getreg(rs1)
local num2 = getreg(rs2)
if num1 >= 2^31 then num1 = num1-(2^32) end
if num2 >= 2^31 then num2 = num2-(2^32) end
setreg(rd,num1 < num2 and 1 or 0)
end,
sltu = function(rd,rs1,rs2)
local num1 = getreg(rs1)
local num2 = getreg(rs2)
setreg(rd,num1 < num2 and 1 or 0)
end,
addi = function(rd,rs1,imm)
local immbits = explodebits(imm,12)
signextend(immbits,12,32)
imm = implodebits(immbits,32,false)
setreg(rd,getreg(rs1)+imm)
end,
xori = function(rd,rs1,imm)
local rs1bits = explodebits(getreg(rs1),32)
local immbits = explodebits(imm,12)
signextend(immbits,12,32)
local rdbits = {}
for i=0,31 do
rdbits[i] = rs1bits[i] ~= immbits[i]
end
setreg(rd,implodebits(rdbits,32,false))
end,
ori = function(rd,rs1,imm)
local rs1bits = explodebits(getreg(rs1),32)
local immbits = explodebits(imm,12)
signextend(immbits,12,32)
local rdbits = {}
for i=0,31 do
rdbits[i] = rs1bits[i] or immbits[i]
end
setreg(rd,implodebits(rdbits,32,false))
end,
andi = function(rd,rs1,imm)
local rs1bits = explodebits(getreg(rs1),32)
local immbits = explodebits(imm,12)
signextend(immbits,12,32)
local rdbits = {}
for i=0,31 do
rdbits[i] = rs1bits[i] and immbits[i]
end
setreg(rd,implodebits(rdbits,32,false))
end,
slli = function(rd,rs1,imm)
setreg(rd,getreg(rs1)*(2^imm))
end,
srli = function(rd,rs1,imm)
setreg(rd,getreg(rs1)/(2^imm))
end,
srai = function(rd,rs1,imm)
local num = getreg(rs1)
local sign = num>=(2^31)
if imm == 0 then return end
for _=1,imm do
num = num/2
if sign then num = num+(2^31) end
end
setreg(rd,num)
end,
slti = function(rd,rs1,imm)
local num1 = getreg(rs1)
local immbits = explodebits(imm,12)
signextend(immbits,12,32)
local num2 = implodebits(immbits,32,false)
if num1 >= 2^31 then num1 = num1-(2^32) end
if num2 >= 2^31 then num2 = num2-(2^32) end
setreg(rd,num1 < num2 and 1 or 0)
end,
sltiu = function(rd,rs1,imm)
local num1 = getreg(rs1)
local immbits = explodebits(imm,12)
signextend(immbits,12,32)
local num2 = implodebits(immbits,32,false)
setreg(rd,num1 < num2 and 1 or 0)
end,
beq = function(rs1,rs2,imm)
local num1 = getreg(rs1)
local num2 = getreg(rs2)
if num1 == num2 then
local immbits = explodebits(imm,13)
signextend(immbits,13,32)
imm = implodebits(immbits,13,true)
mem.registers.pc = (mem.registers.pc + imm) % 2^32
return true
end
end,
bne = function(rs1,rs2,imm)
local num1 = getreg(rs1)
local num2 = getreg(rs2)
if num1 ~= num2 then
local immbits = explodebits(imm,13)
signextend(immbits,13,32)
imm = implodebits(immbits,13,true)
mem.registers.pc = (mem.registers.pc + imm) % 2^32
return true
end
end,
blt = function(rs1,rs2,imm)
local num1 = getreg(rs1)
local num2 = getreg(rs2)
if num1 >= 2^31 then num1 = num1-(2^32) end
if num2 >= 2^31 then num2 = num2-(2^32) end
if num1 < num2 then
local immbits = explodebits(imm,13)
signextend(immbits,13,32)
imm = implodebits(immbits,13,true)
mem.registers.pc = (mem.registers.pc + imm) % 2^32
return true
end
end,
bge = function(rs1,rs2,imm)
local num1 = getreg(rs1)
local num2 = getreg(rs2)
if num1 >= 2^31 then num1 = num1-(2^32) end
if num2 >= 2^31 then num2 = num2-(2^32) end
if num1 >= num2 then
local immbits = explodebits(imm,13)
signextend(immbits,13,32)
imm = implodebits(immbits,13,true)
mem.registers.pc = (mem.registers.pc + imm) % 2^32
return true
end
end,
bltu = function(rs1,rs2,imm)
local num1 = getreg(rs1)
local num2 = getreg(rs2)
if num1 < num2 then
local immbits = explodebits(imm,13)
signextend(immbits,13,32)
imm = implodebits(immbits,13,true)
mem.registers.pc = (mem.registers.pc + imm) % 2^32
return true
end
end,
bgeu = function(rs1,rs2,imm)
local num1 = getreg(rs1)
local num2 = getreg(rs2)
if num1 >= num2 then
local immbits = explodebits(imm,13)
signextend(immbits,13,32)
imm = implodebits(immbits,13,true)
mem.registers.pc = (mem.registers.pc + imm) % 2^32
return true
end
end,
jal = function(rd,imm,compressed)
setreg(rd,mem.registers.pc+(compressed and 2 or 4))
local immbits = explodebits(imm,21)
signextend(immbits,21,32)
imm = implodebits(immbits,32,true)
local oldpc = mem.registers.pc
mem.registers.pc = (mem.registers.pc + imm) % 2^32
return true
end,
jalr = function(rd,rs1,imm,compressed)
local oldpc = mem.registers.pc
local immbits = explodebits(imm,12)
signextend(immbits,12,32)
imm = implodebits(immbits,32,true)
mem.registers.pc = (getreg(rs1) + imm) % 2^32
if mem.registers.pc%2 == 1 then mem.registers.pc = mem.registers.pc - 1 end
setreg(rd,oldpc+(compressed and 2 or 4))
return true
end,
lui = function(rd,imm)
setreg(rd,imm)
end,
auipc = function(rd,imm)
setreg(rd,mem.registers.pc+imm)
end,
lb = function(rd,rs1,imm)
if imm >= 2^11 then imm = imm - 2^12 end
local data = readram(getreg(rs1)+imm,1)
data = explodebits(data,8)
signextend(data,8,32)
data = implodebits(data,32,false)
setreg(rd,data)
end,
lh = function(rd,rs1,imm)
if imm >= 2^11 then imm = imm - 2^12 end
local data = readram(getreg(rs1)+imm,2)
data = explodebits(data,16)
signextend(data,16,32)
data = implodebits(data,32,false)
setreg(rd,data)
end,
lw = function(rd,rs1,imm)
if imm >= 2^11 then imm = imm - 2^12 end
local data = readram(getreg(rs1)+imm,4)
setreg(rd,data)
end,
ld = function(rd,rs1,imm)
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,4))
setreg(rd+1,readram(address+4,4))
end,
lhu = function(rd,rs1,imm)
if imm >= 2^11 then imm = imm - 2^12 end
local data = readram(getreg(rs1)+imm,2)
setreg(rd,data)
end,
lbu = function(rd,rs1,imm)
if imm >= 2^11 then imm = imm - 2^12 end
local data = readram(getreg(rs1)+imm,1)
setreg(rd,data)
end,
sb = function(rs1,rs2,imm)
if imm >= 2^11 then imm = imm - 2^12 end
writeram(getreg(rs1)+imm,getreg(rs2)%0x100,1)
end,
sh = function(rs1,rs2,imm)
if imm >= 2^11 then imm = imm - 2^12 end
writeram(getreg(rs1)+imm,getreg(rs2)%0x10000,2)
end,
sw = function(rs1,rs2,imm)
if imm >= 2^11 then imm = imm - 2^12 end
writeram(getreg(rs1)+imm,getreg(rs2),4)
end,
sd = function(rs1,rs2,imm)
if rs2 == 31 then return end
if imm >= 2^11 then imm = imm - 2^12 end
local address = getreg(rs1)+imm
writeram(address,getreg(rs2),4)
writeram(address+4,getreg(rs2+1),4)
end,
ecall = function()
local func = getreg(17)
local param1 = getreg(10)
local param2 = getreg(11)
if func == 1 then
--a7=1 - Print Integer
if param1 > 2^31 then param1 = param1-2^32 end
stdout(string.format("%d",param1))
elseif func == 4 then
--a7=4 - Print String
local str = ""
for i=0,255 do
local byte = readram(param1+i,1)
if byte == 0 then break end
str = str..string.char(byte)
end
stdout(str)
elseif func == 5 then
--a7=5 - Read Integer
digiline_send("monitordisp","Waiting for input")
mem.running = false
mem.inputwaiting = true
mem.inputwaittype = "integer"
return false,true
elseif func == 8 then
--a7=8 - Read String
digiline_send("monitordisp","Waiting for input")
mem.running = false
mem.inputwaiting = true
mem.inputwaittype = "string"
mem.inputaddr = getreg(10)
mem.inputmax = getreg(11)
return false,true
elseif func == 10 then
--a7=10 - Exit Program
mem.running = false
digiline_send("monitordisp","Program\nexited normally")
digiline_send("monitordisp","System halted")
digiline_send("monitordisp",string.format("PC:%08X",mem.registers.pc))
elseif func == 11 then
--a7=11 - Print Character
stdout(string.char(getreg(10)))
elseif func == 12 then
--a7=12 - Read Character
digiline_send("monitordisp","Waiting for input")
mem.running = false
mem.inputwaiting = true
mem.inputwaittype = "char"
return false,true
elseif func == 128 then
--a7=128 - Get Random Integer
local lowlimit = getreg(10)
local highlimit = getreg(11)
if lowlimit >= 2^31 then lowlimit = lowlimit - 2^32 end
if highlimit >= 2^31 then highlimit = highlimit - 2^32 end
local result = math.random(lowlimit,highlimit)
if result < 0 then result = result + 2^32 end
setreg(10,result)
elseif func == 129 then
--a7=129 - Send digilines string message
local channel = ""
for i=0,255 do
local byte = readram(param1+i,1)
if byte == 0 then break end
channel = channel..string.char(byte)
end
local message = ""
for i=0,255 do
local byte = readram(param2+i,1)
if byte == 0 then break end
message = message..string.char(byte)
end
digiline_send(channel,message)
elseif func == 130 then
--a7=130 - Get Input Buffer Level
setreg(10,string.len(mem.inputbuf))
elseif func == 131 then
--a7=131 - Clear Input Buffer
mem.inputbuf = ""
elseif func == 132 then
--a7=132 -- Read Character From Input Buffer
if mem.inputbuf == "" then
setreg(10,0)
else
setreg(10,string.byte(string.sub(mem.inputbuf,1,1)))
mem.inputbuf = string.sub(mem.inputbuf,2,-1)
end
elseif func == 133 then
--a7=133 - Get Digilines Buffer Level
setreg(10,#mem.digilinesqueue)
elseif func == 134 then
--a7=134 - Clear Digilines Buffer
mem.digilinesqueue = {}
elseif func == 135 then
--a7=135 - Read Digilines Message
local dlevent = mem.digilinesqueue[1]
if not dlevent then dlevent = {channel = "",msg = ""} end
dlevent.channel = string.sub(dlevent.channel,1,getreg(11)-1).."\0"
dlevent.msg = string.sub(dlevent.msg,1,getreg(13)-1).."\0"
local channelstart = getreg(10)
for i=1,string.len(dlevent.channel) do
local address = channelstart+i-1
writeram(address,string.byte(string.sub(dlevent.channel,i,i)),1)
end
local msgstart = getreg(12)
for i=1,string.len(dlevent.msg) do
local address = msgstart+i-1
writeram(address,string.byte(string.sub(dlevent.msg,i,i)),1)
end
table.remove(mem.digilinesqueue,1)
end
end,
ebreak = function()
mem.running = false
digiline_send("monitordisp","Hit breakpoint")
digiline_send("montiordisp","System halted")
digiline_send("monitordisp",string.format("PC:%08X",mem.registers.pc))
end,
csrrw = function(rd,rs1,imm)
setreg(rd,readcsr(imm))
writecsr(imm,getreg(rs1))
end,
csrrs = function(rd,rs1,imm)
setreg(rd,readcsr(imm))
if rs1 == 0 then return end
local csrbits = explodebits(readcsr(imm),32)
local rs1bits = explodebits(getreg(rs1),32)
for i=0,31 do
csrbits[i] = csrbits[i] or rs1bits[i]
end
writecsr(imm,implodebits(csrbits,32))
end,
csrrc = function(rd,rs1,imm)
setreg(rd,readcsr(imm))
if rs1 == 0 then return end
local csrbits = explodebits(readcsr(imm),32)
local rs1bits = explodebits(getreg(rs1),32)
for i=0,31 do
csrbits[i] = csrbits[i] and not rs1bits[i]
end
writecsr(imm,implodebits(csrbits,32))
end,
csrrwi = function(rd,rs1,imm)
setreg(rd,readcsr(imm))
writecsr(imm,rs1)
end,
csrrsi = function(rd,rs1,imm)
setreg(rd,readcsr(imm))
if rs1 == 0 then return end
local csrbits = explodebits(readcsr(imm),32)
local rs1bits = explodebits(rs1,32)
for i=0,31 do
csrbits[i] = csrbits[i] or rs1bits[i]
end
writecsr(imm,implodebits(csrbits,32))
end,
csrrci = function(rd,rs1,imm)
setreg(rd,readcsr(imm))
if rs1 == 0 then return end
local csrbits = explodebits(readcsr(imm),32)
local rs1bits = explodebits(rs1,32)
for i=0,31 do
csrbits[i] = csrbits[i] and not rs1bits[i]
end
writecsr(imm,implodebits(csrbits,32))
end,
mul = function(rd,rs1,rs2)
local plow = mul64(getreg(rs1),getreg(rs2),false,false)
setreg(rd,plow)
end,
mulh = function(rd,rs1,rs2)
local _,phigh = mul64(getreg(rs1),getreg(rs2),true,true)
setreg(rd,phigh)
end,
mulsu = function(rd,rs1,rs2)
local _,phigh = mul64(getreg(rs1),getreg(rs2),true,false)
setreg(rd,phigh)
end,
mulu = function(rd,rs1,rs2)
local _,phigh = mul64(getreg(rs1),getreg(rs2),false,false)
setreg(rd,phigh)
end,
div = function(rd,rs1,rs2)
local a = getreg(rs1)
local b = getreg(rs2)
if b == 0 then
--Division by zero
setreg(rd,2^32-1)
return
end
if a >= 2^31 then a = a - 2^32 end
if b >= 2^31 then b = b - 2^32 end
if a == -2^31 and b == -1 then
--Divide overflow
setreg(rd,a)
end
local result = math.floor(a/b)
if result < 0 then result = result + 2^32 end
setreg(rd,result)
end,
rem = function(rd,rs1,rs2)
local a = getreg(rs1)
local b = getreg(rs2)
if b == 0 then
--Division by zero
setreg(rd,a)
return
end
if a >= 2^31 then a = a - 2^32 end
if b >= 2^31 then b = b - 2^32 end
if a == -2^31 and b == -1 then
--Divide overflow
setreg(rd,0)
end
local result = a%b
setreg(rd,result)
end,
divu = function(rd,rs1,rs2)
local a = getreg(rs1)
local b = getreg(rs2)
if b == 0 then
--Division by zero
setreg(rd,2^32-1)
return
end
local result = math.floor(a/b)
setreg(rd,result)
end,
remu = function(rd,rs1,rs2)
local a = getreg(rs1)
local b = getreg(rs2)
if b == 0 then
--Division by zero
setreg(rd,a)
return
end
local result = a%b
setreg(rd,result)
end,
sh1add = function(rd,rs1,rs2)
setreg(rd,getreg(rs1)*2+getreg(rs2))
end,
sh2add = function(rd,rs1,rs2)
setreg(rd,getreg(rs1)*4+getreg(rs2))
end,
sh3add = function(rd,rs1,rs2)
setreg(rd,getreg(rs1)*8+getreg(rs2))
end,
clz = function(rd,rs1)
local bits = explodebits(getreg(rs1),32)
for i=31,0,-1 do
if bits[i] then
setreg(rd,31-i)
return
end
end
setreg(rd,32)
end,
ctz = function(rd,rs1)
local bits = explodebits(getreg(rs1),32)
for i=0,31 do
if bits[i] then
setreg(rd,i)
return
end
end
setreg(rd,32)
end,
cpop = function(rd,rs1)
local bits = explodebits(getreg(rs1),32)
local out = 0
for i=0,31 do
if bits[i] then
out = out + 1
end
end
setreg(rd,out)
end,
maxu = function(rd,rs1,rs2)
setreg(rd,math.max(getreg(rs1),getreg(rs2)))
end,
minu = function(rd,rs1,rs2)
setreg(rd,math.min(getreg(rs1),getreg(rs2)))
end,
max = function(rd,rs1,rs2)
local a = getreg(rs1)
local b = getreg(rs2)
if a >= 2^31 then a = a - 2^32 end
if b >= 2^31 then b = b - 2^32 end
local out = math.max(a,b)
if out < 0 then out = out + 2^32 end
setreg(rd,out)
end,
min = function(rd,rs1,rs2)
local a = getreg(rs1)
local b = getreg(rs2)
if a >= 2^31 then a = a - 2^32 end
if b >= 2^31 then b = b - 2^32 end
local out = math.min(a,b)
if out < 0 then out = out + 2^32 end
setreg(rd,out)
end,
sextb = function(rd,rs1)
local bits = explodebits(getreg(rs1),8)
signextend(bits,8,32)
setreg(rd,implodebits(bits,32))
end,
sexth = function(rd,rs1)
local bits = explodebits(getreg(rs1),16)
signextend(bits,16,32)
setreg(rd,implodebits(bits,32))
end,
zexth = function(rd,rs1)
setreg(rd,getreg(rs1)%2^16)
end,
rol = function(rd,rs1,rs2)
local num = getreg(rs1)
local amount = getreg(rs2)%32
if amount == 0 then return end
for i=1,amount do
local endbit = num >= 2^31
num = (num*2)%2^32
if endbit then num = num + 1 end
end
setreg(rd,num)
end,
ror = function(rd,rs1,rs2)
local num = getreg(rs1)
local amount = getreg(rs2)%32
if amount == 0 then
setreg(rd,num)
return
end
for _=1,amount do
local endbit = num%2 == 1
num = math.floor(num/2)
if endbit then num = num + 2^31 end
end
setreg(rd,num)
end,
rori = function(rd,rs1,imm)
local num = getreg(rs1)
local amount = imm%32
if amount == 0 then
setreg(rd,num)
return
end
for _=1,amount do
local endbit = num%2 == 1
num = math.floor(num/2)
if endbit then num = num + 2^31 end
end
setreg(rd,num)
end,
orcb = function(rd,rs1)
local input = getreg(rs1)
local b1 = input%2^8 > 0
local b2 = math.floor(input/2^8)%2^8 > 0
local b3 = math.floor(input/2^16)%2^8 > 0
local b4 = math.floor(input/2^24)%2^8 > 0
local out = 0
if b1 then out = out + 0xff end
if b2 then out = out + 0xff00 end
if b3 then out = out + 0xff0000 end
if b4 then out = out + 0xff000000 end
setreg(rd,out)
end,
rev8 = function(rd,rs1)
local input = getreg(rs1)
local b1 = input%2^8
local b2 = math.floor(input/2^8)%2^8
local b3 = math.floor(input/2^16)%2^8
local b4 = math.floor(input/2^24)%2^8
local out = b4
out = out + (b3*2^8)
out = out + (b2*2^16)
out = out + (b1*2^24)
setreg(rd,out)
end,
bclr = function(rd,rs1,rs2)
local bits = explodebits(getreg(rs1),32)
bits[getreg(rs2)%32] = false
setreg(rd,implodebits(bits,32))
end,
bset = function(rd,rs1,rs2)
local bits = explodebits(getreg(rs1),32)
bits[getreg(rs2)%32] = true
setreg(rd,implodebits(bits,32))
end,
binv = function(rd,rs1,rs2)
local bits = explodebits(getreg(rs1),32)
bits[getreg(rs2)%32] = not bits[getreg(rs2)%32]
setreg(rd,implodebits(bits,32))
end,
bclri = function(rd,rs1,imm)
local bits = explodebits(getreg(rs1),32)
bits[imm%32] = false
setreg(rd,implodebits(bits,32))
end,
bseti = function(rd,rs1,imm)
local bits = explodebits(getreg(rs1),32)
bits[imm%32] = true
setreg(rd,implodebits(bits,32))
end,
binvi = function(rd,rs1,imm)
local bits = explodebits(getreg(rs1),32)
bits[imm%32] = not bits[imm%32]
setreg(rd,implodebits(bits,32))
end,
bext = function(rd,rs1,rs2)
local bit = explodebits(getreg(rs1),32)[getreg(rs2)%32]
setreg(rd,bit and 1 or 0)
end,
bexti = function(rd,rs1,imm)
local bit = explodebits(getreg(rs1),32)[imm%32]
setreg(rd,bit and 1 or 0)
end,
xperm8 = function(rd,rs1,rs2)
local a = getreg(rs1)
local outputs = {
[0] = a%2^8,
math.floor(a/2^8)%2^8,
math.floor(a/2^16)%2^8,
math.floor(a/2^24)%2^8,
}
local b = getreg(rs2)
local selections = {
[0] = b%2^8,
math.floor(b/2^8)%2^8,
math.floor(b/2^16)%2^8,
math.floor(b/2^24)%2^8,
}
local out = 0
for i=0,3 do
local num = outputs[selections[i]] or 0
out = out+(num*2^(i*8))
end
setreg(rd,out)
end,
xperm4 = function(rd,rs1,rs2)
local a = getreg(rs1)
local outputs = {
[0] = a%2^4,
math.floor(a/2^4)%2^4,
math.floor(a/2^8)%2^4,
math.floor(a/2^12)%2^4,
math.floor(a/2^16)%2^4,
math.floor(a/2^20)%2^4,
math.floor(a/2^24)%2^4,
math.floor(a/2^28)%2^4,
}
local b = getreg(rs2)
local selections = {
[0] = b%2^4,
math.floor(b/2^4)%2^4,
math.floor(b/2^8)%2^4,
math.floor(b/2^12)%2^4,
math.floor(b/2^16)%2^4,
math.floor(b/2^20)%2^4,
math.floor(b/2^24)%2^4,
math.floor(b/2^28)%2^4,
}
local out = 0
for i=0,7 do
local num = outputs[selections[i]] or 0
out = out+(num*2^(i*4))
end
setreg(rd,out)
end,
lr = function(rd,rs1,rs2)
local address = getreg(rs1)
setreg(rd,readram(address,4))
mem.reservationset = address
end,
sc = function(rd,rs1,rs2)
local address = getreg(rs1)
if mem.reservationset == address then
writeram(address,getreg(rs2),4)
setreg(rd,0)
else
setreg(rd,1)
end
mem.reservationset = nil
end,
amoswapw = function(rd,rs1,rs2)
local address = getreg(rs1)
local newdata = getreg(rs2)
setreg(rd,readram(address,4))
writeram(address,newdata,4)
end,
amoaddw = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,4)
local newdata = getreg(rs2)
setreg(rd,data)
writeram(address,(data+newdata)%2^32,4)
end,
amoandw = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,4)
local newdata = getreg(rs2)
setreg(rd,data)
local bits = explodebits(data,32)
local newbits = explodebits(newdata,32)
for i=0,31 do bits[i] = bits[i] and newbits[i] end
writeram(address,implodebits(bits,32),4)
end,
amoorw = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,4)
local newdata = getreg(rs2)
setreg(rd,data)
local bits = explodebits(data,32)
local newbits = explodebits(newdata,32)
for i=0,31 do bits[i] = bits[i] or newbits[i] end
writeram(address,implodebits(bits,32),4)
end,
amoxorw = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,4)
local newdata = getreg(rs2)
setreg(rd,data)
local bits = explodebits(data,32)
local newbits = explodebits(newdata,32)
for i=0,31 do bits[i] = bits[i] ~= newbits[i] end
writeram(address,implodebits(bits,32),4)
end,
amomaxw = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,4)
local newdata = getreg(rs2)
setreg(rd,data)
if data > 2^31 then data = data - 2^32 end
if newdata > 2^31 then newdata = newdata - 2^32 end
newdata = math.max(data,newdata)
if newdata < 0 then newdata = newdata + 2^32 end
writeram(address,newdata,4)
end,
amomaxuw = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,4)
local newdata = getreg(rs2)
setreg(rd,data)
newdata = math.max(data,newdata)
writeram(address,newdata,4)
end,
amominw = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,4)
local newdata = getreg(rs2)
setreg(rd,data)
if data > 2^31 then data = data - 2^32 end
if newdata > 2^31 then newdata = newdata - 2^32 end
newdata = math.min(data,newdata)
if newdata < 0 then newdata = newdata + 2^32 end
writeram(address,newdata,4)
end,
amominuw = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,4)
local newdata = getreg(rs2)
setreg(rd,data)
newdata = math.min(data,newdata)
writeram(address,newdata,4)
end,
amocasw = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,4)
local compare = getreg(rd)
if data == compare then
writeram(address,getreg(rs2),4)
end
setreg(rd,data)
end,
amocasd = function(rd,rs1,rs2)
if rd == 31 then return end
if rs2 == 31 then return end
local address = getreg(rs1)
local datalow = readram(address,4)
local datahigh = readram(address+4,4)
local comparelow = getreg(rd)
local comparehigh = rd == 0 and 0 or getreg(rd+1)
if datalow == comparelow and datahigh == comparehigh then
writeram(address,getreg(rs2),4)
writeram(address+4,rs2 == 0 and 0 or getreg(rs2+1),4)
end
if rd ~= 0 then
setreg(rd,datalow)
setreg(rd+1,datahigh)
end
end,
amoswaph = function(rd,rs1,rs2)
local address = getreg(rs1)
local newdata = getreg(rs2)%2^16
local olddata = explodebits(readram(address,2),16)
signextend(olddata,16,32)
setreg(rd,implodebits(olddata,32))
writeram(address,newdata,2)
end,
amoaddh = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,2)
local newdata = getreg(rs2)%2^16
local oldbits = explodebits(data,16)
signextend(oldbits,16,32)
setreg(rd,implodebits(oldbits,32))
writeram(address,(data+newdata)%2^16,2)
end,
amoandh = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,2)
local newdata = getreg(rs2)%2^16
local bits = explodebits(data,16)
signextend(bits,16,32)
setreg(rd,implodebits(bits,32))
local newbits = explodebits(newdata,16)
for i=0,15 do bits[i] = bits[i] and newbits[i] end
writeram(address,implodebits(bits,16),2)
end,
amoorh = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,2)
local newdata = getreg(rs2)%2^16
local bits = explodebits(data,16)
signextend(bits,16,32)
setreg(rd,implodebits(bits,32))
local newbits = explodebits(newdata,16)
for i=0,15 do bits[i] = bits[i] or newbits[i] end
writeram(address,implodebits(bits,16),2)
end,
amoxorh = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,2)
local newdata = getreg(rs2)%2^16
local bits = explodebits(data,16)
signextend(bits,16,32)
setreg(rd,implodebits(bits,32))
local newbits = explodebits(newdata,16)
for i=0,15 do bits[i] = bits[i] ~= newbits[i] end
writeram(address,implodebits(bits,16),2)
end,
amomaxh = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,2)
local newdata = getreg(rs2)%2^16
local bits = explodebits(data,16)
signextend(bits,16,32)
setreg(rd,implodebits(bits,32))
if data > 2^15 then data = data - 2^16 end
if newdata > 2^15 then newdata = newdata - 2^16 end
newdata = math.max(data,newdata)
if newdata < 0 then newdata = newdata + 2^16 end
writeram(address,newdata,2)
end,
amomaxuh = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,2)
local newdata = getreg(rs2)%2^16
local bits = explodebits(data,16)
signextend(bits,16,32)
setreg(rd,implodebits(bits,32))
newdata = math.max(data,newdata)
writeram(address,newdata,2)
end,
amominh = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,2)
local newdata = getreg(rs2)%2^16
local bits = explodebits(data,16)
signextend(bits,16,32)
setreg(rd,implodebits(bits,32))
if data > 2^15 then data = data - 2^16 end
if newdata > 2^15 then newdata = newdata - 2^16 end
newdata = math.min(data,newdata)
if newdata < 0 then newdata = newdata + 2^16 end
writeram(address,newdata,2)
end,
amominuh = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,2)
local newdata = getreg(rs2)%2^16
local bits = explodebits(data,16)
signextend(bits,16,32)
setreg(rd,implodebits(bits,32))
newdata = math.min(data,newdata)
writeram(address,newdata,2)
end,
amocash = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,2)
local compare = getreg(rd)%2^16
if data == compare then
writeram(address,getreg(rs2)%2^16,2)
end
local bits = explodebits(data,16)
signextend(bits,16,32)
setreg(rd,implodebits(bits,32))
end,
amoswapb = function(rd,rs1,rs2)
local address = getreg(rs1)
local newdata = getreg(rs2)%2^8
local olddata = explodebits(readram(address,1),8)
signextend(olddata,8,32)
setreg(rd,implodebits(olddata,32))
writeram(address,newdata,1)
end,
amoaddb = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,1)
local newdata = getreg(rs2)%2^8
local oldbits = explodebits(data,8)
signextend(oldbits,8,32)
setreg(rd,implodebits(oldbits,32))
writeram(address,(data+newdata)%2^8,1)
end,
amoandb = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,1)
local newdata = getreg(rs2)%2^8
local bits = explodebits(data,8)
signextend(bits,8,32)
setreg(rd,implodebits(bits,32))
local newbits = explodebits(newdata,8)
for i=0,7 do bits[i] = bits[i] and newbits[i] end
writeram(address,implodebits(bits,8),1)
end,
amoorb = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,1)
local newdata = getreg(rs2)%2^8
local bits = explodebits(data,8)
signextend(bits,8,32)
setreg(rd,implodebits(bits,32))
local newbits = explodebits(newdata,8)
for i=0,7 do bits[i] = bits[i] or newbits[i] end
writeram(address,implodebits(bits,8),1)
end,
amoxorb = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,1)
local newdata = getreg(rs2)%2^8
local bits = explodebits(data,8)
signextend(bits,8,32)
setreg(rd,implodebits(bits,32))
local newbits = explodebits(newdata,8)
for i=0,7 do bits[i] = bits[i] ~= newbits[i] end
writeram(address,implodebits(bits,8),1)
end,
amomaxb = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,1)
local newdata = getreg(rs2)%2^8
local bits = explodebits(data,8)
signextend(bits,8,32)
setreg(rd,implodebits(bits,32))
if data > 2^7 then data = data - 2^8 end
if newdata > 2^7 then newdata = newdata - 2^8 end
newdata = math.max(data,newdata)
if newdata < 0 then newdata = newdata + 2^8 end
writeram(address,newdata,1)
end,
amomaxub = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,1)
local newdata = getreg(rs2)%2^8
local bits = explodebits(data,8)
signextend(bits,8,32)
setreg(rd,implodebits(bits,32))
newdata = math.max(data,newdata)
writeram(address,newdata,1)
end,
amominb = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,1)
local newdata = getreg(rs2)%2^8
local bits = explodebits(data,8)
signextend(bits,8,32)
setreg(rd,implodebits(bits,32))
if data > 2^7 then data = data - 2^8 end
if newdata > 2^7 then newdata = newdata - 2^8 end
newdata = math.min(data,newdata)
if newdata < 0 then newdata = newdata + 2^8 end
writeram(address,newdata,1)
end,
amominub = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,1)
local newdata = getreg(rs2)%2^8
local bits = explodebits(data,8)
signextend(bits,8,32)
setreg(rd,implodebits(bits,8))
newdata = math.min(data,newdata)
writeram(address,newdata,1)
end,
amocasb = function(rd,rs1,rs2)
local address = getreg(rs1)
local data = readram(address,1)
local compare = getreg(rd)%2^8
if data == compare then
writeram(address,getreg(rs2)%2^8,1)
end
local bits = explodebits(data,8)
signextend(bits,8,32)
setreg(rd,implodebits(bits,32))
end,
pack = function(rd,rs1,rs2)
local lowhalf = getreg(rs1)%2^16
local highhalf = (getreg(rs2)%2^16)*2^16
setreg(rd,lowhalf+highhalf)
end,
packh = function(rd,rs1,rs2)
local lowhalf = getreg(rs1)%2^8
local highhalf = (getreg(rs2)%2^8)*2^8
setreg(rd,lowhalf+highhalf)
end,
brev8 = function(rd,rs1,imm)
local bits = explodebits(getreg(rs1),32)
local newbits = {}
for byte=0,3 do
for bit=0,7 do
local source = byte*8+bit
local destination = byte*8+(7-bit)
newbits[destination] = bits[source]
end
end
setreg(rd,implodebits(newbits,32))
end,
zip = function(rd,rs1,imm)
local bits = explodebits(getreg(rs1),32)
local newbits = {}
for i=0,15 do
newbits[i*2] = bits[i]
newbits[i*2+1] = bits[i+16]
end
setreg(rd,implodebits(newbits,32))
end,
unzip = function(rd,rs1,imm)
local bits = explodebits(getreg(rs1),32)
local newbits = {}
for i=0,15 do
newbits[i] = bits[i*2]
newbits[i+16] = bits[i*2+1]
end
setreg(rd,implodebits(newbits,32))
end,
czeroeqz = function(rd,rs1,rs2)
if getreg(rs2) == 0 then
setreg(rd,0)
else
setreg(rd,getreg(rs1))
end
end,
czeronez = function(rd,rs1,rs2)
if getreg(rs2) ~= 0 then
setreg(rd,0)
else
setreg(rd,getreg(rs1))
end
end,
mopr = function(rd,rs1,imm)
setreg(rd,0)
end,
moprr = function(rd,rs1,rs2,imm)
setreg(rd,0)
end,
cmop = function(rd,imm)
--Does nothing until/unless redefined by another extension
end,
wrsnto = function(rd,rs1)
mem.rswaiting = "nto"
mem.running = false
digiline_send("monitordisp","Waiting for\nreservation set")
return false,true
end,
wrssto = function(rd,rs1)
mem.rswaiting = "sto"
return false,true
end,
}
local function runinst(instruction)
local bits = explodebits(instruction,32)
local opcode = implodebits(bits,7)
if opcode == 0x33 then
--R-type
--This is spectaularly inefficient and will probably need to be optimized later.
--Really, the whole program is.
--Focus is on making it work first...
local f3bits = {[0] = bits[12],bits[13],bits[14]}
local f3 = implodebits(f3bits,3)
local f7bits = {[0] = bits[25],bits[26],bits[27],bits[28],bits[29],bits[30],bits[31]}
local f7 = implodebits(f7bits,7)
local rdbits = {[0] = bits[7],bits[8],bits[9],bits[10],bits[11]}
local rd = implodebits(rdbits,5)
local rs1bits = {[0] = bits[15],bits[16],bits[17],bits[18],bits[19]}
local rs1 = implodebits(rs1bits,5)
local rs2bits = {[0] = bits[20],bits[21],bits[22],bits[23],bits[24]}
local rs2 = implodebits(rs2bits,5)
if f3 == 0x0 and f7 == 0x0 then
operations.add(rd,rs1,rs2)
elseif f3 == 0x0 and f7 == 0x20 then
operations.sub(rd,rs1,rs2)
elseif f3 == 0x4 and f7 == 0x0 then
operations.xor(rd,rs1,rs2)
elseif f3 == 0x6 and f7 == 0x0 then
operations.orr(rd,rs1,rs2)
elseif f3 == 0x7 and f7 == 0x0 then
operations.andr(rd,rs1,rs2)
elseif f3 == 0x1 and f7 == 0x0 then
operations.sll(rd,rs1,rs2)
elseif f3 == 0x5 and f7 == 0x0 then
operations.srl(rd,rs1,rs2)
elseif f3 == 0x5 and f7 == 0x20 then
operations.sra(rd,rs1,rs2)
elseif f3 == 0x2 and f7 == 0x0 then
operations.slt(rd,rs1,rs2)
elseif f3 == 0x3 and f7 == 0x0 then
operations.sltu(rd,rs1,rs2)
elseif f3 == 0x0 and f7 == 0x1 then
operations.mul(rd,rs1,rs2)
elseif f3 == 0x1 and f7 == 0x1 then
operations.mulh(rd,rs1,rs2)
elseif f3 == 0x2 and f7 == 0x1 then
operations.mulsu(rd,rs1,rs2)
elseif f3 == 0x3 and f7 == 0x1 then
operations.mulu(rd,rs1,rs2)
elseif f3 == 0x4 and f7 == 0x1 then
operations.div(rd,rs1,rs2)
elseif f3 == 0x5 and f7 == 0x1 then
operations.divu(rd,rs1,rs2)
elseif f3 == 0x6 and f7 == 0x1 then
operations.rem(rd,rs1,rs2)
elseif f3 == 0x7 and f7 == 0x1 then
operations.remu(rd,rs1,rs2)
elseif f3 == 0x2 and f7 == 0x10 then
operations.sh1add(rd,rs1,rs2)
elseif f3 == 0x4 and f7 == 0x10 then
operations.sh2add(rd,rs1,rs2)
elseif f3 == 0x6 and f7 == 0x10 then
operations.sh3add(rd,rs1,rs2)
elseif f3 == 0x7 and f7 == 0x20 then
operations.andn(rd,rs1,rs2)
elseif f3 == 0x6 and f7 == 0x20 then
operations.orn(rd,rs1,rs2)
elseif f3 == 0x4 and f7 == 0x20 then
operations.xnor(rd,rs1,rs2)
elseif f3 == 0x6 and f7 == 0x5 then
operations.max(rd,rs1,rs2)
elseif f3 == 0x7 and f7 == 0x5 then
operations.maxu(rd,rs1,rs2)
elseif f3 == 0x4 and f7 == 0x5 then
operations.min(rd,rs1,rs2)
elseif f3 == 0x5 and f7 == 0x5 then
operations.minu(rd,rs1,rs2)
elseif f3 == 0x4 and f7 == 0x4 and rs2 == 0x0 then
operations.zexth(rd,rs1)
elseif f3 == 0x1 and f7 == 0x30 then
operations.rol(rd,rs1,rs2)
elseif f3 == 0x5 and f7 == 0x30 then
operations.ror(rd,rs1,rs2)
elseif f3 == 0x1 and f7 == 0x24 then
operations.bclr(rd,rs1,rs2)
elseif f3 == 0x5 and f7 == 0x24 then
operations.bext(rd,rs1,rs2)
elseif f3 == 0x1 and f7 == 0x34 then
operations.binv(rd,rs1,rs2)
elseif f3 == 0x1 and f7 == 0x14 then
operations.bset(rd,rs1,rs2)
elseif f3 == 0x2 and f7 == 0x14 then
operations.xperm4(rd,rs1,rs2)
elseif f3 == 0x4 and f7 == 0x14 then
operations.xperm8(rd,rs1,rs2)
elseif f3 == 0x4 and f7 == 0x4 then
operations.pack(rd,rs1,rs2)
elseif f3 == 0x7 and f7 == 0x4 then
operations.packh(rd,rs1,rs2)
elseif f3 == 0x5 and f7 == 0x7 then
operations.czeroeqz(rd,rs1,rs2)
elseif f3 == 0x7 and f7 == 0x7 then
operations.czeronez(rd,rs1,rs2)
end
elseif opcode == 0x13 or opcode == 0x3 or opcode == 0x67 or opcode == 0x73 then
--I-type
local f3bits = {[0] = bits[12],bits[13],bits[14]}
local f3 = implodebits(f3bits,3)
local rdbits = {[0] = bits[7],bits[8],bits[9],bits[10],bits[11]}
local rd = implodebits(rdbits,5)
local rs1bits = {[0] = bits[15],bits[16],bits[17],bits[18],bits[19]}
local rs1 = implodebits(rs1bits,5)
local immbits = {[0] = bits[20],bits[21],bits[22],bits[23],bits[24],bits[25],bits[26],bits[27],bits[28],bits[29],bits[30],bits[31]}
local imm = implodebits(immbits,12)
if opcode == 0x13 then
if f3 == 0x0 then
operations.addi(rd,rs1,imm)
elseif f3 == 0x4 then
operations.xori(rd,rs1,imm)
elseif f3 == 0x6 then
operations.ori(rd,rs1,imm)
elseif f3 == 0x7 then
operations.andi(rd,rs1,imm)
elseif f3 == 0x1 and math.floor(imm/0x20) == 0x0 then
operations.slli(rd,rs1,imm%0x20)
elseif f3 == 0x5 and math.floor(imm/0x20) == 0x0 then
operations.srli(rd,rs1,imm%0x20)
elseif f3 == 0x5 and math.floor(imm/0x20) == 0x20 then
operations.srai(rd,rs1,imm%0x20)
elseif f3 == 0x2 then
operations.slti(rd,rs1,imm)
elseif f3 == 0x3 then
operations.sltiu(rd,rs1,imm)
elseif f3 == 0x1 and imm == 0x600 then
operations.clz(rd,rs1)
elseif f3 == 0x1 and imm == 0x601 then
operations.ctz(rd,rs1)
elseif f3 == 0x1 and imm == 0x602 then
operations.cpop(rd,rs1)
elseif f3 == 0x1 and imm == 0x604 then
operations.sextb(rd,rs1)
elseif f3 == 0x1 and imm == 0x605 then
operations.sexth(rd,rs1)
elseif f3 == 0x5 and math.floor(imm/2^5) == 0x30 then
operations.rori(rd,rs1,imm)
elseif f3 == 0x5 and imm == 0x287 then
operations.orcb(rd,rs1)
elseif f3 == 0x5 and imm == 0x698 then
operations.rev8(rd,rs1)
elseif f3 == 0x1 and math.floor(imm/2^5) == 0x24 then
operations.bclri(rd,rs1,imm)
elseif f3 == 0x5 and math.floor(imm/2^5) == 0x24 then
operations.bexti(rd,rs1,imm)
elseif f3 == 0x1 and math.floor(imm/2^5) == 0x34 then
operations.binvi(rd,rs1,imm)
elseif f3 == 0x1 and math.floor(imm/2^5) == 0x24 then
operations.bseti(rd,rs1,imm)
elseif f3 == 0x5 and imm == 0x687 then
operations.brev8(rd,rs1,imm)
elseif f3 == 0x1 and imm == 0x8f then
operations.zip(rd,rs1,imm)
elseif f3 == 0x5 and imm == 0x8f then
operations.unzip(rd,rs1,imm)
end
elseif opcode == 0x3 then
if f3 == 0x0 then
operations.lb(rd,rs1,imm)
elseif f3 == 0x1 then
operations.lh(rd,rs1,imm)
elseif f3 == 0x2 then
operations.lw(rd,rs1,imm)
elseif f3 == 0x3 then
operations.ld(rd,rs1,imm)
elseif f3 == 0x4 then
operations.lbu(rd,rs1,imm)
elseif f3 == 0x5 then
operations.lhu(rd,rs1,imm)
end
elseif opcode == 0x67 then
if f3 == 0x0 then
return operations.jalr(rd,rs1,imm)
end
elseif opcode == 0x73 then
if f3 == 0x0 then
if imm == 0x0 then
operations.ecall()
elseif imm == 0x1 then
operations.ebreak()
elseif rs1 == 0 and rd == 0 and imm == 0x0d then
return operations.wrsnto()
elseif rs1 == 0 and rd == 0 and imm == 0x1d then
return operations.wrssto()
end
elseif f3 == 0x1 then
operations.csrrw(rd,rs1,imm)
elseif f3 == 0x2 then
operations.csrrs(rd,rs1,imm)
elseif f3 == 0x3 then
operations.csrrc(rd,rs1,imm)
elseif f3 == 0x4 and bits[31] and bits[24] and bits[23] and bits[22] and not (bits[29] or bits[28] or bits[25]) then
local immbits = implodebits({[0] = bits[20],bits[21],bits[26],bits[27],bits[30]},5)
operations.mopr(rd,rs1,imm)
elseif f3 == 0x4 and bits[31] and bits[25] and not (bits[28] or bits[29]) then
local immbits = implodebits({[0] = bits[26],bits[27],bits[30]},3)
operations.moprr(rd,rs1,rs2,imm)
elseif f3 == 0x5 then
operations.csrrwi(rd,rs1,imm)
elseif f3 == 0x6 then
operations.csrrsi(rd,rs1,imm)
elseif f3 == 0x7 then
operations.csrrci(rd,rs1,imm)
end
end
elseif opcode == 0x23 then
--S-type
local f3bits = {[0] = bits[12],bits[13],bits[14]}
local f3 = implodebits(f3bits,3)
local rs1bits = {[0] = bits[15],bits[16],bits[17],bits[18],bits[19]}
local rs1 = implodebits(rs1bits,5)
local rs2bits = {[0] = bits[20],bits[21],bits[22],bits[23],bits[24]}
local rs2 = implodebits(rs2bits,5)
local immbits = {[0] = bits[7],bits[8],bits[9],bits[10],bits[11],bits[25],bits[26],bits[27],bits[28],bits[29],bits[30],bits[31]}
local imm = implodebits(immbits,12)
if f3 == 0x0 then
operations.sb(rs1,rs2,imm)
elseif f3 == 0x1 then
operations.sh(rs1,rs2,imm)
elseif f3 == 0x2 then
operations.sw(rs1,rs2,imm)
elseif f3 == 0x3 then
operations.sd(rs1,rs2,imm)
end
elseif opcode == 0x63 then
--B-type
local f3bits = {[0] = bits[12],bits[13],bits[14]}
local f3 = implodebits(f3bits,3)
local rs1bits = {[0] = bits[15],bits[16],bits[17],bits[18],bits[19]}
local rs1 = implodebits(rs1bits,5)
local rs2bits = {[0] = bits[20],bits[21],bits[22],bits[23],bits[24]}
local rs2 = implodebits(rs2bits,5)
local immbits = {[0] = false,bits[8],bits[9],bits[10],bits[11],bits[25],bits[26],bits[27],bits[28],bits[29],bits[30],bits[7],bits[31]}
local imm = implodebits(immbits,13)
if f3 == 0x0 then
return operations.beq(rs1,rs2,imm)
elseif f3 == 0x1 then
return operations.bne(rs1,rs2,imm)
elseif f3 == 0x4 then
return operations.blt(rs1,rs2,imm)
elseif f3 == 0x5 then
return operations.bge(rs1,rs2,imm)
elseif f3 == 0x6 then
return operations.bltu(rs1,rs2,imm)
elseif f3 == 0x7 then
return operations.bgeu(rs1,rs2,imm)
end
elseif opcode == 0x37 or opcode == 0x17 then
--U-type
local rdbits = {[0] = bits[7],bits[8],bits[9],bits[10],bits[11]}
local rd = implodebits(rdbits,5)
--Immediate bits in this type actually all line up between the instruction and their actual value(!)
--This means it's way easier to just mask out rd/opcode
local imm = instruction - (instruction % 0x1000)
if opcode == 0x37 then
operations.lui(rd,imm)
elseif opcode == 0x17 then
operations.auipc(rd,imm)
end
elseif opcode == 0x6f then
--J-type
local rdbits = {[0] = bits[7],bits[8],bits[9],bits[10],bits[11]}
local rd = implodebits(rdbits,5)
--Something had to give after how easy the U-type immediates were
local immbits = {[0] = false,bits[21],bits[22],bits[23],bits[24],bits[25],bits[26],bits[27],bits[28],bits[29],bits[30],bits[20],bits[12],bits[13],bits[14],bits[15],bits[16],bits[17],bits[18],bits[19],bits[31]}
local imm = implodebits(immbits,21)
return operations.jal(rd,imm)
elseif opcode == 0x2f then
--Atomic memory operation
local f5 = math.floor(instruction/2^27)
local f3 = implodebits({[0] = bits[12],bits[13],bits[14]},3)
local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
local rs1 = implodebits({[0] = bits[15],bits[16],bits[17],bits[18],bits[19]},5)
local rs2 = implodebits({[0] = bits[20],bits[21],bits[22],bits[23],bits[24]},5)
--Due to the way the memory model is implemented, aq and rl bits can be ignored
if f3 == 2 then
if f5 == 2 then
--lr.w
operations.lr(rd,rs1,rs2)
elseif f5 == 3 then
--sc.w
operations.sc(rd,rs1,rs2)
elseif f5 == 1 then
--amoswap.w
operations.amoswapw(rd,rs1,rs2)
elseif f5 == 0 then
--amoadd.w
operations.amoaddw(rd,rs1,rs2)
elseif f5 == 4 then
--amoxor.w
operations.amoxorw(rd,rs1,rs2)
elseif f5 == 12 then
--amoand.w
operations.amoandw(rd,rs1,rs2)
elseif f5 == 8 then
--amoor.w
operations.amoorw(rd,rs1,rs2)
elseif f5 == 16 then
--amomin.w
operations.amominw(rd,rs1,rs2)
elseif f5 == 20 then
--amomax.w
operations.amomaxw(rd,rs1,rs2)
elseif f5 == 24 then
--amominu.w
operations.amominuw(rd,rs1,rs2)
elseif f5 == 28 then
--amomaxu.w
operations.amomaxuw(rd,rs1,rs2)
elseif f5 == 5 then
--amocas.w
operations.amocasw(rd,rs1,rs2)
elseif f5 == 6 and rs2 == 0 then
--lw.aq/lw.aqrl
--The normal lw instruction implementation already meets these requirements
operations.lw(rd,rs1,0)
elseif f5 == 7 and rd == 0 then
--sw.rl/sw.aqrl
--The normal sw instruction implementation already meets these requirements
operations.sw(rs1,rs2,0)
end
elseif f3 == 3 then
if f5 == 5 then
--amocas.d
operations.amocasd(rd,rs1,rs2)
end
elseif f3 == 0 then
if f5 == 1 then
--amoswap.b
operations.amoswapb(rd,rs1,rs2)
elseif f5 == 0 then
--amoadd.b
operations.amoaddb(rd,rs1,rs2)
elseif f5 == 4 then
--amoxor.b
operations.amoxorb(rd,rs1,rs2)
elseif f5 == 12 then
--amoamd.b
operations.amoandb(rd,rs1,rs2)
elseif f5 == 8 then
--amoor.b
operations.amoorb(rd,rs1,rs2)
elseif f5 == 16 then
--amomin.b
operations.amominb(rd,rs1,rs2)
elseif f5 == 20 then
--amomax.b
operations.amomaxb(rd,rs1,rs2)
elseif f5 == 24 then
--amominu.b
operations.amominub(rd,rs1,rs2)
elseif f5 == 28 then
--amomaxu.b
operations.amomaxub(rd,rs1,rs2)
elseif f5 == 5 then
--amocas.b
operations.amocasb(rd,rs1,rs2)
elseif f5 == 6 and rs2 == 0 then
--lb.aq/lb.aqrl
--The normal lb instruction implementation already meets these requirements
operations.lb(rd,rs1,0)
elseif f5 == 7 and rd == 0 then
--sb.rl/sb.aqrl
--The normal sb instruction implementation already meets these requirements
operations.sb(rs1,rs2,0)
end
elseif f3 == 1 then
if f5 == 1 then
--amoswap.h
operations.amoswaph(rd,rs1,rs2)
elseif f5 == 0 then
--amoadd.h
operations.amoaddh(rd,rs1,rs2)
elseif f5 == 4 then
--amoxor.h
operations.amoxorh(rd,rs1,rs2)
elseif f5 == 12 then
--amoamd.h
operations.amoandh(rd,rs1,rs2)
elseif f5 == 8 then
--amoor.h
operations.amoorh(rd,rs1,rs2)
elseif f5 == 16 then
--amomin.h
operations.amominh(rd,rs1,rs2)
elseif f5 == 20 then
--amomax.h
operations.amomaxh(rd,rs1,rs2)
elseif f5 == 24 then
--amominu.h
operations.amominuh(rd,rs1,rs2)
elseif f5 == 28 then
--amomaxu.h
operations.amomaxuh(rd,rs1,rs2)
elseif f5 == 5 then
--amocas.h
operations.amocash(rd,rs1,rs2)
elseif f5 == 6 and rs2 == 0 then
--lh.aq/lh.aqrl
--The normal lh instruction implementation already meets these requirements
operations.lh(rd,rs1,0)
elseif f5 == 7 and rd == 0 then
--sh.rl/sh.aqrl
--The normal sh instruction implementation already meets these requirements
operations.sh(rs1,rs2,0)
end
end
elseif opcode == 0x0f then
--Memory is always consistent on this implementation,
--so all fences can just turn into NOPs
if instruction == 0x0100000f then
--pause
return false,true
end
else
mem.running = false
digiline_send("monitordisp",string.format("Invalid opcode %02X,\nhalted",opcode))
end
end
local function runcinst(instruction)
local bits = explodebits(instruction,16)
local opcode = instruction%2^2
local f8 = math.floor(instruction/2^8)
local f6 = math.floor(f8/2^2)
local f4 = math.floor(f6/2^2)
local f3 = math.floor(f4/2)
if opcode == 2 and f3 == 2 then
--c.lwsp (CI)
local imm = implodebits({[0] = false,false,bits[4],bits[5],bits[6],bits[12],bits[2],bits[3]},8)
local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
operations.lw(rd,2,imm)
elseif opcode == 2 and f3 == 3 then
--c.ldsp
local imm = implodebits({[0] = false,false,false,bits[5],bits[6],bits[12],bits[2],bits[3],bits[4]},9)
local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
operations.ld(rd,2,imm)
elseif opcode == 2 and f3 == 6 then
--c.swsp (CSS)
local imm = implodebits({[0] = false,false,bits[9],bits[10],bits[11],bits[12],bits[7],bits[8]},8)
local rs2 = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6]},5)
operations.sw(2,rs2,imm)
elseif opcode == 2 and f3 == 7 then
--c.sdsp
local imm = implodebits({[0] = false,false,false,bits[10],bits[11],bits[12],bits[7],bits[8],bits[9]},9)
local rs2 = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6]},5)
operations.sd(2,rs2,imm)
elseif opcode == 0 and f3 == 2 then
--c.lw (CL)
local imm = implodebits({[0] = false,false,bits[6],bits[10],bits[11],bits[12],bits[5]},7)
local rd = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
operations.lw(rd,rs1,imm)
elseif opcode == 0 and f3 == 3 then
--c.ld
local imm = implodebits({[0] = false,false,false,bits[6],bits[10],bits[11],bits[12],bits[5]},8)
local rd = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
operations.ld(rd,rs1,imm)
elseif opcode == 0 and f3 == 6 then
--c.sw (CS)
local imm = implodebits({[0] = false,false,bits[6],bits[10],bits[11],bits[12],bits[5]},7)
local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
operations.sw(rs1,rs2,imm)
elseif opcode == 0 and f3 == 7 then
--c.sd
local imm = implodebits({[0] = false,false,false,bits[6],bits[10],bits[11],bits[12],bits[5]},8)
local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
operations.sd(rs1,rs2,imm)
elseif opcode == 1 and f3 == 5 then
--c.j (CJ)
local immbits = {[0] = false,bits[3],bits[4],bits[5],bits[11],bits[2],bits[7],bits[6],bits[9],bits[10],bits[8],bits[12]}
signextend(immbits,12,21)
local offset = implodebits(immbits,21)
return operations.jal(0,offset,true)
elseif opcode == 1 and f3 == 1 then
--c.jal (CJ)
local immbits = {[0] = false,bits[3],bits[4],bits[5],bits[11],bits[2],bits[7],bits[6],bits[9],bits[10],bits[8],bits[12]}
signextend(immbits,12,21)
local offset = implodebits(immbits,21)
return operations.jal(1,offset,true)
elseif opcode == 2 and f4 == 8 and math.floor(instruction/2^2)%2^5 == 0 then
--c.jr (CR)
local rs1 = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
return operations.jalr(0,rs1,0,true)
elseif opcode == 2 and f4 == 9 then
local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
local rs1 = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
local rs2 = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6]},5)
if rd == 0 and rs2 == 0 then
--c.ebreak (CR)
operations.ebreak()
elseif rs2 == 0 then
--c.jalr (CR)
return operations.jalr(1,rs1,0,true)
else
--c.add (CR)
operations.add(rd,rd,rs2)
end
elseif opcode == 1 and f3 == 6 then
--c.beqz (CB)
local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
local imm = implodebits({[0] = false,bits[3],bits[4],bits[10],bits[11],bits[2],bits[5],bits[6],bits[12]},9,true)
return operations.beq(rs1,0,imm)
elseif opcode == 1 and f3 == 7 then
--c.bnez (CB)
local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
local imm = implodebits({[0] = false,bits[3],bits[4],bits[10],bits[11],bits[2],bits[5],bits[6],bits[12]},9,true)
if imm >= 2^8 then imm = imm - 2^9 end
return operations.bne(rs1,0,imm)
elseif opcode == 1 and f3 == 2 then
local imm = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6],bits[12]},6,true)
local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
if imm >= 2^5 then imm = imm - 2^6 end
--c.li (CI)
operations.addi(rd,0,imm)
elseif opcode == 1 and f3 == 3 then
local immbits = {[0] = bits[2],bits[3],bits[4],bits[5],bits[6],bits[12]}
local imm = implodebits(immbits,6)
local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
if rd == 2 then
--c.addi16sp (CI)
--For whatever reason this has a completely different immediate format than c.lui
imm = implodebits({[0] = false,false,false,false,bits[6],bits[2],bits[5],bits[3],bits[4],bits[12]},10,true)
operations.addi(2,2,imm)
elseif imm ~= 0 then
--c.lui (CI)
signextend(immbits,6,20)
local imm = implodebits(immbits,20)
imm = imm*2^12
operations.lui(rd,imm)
elseif rd%2 == 1 and rd <= 15 then
--c.mop
operations.cmop(rd,imm)
end
elseif opcode == 1 and f3 == 0 then
--c.addi (CI)
local imm = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6],bits[12]},6,true)
local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
operations.addi(rd,rd,imm)
elseif opcode == 0 and f3 == 0 and instruction ~= 0 then
--c.addi4spn (CIW)
local imm = implodebits({[0] = false,false,bits[6],bits[5],bits[11],bits[12],bits[7],bits[8],bits[9],bits[10]},10)
local rd = (math.floor(instruction/2^2)%2^3)+8
operations.addi(rd,2,imm)
elseif opcode == 2 and f3 == 0 then
--c.slli (CI)
local imm = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6],bits[12]},6)
local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
operations.slli(rd,rd,imm)
elseif opcode == 1 and f6 == 0x20 then
--c.srli (CB)
local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
local imm = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6],bits[12]},6)
operations.srli(rd,rd,imm)
elseif opcode == 1 and f6 == 0x21 then
--c.srai (CB)
local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
local imm = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6],bits[12]},6)
operations.srai(rd,rd,imm)
elseif opcode == 1 and (f6 == 0x22 or f6 == 0x26) then
--c.andi (CB)
local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
local immbits = {[0] = bits[2],bits[3],bits[4],bits[5],bits[6],bits[12]}
signextend(immbits,6,12)
local imm = implodebits(immbits,12)
operations.andi(rd,rd,imm)
elseif opcode == 2 and f4 == 8 then
--c.mv (CR)
local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
local rs2 = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6]},5)
operations.add(rd,0,rs2)
elseif opcode == 1 and f6 == 0x23 and bits[5] and bits[6] then
--c.and (CS)
local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
operations.andr(rd,rd,rs2)
elseif opcode == 1 and f6 == 0x23 and bits[6] and not bits[5] then
--c.or (CS)
local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
operations.orr(rd,rd,rs2)
elseif opcode == 1 and f6 == 0x23 and bits[5] and not bits[6] then
--c.xor (CS)
local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
operations.xor(rd,rd,rs2)
elseif opcode == 1 and f6 == 0x23 and not (bits[5] or bits[6]) then
--c.sub (CS)
local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
operations.sub(rd,rd,rs2)
elseif opcode == 0 and f6 == 0x20 then
--c.lbu
local rd = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
local imm = implodebits({[0] = bits[6],bits[5]},2)
operations.lbu(rd,rs1,imm)
elseif opcode == 0 and f6 == 0x21 and not bits[6] then
--c.lhu
local rd = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
local imm = implodebits({[0] = bits[5],bits[6]},2)
operations.lhu(rd,rs1,imm)
elseif opcode == 0 and f6 == 0x21 and bits[6] then
--c.lh
local rd = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
local imm = implodebits({[0] = false,bits[5]},2)
operations.lh(rd,rs1,imm)
elseif opcode == 0 and f6 == 0x22 then
--c.sb
local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
local imm = implodebits({[0] = bits[6],bits[5]},2)
operations.sb(rs1,rs2,imm)
elseif opcode == 0 and f6 == 0x23 and not bits[6] then
--c.sh
local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
local imm = implodebits({[0] = false,bits[5]},2)
operations.sh(rs1,rs2,imm)
elseif opcode == 1 and f6 == 0x27 and bits[5] and bits[6] and not (bits[2] or bits[3] or bits[4]) then
--c.zext.b
local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
operations.andi(rd,rd,0xff)
elseif opcode == 1 and f6 == 0x27 and bits[5] and bits[6] and bits[2] and not (bits[3] or bits[4]) then
--c.sext.b
local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
operations.sextb(rd,rd)
elseif opcode == 1 and f6 == 0x27 and bits[5] and bits[6] and bits[3] and not (bits[2] or bits[4]) then
--c.zext.h
local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
operations.zexth(rd,rd)
elseif opcode == 1 and f6 == 0x27 and bits[5] and bits[6] and bits[2] and bits[3] and not bits[4] then
--c.sext.h
local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
operations.sexth(rd,rd)
elseif opcode == 1 and f6 == 0x27 and bits[5] and bits[6] and bits[2] and bits[4] and not bits[3] then
--c.not
local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
operations.xori(rd,rd,0xffffffff)
elseif opcode == 1 and f6 == 0x27 and bits[6] and not bits[5] then
--c.mul
local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
operations.mul(rd,rd,rs2)
elseif opcode == 2 and f8 == 0xb8 then
--cm.push
--This one decodes into possibly a whole bunch of instructions
local rlist = cmpushpopreglists[implodebits({[0] = bits[4],bits[5],bits[6],bits[7]},4)]
if not rlist then return end
stack = implodebits({[0] = bits[2],bits[3]},2) * 16 + rlist.stack
for i,reg in ipairs(rlist.registers) do
operations.sw(2,reg,-4*i)
end
operations.addi(2,2,-1 * stack)
elseif opcode == 2 and f8 == 0xba then
--cm.pop
--This one decodes into possibly a whole bunch of instructions
local rlist = cmpushpopreglists[implodebits({[0] = bits[4],bits[5],bits[6],bits[7]},4)]
if not rlist then return end
stack = implodebits({[0] = bits[2],bits[3]},2) * 16 + rlist.stack
operations.addi(2,2,stack)
for i,reg in ipairs(rlist.registers) do
operations.lw(reg,2,-4*i)
end
elseif opcode == 2 and f8 == 0xbc then
--cm.popretz
--This one decodes into a whole bunch of instructions
local rlist = cmpushpopreglists[implodebits({[0] = bits[4],bits[5],bits[6],bits[7]},4)]
if not rlist then return end
local stack = implodebits({[0] = bits[2],bits[3]},2) * 16 + rlist.stack
operations.addi(2,2,stack)
for i,reg in ipairs(rlist.registers) do
operations.lw(reg,2,-4*i)
end
operations.addi(10,0,0)
return operations.jalr(0,1,0)
--more like CISC-V amirite?
elseif opcode == 2 and f8 == 0xbe then
--cm.popret
--This one decodes into a whole bunch of instructions
local rlist = cmpushpopreglists[implodebits({[0] = bits[4],bits[5],bits[6],bits[7]},4)]
if not rlist then return end
local stack = implodebits({[0] = bits[2],bits[3]},2) * 16 + rlist.stack
operations.addi(2,2,stack)
for i,reg in ipairs(rlist.registers) do
operations.lw(reg,2,-4*i)
end
return operations.jalr(0,1,0)
elseif opcode == 2 and f6 == 0x2b and bits[5] and not bits[6] then
--cm.mvsa01
--This one decodes into multiple instructions
local sreg = {[0] = 8,9,18,19,20,21,22,23}
local r1 = sreg[implodebits({[0] = bits[7],bits[8],bits[9]},3)]
local r2 = sreg[implodebits({[0] = bits[2],bits[3],bits[4]},3)]
operations.addi(r1,10,0)
operations.addi(r2,11,0)
elseif opcode == 2 and f6 == 0x2b and bits[5] and bits[6] then
--cm.mva01s
--This one decodes into multiple instructions
local sreg = {[0] = 8,9,18,19,20,21,22,23}
local r1 = sreg[implodebits({[0] = bits[7],bits[8],bits[9]},3)]
local r2 = sreg[implodebits({[0] = bits[2],bits[3],bits[4]},3)]
operations.addi(10,r1,0)
operations.addi(11,r2,0)
elseif opcode == 2 and f6 == 0x28 then
local index = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6],bits[7],bits[8],bits[9]},8)
if index < 32 then
--cm.jt
local address = readcsr(0x17) --jvt
address = address + 4*index
local target = readram(address,4)
mem.registers.pc = target
return true
else
--cm.jalt
local address = readcsr(0x17) --jvt
address = address + 4*index
local target = readram(address,4)
setreg(1,mem.registers.pc+2)
mem.registers.pc = target
return true
end
else
mem.running = false
digiline_send("monitordisp","Invalid compressed\ninstruction, halted")
end
end
local function run(limit)
--0xc00 = CYCLE
--0xc80 = CYCLEH
mem.csr[0xc00] = mem.csr[0xc00] + 1
if mem.csr[0xc00] >= 2^32 then
mem.csr[0xc80] = mem.csr[0xc80] + math.floor(mem.csr[0xc00]/2^32)
mem.csr[0xc00] = mem.csr[0xc00]%2^32
end
--0xc01 = TIME
--0xc81 = TIMEH
local timediff = os.time()-mem.starttime
mem.csr[0xc01] = timediff%2^32
mem.csr[0xc81] = math.floor(timediff/2^32)
local first = true
repeat
if mem.registers.pc == mem.breakpoint and not first then
digiline_send("monitordisp","Hit breakpoint")
mem.running = false
break
end
first = false
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
if stop then break end
else
local jumped,stop = runcinst(instruction%2^16)
if not jumped then mem.registers.pc = (mem.registers.pc + 2) % 2^32 end
if stop then break end
end
--0xc02 = INSTRET
--0xc82 = INSTRETH
mem.csr[0xc02] = mem.csr[0xc02] + 1
if mem.csr[0xc02] >= 2^32 then
mem.csr[0xc82] = mem.csr[0xc82] + math.floor(mem.csr[0xc02]/2^32)
mem.csr[0xc02] = mem.csr[0xc02]%2^32
end
limit = limit - 1
until (not mem.running) or limit <= 0
end
local regaliases = {
zero = 0,
ra = 1,
sp = 2,
gp = 3,
tp = 4,
t0 = 5,
t1 = 6,
t2 = 7,
fp = 8,
s0 = 8,
s1 = 9,
a0 = 10,
a1 = 11,
a2 = 12,
a3 = 13,
a4 = 14,
a5 = 15,
a6 = 16,
a7 = 17,
s2 = 18,
s3 = 19,
s4 = 20,
s5 = 21,
s6 = 22,
s7 = 23,
s8 = 24,
s9 = 25,
s10 = 26,
s11 = 27,
t3 = 28,
t4 = 29,
t5 = 30,
t6 = 31,
}
if event.type == "program" or event.iid == "reset" then
mem.ram = {}
for i=0,(RAM_SIZE/256)-1 do
mem.ram[i] = string.rep(string.char(0),256)
end
mem.registers = {}
for i=0,31 do mem.registers[i] = 0 end
mem.registers.pc = 0
mem.running = false
mem.inputwaiting = false
mem.rswaiting = false
mem.stdout = {}
mem.starttime = os.time()
mem.csr = {
[0x017] = 0, --jvt
[0xf11] = 0, --mvendorid
[0xf12] = 0, --marchid
[0xf13] = 0x6f435652, --mimpid ("RVCo")
[0xf14] = 0, --mhartid
[0x300] = 0, --mstatus
[0x301] = 0x40001107, --misa (RV32IMACB)
[0x310] = 0, --mstatush
[0x800] = 0, --Lightweight Mode
[0xc00] = 0, --CYCLE
[0xc01] = 0, --TIME
[0xc02] = 0, --INSTRET
[0xc80] = 0, --CYCLEH
[0xc81] = 0, --TIMEH
[0xc82] = 0, --INSTRETH
}
for i=1,6 do mem.stdout[i] = "" end
local mdisp = event.type == "program" and "\nReset: Cold" or "\nReset: Warm"
digiline_send("monitordisp",mdisp.."\n\nRVController Monitor\n\nType 'help' for help\nReady\n")
digiline_send("stdout","\n\n\n\n\n\n\n")
mem.inputbuf = ""
mem.digilinesqueue = {}
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")
digiline_send("stdout","\n\n\n\n\n\n\n")
interrupt(0.5,"reset")
elseif event.channel == "monitorkb" then
digiline_send("monitordisp","> "..event.msg)
local function validateandclamp(value,min,max,base)
base = base or 16
value = tonumber(value or "",base)
if (not value) or value < min or value > max or value ~= math.floor(value) then
return
end
return value
end
local argv = {}
while true do
local spacepos = string.find(event.msg," ",nil,true) or string.len(event.msg)+1
table.insert(argv,string.sub(event.msg,1,spacepos-1))
event.msg = string.sub(event.msg,spacepos+1,-1)
if event.msg == "" then break end
end
local argc = #argv
if argv[1] == "peek" then
local address = validateandclamp(argv[2],0,RAM_SIZE-1)
if not address then
digiline_send("monitordisp","Bad address")
return
end
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)
if not address then
digiline_send("monitordisp","Bad address")
return
end
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)
if not address then
digiline_send("monitordisp","Bad address")
return
end
local data = validateandclamp(argv[3],0,0xff)
if not data then
digiline_send("monitordisp","Bad data")
return
end
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)
if not address then
digiline_send("monitordisp","Bad address")
return
end
local data = validateandclamp(argv[3],0,0xffffffff)
if not data then
digiline_send("monitordisp","Bad data")
return
end
writeram(address,data,4)
digiline_send("monitordisp",string.format("%08X:%08X",address,data))
elseif argv[1] == "setreg" then
argv[2] = regaliases[argv[2]] or argv[2]
local reg = validateandclamp(argv[2],0,0x1f,10)
if not reg then
digiline_send("monitordisp","Bad register")
return
end
local data = validateandclamp(argv[3],0,0xffffffff)
if not data then
digiline_send("monitordisp","Bad data")
return
end
setreg(reg,data)
digiline_send("monitordisp",string.format("x%02d:%08X",reg,data))
elseif argv[1] == "getreg" then
argv[2] = regaliases[argv[2]] or argv[2]
local reg = validateandclamp(argv[2],0,0x1f,10)
if not reg then
digiline_send("monitordisp","Bad register")
return
end
local data = getreg(reg)
digiline_send("monitordisp",string.format("x%02d:%08X",reg,data))
elseif argv[1] == "getpc" then
digiline_send("monitordisp",string.format("PC:%08X",mem.registers.pc))
elseif argv[1] == "setpc" then
local address = validateandclamp(argv[2],0,0xffffffff)
if not address then
digiline_send("monitordisp","Bad address")
return
end
mem.registers.pc = address
digiline_send("monitordisp",string.format("PC:%08X",address))
elseif argv[1] == "reset" then
mem.running = false
digiline_send("monitordisp","\n\n\n\n\n\n\n")
digiline_send("stdout","\n\n\n\n\n\n\n")
interrupt(0.5,"reset")
elseif argv[1] == "step" then
run(1)
digiline_send("monitordisp",string.format("PC:%08X",mem.registers.pc))
elseif argv[1] == "run" then
mem.starttime = os.time()
mem.running = true
digiline_send("monitordisp","CPU started\n\n")
run(50)
interrupt(0.1,"tick")
elseif argv[1] == "stop" then
mem.running = false
mem.inputwaiting = false
mem.rswaiting = false
digiline_send("monitordisp","Stopped by user")
elseif argv[1] == "h" then
--Easter egg
digiline_send("monitordisp","h")
elseif argv[1] == "setbreak" then
local address = validateandclamp(argv[2],0,RAM_SIZE-1)
if not address then
digiline_send("monitordisp","Bad address")
return
end
mem.breakpoint = address
elseif argv[1] == "clearbreak" then
mem.breakpoint = -1
elseif argv[1] == "help" then
if argc == 1 or argv[2] == "1" then
digiline_send("monitordisp","Use: help ")
digiline_send("monitordisp","Commands:\npoke pokew peek\npeekw setreg getreg\ngetpc setpc step run\n'help 2' for page 2")
elseif argv[2] == "poke" then
digiline_send("monitordisp","poke \nWrites the specified\nbyte (8 bits) to\nmemory at the\nspecified address")
elseif argv[2] == "pokew" then
digiline_send("monitordisp","pokew \nWrites the specified\nword (32 bits) to\nmemory at the\nspecified address")
elseif argv[2] == "peek" then
digiline_send("monitordisp","peek \nReads the byte (8\nbits) value from\nmemory at the\nspecified address")
elseif argv[2] == "peekw" then
digiline_send("monitordisp","peekw \nReads the word (32\nbits) value from\nmemory at the\nspecified address")
elseif argv[2] == "setreg" then
digiline_send("monitordisp","setreg \nWrites the specified\nword (32 bits) data\nto the specified\nregister")
elseif argv[2] == "getreg" then
digiline_send("monitordisp","getreg \nReads the word (32\nbits) data from the\nspecified register")
elseif argv[2] == "getpc" then
digiline_send("monitordisp","getpc\nReads the current\nvalue of the program\ncounter")
elseif argv[2] == "setpc" then
digiline_send("monitordisp","setpc \nWrites the specified\nvalue into the\nprogram counter")
elseif argv[2] == "step" then
digiline_send("monitordisp","step\nAllows the CPU to\nrun one instruction,\nthen halts")
elseif argv[2] == "run" then
digiline_send("monitordisp","run\nAllows the CPU to\nrun indefinitely")
elseif argv[2] == "stop" then
digiline_send("monitordisp","stop\nHalts the CPU")
elseif argv[2] == "reset" then
digiline_send("monitordisp","reset\nStops the CPU and\nclears RAM and all\nregisters")
elseif argv[2] == "help" then
digiline_send("monitordisp","help [command]\nShows information\nabout the specified\ncommand, or a list\nof commands if none\nis supplied")
elseif argv[2] == "2" then
digiline_send("monitordisp","Page 2\nreset stop help\nsetbreak clearbreak")
elseif argv[2] == "h" then
digiline_send("monitordisp","h\nhhhhhhhhhh")
elseif argv[2] == "setbreak" then
digiline_send("monitordisp","setbreak \nSets a breakpoint\nat the specified\naddress")
elseif argv[2] == "clearbreak" then
digiline_send("monitordisp","clearbreak\nClears any set\nbreakpoint")
else
digiline_send("monitordisp","No such command or\nno help available")
end
else
digiline_send("monitordisp","Unknown command")
end
elseif event.channel == "stdin" then
if mem.inputwaiting then
--Blocking read in progress
if mem.inputwaittype == "string" then
event.msg = string.sub(event.msg,1,mem.inputmax-1)..string.char(0)
for i=1,string.len(event.msg) do
writeram(mem.inputaddr+i-1,string.byte(string.sub(event.msg,i,i)),1)
end
mem.inputwaiting = false
mem.running = true
digiline_send("monitordisp","CPU started")
run(INSTRUCTIONS_PER_CLOCK)
interrupt(1/CLOCK_SPEED,"tick")
elseif mem.inputwaittype == "integer" and tonumber(event.msg) then
event.msg = math.floor(event.msg)
if event.msg >= 2^32 then event.msg = 2^32-1 end
if event.msg < -1*(2^31) then event.msg = -1*(2^31) end
if event.msg < 0 then event.msg = event.msg + 2^32 end
setreg(10,event.msg)
mem.inputwaiting = false
mem.running = true
digiline_send("monitordisp","CPU started")
run(INSTRUCTIONS_PER_CLOCK)
interrupt(1/CLOCK_SPEED,"tick")
elseif mem.inputwaittype == "char" then
event.msg = string.sub(event.msg,1,1)
if event.msg == "" then event.msg = string.char(0) end
setreg(10,string.byte(event.msg))
mem.inputwaiting = false
mem.running = true
digiline_send("monitordisp","CPU started")
run(INSTRUCTIONS_PER_CLOCK)
interrupt(1/CLOCK_SPEED,"tick")
end
else
--No blocking read in progress, buffer the data for nonblocking reads later
mem.inputbuf = string.sub(mem.inputbuf..event.msg,1,256)
end
elseif event.channel == "load" then
if event.msg.done then
mem.hexloading = false
digiline_send("monitordisp","Load complete\n")
if event.msg.autorun then
mem.running = true
digiline_send("monitordisp","CPU started\n")
run(INSTRUCTIONS_PER_CLOCK)
interrupt(1/CLOCK_SPEED,"tick")
end
else
if not mem.hexloading then
if mem.running then digiline_send("monitordisp","System halted\n") end
mem.running = false
mem.hexloading = true
digiline_send("monitordisp","Loading Intel\nHEX data")
digiline_send("stdout","\n\n\n\n\n\n\n")
mem.registers.pc = 0
end
local address = event.msg.address
local data = event.msg.data
local size = event.msg.size
digiline_send("monitordisp",string.format("%08X\n",address))
for i=0,size-1 do
local thisdata = tonumber(string.sub(data,i*2+1,i*2+2),16)
local thisaddress = address + i
writeram(thisaddress,thisdata,1)
end
end
elseif event.type == "digiline" then
--Unrecognized digilines signals get forwarded on to the program
event.channel = string.sub(event.channel,1,256)
event.msg = string.sub(tostring(event.msg),1,256)
if #mem.digilinesqueue < 16 then
table.insert(mem.digilinesqueue,{channel = event.channel, msg = event.msg})
end
if mem.csr[0x800]%2 == 1 then
interrupt(0,"tick")
end
elseif event.iid == "tick" and mem.running then
run(INSTRUCTIONS_PER_CLOCK)
if mem.csr[0x800]%2 == 1 then
interrupt(1,"tick",true)
else
interrupt(1/CLOCK_SPEED,"tick")
end
end
if stdoutdirty then
local text = table.concat(mem.stdout,"\n")
digiline_send("stdout",text.."\n")
stdoutdirty = false
end