local debugInfo = {} local function getDebugInfo() return " ("..debugInfo.mnem.." sub "..debugInfo.sub..")" end local function hex(n) return string.format("%02X", n) end local function cycleAddSignals(cycle, cyc2, cyc2t, ops, sigs) for _, name in ipairs(cycle) do if ops[name] then cycleAddSignals(ops[name], cyc2, cyc2t, ops, sigs) elseif sigs[name] then if not cyc2t[name] then cyc2t[name] = true table.insert(cyc2, name) else error("overspecified signal name: "..name..getDebugInfo()) end else error("invalid signal name: "..name.." does not name a signal or operation") end end end local function cycleSimplify(cycle, ops, sigs) local cyc2, cyc2t = {}, {} cycleAddSignals(cycle, cyc2, cyc2t, ops, sigs) return cyc2 end local function cycleToUcycle(cycle, ops, sigs) local ucycle = {} local cyc2 = cycleSimplify(cycle, ops, sigs) local hasbase = false local nonempty = false for _, name in ipairs(cyc2) do nonempty = true if name=="always1" then hasbase = true end local sig = sigs[name] assert(sig, "no signal named "..name) for i, sbit in ipairs(sig) do ucycle[sbit.rom] = ucycle[sbit.rom] or {} assert(not ucycle[sbit.rom][sbit.bit], "multiply defined bit") ucycle[sbit.rom][sbit.bit] = true end end if nonempty and (not hasbase) then error("cycle has no base"..getDebugInfo()) end return ucycle end local function encodeInstruction(opcode, instr, ucode, ops, sigs) for sub, cycle in ipairs(instr) do debugInfo.sub = sub-1 local ucycle = cycleToUcycle(cycle, ops, sigs) local uaddr = opcode*4 + (sub-1) assert(not ucode[uaddr], "overused ucode addr "..uaddr) ucode[uaddr] = ucycle end end local function sigsFromRoms(roms) local sigs = {} for romidx, rom in ipairs(roms) do for sigidx, sig in ipairs(rom.signals) do sigs[sig] = sigs[sig] or {} table.insert(sigs[sig], { rom = romidx, bit = sigidx-1, }) end end return sigs end local function archToUcode(arch) local sigs = sigsFromRoms(arch.roms) local ops = arch.operations local ucode = {} local opcodesUsed = {} local numOpcodesUsed = 0 local infolines = {} local catlet = "X" for _, instr in ipairs(arch.instructions) do if instr.category then catlet = instr.catlet table.insert(infolines, "\n") table.insert(infolines, instr.category.." ("..catlet.."):\n") else local mnem = instr.mnem or error("instr has no mnem") local opcode = instr.opcode or error("instr has no opcode "..mnem) local ncycles = instr.ncycles or #instr assert(#instr <= 8, "operation too long "..opcode) local len = math.ceil(#instr / 4) if len>1 then assert(opcode%2==0, "len>1 on odd opcode") end for i = 1, len do local opcode2 = opcode+i-1 assert(not opcodesUsed[opcode2], "overused opcode "..hex(opcode)) opcodesUsed[opcode2] = catlet numOpcodesUsed = numOpcodesUsed+1 end debugInfo.mnem = mnem encodeInstruction(opcode, instr, ucode, ops, sigs) if instr.desc then table.insert(infolines, mnem..(" "):rep(13-#mnem)..hex(opcode).." "..ncycles.." "..instr.desc.."\n") end end end print(table.concat(infolines)) local lt = {"Opcodes used: "..numOpcodesUsed.."/255\n", " "} for i = 0, 15 do table.insert(lt, hex(i):sub(2, 2)) end table.insert(lt, "\n") for line = 0, 255, 16 do table.insert(lt, hex(line).." | ") for opcode = line, line+15 do if opcodesUsed[opcode] then table.insert(lt, opcodesUsed[opcode]) else table.insert(lt, "-") end end table.insert(lt, "\n") end print(table.concat(lt)) return ucode end local function ucodeToBricks(ucode, roms) local bricks = {} for uaddr, ucycle in pairs(ucode) do for romidx, uline in ipairs(ucycle) do for bitidx, t in pairs(uline) do local rom = roms[romidx] assert(bitidx >=0 and bitidx <= rom.size[3]-1) local x = rom.pos[1] + (uaddr % rom.size[1]) local y = rom.pos[2] - math.floor(uaddr / rom.size[1]) local z = rom.pos[3] + bitidx bricks[x] = bricks[x] or {} bricks[x][y] = bricks[x][y] or {} assert(not bricks[x][y][z], "overlapping brick at "..x.." "..y.." "..z) bricks[x][y][z] = true end end end return bricks end ts = ts or { eval = function() end, call = function() end, } ts.eval [[ function commandShiftBrick(%x, %y, %z) { commandToServer('shiftBrick', %x, %y, %z); } function commandPlantBrick() { commandToServer('plantBrick'); } ]] local function plantBrickAt(pos, brickPos) local dx, dy, dz = pos[1]-brickPos[1], pos[2]-brickPos[2], pos[3]-brickPos[3] ts.call("commandShiftBrick", dy, -dx, dz) brickPos[1] = pos[1]; brickPos[2] = pos[2]; brickPos[3] = pos[3]; ts.call("commandPlantBrick") end local function buildBricks(bricks) local brickPos = {0, 0, 0} for x, xb in pairs(bricks) do for y, xyb in pairs(xb) do for z, t in pairs(xyb) do plantBrickAt({x, y, z}, brickPos) end end end end local function buildArch(arch) local ucode = archToUcode(arch) local bricks = ucodeToBricks(ucode, arch.roms) buildBricks(bricks) end local arch = require("rom-8608-defs") buildArch(arch)