initial commit

This commit is contained in:
Redo 2022-10-26 18:27:00 -06:00
commit 5fe3adca2a
4 changed files with 798 additions and 0 deletions

BIN
arch8608.ods Normal file

Binary file not shown.

342
assembler-8608.lua Normal file
View File

@ -0,0 +1,342 @@
local function trim(s) return s:gsub("^ +", ""):gsub(" +$", "").."" end
local function validWordsFromInstrs(instrs)
local words = {}
for mnem, _ in pairs(instrs) do
for word in mnem:gmatch("[^ ]+") do
words[word] = true
end
end
return words
end
local function decodeNumber(n)
n = trim(n)
local sign = 1; if n:sub(1, 1)=="-" then sign = -1; n = n:sub(2, #n); end;
if n:sub(1, 1)=="$" then return sign*tonumber(n:sub(2, #n ), 16), (#n-1)/2
elseif n:sub(1, 2)=="0x" then return sign*tonumber(n:sub(3, #n ), 16), (#n-2)/2
elseif n:sub(#n, #n)=="h" then return sign*tonumber(n:sub(1, #n-1), 16), (#n-1)/2
else
local v = tonumber(n) or error("invalid number "..n)
if v>=-128 and v<=255 then return v, 1
elseif v>=-32768 and v<=65535 then return v, 2
else error("out-of-range number "..v) end
end
end
local function mnemFromLine(line, instrs, validWords)
local firstWord = line:match("^[^ ]+")
local imms = {}
local function addNum(n)
local val, len = decodeNumber(n)
table.insert(imms, { val = val, len = len } )
return " imm"..(len*8).." "
end
local function addLabel(n)
local len = 2
if instrs[line:gsub(trim(n), "imm8", 1, true)] then len = 1 end
n = trim(n)
table.insert(imms, { label = n, len = len } )
return " imm"..(len*8).." "
end
local mnem = " "..line:gsub(" ", " ").." "
mnem = mnem:gsub(" %-?%$[0-9a-fA-F]+ ", function(n) return addNum (n) end)
mnem = mnem:gsub(" %-?0x[0-9a-fA-F]+ ", function(n) return addNum (n) end)
mnem = mnem:gsub(" %-?[0-9a-fA-F]+h " , function(n) if not validWords[trim(n)] then return addNum (n) end end)
mnem = mnem:gsub(" %-?[0-9]+ " , function(n) if not validWords[trim(n)] then return addNum (n) end end)
mnem = mnem:gsub(" [a-zA-Z0-9_]+ " , function(n) if not validWords[trim(n)] then return addLabel(n) end end)
mnem = trim(mnem):gsub(" +", " ")
return mnem, imms
end
local function addByte(state, val)
assert(val>=-128 and val<=255, "invalid byte "..val)
assert(not state.memory[state.curAddr], "overwriting memory at "..state.curAddr)
state.memory[state.curAddr] = val%256
state.curAddr = state.curAddr + 1
end
local function addWord(state, val)
assert(val>=0 and val<=65535, "invalid word "..val)
addByte(state, math.floor(val/256))
addByte(state, val%256)
end
local function assembleInstruction(line, state, instrs, validWords)
local mnem, imms = mnemFromLine(line, instrs, validWords)
local opcode = instrs[mnem] or error("invalid instruction "..line.." (mnem "..mnem..")")
local writeimms = true
local padlen = 0
if type(opcode)=="function" then
padlen, writeimms = opcode(imms)
state.curAddr = state.curAddr + padlen
elseif opcode>=0 then
addByte(state, opcode)
end
if writeimms then
for _, imm in ipairs(imms) do
if imm.val then
if imm.len==1 then addByte(state, imm.val)
elseif imm.len==2 then addWord(state, imm.val)
else error("invalid imm len") end
elseif imm.label then
table.insert(state.labelReplacements, {
name = imm.label,
addr = state.curAddr,
len = imm.len,
rel = imm.len==1,
})
state.curAddr = state.curAddr + imm.len
else error("invalid imm") end
end
end
end
local directiveFunctions = {
fn = function(state, fn) state.fileName = fn end,
ln = function(state, ln) state.lineNum = tonumber(ln) end,
org = function(state, addr) state.curAddr = decodeNumber(addr) end,
align = function(state, alns) local aln = decodeNumber(alns); if state.curAddr%aln~=0 then state.curAddr = state.curAddr + (aln - state.curAddr%aln) end end,
}
local function assembleCode(code, instrs)
local validWords = validWordsFromInstrs(instrs)
local state = {
lineNum = 0,
fileName = "",
curAddr = 0,
memory = {},
labelReplacements = {},
labelAddrs = {},
}
for line in code:gmatch("[^\n]+") do
if line:sub(1, 1)=="." then -- directive
local dir, rest = line:match("^%.([^ ]+) *(.*)$")
assert(dir and rest, "no directive on line "..line)
local dirf = directiveFunctions[dir] or error("invalid directive "..dir)
dirf(state, rest)
elseif line:sub(#line, #line)==":" then -- label
local name = line:sub(1, #line-1)
assert(not state.labelAddrs[name], "redefinition of label "..name)
state.labelAddrs[name] = state.curAddr
elseif line:find("[^ ]") then
assembleInstruction(line, state, instrs, validWords)
end
end
for _, rep in ipairs(state.labelReplacements) do
local labelAddr = state.labelAddrs[rep.name] or error("no label named "..rep.name)
state.curAddr = rep.addr
if rep.len==1 then addByte(state, labelAddr-(rep.addr+1))
elseif rep.len==2 then addWord(state, labelAddr)
else error("invalid labelreplace len") end
end
return state.memory
end
local function readFile(fn)
local fi = io.open(fn, "r") or error("could not open file "..fn)
local text = fi:read("*a")
fi:close()
return text
end
local function separateCommas(l)
local c = {}; for a in l:gmatch("[^,]+") do table.insert(c, trim(a)) end; return c;
end
local function preprocessCode(code)
local funcmacros = {}
code = code:gsub(".define ([a-zA-Z0-9_]+)%(([^%)]+)%) ([^\n]+)", function(name, args, repl)
local argt = separateCommas(args)
for argidx, arg in ipairs(argt) do assert(not arg:find("[^a-zA-Z0-9_]"), "invalid character in macro arg name: "..name.." "..arg) end
repl = " "..repl.." "
funcmacros[name] = function(callargs)
local callargt = separateCommas(callargs)
local callrepl = repl
for argidx, arg in ipairs(argt) do
local callarg = callargt[argidx]
callrepl = callrepl:gsub("([^a-zA-Z0-9_])"..arg.."([^a-zA-Z0-9_])", "%1"..callarg.."%2")
end
return callrepl
end
return ""
end)
for name, replf in pairs(funcmacros) do code = code:gsub(name.." *%(([^%)]+)%)", replf) end
local simplemacros = {}
code = code:gsub("%.define ([a-zA-Z0-9_]+) ([^\n]+)", function(name, repl)
assert(not simplemacros[name], "Redefinition of macro "..name)
simplemacros[name] = repl
return ""
end)
for name, repl in pairs(simplemacros) do code = code:gsub(name, repl, 1, true) end
code = code:gsub("\\", "\n")
return code
end
local function fixCode(code)
code = code:gsub(",", " ")
code = code:gsub("%]", " %] ")
code = code:gsub("%[", " %[ ")
code = code:gsub("\n[ \t\r\n]*", "\n")
code = code:gsub(" +", " ")
return code
end
local stringEscapes = { ["\\"] = "\\", ["n"] = "\n", ["r"] = "\r", ["t"] = "\t", ["0"] = "\0", ["\""] = "\"", ["\'"] = "\'", }
local function prefixCode(code, fn) -- fix strings, add line numbers
local outt = {}
local linenum = 1
local function last() return outt[#outt] end
local function out(c) assert(type(c)=="string"); table.insert(outt, c); end
local function outn(n) out("$"..string.format("%02X", n).."\n"); end
local state = "code" -- code, comment, string, stringesc
local skipnl = false
local lastbracelabel = 0
local function bracelabel() lastbracelabel = lastbracelabel+1; return "_BRACE_"..lastbracelabel.."_"; end
local bracestack = {}
out(".ln 1"); out("\n");
for i = 1, #code do
local c = code:sub(i, i)
if state=="code" then
if c=="\r" then
elseif c=="\n" then
linenum = linenum+1
if skipnl then out("\\")
else out("\n") out(".ln "..linenum) out("\n") end
skipnl = false
elseif c=="\t" or c==" " then out(" ")
elseif c=="#" or c==";" or c=="/" then state = "comment"
elseif c=="\"" then state = "string"
elseif c:find("^[a-zA-Z0-9_%.:%$%(%)%*,%[%]]$") then out(c)
elseif c=="\\" then skipnl = true
elseif c=="{" then
elseif c=="}" then
else error("invalid char "..c) end
elseif state=="comment" then
if c=="\n" then state = "code" out("\n") end
elseif state=="string" then
if c=="\\" then state = "stringesc"
elseif c=="\"" then state = "code"
else outn(c:byte()) end
elseif state=="stringesc" then
out(stringEscapes[c] or error("invalid escape "..c)); state = "string";
end
end
return table.concat(outt)
end
local function includeFile(fn)
fn = fn:gsub("\\", "/")
local code = readFile(fn)
code = prefixCode(code, fn)
code = ".fn "..fn.."\n"..code
code = code:gsub(".include ([^\r\n]+)", function(fn2)
return "\n"..includeFile(fn2).."\n"..".fn "..fn.."\n"
end)
return code
end
local function instrsFromArch(arch)
local function arraySize(imms) local s = 1; for i = 1, #imms do s = s*imms[i].val end; return s; end
local instrs = {
imm8 = function() return 0, true end,
imm16 = function() return 0, true end,
byte = function() return 1, false end,
word = function() return 2, false end,
["byte imm8"] = function() return 0, true end,
["word imm16"] = function() return 0, true end,
["byte [ imm8 ]" ] = function(imms) return arraySize(imms) , false end,
["byte [ imm16 ]"] = function(imms) return arraySize(imms) , false end,
["word [ imm8 ]" ] = function(imms) return arraySize(imms)*2, false end,
["word [ imm16 ]"] = function(imms) return arraySize(imms)*2, false end,
}
for _, instr in ipairs(arch.instructions) do
if instr.mnem then
instrs[instr.mnem] = instr.opcode
end
end
return instrs
end
local function assembleFile(fn)
local code = includeFile(fn)
code = preprocessCode(code)
code = fixCode(code)
local arch = require("rom-8608-defs")
local instrs = instrsFromArch(arch)
local mem = assembleCode(code, instrs)
return mem
end
local function printMemory(mem)
local lastbase = -16
for base = 0, 0xFFF0, 16 do
local line = { string.format("%04X", base), " | " }
local nonempty = false
for addr = base, base+15 do
if mem[addr] then
nonempty = true
table.insert(line, string.format("%02X", mem[addr]).." ")
else
table.insert(line, "-- ")
end
end
if nonempty then
if base ~= lastbase+16 then print("...") end
print(table.concat(line))
lastbase = base
end
end
end
local ts = ts or {
call = function() end,
eval = function() end,
}
ts.eval [[
function commandShiftBrick(%x, %y, %z) { commandToServer('shiftBrick', %x, %y, %z); }
function commandPlantBrick() { commandToServer('plantBrick'); }
]]
local function plantBrickAt(brickpos, pos)
local dx, dy, dz = pos[1]-brickpos[1], pos[2]-brickpos[2], pos[3]-brickpos[3]
ts.call("commandShiftBrick", dy, -dx, dz)
ts.call("commandPlantBrick")
brickpos[1], brickpos[2], brickpos[3] = pos[1], pos[2], pos[3]
end
local function buildMemory(mem, romsize, offset, len)
offset = offset or 0
local rombytes = romsize[1]*romsize[2]*romsize[3]/8
if len and len>rombytes then error("rom not big enough to hold "..len.." bytes (holds "..rombytes..")") end
if not len then
for i = 0, 0xFFFF do
if mem[i] and (i<offset or i>=offset+rombytes) then error("memory does not fit in rom at addr "..string.format("%04X", i)) end
end
end
local brickpos = {0, 0, 0}
for x = 0, romsize[1]-1 do
for y = 0, romsize[2]-1 do
for z = 0, romsize[3]-1 do
local addr = offset + ((romsize[3]/8)*(x + y*romsize[1]) + math.floor(z/8))
local pow = math.pow(2, z%8)
local data = (addr>=offset and ((not len) or addr<offset+len) and mem[addr]) or 0
local bit = math.floor(data/pow)%2
if bit==1 then plantBrickAt(brickpos, {x, y, z}) end
end
end
end
end
local function strtovec(str) local v = {}; for word in str:gmatch("[^ \t\r\n]+") do table.insert(v, tonumber(word)) end; return v; end
function AssembleFile(fn, romsizes, offsets, lens) offset = tonumber(offsets); len = tonumber(lens); romsize = strtovec(romsizes);
local mem = assembleFile(fn)
printMemory(mem)
if #romsize>0 then assert(#romsize==3, "incorrect rom size") end
buildMemory(mem, romsize, offset, len)
end
ts.eval [[
function AssembleFile(%fn, %romsize, %offset, %len) { luacall("AssembleFile", %fn, %romsize, %offset, %len); }
]]
if arg then AssembleFile(arg[1] or "programs/keyboard.asm", "16 16 8", "0", "256") end

276
rom-8608-defs.lua Normal file
View File

@ -0,0 +1,276 @@
return {
roms = {
{ pos = {0, 0, 0}, size = {64, 16, 64}, signals = {
"alulU", "alulT", "alulC", "alulB", "alulA", "alurIL", "alurIH", "alurVL",
"alurVH", "alurSL", "alurSH", "alurQL", "alurQH", "alurPL", "alurPH", "alurU",
"alurT", "alurC", "alurB", "alurA", "alur1", "alur2", "alurm1", "alurm2",
"adrrhU", "adrrhC", "adrrlT", "adrrTX", "adrrlB", "adrrBX", "adwrhU", "adwrhC",
"adwrlT", "adwrTX", "adwrlB", "adwrBX", "adwlI", "adwlV", "adwlS", "adwlQ",
"adwlP", "adrlI", "adrlV", "adrlS", "adrlQ", "adrlP", "aluAdd", "adwSaveV",
"aluRun", "aluRInv", "aluCinOn", "aluCinC", "memWriteAlur", "adrInc", "adwInc", "aluXor",
"aluIor", "aluAnd", "memWriteAlur", "adrOut", "adrSaveI", "adwSaveP", "adwSaveQ", "adwSaveS",
} },
{ pos = {-34, 16, 0}, size = {32, 32, 8}, signals = {
"aluSaveU", "aluSaveT", "aluSaveC", "aluSaveB", "aluSaveA", "aluSaveCarry", "aluSaveNZ", "always1",
} },
{ pos = {-34, 16, 17}, size = {32, 32, 32}, signals = {
"_", "_", "_", "_", "_", "_", "_", "_",
"_", "_", "_", "instrPre", "instrLoadPre", "always1", "instrLoad", "adrOut",
"memWriteAlur", "memSave", "instrNext0NZ", "instrNext0Z", "instrNext0NC", "instrNext0C", "instrLoadSub", "instrLoad",
"instrNext2", "instrNext1", "instrNext0", "memSaveU", "memSaveT", "memSaveC", "memSaveB", "memSaveA",
} },
{ pos = {66, 16, 0}, size = {32, 32, 16}, signals = {
"adrr1", "adrrm1", "adrrm2", "adrr2", "adwrm1", "adwrm2", "adwr2", "adwr1",
"memRead", "memWrite", "runFlgVal", "runFlgClk", "intFlgVal", "intFlgClk", "irqFlgClk", "always1",
} },
},
operations = {
base = {"always1"},
instrNext = {"base","adrlI","adrInc","adrSaveI","loadInstr"},
instrSub1 = {"base","instrLoadSub", "instrNext0"},
instrSub2 = {"base","instrLoadSub", "instrNext1", },
instrSub3 = {"base","instrLoadSub", "instrNext1","instrNext0"},
instrSub4 = {"base","instrLoadSub","instrNext2", },
instrSub5 = {"base","instrLoadSub","instrNext2", "instrNext0"},
instrSub6 = {"base","instrLoadSub","instrNext2","instrNext1", },
instrSub7 = {"base","instrLoadSub","instrNext2","instrNext1","instrNext0"},
instrSub23Cond = {"base","instrLoadSub","instrNext1"},
instrSwapIV = {"base","adwlI","adwSaveV","adrlV","adrSaveI","loadInstr"},
instrPreload = {"adrlI","adrInc","adrSaveI","adrOut","memRead","instrLoadPre"},
instrNextPre = {"base","instrPre","instrLoad","instrLoadSub"},
loadInstr = {"adrOut","memRead","instrLoad","instrLoadSub"},
loadReg = {"adrOut","memRead","memSave"},
storeReg = {"adrOut","memWrite","memWriteAlur"},
loadRegT = {"loadReg","memSaveT"},
pushReg = {"storeReg","adrlS","adwlS","adwInc","adwSaveS"},
popReg = {"loadReg","adrlS","adrrm1","adwlS","adwrm1","adwSaveS"},
pop161 = {"popReg","memSaveT"},
pop162 = {"popReg","memSaveU"},
loadImmed = {"adrlI","adrInc","adrSaveI","loadReg"},
loadImmedT = {"loadImmed","memSaveT"},
loadImm161 = {"loadImmed","memSaveU"},
loadImm162 = {"loadImmed","memSaveT"},
loadStackRel = {"adrlS","adrrTX","loadReg"},
loadStackRelT = {"loadStackRel","memSaveT"},
loadStackRelU = {"loadStackRel","memSaveU"},
loadStackRel161 = {"loadStackRel", "memSaveU"},
loadStackRel162 = {"loadStackRel","adrInc","memSaveT"},
storeStackRel = {"adrlS","adrrTX","storeReg"},
storeStackRel161 = {"storeStackRel" },
storeStackRel162 = {"storeStackRel","adrInc"},
storeStackRelU = {"adrlS","adrrTX","storeReg","alurU"},
load161 = { "loadReg","memSaveU"},
load162 = {"adrInc","loadReg","memSaveT"},
store161 = { "storeReg"},
store162 = {"adrInc","storeReg"},
loadUTU = {"adrrUT","loadReg","memSaveU"},
storeUT = {"adrrUT","storeReg"},
adwrUT = {"adwrhU","adwrlT"},
adrrUT = {"adrrhU","adrrlT"},
adwrCB = {"adwrhC","adwrlB"},
adwIncUT = {"adwrUT","adwInc"},
jmpRelT = {"instrNext","adrrTX"},
jmpAbs = {"base","loadInstr","adrSaveI"},
jmpAbsUT = {"jmpAbs","adrrUT"},
jmpAbsP = {"jmpAbs","adrlP"},
jmpAbsQ = {"jmpAbs","adrlQ"},
saveRetAddr = {"adwlI","adwInc","adwSaveQ"},
aluMove = {"aluAdd","aluRun"},
aluA = {"alulA","aluSaveA","aluRun"},
aluB = {"alulB","aluSaveB","aluRun"},
aluC = {"alulC","aluSaveC","aluRun"},
aluT = {"alulT","aluSaveT","aluRun"},
aluU = {"alulU","aluSaveU","aluRun"},
},
instructions = {
{ category = "Control", catlet="C" },
{ mnem="rst" , opcode=0x00, {"base","intFlgClk","irqFlgClk","runFlgClk","runFlgVal","adrSaveI","aluSaveA","aluSaveB","aluSaveC","aluSaveU","aluSaveT","adwSaveP","adwSaveQ","adwSaveS","adwSaveV","loadInstr"}, desc="Clear all registers and set I=0" },
{ mnem="hlt" , opcode=0xF0, {"runFlgClk","instrNext"}, desc="Halt non-interrupt execution" },
{ mnem="run" , opcode=0xF1, {"runFlgClk","runFlgVal","instrNext"}, desc ="Resume non-interrupt execution" },
{ mnem="int" , opcode=0xF2, {"instrSwapIV","intFlgVal","intFlgClk","irqFlgClk"}, },
{ mnem="brk" , opcode=0xF3, {"instrSwapIV","adwInc","intFlgVal","intFlgClk"}, desc="Trigger interrupt" },
{ mnem="irt" , opcode=0xF4, {"instrSwapIV","adwInc","intFlgClk"}, desc="Return from interrupt" },
{ category = "16-bit Inc/Dec", catlet="I" },
{ mnem="icp" , opcode=0x12, {"adwlP","adwInc","adwSaveP","instrNext"}, desc="P++" },
{ mnem="dcp" , opcode=0x15, {"adwlP","adwrm1","adwSaveP","instrNext"}, desc="P--" },
{ mnem="icq" , opcode=0x13, {"adwlQ","adwInc","adwSaveQ","instrNext"}, desc="Q++" },
{ mnem="dcq" , opcode=0x16, {"adwlQ","adwrm1","adwSaveQ","instrNext"}, desc="Q--" },
{ category = "8-bit Unary", catlet="U" },
{ mnem="inc a" , opcode=0x10, {"aluA","alur1", "aluAdd","aluSaveCarry","aluSaveNZ","instrNext"}, desc="A++, set flags" },
{ mnem="dec a" , opcode=0x11, {"aluA","alurm1", "aluAdd","aluSaveCarry","aluSaveNZ","instrNext"}, desc="A--, set flags" },
{ mnem="icc a" , opcode=0x1B, {"aluA", "aluCinC", "aluAdd","aluSaveCarry","aluSaveNZ","instrNext"}, desc="A+=CF, set flags" },
{ mnem="inc b" , opcode=0x19, {"aluB","alur1", "aluAdd","aluSaveCarry","aluSaveNZ","instrNext"}, desc="B++, set flags" },
{ mnem="dec b" , opcode=0x1A, {"aluB","alurm1", "aluAdd","aluSaveCarry","aluSaveNZ","instrNext"}, desc="B--, set flags" },
{ mnem="icc b" , opcode=0x1C, {"aluB", "aluCinC", "aluAdd","aluSaveCarry","aluSaveNZ","instrNext"}, desc="B+=CF, set flags" },
{ mnem="inc c" , opcode=0x17, {"aluC","alur1", "aluAdd","aluSaveCarry","aluSaveNZ","instrNext"}, desc="C++, set flags" },
{ mnem="dec c" , opcode=0x18, {"aluC","alurm1", "aluAdd","aluSaveCarry","aluSaveNZ","instrNext"}, desc="C--, set flags" },
{ mnem="icc c" , opcode=0x1D, {"aluC", "aluCinC", "aluAdd","aluSaveCarry","aluSaveNZ","instrNext"}, desc="C+=CF, set flags" },
{ mnem="tst a" , opcode=0x14, {"alulA","aluRun","aluRInv","aluCinOn","aluAdd","aluSaveCarry","aluSaveNZ","instrNext"}, desc="Set flags according to A-0" },
{ mnem="tst b" , opcode=0x1E, {"alulB","aluRun","aluRInv","aluCinOn","aluAdd","aluSaveCarry","aluSaveNZ","instrNext"}, desc="Set flags according to B-0" },
{ mnem="tst c" , opcode=0x1F, {"alulC","aluRun","aluRInv","aluCinOn","aluAdd","aluSaveCarry","aluSaveNZ","instrNext"}, desc="Set flags according to C-0" },
{ mnem="inc *s+imm8", opcode=0x2B, {"loadImmedT","instrSub1"}, {"loadStackRelU","instrSub2"}, {"aluU","alur1", "aluAdd","aluSaveCarry","aluSaveNZ","instrSub3","instrPreload"}, {"storeStackRelU","instrNextPre"}, desc="*(S+imm8)++, set flags" },
{ mnem="dec *s+imm8", opcode=0x2C, {"loadImmedT","instrSub1"}, {"loadStackRelU","instrSub2"}, {"aluU","alurm1", "aluAdd","aluSaveCarry","aluSaveNZ","instrSub3","instrPreload"}, {"storeStackRelU","instrNextPre"}, desc="*(S+imm8)--, set flags" },
{ mnem="icc *s+imm8", opcode=0x2D, {"loadImmedT","instrSub1"}, {"loadStackRelU","instrSub2"}, {"aluU", "aluCinC", "aluAdd","aluSaveCarry","aluSaveNZ","instrSub3","instrPreload"}, {"storeStackRelU","instrNextPre"}, desc="*(S+imm8)-=CF, set flags" },
{ mnem="tst *s+imm8", opcode=0x2E, {"loadImmedT","instrSub1"}, {"loadStackRelU","instrSub2"}, {"alulU","aluRun","aluRInv","aluCinOn","aluAdd","aluSaveCarry","aluSaveNZ","instrNext"}, desc="Set flags according to *(S+imm8)-0" },
{ category = "8-bit Arithmetic/Logic", catlet="A" },
{ mnem="add imm8" , opcode=0x24, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluAdd", "aluSaveCarry","aluSaveNZ","instrNext"}, desc="A+=imm8, set flags" },
{ mnem="adb imm8" , opcode=0x72, {"loadImmedT","instrSub1"}, {"aluB", "alurT","aluAdd", "aluSaveCarry","aluSaveNZ","instrNext"}, desc="B+=imm8, set flags" },
{ mnem="adc imm8" , opcode=0x73, {"loadImmedT","instrSub1"}, {"aluC", "alurT","aluAdd", "aluSaveCarry","aluSaveNZ","instrNext"}, desc="C+=imm8, set flags" },
{ mnem="sub imm8" , opcode=0x70, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluAdd","aluRInv","aluCinOn","aluSaveCarry","aluSaveNZ","instrNext"}, desc="A-=imm8, set flags" },
{ mnem="sbb imm8" , opcode=0x99, {"loadImmedT","instrSub1"}, {"aluB", "alurT","aluAdd","aluRInv","aluCinOn","aluSaveCarry","aluSaveNZ","instrNext"}, desc="B-=imm8, set flags" },
{ mnem="sbc imm8" , opcode=0x9A, {"loadImmedT","instrSub1"}, {"aluC", "alurT","aluAdd","aluRInv","aluCinOn","aluSaveCarry","aluSaveNZ","instrNext"}, desc="C-=imm8, set flags" },
{ mnem="acc imm8" , opcode=0x78, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluAdd", "aluCinC", "aluSaveCarry","aluSaveNZ","instrNext"}, desc="A+=imm8+CF, set flags" },
{ mnem="scc imm8" , opcode=0x79, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluAdd","aluRInv","aluCinC" ,"aluSaveCarry","aluSaveNZ","instrNext"}, desc="A-=imm8+CF, set flags" },
{ mnem="cmp imm8" , opcode=0x71, {"loadImmedT","instrSub1"}, {"alulA","aluRun","alurT","aluAdd","aluRInv","aluCinOn","aluSaveCarry","aluSaveNZ","instrNext"}, desc="set flags according to A-imm8" },
{ mnem="and imm8" , opcode=0x74, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluAnd", "aluSaveNZ","instrNext"}, desc="A&=imm8, set zero flag" },
{ mnem="ior imm8" , opcode=0x75, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluIor", "aluSaveNZ","instrNext"}, desc="A|=imm8, set zero flag" },
{ mnem="xor imm8" , opcode=0x76, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluXor", "aluSaveNZ","instrNext"}, desc="A^=imm8, set zero flag" },
{ mnem="ann imm8" , opcode=0x77, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluAnd","aluRInv", "aluSaveNZ","instrNext"}, desc="A&=~imm8, set zero flag" },
{ mnem="add *s+imm8", opcode=0xAE, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluAdd", "aluSaveCarry","aluSaveNZ","instrNext"}, desc="A+=*(S+imm8), set flags" },
{ mnem="adb *s+imm8", opcode=0x9B, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluB", "alurT","aluAdd", "aluSaveCarry","aluSaveNZ","instrNext"}, desc="B+=*(S+imm8), set flags" },
{ mnem="adc *s+imm8", opcode=0x9C, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluC", "alurT","aluAdd", "aluSaveCarry","aluSaveNZ","instrNext"}, desc="C+=*(S+imm8), set flags" },
{ mnem="sub *s+imm8", opcode=0xAF, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluAdd","aluRInv","aluCinOn","aluSaveCarry","aluSaveNZ","instrNext"}, desc="A-=*(S+imm8), set flags" },
{ mnem="sbb *s+imm8", opcode=0x9D, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluB", "alurT","aluAdd","aluRInv","aluCinOn","aluSaveCarry","aluSaveNZ","instrNext"}, desc="B-=*(S+imm8), set flags" },
{ mnem="sbc *s+imm8", opcode=0x9E, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluC", "alurT","aluAdd","aluRInv","aluCinOn","aluSaveCarry","aluSaveNZ","instrNext"}, desc="C-=*(S+imm8), set flags" },
{ mnem="acc *s+imm8", opcode=0xB5, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluAdd", "aluCinC", "aluSaveCarry","aluSaveNZ","instrNext"}, desc="A+=*(S+imm8)+CF, set flags" },
{ mnem="scc *s+imm8", opcode=0xB7, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluAdd","aluRInv","aluCinC", "aluSaveCarry","aluSaveNZ","instrNext"}, desc="A-=*(S+imm8)+CF, set flags" },
{ mnem="cmp *s+imm8", opcode=0xB0, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"alulA","aluRun","alurT","aluAdd","aluRInv","aluCinOn","aluSaveCarry","aluSaveNZ","instrNext"}, desc="set flags according to A-*(S+imm8)" },
{ mnem="and *s+imm8", opcode=0xB1, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluAnd", "aluSaveNZ","instrNext"}, desc="A&=*(S+imm8), set zero flag" },
{ mnem="ior *s+imm8", opcode=0xB2, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluIor", "aluSaveNZ","instrNext"}, desc="A|=*(S+imm8), set zero flag" },
{ mnem="xor *s+imm8", opcode=0xB3, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluXor", "aluSaveNZ","instrNext"}, desc="A^=*(S+imm8), set zero flag" },
{ mnem="ann *s+imm8", opcode=0xB4, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluAnd","aluRInv", "aluSaveNZ","instrNext"}, desc="A&=~*(S+imm8), set zero flag" },
{ mnem="add b" , opcode=0xA0, {"aluA", "alurB","aluAdd", "aluSaveCarry","aluSaveNZ","instrNext"}, desc="A+=B, set flags" },
{ mnem="adc b" , opcode=0x9F, {"aluC", "alurB","aluAdd", "aluSaveCarry","aluSaveNZ","instrNext"}, desc="C+=B, set flags" },
{ mnem="sub b" , opcode=0xA1, {"aluA", "alurB","aluAdd","aluRInv","aluCinOn","aluSaveCarry","aluSaveNZ","instrNext"}, desc="A-=B, set flags" },
{ mnem="sbc b" , opcode=0xB6, {"aluC", "alurB","aluAdd","aluRInv","aluCinOn","aluSaveCarry","aluSaveNZ","instrNext"}, desc="C-=B, set flags" },
{ mnem="acc b" , opcode=0xB8, {"aluA", "alurB","aluAdd", "aluCinC", "aluSaveCarry","aluSaveNZ","instrNext"}, desc="A+=B+CF, set flags" },
{ mnem="scc b" , opcode=0xB9, {"aluA", "alurB","aluAdd","aluRInv","aluCinC", "aluSaveCarry","aluSaveNZ","instrNext"}, desc="A-=B+CF, set flags" },
{ mnem="cmp b" , opcode=0xA2, {"alulA","aluRun","alurB","aluAdd","aluRInv","aluCinOn","aluSaveCarry","aluSaveNZ","instrNext"}, desc="set flags according to A-B" },
{ mnem="and b" , opcode=0xA3, {"aluA", "alurB","aluAnd", "aluSaveNZ","instrNext"}, desc="A&=B, set zero flag" },
{ mnem="ior b" , opcode=0xA4, {"aluA", "alurB","aluIor", "aluSaveNZ","instrNext"}, desc="A|=B, set zero flag" },
{ mnem="xor b" , opcode=0xA5, {"aluA", "alurB","aluXor", "aluSaveNZ","instrNext"}, desc="A^=B, set zero flag" },
{ mnem="ann b" , opcode=0xA6, {"aluA", "alurB","aluAnd","aluRInv", "aluSaveNZ","instrNext"}, desc="A&=~B, set zero flag" },
{ mnem="add c" , opcode=0xA7, {"aluA", "alurC","aluAdd", "aluSaveCarry","aluSaveNZ","instrNext"}, desc="A+=C, set flags" },
{ mnem="adb c" , opcode=0xBD, {"aluB", "alurC","aluAdd", "aluSaveCarry","aluSaveNZ","instrNext"}, desc="B+=C, set flags" },
{ mnem="sub c" , opcode=0xA8, {"aluA", "alurC","aluAdd","aluRInv","aluCinOn","aluSaveCarry","aluSaveNZ","instrNext"}, desc="A-=C, set flags" },
{ mnem="sbb c" , opcode=0xBC, {"aluB", "alurC","aluAdd","aluRInv","aluCinOn","aluSaveCarry","aluSaveNZ","instrNext"}, desc="B-=C, set flags" },
{ mnem="acc c" , opcode=0xBA, {"aluA", "alurC","aluAdd", "aluCinC", "aluSaveCarry","aluSaveNZ","instrNext"}, desc="A+=C+CF, set flags" },
{ mnem="scc c" , opcode=0xBB, {"aluA", "alurC","aluAdd","aluRInv","aluCinC" ,"aluSaveCarry","aluSaveNZ","instrNext"}, desc="A-=C+CF, set flags" },
{ mnem="cmp c" , opcode=0xA9, {"alulA","aluRun","alurC","aluAdd","aluRInv","aluCinOn","aluSaveCarry","aluSaveNZ","instrNext"}, desc="set flags according to A-C" },
{ mnem="and c" , opcode=0xAA, {"aluA", "alurC","aluAnd", "aluSaveNZ","instrNext"}, desc="A&=C, set zero flag" },
{ mnem="ior c" , opcode=0xAB, {"aluA", "alurC","aluIor", "aluSaveNZ","instrNext"}, desc="A|=C, set zero flag" },
{ mnem="xor c" , opcode=0xAC, {"aluA", "alurC","aluXor", "aluSaveNZ","instrNext"}, desc="A^=C, set zero flag" },
{ mnem="ann c" , opcode=0xAD, {"aluA", "alurC","aluAnd","aluRInv", "aluSaveNZ","instrNext"}, desc="A&=~C, set zero flag" },
{ category = "Jumps", catlet="J" },
{ mnem="jmp imm16" , opcode=0x60, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"jmpAbsUT" }, desc="I=imm16" },
{ mnem="jsr imm16" , opcode=0x63, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"jmpAbsUT","saveRetAddr"}, desc="I=imm16, Q=I" },
{ mnem="jmp p" , opcode=0x64, {"jmpAbsP" }, desc="I=P" },
{ mnem="jsr p" , opcode=0x65, {"jmpAbsP","saveRetAddr"}, desc="I=P, Q=I" },
{ mnem="jmp q" , opcode=0x66, {"jmpAbsQ" }, desc="I=Q" },
{ mnem="jsr q" , opcode=0x67, {"jmpAbsQ","saveRetAddr"}, desc="I=Q, Q=I" },
{ mnem="jpr imm8" , opcode=0x31, ncycles=2, {"loadImmed","memSaveT","instrSub1"}, {"jmpRelT"}, desc="I+=imm8" },
{ mnem="jnz imm8" , opcode=0x30, ncycles=2, {"loadImmed","memSaveT","instrSub23Cond","instrNext0NZ" }, {}, {"instrNext"}, {"jmpRelT"}, desc="I+=imm8 if !Zero" },
{ mnem="jpz imm8" , opcode=0x32, ncycles=2, {"loadImmed","memSaveT","instrSub23Cond","instrNext0Z" }, {}, {"instrNext"}, {"jmpRelT"}, desc="I+=imm8 if Zero" },
{ mnem="jge imm8" , opcode=0x33, ncycles=2, {"loadImmed","memSaveT","instrSub23Cond","instrNext0NC" }, {}, {"instrNext"}, {"jmpRelT"}, desc="I+=imm8 if Carry" },
{ mnem="jlt imm8" , opcode=0x34, ncycles=2, {"loadImmed","memSaveT","instrSub23Cond","instrNext0C" }, {}, {"instrNext"}, {"jmpRelT"}, desc="I+=imm8 if !Carry" },
{ mnem="jgt imm8" , opcode=0x35, ncycles=2, {"loadImmed","memSaveT","instrSub23Cond","instrNext0C","instrNext0Z"}, {}, {"jmpRelT"}, {"instrNext"}, desc="I+=imm8 if !Zero&!Carry" },
{ mnem="jle imm8" , opcode=0x36, ncycles=2, {"loadImmed","memSaveT","instrSub23Cond","instrNext0C","instrNext0Z"}, {}, {"instrNext"}, {"jmpRelT"}, desc="I+=imm8 if Zero|Carry" },
{ category = "Stack", catlet="S" },
{ mnem="pha" , opcode=0x40, {"pushReg","alurA","instrSub1"}, {"instrNext"}, desc="*(S++)=A" },
{ mnem="phb" , opcode=0x44, {"pushReg","alurB","instrSub1"}, {"instrNext"}, desc="*(S++)=B" },
{ mnem="phc" , opcode=0x45, {"pushReg","alurC","instrSub1"}, {"instrNext"}, desc="*(S++)=C" },
{ mnem="php" , opcode=0x41, {"pushReg","alurPH","instrSub1"}, {"pushReg","alurPL","instrSub2"}, {"instrNext"}, desc="*(S++++)=P" },
{ mnem="phq" , opcode=0x46, {"pushReg","alurQH","instrSub1"}, {"pushReg","alurQL","instrSub2"}, {"instrNext"}, desc="*(S++++)=Q" },
{ mnem="ppa" , opcode=0x42, {"popReg","memSaveA","instrSub1"}, {"instrNext"}, desc="A=*(--S)" },
{ mnem="ppb" , opcode=0x47, {"popReg","memSaveB","instrSub1"}, {"instrNext"}, desc="B=*(--S)" },
{ mnem="ppc" , opcode=0x48, {"popReg","memSaveC","instrSub1"}, {"instrNext"}, desc="C=*(--S)" },
{ mnem="ppp" , opcode=0x43, {"pop161","instrSub1"}, {"pop162","instrSub2"}, {"adwrUT","adwSaveP","instrNext"}, desc="P=*(----S)" },
{ mnem="ppq" , opcode=0x49, {"pop161","instrSub1"}, {"pop162","instrSub2"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Q=*(----S)" },
{ category = "8-bit Load/Store", catlet="B" },
{ mnem="lda imm8" , opcode=0x20, {"loadImmed", "memSaveA","instrSub1"}, {"instrNext"}, desc="A=imm8" },
{ mnem="ldb imm8" , opcode=0x26, {"loadImmed", "memSaveB","instrSub1"}, {"instrNext"}, desc="B=imm8" },
{ mnem="ldc imm8" , opcode=0x27, {"loadImmed", "memSaveC","instrSub1"}, {"instrNext"}, desc="C=imm8" },
{ mnem="lda *s+imm8", opcode=0x28, {"loadImmedT","instrSub1"}, {"loadStackRel","memSaveA","instrSub2"}, {"instrNext"}, desc="A=*s+imm8" },
{ mnem="ldb *s+imm8", opcode=0x29, {"loadImmedT","instrSub1"}, {"loadStackRel","memSaveB","instrSub2"}, {"instrNext"}, desc="B=*s+imm8" },
{ mnem="ldc *s+imm8", opcode=0x2A, {"loadImmedT","instrSub1"}, {"loadStackRel","memSaveC","instrSub2"}, {"instrNext"}, desc="C=*s+imm8" },
{ mnem="sta *s+imm8", opcode=0x96, {"loadImmedT","instrSub1"}, {"storeStackRel","alurA","instrSub2"}, {"instrNext"}, desc="*s+imm8=A" },
{ mnem="stb *s+imm8", opcode=0x97, {"loadImmedT","instrSub1"}, {"storeStackRel","alurB","instrSub2"}, {"instrNext"}, desc="*s+imm8=B" },
{ mnem="stc *s+imm8", opcode=0x98, {"loadImmedT","instrSub1"}, {"storeStackRel","alurC","instrSub2"}, {"instrNext"}, desc="*s+imm8=C" },
{ mnem="lda *imm16" , opcode=0x51, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2",}, {"adrrUT","loadReg","memSaveA","instrSub3"}, {"instrNext"}, desc="A=*imm16" },
{ mnem="ldb *imm16" , opcode=0x56, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2",}, {"adrrUT","loadReg","memSaveB","instrSub3"}, {"instrNext"}, desc="B=*imm16" },
{ mnem="ldc *imm16" , opcode=0x57, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2",}, {"adrrUT","loadReg","memSaveC","instrSub3"}, {"instrNext"}, desc="C=*imm16" },
{ mnem="sta *imm16" , opcode=0x50, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2",}, {"adrrUT","storeReg","alurA","instrSub3"}, {"instrNext"}, desc="*imm16=A" },
{ mnem="stb *imm16" , opcode=0x58, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2",}, {"adrrUT","storeReg","alurB","instrSub3"}, {"instrNext"}, desc="*imm16=B" },
{ mnem="stc *imm16" , opcode=0x59, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2",}, {"adrrUT","storeReg","alurC","instrSub3"}, {"instrNext"}, desc="*imm16=C" },
{ mnem="sta *p" , opcode=0x52, {"adrlP","storeReg","alurA","instrSub1"}, {"instrNext"}, desc="*P=A" },
{ mnem="stb *p" , opcode=0x5A, {"adrlP","storeReg","alurB","instrSub1"}, {"instrNext"}, desc="*P=B" },
{ mnem="stc *p" , opcode=0x5B, {"adrlP","storeReg","alurC","instrSub1"}, {"instrNext"}, desc="*P=C" },
{ mnem="sta *q" , opcode=0x54, {"adrlQ","storeReg","alurA","instrSub1"}, {"instrNext"}, desc="*Q=A" },
{ mnem="stb *q" , opcode=0x5C, {"adrlQ","storeReg","alurB","instrSub1"}, {"instrNext"}, desc="*Q=B" },
{ mnem="stc *q" , opcode=0x5D, {"adrlQ","storeReg","alurC","instrSub1"}, {"instrNext"}, desc="*Q=C" },
{ mnem="lda *p" , opcode=0x53, {"adrlP","loadReg","memSaveA","instrSub1"}, {"instrNext"}, desc="A=*P" },
{ mnem="ldb *p" , opcode=0x5E, {"adrlP","loadReg","memSaveB","instrSub1"}, {"instrNext"}, desc="B=*P" },
{ mnem="ldc *p" , opcode=0x5F, {"adrlP","loadReg","memSaveC","instrSub1"}, {"instrNext"}, desc="C=*P" },
{ mnem="lda *q" , opcode=0x55, {"adrlQ","loadReg","memSaveA","instrSub1"}, {"instrNext"}, desc="A=*Q" },
{ mnem="ldb *q" , opcode=0x61, {"adrlQ","loadReg","memSaveB","instrSub1"}, {"instrNext"}, desc="B=*Q" },
{ mnem="ldc *q" , opcode=0x62, {"adrlQ","loadReg","memSaveC","instrSub1"}, {"instrNext"}, desc="C=*Q" },
{ category = "16-bit Load/Store", catlet="W" },
{ mnem="ldp imm16" , opcode=0x21, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"adwrUT","adwSaveP","instrNext"}, desc="P=imm16" },
{ mnem="ldq imm16" , opcode=0x23, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Q=imm16" },
{ mnem="lds imm16" , opcode=0x25, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"adwrUT","adwSaveS","instrNext"}, desc="S=imm16" },
{ mnem="ldv imm16" , opcode=0x22, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"adwrUT","adwSaveV","instrNext"}, desc="V=imm16" },
{ mnem="ldp *s+imm8", opcode=0x7A, {"loadImmedT","instrSub1"}, {"loadStackRel161","instrSub2"}, {"loadStackRel162","instrSub3"}, {"adwrUT","adwSaveP","instrNext"}, desc="P=*S+imm8" },
{ mnem="ldq *s+imm8", opcode=0x7B, {"loadImmedT","instrSub1"}, {"loadStackRel161","instrSub2"}, {"loadStackRel162","instrSub3"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Q=*S+imm8" },
{ mnem="stp *s+imm8", opcode=0x7E, {"loadImmedT","instrSub1"}, {"storeStackRel161","alurPH","instrSub2"}, {"storeStackRel162","alurPL","instrSub3"}, {"instrNext"}, desc="*S+imm8=P" },
{ mnem="stq *s+imm8", opcode=0x7F, {"loadImmedT","instrSub1"}, {"storeStackRel161","alurQH","instrSub2"}, {"storeStackRel162","alurQL","instrSub3"}, {"instrNext"}, desc="*S+imm8=Q" },
{ mnem="ldp *imm16" , opcode=0x68, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"loadUTU","adwIncUT","adwSaveP","instrSub3"}, {"adrlP","loadRegT","instrSub4"}, {"adwrUT","adwSaveP","instrNext"}, desc="P=*imm16" }, -- 0x69
{ mnem="ldq *imm16" , opcode=0x6A, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"loadUTU","adwIncUT","adwSaveQ","instrSub3"}, {"adrlQ","loadRegT","instrSub4"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Q=*imm16" }, -- 0x6B
{ mnem="stp *imm16" , opcode=0x6C, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"storeUT","alurPH","instrSub3"}, {"storeUT","adrInc","alurPL","instrSub4"}, {"instrNext"}, desc="*imm16=P" }, -- 0x6D
{ mnem="stq *imm16" , opcode=0x6E, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"storeUT","alurQH","instrSub3"}, {"storeUT","adrInc","alurQL","instrSub4"}, {"instrNext"}, desc="*imm16=Q" }, -- 0x6F
{ mnem="ldp *p" , opcode=0x92, {"adrlP","load161","instrSub1"}, {"adrlP","load162","instrSub2"}, {"adwrUT","adwSaveP","instrNext"}, desc="P=*P" },
{ mnem="ldq *p" , opcode=0x93, {"adrlP","load161","instrSub1"}, {"adrlP","load162","instrSub2"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Q=*P" },
{ mnem="ldp *q" , opcode=0x94, {"adrlQ","load161","instrSub1"}, {"adrlQ","load162","instrSub2"}, {"adwrUT","adwSaveP","instrNext"}, desc="P=*Q" },
{ mnem="ldq *q" , opcode=0x95, {"adrlQ","load161","instrSub1"}, {"adrlQ","load162","instrSub2"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Q=*Q" },
{ mnem="stp *q" , opcode=0x7C, {"adrlQ","store161","alurPH","instrSub1"}, {"adrlQ","store162","alurPL","instrSub2"}, {"instrNext"}, desc="*Q=P" },
{ mnem="stq *p" , opcode=0x7D, {"adrlP","store161","alurQH","instrSub1"}, {"adrlP","store162","alurQL","instrSub2"}, {"instrNext"}, desc="*P=Q" },
{ category = "Moves", catlet="M" },
{ mnem="lda b" , opcode=0x80, {"alurB" ,"aluAdd","aluSaveA","instrNext"}, desc="A=B" },
{ mnem="lda c" , opcode=0x81, {"alurC" ,"aluAdd","aluSaveA","instrNext"}, desc="A=C" },
{ mnem="ldb a" , opcode=0x82, {"alurA" ,"aluAdd","aluSaveB","instrNext"}, desc="B=A" },
{ mnem="ldb c" , opcode=0x83, {"alurC" ,"aluAdd","aluSaveB","instrNext"}, desc="B=C" },
{ mnem="ldc a" , opcode=0x84, {"alurA" ,"aluAdd","aluSaveC","instrNext"}, desc="C=A" },
{ mnem="ldc b" , opcode=0x85, {"alurB" ,"aluAdd","aluSaveC","instrNext"}, desc="C=B" },
{ mnem="lda pl" , opcode=0x86, {"alurPL","aluAdd","aluSaveA","instrNext"}, desc="A=P&FF" },
{ mnem="lda ph" , opcode=0x87, {"alurPH","aluAdd","aluSaveA","instrNext"}, desc="A=P>>8" },
{ mnem="lda ql" , opcode=0x88, {"alurQL","aluAdd","aluSaveA","instrNext"}, desc="A=Q&FF" },
{ mnem="lda qh" , opcode=0x89, {"alurQH","aluAdd","aluSaveA","instrNext"}, desc="A=Q>>8" },
{ mnem="ldp q" , opcode=0x8A, {"adwlQ" ,"adwSaveP","instrNext"}, desc="P=Q" },
{ mnem="ldp s" , opcode=0x8B, {"adwlS" ,"adwSaveP","instrNext"}, desc="P=S" },
{ mnem="ldp v" , opcode=0x8C, {"adwlV" ,"adwSaveP","instrNext"}, desc="P=V" },
{ mnem="ldp i" , opcode=0x8D, {"adwlI" ,"adwSaveP","instrNext"}, desc="P=I" },
{ mnem="ldp cb" , opcode=0x91, {"adwrCB","adwSaveP","instrNext"}, desc="P=C<<8+B" },
{ mnem="ldq p" , opcode=0x8E, {"adwlP" ,"adwSaveQ","instrNext"}, desc="Q=P" },
{ mnem="lds p" , opcode=0x8F, {"adwlP" ,"adwSaveS","instrNext"}, desc="S=P" },
{ mnem="ldv p" , opcode=0x90, {"adwlP" ,"adwSaveV","instrNext"}, desc="V=P" },
},
}

180
rom-8608.lua Normal file
View File

@ -0,0 +1,180 @@
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)