diff options
Diffstat (limited to 'rvcontroller.lua')
| -rw-r--r-- | rvcontroller.lua | 183 |
1 files changed, 172 insertions, 11 deletions
diff --git a/rvcontroller.lua b/rvcontroller.lua index fbab09d..6130659 100644 --- a/rvcontroller.lua +++ b/rvcontroller.lua @@ -200,6 +200,12 @@ Format: [0000dcba] (Input bits are RO, output bits are RW) For inputs: Each bit contains the state of the corresponding input. Writes are ignored. For outputs: Each bit contains the state of the corresponding output. Writing to these bits turns the output on/off. +Base + 2: mtime (see RISC-V Machine Level ISA specification) + +Base + 10: mtimecmp (see RISC-V Machine Level ISA specification) + +Base + 18 - Base + 255: Reserved + ]] --Settings @@ -341,7 +347,7 @@ 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] + 1) then + if address > RAM_SIZE-1 and not (address >= mem.csr[0x801] and address <= mem.csr[0x801] + 17) then fault = instfetch and 1 or 5 return instfetch and 0x13 or 0 --0x13 = addi x0,x0,0 end @@ -356,7 +362,7 @@ local function readram(address,bytes,instfetch) 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) + 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} @@ -372,7 +378,57 @@ local function readram(address,bytes,instfetch) if mem.meseconsdir.d then bits[3] = mem.meseconsdata.d end - out = out + implodebits(bits,4) + 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 @@ -383,7 +439,7 @@ local function readram(address,bytes,instfetch) 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] + 1) then + if address > RAM_SIZE-1 and not fake and not (address >= mem.csr[0x801] and address <= mem.csr[0x801] + 17) then fault = 7 return end @@ -410,7 +466,7 @@ local function writeram(address,data,bytes,fake) end if offsetaddr == mem.csr[0x801] and mem.csr[0x801] ~= 0 then --Mesecons I/O Direction - local bits = explodebits(data,8) + local bits = explodebits(thisbyte,8) mem.meseconsdir = { a = bits[0], b = bits[1], @@ -443,7 +499,7 @@ local function writeram(address,data,bytes,fake) end elseif offsetaddr == mem.csr[0x801] + 1 and mem.csr[0x801] ~= 0 then --Mesecons I/O Data - local bits = explodebits(data,8) + local bits = explodebits(thisbyte,8) if mem.meseconsdir.a then mem.meseconsdata.a = bits[0] port.a = bits[0] @@ -460,6 +516,47 @@ local function writeram(address,data,bytes,fake) 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 @@ -574,6 +671,7 @@ local function writecsr(address,data) --mtvec mem.trapmode = data%4 mem.trapbase = data-mem.trapmode + mem.mtvecwritten = true 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)) @@ -584,13 +682,18 @@ local function writecsr(address,data) end local function trap(reason) + 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,0) --mtval mem.mpie = mem.mie mem.mie = false if not mem.mdt then - mem.mdt = 1 + mem.mdt = true if mem.trapmode == 1 then --vectored mode local int = reason >= 0x8000000 @@ -604,7 +707,12 @@ local function trap(reason) end else digiline_send("monitordisp","Unexpected trap!") - digiline_send("monitordisp",traptypes[reason] or "Unknown reason") + if not mem.mtvecwritten then + digiline_send("monitordisp",traptypes[oldreason] or "Unknown reason") + digiline_send("monitordisp","(no handler present)") + else + digiline_send("monitordisp",traptypes[reason] or "Unknown reason") + end digiline_send("monitordisp",string.format("PC: %08X",mem.registers.pc)) digiline_send("monitordisp","System halted") mem.running = false @@ -612,6 +720,24 @@ local function trap(reason) end end +local function checkinterrupts() + local miebits = explodebits(mem.csr[0x304],32) + local mipbits = {} + 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 + end + mem.csr[0x344] = implodebits(mipbits,32) + if not mem.mie then return end + local order = {11,3,7,9,1,5,13} + 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}, @@ -1044,6 +1170,7 @@ local operations = { csrrw = function(rd,rs1,imm) setreg(rd,readcsr(imm)) writecsr(imm,getreg(rs1)) + return checkinterrupts() end, csrrs = function(rd,rs1,imm) setreg(rd,readcsr(imm)) @@ -1054,6 +1181,7 @@ local operations = { csrbits[i] = csrbits[i] or rs1bits[i] end writecsr(imm,implodebits(csrbits,32)) + return checkinterrupts() end, csrrc = function(rd,rs1,imm) setreg(rd,readcsr(imm)) @@ -1064,10 +1192,12 @@ local operations = { csrbits[i] = csrbits[i] and not rs1bits[i] end writecsr(imm,implodebits(csrbits,32)) + 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)) @@ -1078,6 +1208,7 @@ local operations = { 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)) @@ -1088,6 +1219,7 @@ local operations = { 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) @@ -1821,12 +1953,20 @@ local operations = { end, mret = function() mem.registers.pc = readcsr(0x341) + mem.mdt = false mem.mie = mem.mpie mem.mpie = true mem.mpp = 3 - mem.mdt = false + 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) @@ -2028,6 +2168,8 @@ local function runinst(instruction) 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) end @@ -2619,10 +2761,8 @@ local function run(limit) end --0xc01 = TIME - --0xc81 = TIMEH local timediff = os.time()-mem.starttime mem.csr[0xc01] = timediff%2^32 - mem.csr[0xc81] = math.floor(timediff/2^32) local first = true repeat @@ -2632,6 +2772,9 @@ local function run(limit) mem.running = false break end + if first then + checkinterrupts() + end first = false local instruction = readram(mem.registers.pc,4,true) if instruction%4 == 3 or not mem.isa.c then @@ -2751,11 +2894,14 @@ if event.type == "program" or event.iid == "reset" then [0xf14] = 0, --mhartid [0x300] = 0, --mstatus [0x301] = 0x40001107, --misa (RV32IMACB) + [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 @@ -2787,10 +2933,15 @@ if event.type == "program" or event.iid == "reset" then 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 elseif event.type == "on" or event.type == "off" then local pname = string.lower(event.pin.name) local pstate = pin[pname] @@ -3112,6 +3263,16 @@ elseif event.iid == "tick" and mem.running then 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 + interrupt(1,"checkinterrupt",mem.csr[0x800]%2 == 1) + end end if stdoutdirty then |
