8608/rom-8608.lua
2022-10-31 14:02:37 -06:00

186 lines
5.1 KiB
Lua

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
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
local info = table.concat(infolines).."\n"..table.concat(lt)
print(info)
local fo = io.open("instructionList.txt", "w")
fo:write(info)
fo:close()
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)