Last active
August 29, 2015 14:18
-
-
Save pingbird/a3791745322d63bdc948 to your computer and use it in GitHub Desktop.
MP238-L
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --[[ | |
| 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