--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

--Documentation has moved to the "doc" directory in the repository.
--If you don't have a copy of this, you can find it here:
--https://cheapiesystems.com/git/rvcontroller/tree/doc

--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 traptypes = {
	--Not all of these are implemented, some are impossible on RVController
	[0x0] = "Inst addr misaligned",
	[0x1] = "Inst access fault",
	[0x2] = "Illegal instruction",
	[0x3] = "Breakpoint",
	[0x4] = "Load addr misaligned",
	[0x5] = "Load access fault",
	[0x6] = "St/AMO addr misalign",
	[0x7] = "St/AMO access fault",
	[0x8] = "U-mode env call",
	[0x9] = "S-mode env call",
	--0xa = reserved
	[0xb] = "M-mode env call",
	[0xc] = "Instr page fault",
	[0xd] = "Load page fault",
	--0xe = reserved
	[0xf] = "St/AMO page fault",
	[0x10] = "Double trap",
	--0x11 = reserved
	[0x12] = "Software check",
	[0x13] = "Hardware error",
	--0x14-0x80000000 = reserved/custom
	[0x8000001] = "Supv soft interrupt",
	--0x80000002 = reserved
	[0x8000003] = "Mach soft interrupt",
	--0x80000004 = reserved
	[0x8000005] = "Supv timer interrupt",
	--0x80000006 = reserved
	[0x8000007] = "Mach timer interrupt",
	--0x80000008 = reserved
	[0x8000009] = "Supv ext interrupt",
	--0x8000000a = reserved
	[0x800000b] = "Mach ext interrupt",
	--0x8000000c = reserved
	[0x800000d] = "Count over interrupt",
	--0x8000000e-0xffffffff = reserved/platform
}

local fault --non-nil values are for deferred faults that will trap after the instruction finishes
local fval

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)
	if reg > 15 and not mem.isa.i then
		digiline_send("monitordisp",string.format("Attempted read from\nregister x%d\nin E mode\nPC: %08X",reg,mem.registers.pc))
		fault = 2
		return 0
	end
	return reg == 0 and 0 or mem.registers[reg]
end

local function setreg(reg,val)
	if reg > 15 and not mem.isa.i then
		digiline_send("monitordisp",string.format("Attempted write to\nregister x%d\nin E mode\nPC: %08X",reg,mem.registers.pc))
		fault = 2
		return
	end
	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.mbe and not instfetch --Instruction fetches must always be little-endian
	if address > RAM_SIZE-1 and not (address >= mem.csr[0x801] and address <= mem.csr[0x801] + 17) then
		fault = instfetch and 1 or 5
		fval = address
		return instfetch and 0x13 or 0 --0x13 = addi x0,x0,0 (nop)
	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
		if offsetaddr == mem.csr[0x801] and mem.csr[0x801] ~= 0 then
			--Mesecons I/O Direction
			local bits = {[0] = mem.meseconsdir.a,mem.meseconsdir.b,mem.meseconsdir.c,mem.meseconsdir.d}
			out = out + implodebits(bits,4)*2^(8*i)
		elseif offsetaddr == mem.csr[0x801]+1 and mem.csr[0x801] ~= 0 then
			--Mesecons I/O Data
			local bits = {[0] = pin.a,pin.b,pin.c,pin.d}
			if mem.meseconsdir.a then
				bits[0] = mem.meseconsdata.a
			end
			if mem.meseconsdir.b then
				bits[1] = mem.meseconsdata.b
			end
			if mem.meseconsdir.c then
				bits[2] = mem.meseconsdata.c
			end
			if mem.meseconsdir.d then
				bits[3] = mem.meseconsdata.d
			end
			out = out + implodebits(bits,4)*2^(8*i)
		elseif offsetaddr >= mem.csr[0x801]+2 and offsetaddr < mem.csr[0x801]+2+8 and mem.csr[0x801] ~= 0 then
			--mtime
			local byteindex = offsetaddr - (mem.csr[0x801]+2)
			if mem.mbe then byteindex = 7-byteindex end
			local time = mem.csr[0xc01]
			local timeh = mem.csr[0xc81]
			local thisout = 0
			if byteindex == 0 then
				thisout = time%2^8
			elseif byteindex == 1 then
				thisout = math.floor(time/2^8)%2^8
			elseif byteindex == 2 then
				thisout = math.floor(time/2^16)%2^8
			elseif byteindex == 3 then
				thisout = math.floor(time/2^24)
			elseif byteindex == 4 then
				thisout = timeh%2^8
			elseif byteindex == 5 then
				thisout = math.floor(timeh/2^8)%2^8
			elseif byteindex == 6 then
				thisout = math.floor(timeh/2^16)%2^8
			elseif byteindex == 7 then
				thisout = math.floor(timeh/2^24)
			end
			thisout = thisout*2^(i*8)
			out = out + thisout
		elseif offsetaddr >= mem.csr[0x801]+10 and offsetaddr < mem.csr[0x801]+10+8 and mem.csr[0x801] ~= 0 then
			--mtimecmp
			local byteindex = offsetaddr - (mem.csr[0x801]+10)
			if mem.mbe then byteindex = 7-byteindex end
			local thisout = 0
			if byteindex == 0 then
				thisout = mem.mtimecmplow%2^8
			elseif byteindex == 1 then
				thisout = math.floor(mem.mtimecmplow/2^8)%2^8
			elseif byteindex == 2 then
				thisout = math.floor(mem.mtimecmplow/2^16)%2^8
			elseif byteindex == 3 then
				thisout = math.floor(mem.mtimecmplow/2^24)
			elseif byteindex == 4 then
				thisout = mem.mtimecmphigh%2^8
			elseif byteindex == 5 then
				thisout = math.floor(mem.mtimecmphigh/2^8)%2^8
			elseif byteindex == 6 then
				thisout = math.floor(mem.mtimecmphigh/2^16)%2^8
			elseif byteindex == 7 then
				thisout = math.floor(mem.mtimecmphigh/2^24)
			end
			thisout = thisout*2^(i*8)
			out = out + thisout
		elseif offsetaddr < RAM_SIZE then
			local segment = math.floor(offsetaddr/256)
			local offset = offsetaddr%256
			out = out + (string.byte(string.sub(mem.ram[segment],offset+1,offset+1)) or 0) * 2^(8*i)
		end
	end
	return out
end

local function writeram(address,data,bytes,fake)
	if address > RAM_SIZE-1 and not fake and not (address >= mem.csr[0x801] and address <= mem.csr[0x801] + 17) then
		fault = 7
		fval = address
		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
	if fake then return end
	for i=0,bytes-1 do
		local thisbyte = data % (2^((i+1)*8)) / 2^(i*8)
		thisbyte = math.floor(thisbyte) % 2^32
		local offsetaddr
		if mem.mbe then
			offsetaddr = address+bytes-1-i
		else
			offsetaddr = address+i
		end
		if offsetaddr == mem.csr[0x801] and mem.csr[0x801] ~= 0 then
			--Mesecons I/O Direction
			local bits = explodebits(thisbyte,8)
			mem.meseconsdir = {
				a = bits[0],
				b = bits[1],
				c = bits[2],
				d = bits[3],
			}
			if not bits[0] then
				port.a = false
				mem.meseconsdata.a = pin.a
			else
				port.a = mem.meseconsdata.a
			end
			if not bits[1] then
				port.b = false
				mem.meseconsdata.b = pin.b
			else
				port.b = mem.meseconsdata.b
			end
			if not bits[2] then
				port.c = false
				mem.meseconsdata.c = pin.c
			else
				port.c = mem.meseconsdata.c
			end
			if not bits[3] then
				port.d = false
				mem.meseconsdata.d = pin.d
			else
				port.d = mem.meseconsdata.d
			end
		elseif offsetaddr == mem.csr[0x801] + 1 and mem.csr[0x801] ~= 0 then
			--Mesecons I/O Data
			local bits = explodebits(thisbyte,8)
			if mem.meseconsdir.a then
				mem.meseconsdata.a = bits[0]
				port.a = bits[0]
			end
			if mem.meseconsdir.b then
				mem.meseconsdata.b = bits[1]
				port.b = bits[1]
			end
			if mem.meseconsdir.c then
				mem.meseconsdata.c = bits[2]
				port.c = bits[2]
			end
			if mem.meseconsdir.d then
				mem.meseconsdata.d = bits[3]
				port.d = bits[3]
			end
		elseif offsetaddr >= mem.csr[0x801]+2 and offsetaddr < mem.csr[0x801]+2+8 and mem.csr[0x801] ~= 0 then
			--mtime
			local byteindex = offsetaddr - (mem.csr[0x801]+2)
			if mem.mbe then byteindex = 7-byteindex end
			if byteindex >= 4 then
				local bits = explodebits(mem.csr[0xc81],32)
				local newbits = explodebits(thisbyte,8)
				byteindex = byteindex - 4
				for i=0,7 do
					bits[byteindex*8+i] = newbits[i]
				end
				mem.csr[0xc81] = implodebits(bits,32)
			else
				local bits = explodebits(os.time()-mem.starttime,32)
				local newbits = explodebits(thisbyte,8)
				for i=0,7 do
					bits[byteindex*8+i] = newbits[i]
				end
				local newmtime = implodebits(bits,32)
				mem.starttime = os.time()-newmtime
			end
		elseif offsetaddr >= mem.csr[0x801]+10 and offsetaddr < mem.csr[0x801]+10+8 and mem.csr[0x801] ~= 0 then
			--mtimecmp
			local byteindex = offsetaddr - (mem.csr[0x801]+10)
			if mem.mbe then byteindex = 7-byteindex end
			if byteindex >= 4 then
				local bits = explodebits(mem.mtimecmphigh,32)
				local newbits = explodebits(thisbyte,8)
				byteindex = byteindex - 4
				for i=0,7 do
					bits[byteindex*8+i] = newbits[i]
				end
				mem.mtimecmphigh = implodebits(bits,32)
			else
				local bits = explodebits(mem.mtimecmplow,32)
				local newbits = explodebits(thisbyte,8)
				for i=0,7 do
					bits[byteindex*8+i] = newbits[i]
				end
				mem.mtimecmplow = implodebits(bits,32)
			end
		elseif address < RAM_SIZE then
			local segment = math.floor(offsetaddr/256)
			local offset = offsetaddr%256
			mem.ram[segment] = string.sub(mem.ram[segment],0,offset)..string.char(thisbyte)..string.sub(mem.ram[segment],offset+2,-1)
		end
	end
end

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 address == 0x341 then --mepc
		local ret = mem.csr[0x341]
		--mepc[0] must be 0
		if ret%2 == 1 then ret = ret-1 end
		--mepc[1] must be 0 if IALIGN=32
		if not mem.isa.c and ret%4 >= 2 then
			ret = ret - 2
		end
		return ret
	elseif address == 0x300 then --mstatus
		local bits = {}
		bits[3] = mem.mie
		bits[7] = mem.mpie
		bits[11] = mem.mpp%2 == 1
		bits[12] = mem.mpp >= 2
		return implodebits(bits,32)
	elseif address == 0x310 then --mstatush
		local bits = {}
		bits[5] = mem.mbe
		bits[9] = mem.mpelp
		bits[10] = mem.mdt
		return implodebits(bits,32)
	elseif address == 0x747 then --mseccfg
		local bits = {}
		bits[10] = mem.mlpe
		return implodebits(bits,32)
	elseif not mem.csr[address] then
		digiline_send("monitordisp",string.format("Attempted read\nfrom unknown\nCSR 0x%03X\nPC: %08X",address,mem.registers.pc))
		fault = 2
		fval = readram(mem.registers.pc,4)
		return 0
	elseif address == 0xb00 or address == 0xb02 or address == 0xb80 or address == 0xb82 then
		--mcycle(h)/minstret(h) - redirect to cycle(h)/instret(h)
		address = address + 0x100
	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
		fault = 2
		fval = readram(mem.registers.pc,4)
		return
	elseif address == 0xf11 or address == 0xf12 or address == 0xf13 or address == 0xf14 or address == 0xf15 then
		--Read-only machine information register
		fault = 2
		fval = readram(mem.registers.pc,4)
		return
	elseif address == 0x300 then
		--mstatus
		local bits = explodebits(data,32)
		mem.mie = bits[3] and not mem.mdt
		mem.mpie = bits[7]
		return
	elseif address == 0x310 then
		--mstatush
		local bits = explodebits(data,32)
		mem.mbe = bits[5]
		mem.mpelp = bits[9]
		mem.mdt = bits[10]
		return
	elseif address == 0x301 then
		--misa
		local bits = explodebits(data,32)
		if mem.registers.pc % 4 == 2 and not bits[2] then
			digiline_send("monitordisp",string.format("Attempted to disable\nC extension but\ninstruction would be\nmisaligned,\nwrite ignored\nPC: %08X",mem.registers.pc))
		end
		mem.isa.a = bits[0]
		mem.isa.b = bits[1]
		mem.isa.c = bits[2]
		mem.isa.i = bits[8]
		mem.isa.m = bits[12]
		mem.isa.x = bits[23]
		local newbits = {[0] = mem.isa.a,mem.isa.b,mem.isa.c,[4] = not mem.isa.i,[8] = mem.isa.i,[12] = mem.isa.m,[23] = mem.isa.x,[30] = true}
		mem.csr[0x301] = implodebits(newbits,32)
		return
	elseif address == 0x801 then
		--MMIO base address
		local oldaddr = readcsr(0x801)
		if oldaddr ~= 0 then writeram(oldaddr,0,1,true) end --Invalidate reservation set at old address
		mem.csr[0x801] = data
		if data ~= 0 then
			writeram(data,0,1,true) --Invalidate reservation set at new address
		end
		return
	elseif address == 0x305 then
		--mtvec
		mem.trapmode = data%4
		mem.trapbase = data-mem.trapmode
		mem.mtvecwritten = true
		return
	elseif address == 0xb00 or address == 0xb02 or address == 0xb80 or address == 0xb82 then
		--mcycle(h)/minstret(h) - redirect to cycle(h)/instret(h)
		address = address + 0x100
	elseif address == 0x747 then
		--mseccfg then
		local bits = explodebits(data,32)
		mem.mlpe = bits[10]
		return
	end
	if not mem.csr[address] then
		digiline_send("monitordisp",string.format("Attempted write\nto unknown\nCSR 0x%03X\nPC: %08X",address,mem.registers.pc))
		fault = 2
		fval = readram(mem.registers.pc,4)
		return
	end
	mem.csr[address] = data
end

local function trap(reason,val)
	local oldreason = reason
	if mem.mdt then
		writecsr(0x34b,reason) --mtval2
		reason = 0x10
	end
	writecsr(0x342,reason) --mcause
	writecsr(0x341,mem.registers.pc) --mepc
	writecsr(0x343,val or 0) --mtval
	mem.mpie = mem.mie
	mem.mie = false
	mem.mpelp = mem.mlpe and mem.elp
	mem.elp = false
	if not mem.mdt then
		mem.mdt = true
		if mem.trapmode == 1 then
			--vectored mode
			local int = reason >= 0x8000000
			reason = reason%0x80000000
			mem.registers.pc = reason*4+mem.trapbase
			return true,false
		else
			--direct or reserved (treated as direct) mode
			mem.registers.pc = mem.trapbase
			return true,false
		end
	else
		digiline_send("monitordisp","Unexpected trap!")
		if not mem.mtvecwritten then
			digiline_send("monitordisp",traptypes[oldreason] or "Unknown reason")
			if oldreason == 18 then
				local subtypes = {
					[2] = "Landing pad fault",
					[3] = "Shadow stack fault",
				}
				digiline_send("monitordisp",subtypes[val] or "Unknown cause")
			end
			digiline_send("monitordisp","(no handler present)")
		else
			digiline_send("monitordisp",traptypes[reason] or "Unknown reason")
			if reason == 18 then
				local subtypes = {
					[2] = "Landing pad fault",
					[3] = "Shadow stack fault",
				}
				digiline_send("monitordisp",subtypes[val] or "Unknown cause")
			end
		end
		digiline_send("monitordisp",string.format("PC: %08X",mem.registers.pc))
		digiline_send("monitordisp","System halted")
		mem.running = false
		return true,true
	end
end

local function checkinterrupts()
	local miebits = explodebits(mem.csr[0x304],32)
	local mipbits = explodebits(mem.csr[0x344],32)
	if mem.mtimecmphigh == mem.csr[0xc81] and (os.time() - mem.starttime) >= mem.mtimecmplow then
		mipbits[7] = true --mtip
	elseif mem.mtimecmphigh < mem.csr[0xc81] then
		mipbits[7] = true --mtip
	else
		mipbits[7] = false
	end
	mem.csr[0x344] = implodebits(mipbits,32)
	if not mem.mie then return end
	local order = {11,3,7,9,1,5,13,16,17}
	for _,i in ipairs(order) do
		if miebits[i] and mipbits[i] then
			return trap(0x80000000+i)
		end
	end
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+(mem.mbe and 4 or 0),4))
		setreg(rd+1,readram(address+(mem.mbe and 0 or 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+(mem.mbe and 4 or 0),getreg(rs2),4)
		writeram(address+(mem.mbe and 0 or 4),getreg(rs2+1),4)
	end,
	ecall = function()
		local func = mem.isa.i and getreg(17) or getreg(15)
		if mem.isa.i and func == 0 then func = getreg(15) end
		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()
		return trap(3,0)
	end,
	csrrw = function(rd,rs1,imm)
		local out = readcsr(imm)
		writecsr(imm,getreg(rs1))
		setreg(rd,out)
		return checkinterrupts()
	end,
	csrrs = function(rd,rs1,imm)
		local out = readcsr(imm)
		if rs1 == 0 then
			setreg(rd,out)
			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))
		setreg(rd,out)
		return checkinterrupts()
	end,
	csrrc = function(rd,rs1,imm)
		local out = readcsr(imm)
		if rs1 == 0 then
			setreg(rd,out)
			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))
		setreg(rd,out)
		return checkinterrupts()
	end,
	csrrwi = function(rd,rs1,imm)
		setreg(rd,readcsr(imm))
		writecsr(imm,rs1)
		return checkinterrupts()
	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))
		return checkinterrupts()
	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))
		return checkinterrupts()
	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,
	h3bextm = function(rd,rs1,rs2,size)
		local bits = explodebits(getreg(rs1),32)
		local shamt = getreg(rs2)
		local outbits = {}
		for i=0,size-1 do
			outbits[i] = bits[i+shamt] --May be nil if out of bounds but that's OK
		end
		setreg(rd,implodebits(outbits,32))
	end,
	h3bextmi = function(rd,rs1,rs2,size)
		local bits = explodebits(getreg(rs1),32)
		local shamt = rs2 --Register number field actually contains an immediate here
		local outbits = {}
		for i=0,size-1 do
			outbits[i] = bits[i+shamt] --May be nil if out of bounds but that's OK
		end
		setreg(rd,implodebits(outbits,32))
	end,
	mret = function()
		mem.registers.pc = readcsr(0x341)
		mem.mdt = false
		mem.mie = mem.mpie
		mem.mpie = true
		mem.elp = mem.mlpe and mem.mpelp
		mem.mpelp = false
		mem.mpp = 3
		checkinterrupts()
		return true
	end,
	wfi = function()
		mem.interruptwaiting = true
		mem.running = false
		digiline_send("monitordisp","Waiting for\ninterrupt")
		interrupt(1,"checkinterrupt")
		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 and mem.isa.m then
			operations.mul(rd,rs1,rs2)
		elseif f3 == 0x1 and f7 == 0x1 and mem.isa.m then
			operations.mulh(rd,rs1,rs2)
		elseif f3 == 0x2 and f7 == 0x1 and mem.isa.m then
			operations.mulsu(rd,rs1,rs2)
		elseif f3 == 0x3 and f7 == 0x1 and mem.isa.m then
			operations.mulu(rd,rs1,rs2)
		elseif f3 == 0x4 and f7 == 0x1 and mem.isa.m then
			operations.div(rd,rs1,rs2)
		elseif f3 == 0x5 and f7 == 0x1 and mem.isa.m then
			operations.divu(rd,rs1,rs2)
		elseif f3 == 0x6 and f7 == 0x1 and mem.isa.m then
			operations.rem(rd,rs1,rs2)
		elseif f3 == 0x7 and f7 == 0x1 and mem.isa.m then
			operations.remu(rd,rs1,rs2)
		elseif f3 == 0x2 and f7 == 0x10 and mem.isa.b then
			operations.sh1add(rd,rs1,rs2)
		elseif f3 == 0x4 and f7 == 0x10 and mem.isa.b then
			operations.sh2add(rd,rs1,rs2)
		elseif f3 == 0x6 and f7 == 0x10 and mem.isa.b then
			operations.sh3add(rd,rs1,rs2)
		elseif f3 == 0x7 and f7 == 0x20 and mem.isa.b then
			operations.andn(rd,rs1,rs2)
		elseif f3 == 0x6 and f7 == 0x20 and mem.isa.b then
			operations.orn(rd,rs1,rs2)
		elseif f3 == 0x4 and f7 == 0x20 and mem.isa.b 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 and mem.isa.b then
			operations.zexth(rd,rs1)
		elseif f3 == 0x1 and f7 == 0x30 and mem.isa.b then
			operations.rol(rd,rs1,rs2)
		elseif f3 == 0x5 and f7 == 0x30 and mem.isa.b then
			operations.ror(rd,rs1,rs2)
		elseif f3 == 0x1 and f7 == 0x24 and mem.isa.b then
			operations.bclr(rd,rs1,rs2)
		elseif f3 == 0x5 and f7 == 0x24 and mem.isa.b then
			operations.bext(rd,rs1,rs2)
		elseif f3 == 0x1 and f7 == 0x34 and mem.isa.b then
			operations.binv(rd,rs1,rs2)
		elseif f3 == 0x1 and f7 == 0x14 and mem.isa.b then
			operations.bset(rd,rs1,rs2)
		elseif f3 == 0x2 and f7 == 0x14 and mem.isa.b then
			operations.xperm4(rd,rs1,rs2)
		elseif f3 == 0x4 and f7 == 0x14 and mem.isa.b 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)
		else
			return trap(2,instruction)
		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 and mem.isa.b then
				operations.clz(rd,rs1)
			elseif f3 == 0x1 and imm == 0x601 and mem.isa.b then
				operations.ctz(rd,rs1)
			elseif f3 == 0x1 and imm == 0x602 and mem.isa.b then
				operations.cpop(rd,rs1)
			elseif f3 == 0x1 and imm == 0x604 and mem.isa.b then
				operations.sextb(rd,rs1)
			elseif f3 == 0x1 and imm == 0x605 and mem.isa.b 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 and mem.isa.b then
				operations.orcb(rd,rs1)
			elseif f3 == 0x5 and imm == 0x698 and mem.isa.b 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)
			else
				return trap(2,instruction)
			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)
			else
				return trap(2,instruction)
			end
		elseif opcode == 0x67 then
			if f3 == 0x0 then
				return operations.jalr(rd,rs1,imm)
			else
				return trap(2,instruction)
			end
		elseif opcode == 0x73 then
			if f3 == 0x0 then
				if imm == 0x0 then
					operations.ecall()
				elseif imm == 0x1 then
					return operations.ebreak()
				elseif rs1 == 0 and rd == 0 and imm == 0x0d and mem.isa.a then
					return operations.wrsnto()
				elseif rs1 == 0 and rd == 0 and imm == 0x1d and mem.isa.a then
					return operations.wrssto()
				elseif imm == 0x302 and rd == 0 and rs1 == 0 then
					return operations.mret()
				elseif imm == 0x105 and rd == 0 and rs1 == 0 then
					return operations.wfi()
				else
					return trap(2,instruction)
				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)
			else
				return trap(2,instruction)
			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)
		else
			return trap(2,instruction)
		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)
		else
			return trap(2,instruction)
		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)
		else
			return trap(2,instruction)
		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 and mem.isa.a 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)
			else
				return trap(2,instruction)
			end
		elseif f3 == 3 then
			if f5 == 5 then
				--amocas.d
				operations.amocasd(rd,rs1,rs2)
			else
				return trap(2,instruction)
			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)
			else
				return trap(2,instruction)
			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)
			else
				return trap(2,instruction)
			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
	elseif opcode == 0x0b and mem.isa.x then
		--Custom0 instruction (currently all R-type)
		local f3 = implodebits({[0] = bits[12],bits[13],bits[14]},3)
		local xh3bextmsize = implodebits({[0] = bits[26],bits[27],bits[28]},3)+1
		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)
		if f3 == 0 then
			operations.h3bextm(rd,rs1,rs2,xh3bextmsize)
		elseif f3 == 4 then
			operations.h3bextmi(rd,rs1,rs2,xh3bextmsize)
		else
			return trap(2,instruction)
		end
	else
		trap(2,instruction)
	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)
			return 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)
		else
			return trap(2,instruction%2^16)
		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 mem.isa.b 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 mem.isa.b 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 mem.isa.b 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 mem.isa.m 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
		return trap(2,instruction%2^16)
	end
end

local function checklpe(instruction)
	if not mem.mlpe then
		return false
	elseif instruction%4 == 3 then
		--Uncompressed
		local opcode = instruction%0x100
		local bits = explodebits(instruction,32)
		if opcode == 0x67 and not (bits[12] or bits[13] or bits[14]) then
			--jalr
			local rs1 = math.floor(instruction/2^15)%2^5
			return (rs1 ~= 1 and rs1 ~= 5 and rs1 ~= 7)
		end
	else
		--Compressed
		local f4 = math.floor(instruction/2^12)
		if instruction %4 == 2 and (f4 == 8 or f4 == 9) then
			--c.jr or c.jalr
			local rs1 = math.floor(instruction/2^7)%2^5
			return (rs1 ~= 1 and rs1 ~= 5 and rs1 ~= 7)
		end
	end
	return false
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
	local timediff = os.time()-mem.starttime
	mem.csr[0xc01] = timediff%2^32

	local first = true
	repeat
		fault = nil
		if mem.registers.pc == mem.breakpoint and not first then
			digiline_send("monitordisp","Hit breakpoint")
			mem.running = false
			break
		end
		if first then
			checkinterrupts()
		end
		first = false
		local instruction = readram(mem.registers.pc,4,true)
		if mem.lpe and mem.mlpe then
			if instruction%2^12 == 0x017 and mem.registers.pc%4 == 0 and (math.floor(instruction/2^12) == mem.lplabel or math.floor(instruction/2^12) == 0) then
				mem.lpe = false
			else
				trap(18,2)
			end
		end
		mem.lpe = mem.mlpe and checklpe(instruction)
		if mem.lpe then
			mem.lplabel = math.floor(getreg(7)/2^12)
		end
		if instruction%4 == 3 or not mem.isa.c then
			if mem.registers.pc%4 ~= 0 and not mem.isa.c then
				local _,stop = trap(0)
				if stop then break end
			end
			local jumped,stop = runinst(instruction)
			if fault then
				jumped,stop = trap(fault,fval)
			end
			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 fault then
				jumped,stop = trap(fault,fval)
			end
			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,
}

local csraliases = {
	cycle = 0xc00,
	time = 0xc01,
	instret = 0xc02,
	cycleh = 0xc80,
	timeh = 0xc81,
	instreth = 0xc82,
	mvendorid = 0xf11,
	marchid = 0xf12,
	mimpid = 0xf13,
	mhartid = 0xf14,
	mstatus = 0x300,
	misa = 0x301,
	medeleg = 0x302,
	mideleg = 0x303,
	mie = 0x304,
	mtvec = 0x305,
	mcounteren = 0x306,
	mstatush = 0x310,
	medelegh = 0x312,
	mscratch = 0x340,
	mepc = 0x341,
	mcause = 0x342,
	mtval = 0x343,
	mip = 0x344,
	mtinst = 0x34a,
	mtval2 = 0x34b,
	mcycle = 0xb00,
	minstret = 0xb02,
	mcycleh = 0xb80,
	minstreth = 0xb82,
	mseccfg = 0x747,
}

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] = 53, --marchid (53 is RVController's officially assigned value, see https://github.com/riscv/riscv-isa-manual/blob/main/marchid.md )
			[0xf13] = 0x6f435652, --mimpid ("RVCo")
			[0xf14] = 0, --mhartid
			[0x300] = 0, --mstatus
			[0x301] = 0x40801107, --misa (RV32IMACBX)
			[0x304] = 0, --mie
			[0x305] = 0, --mtvec
			[0x340] = 0, --mscratch
			[0x341] = 0, --mepc
			[0x342] = 0, --mcause
			[0x343] = 0, --mtval
			[0x344] = 0, --mip
			[0x34b] = 0, --mtval2
			[0x800] = 0, --Clock Controls
			[0x801] = 0, --MMIO Base Address
			[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.mbe = false
	mem.isa = {
		a = true,
		b = true,
		c = true,
		i = true,
		m = true,
		x = true,
	}
	mem.meseconsdir = {}
	mem.meseconsdata = {}
	port = {}
	mem.trapbase = 0
	mem.trapmode = 0
	mem.mtvecwritten = false
	mem.mie = false
	mem.mpie = true
	mem.mpp = 3
	mem.mdt = true
	mem.mtimecmplow = 0
	mem.mtimecmphigh = 0
	mem.mtimehigh = 0
	mem.interruptwaiting = false
	mem.mlpe = false
	mem.elp = false
	mem.mpelp = false
elseif event.type == "on" or event.type == "off" then
	local pname = string.lower(event.pin.name)
	local pstate = pin[pname]
	if not mem.meseconsdir[pname] then
		--Pin is input
		mem.meseconsdata[pname] = pstate
		if readcsr(0x801) ~= 0 then
			--MMIO is enabled
			writeram(readcsr(0x801)+1,0,1,true) --Invalidate any existing reservation set
		end
		local mipbits = explodebits(mem.csr[0x344],32)
		mipbits[16] = true
		mem.csr[0x344] = implodebits(mipbits,32)
		local miebits = explodebits(mem.csr[0x304],32)
		if miebits[16] and mem.interruptwaiting then
			mem.interruptwaiting = false
			mem.running = true
			digiline_send("monitordisp","CPU started")
			interrupt(1/CLOCK_SPEED,"tick")
		end
	end
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,0xffffffff)
		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,0xffffffff)
		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,0xffffffff)
		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,0xffffffff)
		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
		if mem.inputwaiting then
			digiline_send("monitordisp","Unable to step,\nwaiting for input")
			return
		elseif mem.rswaiting then
			digiline_send("monitordisp","Unable to step,\nwaiting for\nreservation set")
			return
		elseif mem.running then
			digiline_send("monitordisp","Already running")
			return
		end
		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 = csraliases[argv[2]] or 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 = csraliases[argv[2]] or validateandclamp(argv[2],0,0xfff)
		if not address then
			digiline_send("monitordisp","Bad CSR address")
			return
		end
		local data = validateandclamp(argv[3],0,0xffffffff)
		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.mbe 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")
		else
			digiline_send("monitordisp","Invalid argument")
		end
	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\nrdcsr wrcsr endian")
		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")
		elseif argv[2] == "rdcsr" then
			digiline_send("monitordisp","rdcsr <address>\nReads the value of\nthe specified CSR")
		elseif argv[2] == "wrcsr" then
			digiline_send("monitordisp","wrcsr <addr> <data>\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
	local mipbits = explodebits(mem.csr[0x344],32)
	mipbits[17] = true
	mem.csr[0x344] = implodebits(mipbits,32)
	local miebits = explodebits(mem.csr[0x304],32)
	if miebits[17] and mem.interruptwaiting then
		mem.interruptwaiting = false
		mem.running = true
		digiline_send("monitordisp","CPU started")
		interrupt(1/CLOCK_SPEED,"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
elseif event.iid == "checkinterrupt" and mem.interruptwaiting then
	local restarted = checkinterrupts()
	if restarted then
		mem.interruptwaiting = false
		mem.running = true
		digiline_send("monitordisp","CPU started")
		interrupt(1/CLOCK_SPEED,"tick")
	else
		local miebits = explodebits(mem.csr[0x304],32)
		if not miebits[7] then return end -- No need to keep checking the timer if it's not even on
		interrupt(1,"checkinterrupt",mem.csr[0x800]%2 == 1)
	end
end

if stdoutdirty then
	local text = table.concat(mem.stdout,"\n")
	digiline_send("stdout",text.."\n")
	stdoutdirty = false
end
