Skip to content

Instantly share code, notes, and snippets.

@pingbird
Last active August 29, 2015 14:18
Show Gist options
  • Select an option

  • Save pingbird/a3791745322d63bdc948 to your computer and use it in GitHub Desktop.

Select an option

Save pingbird/a3791745322d63bdc948 to your computer and use it in GitHub Desktop.
MP238-L
--[[
MP238-L Specifications
Types:
constant
register
interrupt
memory
Constant registers:
uo = 0xFB -- ALU output
ui = 0xFC -- ALU carry in
uc = 0xFD -- ALU carry out
ip = 0xFE -- Instruction number
ht = 0xFF -- Halt
Statements:
register|interrupt|memory=value; --
function(...); --
-name; -- unassigns register
:label --
Objects:
register R[*] --
register name -- assigns next available register
interrupt I[constant] --
memory M[*] --
constant %d+ --
constant 0x%x+ --
Functions:
register ALU(OP,A,B[,C]) -- ALU Operator
OP: constant operator --
A: first number --
B: second number --
C: optional carry in --
instruction I(A) -- Waits for interrupt A to update
A: constant interrupt --
constant C(A) -- Gets the constant value of A
A: anything with a value --
ALU Operators:
0x00 = ui+A+B
0x01 = ui-A-B
0x02 = ui+A*B
0x03 = ui?A:B
0x04 = A&B
0x05 = A|B
0x06 = A^B
0x07 = A>>B
0x08 = A<<B
0x09 = A==B
0x0A = !A
0x0B = A>B
]]
function asmcompile(txt,raw)
local dregs={
[0xFB]="uo",
[0xFC]="ui",
[0xFD]="uc",
[0xFE]="ip",
[0xFF]="ht",
}
local regs={}
local jmps={}
local lbls={}
local function findNext(txt,ch)
local bb={
["("]=1,
["["]=2,
}
local eb={
[")"]=1,
["]"]=2,
}
local brs={}
local n=0
for char in txt:gmatch(".") do
if bb[char] then
table.insert(brs,bb[char])
elseif eb[char] then
if #brs==0 then
break
end
if brs[#brs]~=eb[char] then
error("Syntax error ("..txt.."):"..n..":"..char.." "..serialize(brs))
end
table.remove(brs)
elseif char==ch and #brs==0 then
break
end
n=n+1
end
return txt:sub(1,n),txt:sub(n+1)
end
local function findMatching(txt,a,b)
local c=1
local o=""
repeat
local co=txt:match("^[^"..pescape(a..b).."]*")
o=o..co
txt=txt:sub(#co+1)
if txt=="" then
return false
end
if txt:sub(1,1)==a then
c=c+1
elseif txt:sub(1,1)==b then
c=c-1
end
o=o..txt:sub(1,1)
txt=txt:sub(2)
until c==0
return o,txt
end
local function newReg()
local nr
for l1=0x00,0xFA do
if not regs[l1] then
nr=l1
break
end
end
if not nr then
error("Out of registers")
end
return nr
end
local function getReg(n)
for k,v in pairs(regs) do
if n==v then
return k
end
end
for k,v in pairs(dregs) do
if n==v then
return k
end
end
local nr=newReg()
regs[nr]=n
return nr
end
local function cleanup(v)
if v.temp then
regs[v.value]=nil
end
end
local function conv(k,v)
if type(k)=="string" then
if v.type==k then
return v
end
if k~="register" then
error("Cannot create "..k)
end
k={type=k,value=newReg(),temp=true}
regs[k.value]=true
end
tpe=k.type
local code=(k.code or "")..(v.code or "")
if tpe=="register" then
if v.type=="constant" then
code=code.."rsl "..k.value.." "..(v.value%0x10000).."\n"
if v.value>0xFFFF then
code=code.."rsu "..k.value.." "..(v.value/0x10000).."\n"
end
k.code=code
return k
elseif v.type=="register" then
if v.notemp then
code=(k.code or "")..v.notemp.."rsm "..k.value.." "..v.notempv.."\n"
elseif k.notemp then
cleanup(k)
code=k.notemp..(v.code or "").."rrm "..k.notempv.." "..v.value.."\n"
else
code=code.."rsr "..k.value.." "..v.value.."\n"
end
cleanup(v)
k.code=code
return k
elseif v.type=="interrupt" then
code=code.."inr "..k.value.." "..v.value.."\n"
k.code=code
return k
elseif v.type=="memory" then
code=code.."mrc "..k.value.." "..v.value.."\n"
k.code=code
return k
end
elseif k.type=="interrupt" then
local n=conv("register",v)
code=code..n.code.."ins "..k.value.." "..n.value.."\n"
cleanup(n)
elseif k.type=="memory" then
local n=conv("register",v)
code=code..n.code.."msc "..k.value.." "..n.value.."\n"
cleanup(n)
end
error("Cannot convert "..val.type.." to "..tpe)
end
local parseExp
function parseExp(txt)
txt=txt:match("^%s*(.-)%s*$")
while txt:match("^%(.-%)$") do
txt=txt:match("^%(%s*(.-)%s*%)$")
end
local fp,etxt=findNext(txt,"=")
if etxt and etxt:sub(1,1)=="=" then
local kr=parseExp(fp)
local v=etxt:sub(2)
local vr=parseExp(v)
o=conv(kr,vr)
if o then
return o
end
error("no such instruction "..g.."["..kr.type.."]="..vr.type)
end
local g,k=txt:match("^(%u+)%[%s*(.-)%s*%]$")
if g then
local kr=parseExp(k)
if g=="R" then
if kr.type=="constant" then
o={type="register",value=kr.value}
elseif kr.type=="register" then
if kr.temp then
kr.code=(kr.code or "").."rsm "..kr.value.." "..kr.value.."\n"
return kr
else
local o={
type="register",
temp=true,
value=newReg()
}
regs[o.value]=true
o.notemp=kr.code or ""
o.notempv=kr.value
o.code=(kr.code or "").."rsm "..o.value.." "..kr.value.."\n"
return o
end
end
elseif g=="I" then
if kr.type=="constant" then
o={type="interrupt",value=kr.value}
end
elseif g=="M" then
if kr.type=="constant" then
o={type="memory",value=kr.value}
elseif kr.type=="register" then
if kr.temp then
kr.code=(kr.code or "").."rsm "..kr.value.." "..kr.value.."\n"
return kr
else
local o={
type="register",
temp=true,
value=newReg()
}
regs[o.value]=true
o.notemp=kr.code or ""
o.notempv=kr.value
o.code=(kr.code or "").."rsm "..o.value.." "..kr.value.."\n"
return o
end
end
end
if kr.temp then
reg[kr.value]=nil
end
if o then
return o
end
error("no such value "..g.."["..kr.type.."]")
end
local rg=txt:match("^(%l+)$")
if rg then
return {type="register",value=getReg(rg)}
end
local lb=txt:match("^:(%l+)$")
if lb then
return {type="label",value=lb}
end
local num=txt:match("^(%d+)$")
if num then
return {type="constant",value=tonumber(num)}
end
local num=txt:match("^0x(%x+)$")
if num then
return {type="constant",value=tonumber(num,16)}
end
local func,args=txt:match("^(%u+)%(%s*(.-)%s*%)$")
if func then
local code=""
local oargs={}
while #args>0 do
local carg
carg,args=findNext(args,",")
args=args:sub(2)
table.insert(oargs,parseExp(carg))
end
if func=="ALU" then
assert(#oargs==3,"Invalid arguments")
local a=conv("register",oargs[1])
local b=conv("register",oargs[2])
local c=conv("constant",oargs[3])
code=code..(a.code or "")..(b.code or "").."acl "..a.value.." "..b.value.." "..c.value.."\n"
cleanup(a)
cleanup(b)
return {type="register",value=0xFB,code=code}
elseif func=="I" then
assert(#oargs==1,"Invalid arguments")
local a=conv("constant",oargs[1])
code=code.."inw "..a.value.."\n"
return {type="interrupt",value=a.value,code=code}
elseif func=="C" then
assert(#oargs==1,"Invalid arguments")
assert(oargs[1].type=="register","Argument must be register")
assert((oargs[1].code or "")=="","Argument must be constant register")
return {type="constant",value=oargs[1].value,code=code}
end
error("No such function "..func)
end
error("Syntax error "..serialize(txt))
end
local o=""
while #txt>1 do
local statement,otxt=txt:match("^%s*(.-)%s*;%s*(.*)")
txt=otxt
assert(statement,"Syntax error")
local st=parseExp(statement)
assert(st.code,"Null statement")
o=o..st.code
end
if raw then
return asmbinary(o)
end
return o,regs
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment