initial commit
This commit is contained in:
commit
5fe3adca2a
BIN
arch8608.ods
Normal file
BIN
arch8608.ods
Normal file
Binary file not shown.
342
assembler-8608.lua
Normal file
342
assembler-8608.lua
Normal 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
276
rom-8608-defs.lua
Normal 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
180
rom-8608.lua
Normal 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)
|
Loading…
x
Reference in New Issue
Block a user