diff options
| author | cheapie <no-email-for-you@example.com> | 2026-05-23 20:14:34 -0500 |
|---|---|---|
| committer | cheapie <no-email-for-you@example.com> | 2026-05-23 20:14:34 -0500 |
| commit | 85b5fde272be6ab543aa866baebabddc24566bdb (patch) | |
| tree | b4f2e3bb634effe51c2bdc5585ca4ea8b98d6dfa /rvcontroller.lua | |
| download | rvcontroller-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.lua | 2604 |
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 |
