gambatte/testrunner/qdgbas.py
sinamas 9dc2f7ec48 - libgambatte: *
- tons of re (cgb _and_ dmg).

$ ./run_tests.sh
...
Ran 2755 tests.
0 failures.



git-svn-id: https://gambatte.svn.sourceforge.net/svnroot/gambatte@246 9dfb2916-2d38-0410-aef4-c5fe6c9ffc24
2011-07-23 17:02:32 +00:00

285 lines
7.3 KiB
Python

# -*- coding: utf-8 -*-
# Quick and Dirty Game Boy Assembler
import re
import sys
import collections
class InputError(RuntimeError): pass
Op = collections.namedtuple('Op', ['string', 'code', 'size', 'assemble'])
def mkrestr(s):
return re.sub(r'\s+', r'\s*', re.sub(r'([,)(+])', r' \\\1 ', s))
imm8 = r'[0-9a-fA-F][0-9a-fA-F]'
imm16 = imm8 + imm8
labelregexp = re.compile('\w+\s+(\w+)')
def assembleNormal(outdata, outpos, indata, inpos, targets, op):
pass
def assembleImm8(outdata, outpos, indata, inpos, targets, op):
m = re.match(mkrestr(op.string).replace('imm8', '('+imm8+')'), indata[inpos])
outdata[outpos] = int(m.group(1), 0x10)
def assembleImm16(outdata, outpos, indata, inpos, targets, op):
m = re.match(mkrestr(op.string).replace('imm16', '('+imm16+')'), indata[inpos])
outdata[outpos ] = int(m.group(1)[2:4], 0x10)
outdata[outpos+1] = int(m.group(1)[0:2], 0x10)
def assembleJr(outdata, outpos, indata, inpos, targets, op):
label = labelregexp.match(indata[inpos]).group(1)
t = targets.get(label)
t = t - (outpos + 1) if t != None else int(label, 0x10)
if t < -0x80 or t > 0x7f:
raise InputError('line ' + str(i) + ': ' + indata[inpos], 'Relative jump target too far away')
outdata[outpos] = t & 0xff
def assembleJp(outdata, outpos, indata, inpos, targets, op):
label = labelregexp.match(indata[inpos]).group(1)
t = targets.get(label)
if t == None:
t = int(label, 0x10)
elif t >= 0x8000:
t = 0x4000 | (t & 0x3fff)
outdata[outpos ] = t & 0xFF
outdata[outpos+1] = t >> 8
def makeoplist():
l = []
def addop(opstr, opcode):
size = (opcode >= 0) + (opcode >= 0x100)
moperand = re.match(r'(.*imm8)|(jr.* target)|(.*imm16)|(call.* target|jp.* target)', opstr)
if moperand:
optype = [(0, assembleNormal), (1, assembleImm8), (1, assembleJr), (2, assembleImm16), (2, assembleJp)][moperand.lastindex]
l.append(Op(opstr, opcode, size + optype[0], optype[1]))
else:
l.append(Op(opstr, opcode, size, assembleNormal))
addop('nop', 0x00)
addop('ld bc, imm16', 0x01)
addop('ld(bc), a', 0x02)
addop('inc bc', 0x03)
addop('inc b', 0x04)
addop('dec b', 0x05)
addop('ld b, imm8', 0x06)
addop('ld a, (bc)', 0x0a)
addop('inc c', 0x0c)
addop('dec c', 0x0d)
addop('ld c, imm8', 0x0e)
addop('rrca', 0x0f)
addop('stop, imm8', 0x10)
addop('ld de, imm16', 0x11)
addop('ld(de), a', 0x12)
addop('inc d', 0x14)
addop('dec d', 0x15)
addop('ld d, imm8', 0x16)
addop('jr target', 0x18)
addop('add hl, de', 0x19)
addop('ld a, (de)', 0x1a)
addop('inc e', 0x1c)
addop('dec e', 0x1d)
addop('jrnz target', 0x20)
addop('ld hl, imm16', 0x21)
addop('ld(hl++), a', 0x22)
addop('inc h', 0x24)
addop('dec h', 0x25)
addop('inc l', 0x2c)
addop('dec l', 0x2d)
addop('ld sp, imm16', 0x31)
addop('ld(hl--), a', 0x32)
addop('ld(hl), imm8', 0x36)
addop('ld a, (hl--)', 0x3a)
addop('inc a', 0x3c)
addop('dec a', 0x3d)
addop('ld a, imm8', 0x3e)
addop('ld b, a', 0x47)
addop('ld d, a', 0x57)
addop('halt', 0x76)
addop('ld(hl), a', 0x77)
addop('ld a, b', 0x78)
addop('ld a, c', 0x79)
addop('ld a, d', 0x7a)
addop('ld a, e', 0x7b)
addop('ld a, (hl)', 0x7e)
addop('sub a, b', 0x90)
addop('sub a, c', 0x91)
addop('sub a, d', 0x92)
addop('and a, b', 0xa0)
addop('and a, c', 0xa1)
addop('and a, d', 0xa2)
addop('xor a, a', 0xaf)
addop('or a, a', 0xb7)
addop('cmp a, b', 0xb8)
addop('cmp a, c', 0xb9)
addop('cmp a, d', 0xba)
addop('cmp a, e', 0xbb)
addop('cmp a, h', 0xbc)
addop('jpnz target', 0xc2)
addop('jp target', 0xc3)
addop('ret', 0xc9)
addop('call target', 0xcd)
addop('pop de', 0xd1)
addop('sub a, imm8', 0xd6)
addop('ldff(imm8), a', 0xe0)
addop('pop hl', 0xe1)
addop('ldff(c), a', 0xe2)
addop('push hl', 0xe5)
addop('and a, imm8', 0xe6)
addop('ld(imm16), a', 0xea)
addop('xor a, imm8', 0xee)
addop('ldff a, (imm8)', 0xf0)
addop('ldff a, (c)', 0xf2)
addop('ld a, (imm16)', 0xfa)
addop('ei', 0xfb)
addop('cmp a, imm8', 0xfe)
addop('srl a', 0xcb3f)
addop('\w* : ', -1)
return l
def makeopregexp(oplist):
rxps = ''
for e in oplist:
rxps += '(' + mkrestr(e.string) + ')|'
return re.compile(rxps[0:len(rxps)-1].replace('imm8', imm8).replace('imm16', imm16).replace('target', r'\s\w+'))
oplist = makeoplist()
opregexp = makeopregexp(oplist)
def maptargets(targets, indata, instart, addr):
for i in xrange(instart, len(indata)):
match = opregexp.match(indata[i])
if match == None:
break
op = oplist[match.lastindex - 1]
if op.size == 0:
targets[re.match('(\w*)\s*:', indata[i]).group(1)] = addr
addr += op.size
return i
def ascode(outdata, addr, indata, instart, targets):
for i in xrange(instart, len(indata)):
match = opregexp.match(indata[i])
if match == None:
break
op = oplist[match.lastindex - 1]
outpos = addr
if op.code >= 0x100:
outdata[outpos ] = op.code >> 8
outdata[outpos+1] = op.code & 0xff
outpos += 2
elif op.code >= 0:
outdata[outpos] = op.code
outpos += 1
op.assemble(outdata, outpos, indata, i, targets, op)
addr += op.size
return i
def asdata(outdata, addr, indata, instart):
try:
for i in xrange(instart, len(indata)):
ints = [int(x, 0x10) for x in indata[i].split()]
outdata[addr:addr+len(ints)] = ints
addr += len(ints)
except ValueError:
pass
return i
def putgblogo(outdata):
outdata[0x104:0x134] = \
[0xce, 0xed, 0x66, 0x66, 0xcc, 0x0d, 0x00, 0x0b,
0x03, 0x73, 0x00, 0x83, 0x00, 0x0c, 0x00, 0x0d,
0x00, 0x08, 0x11, 0x1f, 0x88, 0x89, 0x00, 0x0e,
0xdc, 0xcc, 0x6e, 0xe6, 0xdd, 0xdd, 0xd9, 0x99,
0xbb, 0xbb, 0x67, 0x63, 0x6e, 0x0e, 0xec, 0xcc,
0xdd, 0xdc, 0x99, 0x9f, 0xbb, 0xb9, 0x33, 0x3e]
def putheadercsum(outdata):
outdata[0x14d] = sum([-(x+1) for x in outdata[0x134:0x14d]]) & 0xFF
def putromcsum(outdata):
csum = sum(outdata)
outdata[0x14e:0x150] = [csum >> 8 & 0xff, csum & 0xff]
def assembleFile(indata):
size = 0x8000
startpos = 0
for i in xrange(0, len(indata)):
spl = indata[i].split()
if len(spl) > 0 and spl[0] == '.size':
size = int(spl[1], 0x10)
startpos = i + 1
break
targets = {}
i = startpos
while i < len(indata):
spl = [x.strip() for x in indata[i].split('@')]
i += 1;
if spl[0] == '.code':
i = maptargets(targets, indata, i, int(spl[1], 0x10))
outdata = bytearray(size)
i = startpos
while i < len(indata):
if indata[i] != '':
spl = [x.strip() for x in indata[i].split('@')]
if spl[0] == '.code':
i = ascode(outdata, int(spl[1], 0x10), indata, i+1, targets)
elif spl[0] == '.data':
i = asdata(outdata, int(spl[1], 0x10), indata, i+1)
else:
raise RuntimeError('line ' + str(i) + ': ' + indata[i])
else:
i += 1
putgblogo(outdata)
putheadercsum(outdata)
putromcsum(outdata)
return outdata
def readDataFromFile(filename):
infile = open(filename, 'r')
indata = [line.strip() for line in infile]
infile.close()
return indata
def writeDataToFile(filename, data):
outfile = open(filename, 'wb')
outfile.write(data)
outfile.close()
def outFilenameFromInFilename(inname, h143):
return inname.rsplit('.', 1)[0] + ('.gbc' if (h143 & 0x80) else '.gb')
def main():
for arg in sys.argv[1:]:
print 'processing ' + arg
outdata = assembleFile(readDataFromFile(arg))
writeDataToFile(outFilenameFromInFilename(arg, outdata[0x143]), outdata)
print "\nassembled " + str(len(sys.argv) - 1) + (' files' if len(sys.argv) != 2 else ' file')
if __name__ == "__main__":
main()