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