1
0
Fork 0
mirror of https://github.com/ctruLua/ctruLua.git synced 2025-10-27 16:39:29 +00:00

Added missing dependicies

This commit is contained in:
Reuh 2015-08-17 21:10:54 +02:00
parent 03baa21c10
commit ebcd9f00ed
47 changed files with 18405 additions and 0 deletions

27
libs/aemstro/README.md Normal file
View file

@ -0,0 +1,27 @@
aemstro
=======
''THE ORIGINAL'' pica200 shader (dis)assembly toolkit !
set of tools used to disassemble and assemble shader code for DMP's MAESTRO shader extension used in the 3DS's PICA200 GPU
see http://3dbrew.org/wiki/Shader_Instruction_Set for more information
it is meant for rapid iteration and experimentation as I reverse engineer the instruction set. as such, the code is dirty and ugly and poorly organized. functionality is also lacking and overall it is not recommended that you use this for your own homebrew projects unless they involve reverse engineering. for more user friendly implementations, see neobrain's nihstro and fincs's picasso.
requires python 3. sorry !
please note that the current iteration of aemstro is very experimental as we are still in the process of reverse engineering the instruction set. the current version is a prototype meant to be iterated upon quickly; not a well thought out piece of clean software. so basically don't fret if you think the code looks like shit and could be written in a much more efficient manner; you're not alone.
aemstro.py :
- disassembles shbin/bcsdr files
- usage : aemstro.py <input.shbin/input.bcsdr>
- outputs to stdout
aemstro_as.py :
- assembles vertex shaders
- usage : aemstro_as.py <input.vsh> <output.shbin>
- see test.vsh for sample code
- can *not* assemble output from aemstro.py
- is currently much less up to date than aemstro.py (mostly the instruction format thing is all wrong)

749
libs/aemstro/aemstro.py Executable file
View file

@ -0,0 +1,749 @@
import struct
import os
import sys
input={}
# '''0x0 : "vertex.position",
# 0x1 : "vertex.texcoord",
# 0x4 : "vertex.color?"}'''
output={}
# {0x0 : "glPosition",
# 0x2 : "glTexcoord",
# 0x4 : "glTexcoord",
# 0x6 : "glColor?",
# 0x8 : "glTexcoord?"}
lineIndentLevel={}
def indentLine(k):
if not(k in lineIndentLevel):
lineIndentLevel[k]=0
lineIndentLevel[k]+=1
def unindentLine(k):
if not(k in lineIndentLevel):
lineIndentLevel[k]=0
lineIndentLevel[k]-=1
def resetIndentLevel():
for k in lineIndentLevel:
lineIndentLevel[k]=0
def getWord(b, k, n=4):
return sum(list(map(lambda c: b[k+c]<<(c*8),range(n))))
def convFloat24(f):
#seee eeee mmmm mmmm mmmm mmmm
if f==0x0:
return 0.0
s=f>>23
e=(f>>16)&0x7F
m=f&0xffff
x=pow(2.0,e-63)*(1 + m*pow(2.0,-16))
if f&0x800000!=0:
return -x
return x
# # doesn't quite work, but could be a more accurate approach ?
# def convFloat24(val):
# if val==0x0:
# return 0.0
# tmp=((val>>16)&0xFF)+0x40
# out=(tmp<<23)|((val&0x800000)<<31)|((val&0xFFFF)<<7)
# try:
# return (struct.unpack("f",struct.pack("I",out)))[0]
# except:
# return (val)
def parseSymbol(b,o):
len=0
while getWord(b,o+len,1)!=0x00:
len+=1
return(b[o:o+len].decode("ascii"))
def parseExtTable(data):
l=len(data)
out=[]
for i in range(0,l,8):
out+=[(getWord(data, i), getWord(data, i+0x4))]
return out
def getRegisterNameSRC(v):
if v<0x80:
return getRegisterNameSRC1(v)
elif v<0x88:
return "i"+str(v-0x80)
else:
return "b"+str(v-0x88)
def getRegisterNameSRC1(v):
if v<0x10:
return "v"+str(v&0xF)
elif v<0x20:
return "r"+str(v-0x10)
elif v<0x80:
return "c"+str(v-0x20)
else:
return ("r%02X"%(v))
def getRegisterNameSRC2(v):
return getRegisterNameSRC1(v)
def getRegisterNameDST(v):
if v<0x10:
return ("o%X"%(v))
elif v<0x20:
return "r"+str(v-0x10)
else:
return ("r%02X"%(v))
def getRegisterName(v):
return ("r%02X"%(v))
# if v<16:
# return "v"+str(v&0xF)
# elif v<120:
# return "c"+str(v-16)
# else:
# return "b"+str(v-0x88)
def getInputSymbol(v, vt, ut, idx):
src=getRegisterNameSRC(v)
return getInputSymbolFromString(src, vt, ut, idx)
def getInputSymbolFromString(src, vt, ut, idx):
idxstr=""
if idx==1:
idxstr="[idx1]"
elif idx==2:
idxstr="[idx2]"
elif idx==3:
idxstr="[lcnt]"
if src in vt:
return vt[src]+idxstr
if src in ut:
return ut[src]+idxstr
else:
f=src.find(".")
if f>=0:
src=getInputSymbolFromString(src[:f], vt, ut, idx)+src[f:]
idxstr=""
return src+idxstr
def getOutputSymbol(v, ot):
dst=getRegisterNameDST(v)
return ot[dst] if dst in ot else dst
def getLabelSymbol(v, t):
return t[v][1] if v in t else hex(v)
def initIndent():
global numIdent
numIdent=0
def indentOut():
global numIdent
numIdent=numIdent+1
def unindentOut():
global numIdent
numIdent=numIdent-1
def iprint(s, e=False):
global numIdent
if e:
print(" "*numIdent+s,end='')
else:
print(" "*numIdent+s)
comp=["x", "y", "z", "w"]
def parseComponentMask(v):
out=""
for i in range(4):
if v&(1<<(3-i))!=0x0:
out+=comp[i]
else:
out+="_"
return out
def parseExt(v):
return {"src1" : (v>>5)&0xFF,
"src2" : (v>>14)&0xFF,
"src3" : (v>>23)&0xFF,
"nsrc1" : (v>>4)&0x1, #negation bit
"nsrc2" : (v>>13)&0x1, #negation bit
"nsrc3" : (v>>22)&0x1, #negation bit
"dst" : (v)&0x1F,
"dstcomp" : parseComponentMask(v&0xF),
"rest" : (v>>22)}
def parseComponentSwizzle(v):
out=""
for i in range(4):
out+=comp[(v>>((3-i)*2))&0x3]
return out
def parseInstFormat10(k, v, lt={}):
return {"opcode" : v>>26,
"src2" : (v>>7)&0x1F,
"src1" : (v>>12)&0x7F,
"idx_1" : (v>>19)&0x3,
"idx_2" : 0x0,
"cmpY" : (v>>21)&0x7,
"cmpX" : (v>>24)&0x7,
"extid" : (v)&0x7F}
def parseInstFormat1(k, v, lt={}):
return {"opcode" : v>>26,
"src2" : (v>>7)&0x1F,
"src1" : (v>>12)&0x7F,
"idx_1" : (v>>19)&0x3,
"idx_2" : 0x0,
"dst" : (v>>21)&0x1F,
"extid" : (v)&0x7F}
def parseInstFormat8(k, v, lt={}):
return {"opcode" : v>>26,
"src2" : (v>>7)&0x7F,
"src1" : (v>>14)&0x1F,
"idx_1" : 0x0,
"idx_2" : (v>>19)&0x3,
"dst" : (v>>21)&0x1F,
"extid" : (v)&0x7F}
def parseInstFormat9(k, v, lt={}):
return {"opcode" : v>>26,
"dst" : (v>>24)&0x1F,
"src1" : (v>>17)&0x7F,
"src2" : (v>>10)&0x7F,
"src3" : (v>>5)&0x1F,
"idx_1" : 0x0,
"idx_2" : 0x0,
"extid" : (v)&0x1F}
def parseInstFormat12(k, v, lt={}):
return {"opcode" : v>>26,
"dst" : (v>>24)&0x1F,
"src1" : (v>>17)&0x7F,
"src2" : (v>>12)&0x1F,
"src3" : (v>>5)&0x7F,
"idx_1" : 0x0,
"idx_2" : 0x0,
"extid" : (v)&0x1F}
def parseInstFormat2(k, v, lt={}):
ret={"opcode" : v>>26,
"addr" : (v>>8)&0x3FFC,
"flags" : (v>>22)&0xF,
"ret" : (v)&0x3FF}
if ret["opcode"]==0x28: #IF?
for i in range(k+4,ret["addr"],4):
indentLine(i)
for i in range(ret["addr"],ret["addr"]+ret["ret"]*4,4):
indentLine(i)
if ret["ret"]>0:
lt[ret["addr"]]=(-1,"ELSE_%X"%(k))
return ret
#?
def parseInstFormat3(k, v, lt={}):
return {"opcode" : v>>26,
"src2" : (v>>0)&0x1F,
"src1" : (v>>7)&0x7F,
"dst" : (v>>14)&0x1F}
#?
def parseInstFormat6(k, v, lt={}):
return {"opcode" : v>>26,
"vtxid" : (v>>24)&0x3,
"primid" : (v>>22)&0x3}
# MOV?
def parseInstFormat4(k, v, lt={}):
return {"opcode" : v>>26,
"src1" : (v>>7)&0x7F,
"dst" : (v>>14)&0x1F,
"extid" : (v)&0x3F}
# CONDJUMP
def parseInstFormat5(k, v, lt={}):
ret={"opcode" : v>>26,
"addr" : (v>>8)&0x3FFC,
"bool" : (v>>22)&0xF,
"ret" : (v)&0x3FF}
if ret["opcode"]==0x27: #IFU
for i in range(k+4,ret["addr"],4):
indentLine(i)
for i in range(ret["addr"],ret["addr"]+ret["ret"]*4,4):
indentLine(i)
if ret["ret"]>0:
lt[ret["addr"]]=(-1,"ELSE_%X"%(k))
elif ret["opcode"]==0x29: #LOOP
for i in range(k+4,ret["addr"]+4,4):
indentLine(i)
return ret
def outputStringList(k, strl, fmtl):
l=len(strl)
if k in lineIndentLevel and lineIndentLevel[k]>0:
out=" "*lineIndentLevel[k]
else:
out=""
if l==len(fmtl):
for i in range(l):
str=strl[i]
fmt=fmtl[i]
if fmt:
v=len(str)
if v<fmt:
str+=" "*(fmt-v)
out+=str
iprint(out)
def printInstFormat1(k, n, inst, e, lt, vt, ut, ot):
ext=e[inst["extid"]][0]
extd=parseExt(ext)
nsrc1="-" if extd["nsrc1"]==1 else ""
nsrc2="-" if extd["nsrc2"]==1 else ""
outputStringList(k, [n,
getOutputSymbol(inst["dst"], ot)+"."+extd["dstcomp"],
" <- ",
nsrc1+getInputSymbol(inst["src1"], vt, ut, inst["idx_1"])+"."+(parseComponentSwizzle(extd["src1"])),
" , ",
nsrc2+getInputSymbol(inst["src2"], vt, ut, inst["idx_2"])+"."+(parseComponentSwizzle(extd["src2"])),
" ("+hex(inst["extid"])+" "+hex(extd["rest"])+")"],
[8, 32, None, 32, None, 32, None])
cmpOp={0x0 : "EQ", 0x1 : "NE", 0x2 : "LT", 0x3 : "LE", 0x4 : "GT", 0x5 : "GE", 0x6 : "??", 0x7 : "??"}
def printInstFormat10(k, n, inst, e, lt, vt, ut, ot):
ext=e[inst["extid"]][0]
extd=parseExt(ext)
nsrc1="-" if extd["nsrc1"]==1 else ""
nsrc2="-" if extd["nsrc2"]==1 else ""
outputStringList(k, [n,
nsrc1+getInputSymbol(inst["src1"], vt, ut, inst["idx_1"])+"."+(parseComponentSwizzle(extd["src1"])),
"("+cmpOp[inst["cmpX"]]+", "+cmpOp[inst["cmpY"]]+")",
nsrc2+getInputSymbol(inst["src2"], vt, ut, inst["idx_2"])+"."+(parseComponentSwizzle(extd["src2"])),
" ("+hex(inst["extid"])+")"],
[8, 32, 12, 32, None])
def printInstFormat9(k, n, inst, e, lt, vt, ut, ot):
ext=e[inst["extid"]][0]
extd=parseExt(ext)
nsrc1="-" if extd["nsrc1"]==1 else ""
nsrc2="-" if extd["nsrc2"]==1 else ""
nsrc3="-" if extd["nsrc3"]==1 else ""
outputStringList(k, [n,
getOutputSymbol(inst["dst"], ot)+"."+extd["dstcomp"],
" <- ",
nsrc1+getInputSymbol(inst["src1"], vt, ut, inst["idx_1"])+"."+(parseComponentSwizzle(extd["src1"])),
" , ",
nsrc2+getInputSymbol(inst["src2"], vt, ut, inst["idx_2"])+"."+(parseComponentSwizzle(extd["src2"])),
" , ",
nsrc3+getInputSymbol(inst["src3"], vt, ut, 0)+"."+(parseComponentSwizzle(extd["src3"])),
" ("+hex(extd["rest"])+")"],
[8, 32, None, 16, None, 16, None, 16, None])
def printInstFormat4(k, n, inst, e, lt, vt, ut, ot):
ext=e[inst["extid"]][0]
extd=parseExt(ext)
nsrc1="-" if extd["nsrc1"]==1 else ""
nsrc2="-" if extd["nsrc2"]==1 else ""
outputStringList(k, [n,
getOutputSymbol(inst["dst"], ot)+"."+extd["dstcomp"],
" <- ",
nsrc1+getInputSymbol(inst["src1"], vt, ut, inst["idx_1"])+"."+(parseComponentSwizzle(extd["src1"])),
" ", "",
" ("+hex(inst["extid"])+")"],
[8, 32, None, 32, None, 32, None])
def printInstFormat7(k, n, inst, e, lt, vt, ut, ot):
ext=e[inst["extid"]][0]
extd=parseExt(ext)
nsrc1="-" if extd["nsrc1"]==1 else ""
nsrc2="-" if extd["nsrc2"]==1 else ""
outputStringList(k, [n,
"idx.xy__",
" <- ",
nsrc1+getInputSymbol(inst["src1"], vt, ut, inst["idx_1"])+"."+(parseComponentSwizzle(extd["src1"])),
" ", "",
" ("+hex(inst["extid"])+")"],
[8, 32, None, 32, None, 32, None])
def printInstFormat6(k, n, inst, e, lt, vt, ut, ot):
outputStringList(k, [n,
"vtx%02X," % inst["vtxid"],
"PRIM_EMIT" if inst["primid"]&2==2 else "",
"UNK_FLAG" if inst["primid"]&1==1 else ""],
[8, 8, 12, 16])
def printInstFormat2(k, n, inst, e, lt, vt, ut, ot):
outputStringList(k, [n,
getLabelSymbol(inst["addr"], lt),
" ("+str(inst["ret"])+ " words, flags: "+bin(inst['flags'])+")"],
[8, 32, 32])
# CONDJUMP (uniform)
def printInstFormat5(k, n, inst, e, lt, vt, ut, ot):
if inst["opcode"]==0x29: #LOOP
reg=getRegisterNameSRC((inst['bool']&0xF)+0x80)
start=getInputSymbolFromString(reg+".y", vt, ut, 0)
end=start+"+"+getInputSymbolFromString(reg+".x", vt, ut, 0)
stride=getInputSymbolFromString(reg+".z", vt, ut, 0)
outputStringList(k, [n,
"(lcnt = "+start+"; lcnt <= "+end+"; lcnt += "+stride+")",
" (adr "+getLabelSymbol(inst["addr"], lt)+", "+str(inst["ret"])+ " words, "+str(inst['bool']&0xF)+")"],
[8, 16, 16])
elif inst["opcode"]==0x27: #IFU
outputStringList(k, [n,
"("+getInputSymbol((inst['bool']&0xF)+0x88, vt, ut, 0)+")",
" ("+getLabelSymbol(inst["addr"], lt)+", "+str(inst["ret"])+ " words, "+str(inst['bool']&0xF)+")"],
[8, 16, 16])
elif inst["opcode"]==0x2d: #JMPU
outputStringList(k, [n,
getLabelSymbol(inst["addr"], lt),
" , ",
("!" if inst["ret"]==1 else "")+getInputSymbol((inst['bool']&0xF)+0x88, vt, ut, 0),
" ", "",
" ("+str(inst["ret"])+ " words, "+str(inst['bool']&0xF)+")"],
[8, 16, None, 16, None, 16, None])
else:
outputStringList(k, [n,
getLabelSymbol(inst["addr"], lt),
" , ",
getInputSymbol((inst['bool']&0xF)+(0x80 if inst["opcode"]==0x29 else 0x88), vt, ut, 0),
" ", "",
" ("+str(inst["ret"])+ " words, "+str(inst['bool']&0xF)+")"],
[8, 16, None, 16, None, 16, None])
# CONDJUMP (dynamic)
def printInstFormat11(k, n, inst, e, lt, vt, ut, ot):
cond=""
if inst["flags"]&0x3==0x0: #OR
cond=("!" if inst["flags"]&0x8 == 0 else "")+"cmp.x"+" || "+("!" if inst["flags"]&0x4 == 0 else "")+"cmp.y"
elif inst["flags"]&0x3==0x1: #AND
cond=("!" if inst["flags"]&0x8 == 0 else "")+"cmp.x"+" && "+("!" if inst["flags"]&0x4 == 0 else "")+"cmp.y"
elif inst["flags"]&0x3==0x2: #X
cond=("!" if inst["flags"]&0x8 == 0 else "")+"cmp.x"
elif inst["flags"]&0x3==0x3: #Y
cond=("!" if inst["flags"]&0x4 == 0 else "")+"cmp.y"
if inst["opcode"]==0x23: #BREAK
outputStringList(k, [n,
"("+cond+")",
" ", "",
" ("+str(inst["ret"])+ " words, "+str(inst['flags']&0xF)+")"],
[8, 16, None, 16, None])
elif inst["opcode"]==0x28: #IF
outputStringList(k, [n,
"("+cond+")",
" , ",
getLabelSymbol(inst["addr"], lt),
" ", "",
" ("+str(inst["ret"])+ " words, "+str(inst['flags']&0xF)+")"],
[8, 16, None, 16, None, 16, None])
else:
outputStringList(k, [n,
getLabelSymbol(inst["addr"], lt),
" , ",
"("+cond+")",
" ", "",
" ("+str(inst["ret"])+ " words, "+str(inst['flags']&0xF)+")"],
[8, 16, None, 16, None, 16, None])
instList={}
fmtList=[(parseInstFormat1, printInstFormat1), (parseInstFormat2, printInstFormat2), (parseInstFormat2, printInstFormat2), (parseInstFormat1, printInstFormat4), (parseInstFormat5, printInstFormat5), (parseInstFormat6, printInstFormat6), (parseInstFormat1, printInstFormat7), (parseInstFormat8, printInstFormat1), (parseInstFormat9, printInstFormat9), (parseInstFormat10, printInstFormat10), (parseInstFormat2, printInstFormat11), (parseInstFormat12, printInstFormat9)]
instList[0x00]={"name" : "ADD", "format" : 0} #really SUB ?
instList[0x01]={"name" : "DP3", "format" : 0}
instList[0x02]={"name" : "DP4", "format" : 0}
instList[0x03]={"name" : "DPH", "format" : 0} #tested, definitely
instList[0x05]={"name" : "EX2", "format" : 3} #tested, definitely
instList[0x06]={"name" : "LG2", "format" : 3} #tested, definitely
instList[0x08]={"name" : "MUL", "format" : 0}
instList[0x09]={"name" : "SGE", "format" : 0}
instList[0x0A]={"name" : "SLT", "format" : 0}
instList[0x0B]={"name" : "FLR", "format" : 3} #tested, definitely FLR and not FRC
instList[0x0C]={"name" : "MAX", "format" : 0} #definitely
instList[0x0D]={"name" : "MIN", "format" : 0} #definitely
instList[0x0E]={"name" : "RCP", "format" : 3} #1/op1
instList[0x0F]={"name" : "RSQ", "format" : 3} #1/sqrt(op1)
instList[0x12]={"name" : "SETIDX", "format" : 6}
instList[0x13]={"name" : "MOV", "format" : 3}
instList[0x18]={"name" : "DPHI", "format" : 7}
instList[0x1A]={"name" : "SGEI", "format" : 7}
instList[0x1B]={"name" : "SLTI", "format" : 7}
instList[0x23]={"name" : "BREAKC", "format" : 10} #conditional break
instList[0x24]={"name" : "CALL", "format" : 1} #unconditional call
instList[0x25]={"name" : "CALLC", "format" : 10} #conditional call
instList[0x26]={"name" : "CALLU", "format" : 4} #conditional call (uniform bool)
instList[0x27]={"name" : "IFU", "format" : 4} #if/else statement (uniform bool)
instList[0x28]={"name" : "IFC", "format" : 10}
instList[0x29]={"name" : "LOOP", "format" : 4}
instList[0x2b]={"name" : "SETEMIT", "format" : 5}
instList[0x2c]={"name" : "JMPC", "format" : 10} #conditional jump
instList[0x2d]={"name" : "JMPU", "format" : 4} #conditional jump (uniform bool)
for i in range(0x2):
instList[0x2e+i]={"name" : "CMP", "format" : 9}
for i in range(0x8):
instList[0x30+i]={"name" : "MADI", "format" : 11}
for i in range(0x8):
instList[0x38+i]={"name" : "MAD", "format" : 8}
def parseCode(data, e, lt, vt, ut, ot):
l=len(data)
for k in range(0,l,4):
v=getWord(data,k)
opcode=v>>26
if k in lt:
iprint("%08x [--------] "%(k), True)
unindentLine(k)
outputStringList(k, [lt[k][1]+":"], [8])
indentLine(k)
iprint("%08x [%08x] "%(k,v), True)
if opcode in instList:
fmt=instList[opcode]["format"]
inst=fmtList[fmt][0](k, v, lt)
fmtList[fmt][1](k, instList[opcode]["name"], inst, e, lt, vt, ut, ot)
elif opcode==0x21:
# outputStringList(k,["END"],[8])
outputStringList(k,["NOP"],[8])
elif opcode==0x22:
outputStringList(k,["END"],[8])
elif opcode==0x2A:
inst=parseInstFormat1(k, v)
outputStringList(k,["EMITVERTEX"],[10])
else:
inst=parseInstFormat1(k, v)
if inst["extid"] < len(e):
ext=e[inst["extid"]][0]
extd=parseExt(ext)
printInstFormat1(k, "???%02X"%(inst["opcode"]), inst, e, lt, vt, ut, ot)
else:
inst=parseInstFormat3(k, v)
outputStringList(k,["???%02X"%(inst["opcode"]),
getOutputSymbol(inst["dst"], ot),
" <- ",
getInputSymbol(inst["src1"], vt, ut, 0),
" , ",
getInputSymbol(inst["src2"], vt, ut, 0),
"(invalid extension id)"],
[8, 16, None, 16, None, 16, None])
k+=0x4
def parseDVLP(data, lt, vt, ut, ot, k):
l=len(data)
extOffset=getWord(data, 0x10)
fnOffset=getWord(data, 0x18)
# for i in range(fnOffset, l):
# if k==0:
# break
# elif data[i]==0:
# k-=1
# print(parseSymbol(data,i))
extSize=getWord(data, 0x14)*8
ext=parseExtTable(data[extOffset:(extOffset+extSize)])
codeOffset=getWord(data, 0x8)
codeSize=getWord(data, 0xC)*4
parseCode(data[codeOffset:(codeOffset+codeSize)], ext, lt, vt, ut, ot)
def parseLabelTable(data, sym):
l=len(data)
out={}
for i in range(0,l,0x10):
id=getWord(data,i,1)
loc=getWord(data,i+0x4)*4
off=getWord(data,i+0xC)
out[loc]=(id,parseSymbol(sym,off))
return out
def transformRegisterValue(v):
if v<16:
return (v&0xF)
return v+16
def parseVarTable(data, sym):
l=len(data)
iprint("Uniforms :")
indentOut()
src={}
for i in range(0,l,0x8):
off=getWord(data,i)
v1=getWord(data,i+4,2)
v2=getWord(data,i+6,2)
base=transformRegisterValue(v1)
end=transformRegisterValue(v2)
# iprint(getRegisterNameSRC(base)+" - "+getRegisterNameSRC(end)+" : "+parseSymbol(sym,off))
iprint(getRegisterNameSRC(base)+" - "+getRegisterNameSRC(end)+" : "+parseSymbol(sym,off)+" ("+hex(getWord(data,i))+", "+hex(getWord(data,i+4))+")")
if base==end:
name=parseSymbol(sym,off)
src[getRegisterNameSRC(base)]=name
else:
for k in range(base, end+1):
name=parseSymbol(sym,off)+"["+str(k-base)+"]"
src[getRegisterNameSRC(k)]=name
unindentOut()
print("")
return src
def parseConstTable(data, sym):
l=len(data)
iprint("Constants :")
indentOut()
out={}
for i in range(0,l,0x14):
type=getWord(data,i,2)
r=getWord(data,i+2,2)
name=None
if type==0x0:
#constant bool
vec=False if getWord(data,i+4)==0x0 else True
r+=0x88
name=str(vec)
elif type==0x1:
#constant integer vec4
vec=[hex(getWord(data,i+k,1)) for k in range(4,8,1)]
r+=0x80
out[getRegisterNameSRC(r)+".x"]=vec[0]
out[getRegisterNameSRC(r)+".y"]=vec[1]
out[getRegisterNameSRC(r)+".z"]=vec[2]
out[getRegisterNameSRC(r)+".w"]=vec[3]
else:
#constant float24 vec4 (should be type==0x2 but would rather output potential unknowns too)
vec=[convFloat24(getWord(data,i+k)) for k in range(4,0x14,4)]
r+=0x20
name="["+", ".join(["%4.2f"%(v) for v in vec])+"]"
# iprint(getRegisterNameSRC(r)+" = "+str(vec)+" ("+str([hex(getWord(data,i+k)) for k in range(0,0x14,4)])+")")
iprint(getRegisterNameSRC(r)+" = "+str(vec))
if name!=None:
out[getRegisterNameSRC(r)]=name
unindentOut()
print("")
return out
outputTypes={0x0 : "result.position",
0x1 : "result.normalquat", #maybe
0x2 : "result.color",
0x3 : "result.texcoord0",
0x4 : "result.texcoord0w",
0x5 : "result.texcoord1",
0x6 : "result.texcoord2",
# 0x7 : "?", #sets outreg info to 0x1f1f1f1f...
0x8 : "result.view", #"result.view" seems to be pre-projmatrix vertex coordinates
}
def parseOutputTable(data, sym):
l=len(data)
iprint("Output :")
indentOut()
out={}
for i in range(0,l,0x8):
off=getWord(data,i+4)
v1=getWord(data,i,2)
v2=getWord(data,i+2,2)
dst=getRegisterNameDST(v2)
if v1 in outputTypes:
out[dst]=outputTypes[v1]
iprint("o"+str(v2)+" = "+(outputTypes[v1] if v1 in outputTypes else hex(v1))+" ("+hex(off)+", "+hex(v1)+", "+hex(v2)+")")
unindentOut()
print("")
return out
def parseDVLE(data,dvlp, k):
l=len(data)
iprint("DVLE "+str(k))
shaderType=getWord(data, 0x6, 1)
mainStart=getWord(data, 0x8)*4
mainEnd=getWord(data, 0xC)*4
resetIndentLevel()
iprint("unkval "+hex(getWord(data, 0x4, 2)))
iprint("vertex shader" if shaderType==0x0 else "geometry shader")
iprint("main : "+hex(mainStart)+"-"+hex(mainEnd))
print("")
# # temporarily filter out geometry shaders
# if shaderType!=0x0:
# return
# # temporarily filter out vertex shaders
# if shaderType==0x0:
# return
codeStartOffset=getWord(data, 0x8)
codeEndOffset=getWord(data, 0xC)
unifOffset=getWord(data, 0x18)
unifSize=getWord(data, 0x1C)*0x14
labelOffset=getWord(data, 0x20)
labelSize=getWord(data, 0x24)*0x10
outputOffset=getWord(data, 0x28)
outputSize=getWord(data, 0x2C)*0x8
varOffset=getWord(data, 0x30)
varSize=getWord(data, 0x34)*0x8
symbolOffset=getWord(data, 0x38)
symbolSize=getWord(data, 0x3C)
sym=data[symbolOffset:(symbolOffset+symbolSize)]
labelTable=parseLabelTable(data[labelOffset:(labelOffset+labelSize)],sym)
varTable=parseVarTable(data[varOffset:(varOffset+varSize)],sym)
unifTable=parseConstTable(data[unifOffset:(unifOffset+unifSize)],sym)
outputTable=parseOutputTable(data[outputOffset:(outputOffset+outputSize)],sym)
parseDVLP(dvlp, labelTable, varTable, unifTable, outputTable, k)
print("")
return (labelTable,varTable,unifTable,range(codeStartOffset,codeEndOffset))
def parseDVLB(data):
l=len(data)
n=getWord(data, 0x4)
dvleTable={}
labelTable={}
varTable={}
unifTable={}
dvlp=data[(0x8+0x4*n):l]
for i in range(n):
offset=getWord(data, 0x8+0x4*i)
r=parseDVLE(data[offset:l],dvlp,i)
# for k in r[3]:
# dvleTable[k*4]=i
# labelTable.update(r[0])
# varTable[i]=r[1]
# unifTable[i]=r[2]
# parseDVLP(dvlp,labelTable,varTable,unifTable,dvleTable)
if len(sys.argv)<2:
print("AEMSTRO :")
print(" aemstro.py <input.shbin/input.bcsdr>")
else:
initIndent()
src1fn=sys.argv[1]
data=bytearray(open(src1fn, "rb").read())
l=len(data)
for i in range(0,l-4,4):
if getWord(data, i)==0x424C5644:
parseDVLB(data[i:l])

682
libs/aemstro/aemstro_as.py Normal file
View file

@ -0,0 +1,682 @@
import sys
import os
import re
import copy
import struct
#TODO : add parsing checks, handle errors more gracefully
def toFloat24(f):
f=bytearray(struct.pack('f', f))
s=f[3]>>7
tmp=(((f[3]<<1)|(f[2]>>7))&0xFF)-0x40
tmp2=(((f[0])|(f[1]<<8)|(f[2]<<16))>>7)&0xFFFF
if tmp>=0:
tmp2|=tmp<<16
tmp2|=s<<23
else:
tmp2=s<<23
return tmp2
vshMain=None
vshEndmain=None
gshMain=None
gshEndmain=None
class DVLE(object):
def __init__(self, type):
self._main = 0
self._endmain = 0
self._type = type
self._const = []
self._label = []
self._labelmap = {}
self._outmap = []
self._inmap = []
self._symbol = bytearray()
self._symbolnum = 0
def setMain(self, main):
self._main = main
def setEndmain(self, endmain):
self._endmain = endmain
#binary word tuple
def addConstant(self, const):
self._const.append(const)
#(reg, v)
def addConstantB(self, const):
self._const.append(((const[0]<<16)|(0x0), const[1], 0, 0, 0))
#(reg, x, y, z, w)
def addConstantI(self, const):
self._const.append(((const[0]<<16)|(0x1), ((const[1]&0xff)|((const[2]&0xff)<<8)|((const[3]&0xff)<<16)|(const[4]<<24)), (0), (0), (0)))
#(reg, x, y, z, w)
def addConstantF(self, const):
self._const.append(((const[0]<<16)|(0x2), toFloat24(const[1]), toFloat24(const[2]), toFloat24(const[3]), toFloat24(const[4])))
#string
def addSymbol(self, s):
ret=len(self._symbol)
self._symbol+=bytearray(s, "ascii")+bytearray(b"\x00")
self._symbolnum+=1
return ret
#(code offset, symbol offset)
def addLabel(self, label):
self._label.append((label[0],self.addSymbol(label[1])))
self._labelmap[label[1]]=label[0]
def getLabelAddress(self, label):
if label in self._labelmap:
return self._labelmap[label]
else:
return 0x0
#binary word tuple
def addOutput(self, out):
self._outmap.append(out)
#(startreg, endreg, symbol offset)
def addInput(self, ind):
self._inmap.append((ind[0],ind[1],self.addSymbol(ind[2])))
def toBinary(self):
ret=[]
offsetConst=0x40
offsetLabel=offsetConst+len(self._const)*0x14
offsetOutmap=offsetLabel+len(self._label)*0x10
offsetInmap=offsetOutmap+len(self._outmap)*0x8
offsetSymbol=offsetInmap+len(self._inmap)*0x8
ret.append(0x454C5644) #DVLE magic
ret.append((self._type&1)<<16)
ret.append(self._main)
ret.append(self._endmain)
ret.append(0x00000000) # ?
ret.append(0x00000000) # ?
ret.append(offsetConst)
ret.append(len(self._const))
ret.append(offsetLabel)
ret.append(len(self._label))
ret.append(offsetOutmap)
ret.append(len(self._outmap))
ret.append(offsetInmap)
ret.append(len(self._inmap))
ret.append(offsetSymbol)
ret.append(len(self._symbol))
for k in self._const:
ret.append(k[0])
ret.append(k[1])
ret.append(k[2])
ret.append(k[3])
ret.append(k[4])
i=0
for k in self._label:
ret.append(i)
ret.append(k[0])
ret.append(0x00000000) # ?
ret.append(k[1])
i+=1
for k in self._outmap:
ret.append(k[0])
ret.append(k[1])
for k in self._inmap:
ret.append(k[2])
ret.append(((k[1]&0xFFFF)<<16)|(k[0]&0xFFFF))
retb=bytearray()
for k in ret:
retb+=struct.pack("I",k)
retb+=self._symbol
return retb
class DVLP(object):
def __init__(self):
self._code = []
self._opdesc = []
def clearCode(self):
self._code[:] = []
def addInstruction(self, inst):
self._code.append(inst)
return len(self._code)
def addOpdesc(self, opdesc):
self._opdesc.append(opdesc)
return len(self._opdesc)
def getCodelength(self):
return len(self._code)
def toBinary(self):
ret=[]
offsetCode=0x28
offsetOpdesc=offsetCode+len(self._code)*0x4
symbolOffset=offsetOpdesc+len(self._opdesc)*0x8
ret.append(0x504C5644) #DVLP magic
ret.append(0x00000000) # ?
ret.append(offsetCode)
ret.append(len(self._code))
ret.append(offsetOpdesc)
ret.append(len(self._opdesc))
ret.append(symbolOffset)
ret.append(0x00000000) # ?
ret.append(0x00000000) # ?
ret.append(0x00000000) # ?
retb=bytearray()
for k in ret:
retb+=struct.pack("I",k)
for k in self._code:
retb+=struct.pack("I",k)
for k in self._opdesc:
retb+=struct.pack("I",k[0])
retb+=struct.pack("I",k[1])
return retb
class DVLB(object):
def __init__(self):
self._dvlp = DVLP()
self._dvle = []
def getDVLP(self):
return self._dvlp
def addDVLE(self, dvle):
self._dvle.append(dvle)
def toBinary(self):
ret=[]
ret.append(0x424C5644) #DVLB magic
ret.append(len(self._dvle))
off=len(self._dvle)*0x4+0x8
retb=bytearray()
retb+=self._dvlp.toBinary()
for k in self._dvle:
retb+=bytearray([0x00]*(0 if len(retb)%4==0 else 4-(len(retb)%4)))
ret.append(off+len(retb))
retb+=k.toBinary()
retb2=bytearray()
for k in ret:
retb2+=struct.pack("I",k)
return retb2+retb
def getRegisterFromNameDst(s):
if s[0]=="o": # output
return int(s[1:])
elif s[0]=="v": # attribute
print("error : "+s+" cannot be accessed from dst")
elif s[0]=="r": # temporary register
return int(s[1:])+0x10
elif s[0]=="c": # uniform
print("error : "+s+" cannot be accessed from dst")
elif s[0]=="d": # direct hex; unambiguous
return int("0x"+s[1:],0)
else:
print("error : "+s+" is not a valid register name")
def getRegisterFromNameSrc1(s):
index=0
if "[" in s:
i=s.index("[")
index=s[i+1:-1]
s=s[:i]
if index=="a0.x":
index=1
elif index=="a0.y":
index=2
elif index=="aL":
index=3
if s[0]=="o": # output
print("error : "+s+" cannot be accessed from src1")
elif s[0]=="v": # attribute
return (int(s[1:]), index)
elif s[0]=="r": # temporary register
return (int(s[1:])+0x10, index)
elif s[0]=="c": # uniform
return (int(s[1:])+0x20, index)
elif s[0]=="d": # direct hex; unambiguous
return (int("0x"+s[1:],0), index)
else:
print("error : "+s+" is not a valid register name")
def getRegisterFromNameSrc2(s):
if s[0]=="o": # output
print("error : "+s+" cannot be accessed from src2")
elif s[0]=="v": # attribute
return int(s[1:])
elif s[0]=="r": # temporary register
return int(s[1:])+0x10
elif s[0]=="c": # uniform
print("error : "+s+" cannot be accessed from src2")
elif s[0]=="d": # direct hex; unambiguous
return int("0x"+s[1:],0)
else:
print("error : "+s+" is not a valid register name")
def assembleFormat11(d):
return (d["opcode"]<<26)|((d["dst"]&0x1F)<<24)|((d["src1"]&0x7F)<<17)|((d["src2"]&0x7F)<<10)|((d["src3"]&0x1F)<<5)|(d["extid"]&0x1F)
def parseFormat11(dvle, s):
operandFmt="[^\s,]*"
descFmt="(?:(?:0x)[0-9a-f]+)|[0-9a-f]+"
p=re.compile("^\s*("+operandFmt+"),\s*("+operandFmt+"),\s*("+operandFmt+"),\s*("+operandFmt+")\s*\(("+descFmt+")\)")
r=p.match(s)
if r:
src1 = getRegisterFromNameSrc1(r.group(2))
src2 = getRegisterFromNameSrc1(r.group(3))
return {"dst" : getRegisterFromNameDst(r.group(1)),
"src1" : src1[0],
"src2" : src2[0],
"src3" : getRegisterFromNameSrc2(r.group(4)),
"extid" : int(r.group(5),0)}
else:
raise Exception("encountered error while parsing instruction")
def assembleFormat12(d):
return (d["opcode"]<<26)|((d["dst"]&0x1F)<<24)|((d["src1"]&0x7F)<<17)|((d["src2"]&0x1F)<<12)|((d["src3"]&0x7F)<<5)|(d["extid"]&0x1F)
def parseFormat12(dvle, s):
operandFmt="[^\s,]*"
descFmt="(?:(?:0x)[0-9a-f]+)|[0-9a-f]+"
p=re.compile("^\s*("+operandFmt+"),\s*("+operandFmt+"),\s*("+operandFmt+"),\s*("+operandFmt+")\s*\(("+descFmt+")\)")
r=p.match(s)
if r:
src1 = getRegisterFromNameSrc1(r.group(2))
src3 = getRegisterFromNameSrc1(r.group(4))
return {"dst" : getRegisterFromNameDst(r.group(1)),
"src1" : src1[0],
"src2" : getRegisterFromNameSrc2(r.group(3)),
"src3" : src3[0],
"extid" : int(r.group(5),0)}
else:
raise Exception("encountered error while parsing instruction")
def assembleFormat1(d):
return (d["opcode"]<<26)|((d["dst"]&0x1F)<<21)|((d["idx"]&0x3)<<19)|((d["src1"]&0x7F)<<12)|((d["src2"]&0x1F)<<7)|(d["extid"]&0x7F)
def parseFormat1(dvle, s):
operandFmt="[^\s,]*"
descFmt="(?:(?:0x)[0-9a-f]+)|[0-9a-f]+"
p=re.compile("^\s*("+operandFmt+"),\s*("+operandFmt+"),\s*("+operandFmt+")\s*\(("+descFmt+")\)")
r=p.match(s)
if r:
src1 = getRegisterFromNameSrc1(r.group(2))
return {"dst" : getRegisterFromNameDst(r.group(1)),
"src1" : src1[0],
"idx" : src1[1],
"src2" : getRegisterFromNameSrc2(r.group(3)),
"extid" : int(r.group(4),0)}
else:
raise Exception("encountered error while parsing instruction")
def assembleFormat2(d):
print(d)
return (d["opcode"]<<26)|((d["flags"]&0xF)<<22)|((d["addr"]&0xFFF)<<10)|(d["ret"]&0x3FF)
def parseFormat2(dvle, s):
operandFmt1="[^\s,]*"
# operandFmt3="0b[01]+"
operandFmt3="([!]?)cmp.([xy])"
operandFmt3=operandFmt3+"\s*(?:(&&|\|\|)\s*"+operandFmt3+")?"
p=re.compile("^\s*("+operandFmt1+"),\s*("+operandFmt1+"),\s*"+operandFmt3+"\s*$")
# p=re.compile("^\s*("+operandFmt1+"),\s*("+operandFmt1+"),\s*("+operandFmt3+")\s*")
r=p.match(s)
if r:
neg = [0 if r.group(3)=="!" else 1, 0 if r.group(6)=="!" else 1]
comp = [2 if r.group(4)=="y" else 3, None if r.group(7)==None else (2 if r.group(7)=="y" else 3)]
op = r.group(5)
if comp[0]!=comp[1]:
flags=0
flags|=neg[0]<<comp[0]
flags|=neg[1]<<comp[1] if comp[1]!=None else 0
flags|=1 if op=="&&" else (0 if op=="||" else (3 if comp[0]==2 else 2))
# print(s)
# flags=int(r.group(3),0)
print(bin(flags))
return {"addr" : dvle.getLabelAddress(r.group(2)),
"ret" : dvle.getLabelAddress(r.group(1))-dvle.getLabelAddress(r.group(2)),
"flags" : flags}
else:
raise Exception("invalid or redundant condition "+s)
else:
raise Exception("encountered error while parsing instruction "+s)
def assembleFormat3(d):
return (d["opcode"]<<26)
def parseFormat3(dvle, s):
# doesn't check that there are no operands.
# (but really if you want to be an idiot and add useless operands to your code, go ahead)
return {}
def assembleFormat4(d):
return (d["opcode"]<<26)|((d["dst"]&0x1F)<<21)|((d["idx"]&0x3)<<19)|((d["src1"]&0x7F)<<12)|(d["extid"]&0x7F)
def parseFormat4(dvle, s):
operandFmt="[^\s,]*"
descFmt="(?:(?:0x)[0-9a-f]+)|[0-9a-f]+"
p=re.compile("^\s*("+operandFmt+"),\s*("+operandFmt+")\s*\(("+descFmt+")\)")
r=p.match(s)
if r:
src1 = getRegisterFromNameSrc1(r.group(2))
return {"dst" : getRegisterFromNameDst(r.group(1)),
"src1" : src1[0],
"idx" : src1[1],
"extid" : int(r.group(3),0)}
else:
raise Exception("encountered error while parsing instruction "+s)
def assembleFormat5(d):
return (d["opcode"]<<26)|((d["cmpx"]&0x7)<<24)|((d["cmpy"]&0x7)<<21)|((d["src1"]&0x7F)<<12)|((d["src2"]&0x1F)<<7)|(d["extid"]&0x7F)
cmpOp = {"eq" : 0x0, "ne" : 0x1, "lt" : 0x2, "le" : 0x3, "gt" : 0x4, "ge" : 0x5}
def parseFormat5(dvle, s):
operandFmt="[^\s,]*"
descFmt="(?:(?:0x)[0-9a-f]+)|[0-9a-f]+"
opFmt="[a-z]+"
p=re.compile("^\s*("+operandFmt+"),\s*("+opFmt+"),\s*("+opFmt+"),\s*("+operandFmt+")\s*\(("+descFmt+")\)")
r=p.match(s)
if r:
src1 = getRegisterFromNameSrc1(r.group(1))
return {"src1" : src1[0],
"idx" : src1[1],
"cmpx" : cmpOp[r.group(2)],
"cmpy" : cmpOp[r.group(3)],
"src2" : getRegisterFromNameSrc2(r.group(4)),
"extid" : int(r.group(5),0)}
else:
raise Exception("encountered error while parsing instruction (5)")
def assembleFormat6(d):
return (d["opcode"]<<26)|((d["dst"]&0x1F)<<21)|((d["src2"]&0x7F)<<7)|((d["src1"]&0x1F)<<14)|(d["extid"]&0x7F)
def parseFormat7(dvle, s):
operandFmt1="[^\s,]*"
operandFmt3="i[0-9]+"
p=re.compile("^\s*("+operandFmt1+"),\s*("+operandFmt3+")")
r=p.match(s)
if r:
return {"addr" : dvle.getLabelAddress(r.group(1))-1,
"ret" : 0,
"int" : int(r.group(2).strip()[1:],0)}
else:
raise Exception("encountered error while parsing instruction")
def assembleFormat7(d):
return (d["opcode"]<<26)|((d["int"]&0xF)<<22)|((d["addr"]&0xFFF)<<10)|(d["ret"]&0x3FF)
def parseFormat8(dvle, s):
operandFmt1="[^\s,]*"
operandFmt3="b[0-9]+"
p=re.compile("^\s*("+operandFmt1+"),\s*("+operandFmt1+"),\s*("+operandFmt3+")")
r=p.match(s)
if r:
return {"addr" : dvle.getLabelAddress(r.group(2)),
"ret" : dvle.getLabelAddress(r.group(1))-dvle.getLabelAddress(r.group(2)),
"bool" : int(r.group(3).strip()[1:],0)}
else:
raise Exception("encountered error while parsing instruction")
def assembleFormat8(d):
return (d["opcode"]<<26)|((d["bool"]&0xF)<<22)|((d["addr"]&0xFFF)<<10)|(d["ret"]&0x3FF)
def parseFormat9(dvle, s):
operandFmt1="true|false"
operandFmt3="vtx[0-9]+"
p=re.compile("^\s*("+operandFmt3+"),\s*("+operandFmt1+"),\s*("+operandFmt1+")")
r=p.match(s)
if r:
return {"unk" : r.group(3)=="true",
"prim" : r.group(2)=="true",
"vtx" : int(r.group(1).strip()[3:],0)}
else:
raise Exception("encountered error while parsing instruction")
def assembleFormat9(d):
return (d["opcode"]<<26)|((d["vtx"]&0x3)<<24)|((d["unk"]&0x1)<<22)|((d["prim"]&0x1)<<23)
def parseFormat10(dvle, s):
operandFmt1="[^\s,]*"
p=re.compile("^\s*("+operandFmt1+"),\s*("+operandFmt1+")")
r=p.match(s)
if r:
return {"addr" : dvle.getLabelAddress(r.group(1)),
"ret" : dvle.getLabelAddress(r.group(2))-dvle.getLabelAddress(r.group(1)),
"flags" : 0x0}
else:
raise Exception("encountered error while parsing instruction")
instList={}
fmtList=[(parseFormat1, assembleFormat1), (parseFormat2, assembleFormat2), (parseFormat3, assembleFormat3), (parseFormat4, assembleFormat4), (parseFormat5, assembleFormat5), (parseFormat1, assembleFormat6), (parseFormat7, assembleFormat7), (parseFormat8, assembleFormat8), (parseFormat9, assembleFormat9), (parseFormat10, assembleFormat2), (parseFormat11, assembleFormat11), (parseFormat12, assembleFormat12)]
instList["add"]={"opcode" : 0x00, "format" : 0}
instList["dp3"]={"opcode" : 0x01, "format" : 0}
instList["dp4"]={"opcode" : 0x02, "format" : 0}
instList["dph"]={"opcode" : 0x03, "format" : 0}
instList["op4"]={"opcode" : 0x04, "format" : 0}
instList["ex2"]={"opcode" : 0x05, "format" : 3}
instList["lg2"]={"opcode" : 0x06, "format" : 3}
instList["op7"]={"opcode" : 0x07, "format" : 3}
instList["mul"]={"opcode" : 0x08, "format" : 0}
instList["sge"]={"opcode" : 0x09, "format" : 0}
instList["slt"]={"opcode" : 0x0a, "format" : 0}
instList["flr"]={"opcode" : 0x0B, "format" : 3}
instList["max"]={"opcode" : 0x0C, "format" : 0}
instList["min"]={"opcode" : 0x0D, "format" : 0}
instList["rcp"]={"opcode" : 0x0E, "format" : 3}
instList["rsq"]={"opcode" : 0x0F, "format" : 3}
instList["mova"]={"opcode" : 0x12, "format" : 3}
instList["mov"]={"opcode" : 0x13, "format" : 3}
instList["dphi"]={"opcode" : 0x18, "format" : 5}
instList["op19"]={"opcode" : 0x19, "format" : 5}
instList["sgei"]={"opcode" : 0x1a, "format" : 5}
instList["slti"]={"opcode" : 0x1b, "format" : 5}
instList["nop"]={"opcode" : 0x21, "format" : 2}
instList["end"]={"opcode" : 0x22, "format" : 2}
instList["call"] ={"opcode" : 0x24, "format" : 9}
instList["ifu"] ={"opcode" : 0x27, "format" : 7}
instList["ifc"] ={"opcode" : 0x28, "format" : 1}
instList["loop"] ={"opcode" : 0x29, "format" : 6}
instList["emit"]={"opcode" : 0x2a, "format" : 2}
instList["setemit"]={"opcode" : 0x2b, "format" : 8}
instList["cmp"]={"opcode" : 0x2e, "format" : 4}
instList["madi"]={"opcode" : 0x30, "format" : 11}
instList["mad"]={"opcode" : 0x38, "format" : 10}
def parseConst(dvlp, dvle, s):
s=s.split(",")
s[0]=s[0].strip()
if s[0][0]=="b":
# bool constant
dvle.addConstantB((int(s[0][1:],0), int(s[1])))
elif s[0][0]=="i":
# int vec4 constant
dvle.addConstantI((int(s[0][1:],0), int(s[1],0), int(s[2],0), int(s[3],0), int(s[4],0)))
elif s[0][0]=="c":
# float vec4 constant
dvle.addConstantF((int(s[0][1:],0), float(s[1]), float(s[2]), float(s[3]), float(s[4])))
outputTypes={"result.position" : 0x0,
"result.normalquat" : 0x1,
"result.color" : 0x2,
"result.texcoord0" : 0x3,
"result.texcoord0w" : 0x4,
"result.texcoord1" : 0x5,
"result.texcoord2" : 0x6,
"result.view" : 0x8}
def parseOut(dvlp, dvle, s):
s=s.split(",")
s[0]=s[0].replace(" ", "")
s[1]=s[1].replace(" ", "")
s[2]=s[2].replace(" ", "")
reg=int(s[0][1:])
if s[1] in outputTypes:
type=outputTypes[s[1]]
mask=int(s[2], 0)
dvle.addOutput((type|(reg<<16), mask))
swizVal={"w":0x3,"z":0x2,"y":0x1,"x":0x0}
def parseOpdesc(dvlp, dvle, s):
s=s.split(",")
for k in range(len(s)):
s[k]=s[k].replace(" ", "")
#dst mask
mask=0
for k in range(4):
if s[0][k]!="_":
mask|=1<<(3-k)
swiz=[0,0,0]
neg=[0,0,0]
for i in range(len(s)-1):
l=s[1+i]
if l[0]=='-':
neg[i]=1
l=l[1:]
for k in range(4):
swiz[i]=((swiz[i]<<2)|swizVal[l[k]])
dvlp.addOpdesc(((1<<31)|(swiz[2]<<23)|(neg[2]<<22)|(swiz[1]<<14)|(neg[1]<<13)|(swiz[0]<<5)|(neg[0]<<4)|(mask),0x0000000F))
def parseUniform(dvlp, dvle, s):
s=s.split(",")
for k in range(len(s)):
s[k]=s[k].replace(" ", "")
type=s[0][0]
if type!=s[1][0]:
print("inconsistent uniform register assignment !")
return
if type=="c":
offset=0x10
elif type=="i":
offset=0x70
elif type=="b":
offset=0x78
dvle.addInput((int(s[0][1:],0)+offset,int(s[1][1:],0)+offset,s[2]))
def parseVsh(dvlp, dvle, s):
global vshMain, vshEndmain
s=s.split(",")
for k in range(len(s)):
s[k]=s[k].replace(" ", "")
vshMain, vshEndmain = s[0], s[1]
def parseGsh(dvlp, dvle, s):
global gshMain, gshEndmain
s=s.split(",")
for k in range(len(s)):
s[k]=s[k].replace(" ", "")
gshMain, gshEndmain = s[0], s[1]
dirList={}
dirList["const"]=(parseConst)
dirList["out"]=(parseOut)
dirList["opdesc"]=(parseOpdesc)
dirList["uniform"]=(parseUniform)
dirList["vsh"]=(parseVsh)
dirList["gsh"]=(parseGsh)
def parseInstruction(dvle, s):
s=s.lower()
p=re.compile("^\s*([^\s]*)(.*)")
r=p.match(s)
if r:
name=r.group(1)
if name in instList:
fmt=instList[name]["format"]
out=fmtList[fmt][0](dvle, r.group(2))
out["opcode"]=instList[name]["opcode"]
v=fmtList[fmt][1](out)
return v
else:
print(name+" : no such instruction")
return None
def parseLabel(s):
s=s.lower()
p=re.compile("^\s*([a-z_0-9]*):")
r=p.match(s)
if r:
return r.group(1)
return None
def parseLine(dvlp, dvle, l, mode):
l=l.split(";")[0] #remove comments
k=0
while (k<len(l) and (l[k]==" " or l[k]==" ")):
k+=1
l=l[k:]
if len(l)>1:
if l[0]==".": #directive
if not(mode):
p=re.compile("^\s*\.([^\s]*)(.*)")
r=p.match(l)
if r:
name=r.group(1)
if name in dirList:
dirList[name](dvlp, dvle, r.group(2))
else:
print(name+" : no such directive")
else:
v=parseLabel(l)
if v: #label
if not(mode):
dvle.addLabel((dvlp.getCodelength(), v))
else: #instruction
v=parseInstruction(dvle, l)
if v:
dvlp.addInstruction(v)
if len(sys.argv)<3:
print("AEMSTRO AS :")
print(" aemstro_as.py <input.vsh> <output.shbin>")
else:
dvlb=DVLB()
vsh_dvle=DVLE(0x0)
with open(sys.argv[1], "r") as f:
for line in f:
parseLine(dvlb.getDVLP(), vsh_dvle, line, False)
dvlb.getDVLP().clearCode()
with open(sys.argv[1], "r") as f:
for line in f:
parseLine(dvlb.getDVLP(), vsh_dvle, line, True)
vsh_dvle.setMain(vsh_dvle.getLabelAddress(vshMain))
vsh_dvle.setEndmain(vsh_dvle.getLabelAddress(vshEndmain))
dvlb.addDVLE(vsh_dvle)
if gshMain!=None and gshEndmain!=None:
gsh_dvle=copy.deepcopy(vsh_dvle)
gsh_dvle._type=0x1
gsh_dvle.setMain(gsh_dvle.getLabelAddress(gshMain))
gsh_dvle.setEndmain(gsh_dvle.getLabelAddress(gshEndmain))
dvlb.addDVLE(gsh_dvle)
open(sys.argv[2],"wb").write(dvlb.toBinary())

43
libs/aemstro/test.vsh Normal file
View file

@ -0,0 +1,43 @@
; setup constants
.const 5, 0.0, 1.0, 2.0, 3.0
; setup outmap
.out o0, result.position
.out o1, result.color
.out o2, result.texcoord0
.out o3, result.texcoord1
.out o4, result.texcoord2
; setup uniform map (not required)
.uniform 0x10, 0x13, mdlvMtx
.uniform 0x14, 0x17, projMtx
;code
main:
; result.pos = mdlvMtx * in.pos
dp4 d40, d40, d00 (0x0)
dp4 d40, d41, d00 (0x1)
dp4 d40, d42, d00 (0x2)
mov d40, d25 (0x4)
; result.pos = projMtx * in.pos
dp4 d00, d44, d40 (0x0)
dp4 d00, d45, d40 (0x1)
dp4 d00, d46, d40 (0x2)
dp4 d00, d47, d40 (0x3)
; result.color = in.pos
mov d04, d25 (0x5)
; result.texcoord = const
mov d08, d25 (0x5)
mov d0C, d25 (0x5)
mov d10, d25 (0x5)
flush
end
endmain:
;operand descriptors
.opdesc x___, xyzw, xyzw ; 0x0
.opdesc _y__, xyzw, xyzw ; 0x1
.opdesc __z_, xyzw, xyzw ; 0x2
.opdesc ___w, xyzw, xyzw ; 0x3
.opdesc ___w, yyyy, xyzw ; 0x4
.opdesc xyzw, xyzw, xyzw ; 0x5