summaryrefslogtreecommitdiff
path: root/rvcontroller.lua
diff options
context:
space:
mode:
authorcheapie <no-email-for-you@example.com>2026-05-23 20:14:34 -0500
committercheapie <no-email-for-you@example.com>2026-05-23 20:14:34 -0500
commit85b5fde272be6ab543aa866baebabddc24566bdb (patch)
treeb4f2e3bb634effe51c2bdc5585ca4ea8b98d6dfa /rvcontroller.lua
downloadrvcontroller-85b5fde272be6ab543aa866baebabddc24566bdb.tar
rvcontroller-85b5fde272be6ab543aa866baebabddc24566bdb.tar.gz
rvcontroller-85b5fde272be6ab543aa866baebabddc24566bdb.tar.bz2
rvcontroller-85b5fde272be6ab543aa866baebabddc24566bdb.tar.xz
rvcontroller-85b5fde272be6ab543aa866baebabddc24566bdb.zip
Add initial content
Diffstat (limited to 'rvcontroller.lua')
-rw-r--r--rvcontroller.lua2604
1 files changed, 2604 insertions, 0 deletions
diff --git a/rvcontroller.lua b/rvcontroller.lua
new file mode 100644
index 0000000..3fda5db
--- /dev/null
+++ b/rvcontroller.lua
@@ -0,0 +1,2604 @@
+--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, RV32IMACB_Zicntr_Zicond_Zicsr_Zifencei_Zihintpause_Zilsd_Zabha_Zacas_Zcb_Zclsd_Zcmp_Zcmt_Zbkb_Zbkx instruction set, little-endian
+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
+* "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
+* 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
+* 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 <address>
+Reads and displays the byte (8 bits) value from RAM at the specified address
+
+poke <address> <data>
+Writes the specified byte (8 bits) value to RAM at the specified address
+
+peekw <address>
+Reads and displays the word (32 bits) value from RAM starting at the specified address
+
+pokew <address> <data>
+Writes the specified word (32 bits) value to RAM starting at the specified address
+
+getreg <register number>
+Displays the current value of the specified register number (0-31)
+
+setreg <register number> <value>
+Sets the specified register (0-31) to the specified value
+
+getpc
+Displays the current value of the program counter
+
+setpc <value>
+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 <address>
+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)
+ 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 = address+i
+ 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
+ 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 = address+i
+ 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 or address == 0x310 then
+ --Read-only machine information register, ignore write
+ 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,
+}
+
+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()
+ 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 == 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)
+ 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)
+ 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)
+ 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 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)
+ else
+ --c.lui (CI)
+ signextend(immbits,6,20)
+ local imm = implodebits(immbits,20)
+ imm = imm*2^12
+ operations.lui(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)
+ 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.stdout = {}
+ mem.starttime = os.time()
+ mem.csr = {
+ [0x017] = 0, --jvt
+ [0xf11] = 0, --mvendorid
+ [0xf12] = 0x6f435652, --marchid ("RVCo")
+ [0xf13] = 0, --mimpid
+ [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
+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
+ 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 <command>")
+ 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 <addr> <data>\nWrites the specified\nbyte (8 bits) to\nmemory at the\nspecified address")
+ elseif argv[2] == "pokew" then
+ digiline_send("monitordisp","pokew <addr> <data>\nWrites the specified\nword (32 bits) to\nmemory at the\nspecified address")
+ elseif argv[2] == "peek" then
+ digiline_send("monitordisp","peek <address>\nReads the byte (8\nbits) value from\nmemory at the\nspecified address")
+ elseif argv[2] == "peekw" then
+ digiline_send("monitordisp","peekw <address>\nReads the word (32\nbits) value from\nmemory at the\nspecified address")
+ elseif argv[2] == "setreg" then
+ digiline_send("monitordisp","setreg <reg> <data>\nWrites the specified\nword (32 bits) data\nto the specified\nregister")
+ elseif argv[2] == "getreg" then
+ digiline_send("monitordisp","getreg <register>\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 <value>\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 <address>\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