Cybernoid/ConvertZ80/ConvertZ80.py

595 lines
13 KiB
Python

import os
import re
import sys
Z80Regs8 = ('a','b','c','d','e','f','h','l')
Z80Regs16 = ('af', 'bc', 'de', 'hl', 'ix')
#==============================================================================
def GetLine(f):
szLine = f.readline()
while szLine != '':
if szLine[0] != ';':
return szLine
szLine = f.readline()
return ''
#------------------------------------------------------------------------------
def GetConst(S):
const = S
if re.match('\d', const): # 1st char is [0..9]
if const[len(const)-1] == 'h':
const = const[:len(const)-1] # Strip last char
if len(const) > 4 and const[0] == '0':
const = const[1:] # Strip leading zero
if len(const) > 2 and const[0] == '0':
const = const[1:] # Strip leading zero
const = '$' + const
return const
#--------------------------------------
# S = 0008h -> $0008
# S = label -> label
# S = labeh -> labeh
def GetAddr16(S):
return GetConst(S)
#--------------------------------------
# S = (0008h) -> $0008
# S = (label) -> label
# S = (labeh) -> labeh
def GetIndirectAddr16(S):
res = S[:len(S)-1] # Strip last char
res = res[1:] # Strip 1st char
return GetConst(res)
#--------------------------------------
def GetRegOffset(S):
reg = S[1:3] # Middle 2 chars
if reg not in Z80Regs16:
print 'Illegal Z80 reg: ' + reg
return ('', '')
offset = S[4:] # Strip 1st 4 chars: '(ix+'
offset = offset[:len(offset)-1] # Strip last char: ')'
if offset[len(offset)-1] == 'h':
offset = offset[:len(offset)-1] # Strip last char: 'h'
offset = '$' + offset
return reg, offset
#==============================================================================
def adc(S):
if S[2] in Z80Regs8 and S[3] not in Z80Regs8:
const = GetConst(S[3])
print '\tlda\t' + 'Reg' + S[2].upper()
print '\tadc\t' + '#' + const
print '\tsta\t' + 'Reg' + S[2].upper()
else:
print 'ADC error: unsupported addressing mode: ' + S[2], S[3]
#------------------------------------------------------------------------------
def add(S):
ind2 = S[3][0] == '(' # S[3] is indirect
m2plus = re.search('\+', S[3])
if S[2] in Z80Regs8 and S[3] in Z80Regs8:
# add a,a
if S[2] == S[3]:
print '\tlda\t' + 'Reg' + S[2].upper()
print '\tasl\t'
print '\tsta\t' + 'Reg' + S[2].upper()
else:
print '\tclc\t'
print '\tlda\t' + 'Reg' + S[2].upper()
print '\tadc\t' + 'Reg' + S[3].upper()
print '\tsta\t' + 'Reg' + S[2].upper()
elif S[2] in Z80Regs8 and ind2 and m2plus:
# add a,(ix+18h)
reg, offset = GetRegOffset(S[3])
print '\tclc\t' + '\t; CARRY possibly wrong'
print '\tldy\t' + '#' + offset
print '\tlda\t' + 'Reg' + S[2].upper()
print '\tadc\t' + '(Reg' + reg.upper() + '),y'
print '\tsta\t' + 'Reg' + S[2].upper()
elif S[2] in Z80Regs8:
# add a,05h
const = GetConst(S[3])
print '\tclc\t' + '\t; CARRY possibly wrong'
print '\tlda\t' + 'Reg' + S[2].upper()
print '\tadc\t' + '#' + const
print '\tsta\t' + 'Reg' + S[2].upper()
elif S[2] in Z80Regs16 and S[3] in Z80Regs16:
# add hl,bc
print '\t+ADDW\t' + 'Reg' + S[2].upper() + ', ' + 'Reg' + S[3].upper()
else:
print 'ADD error: unsupported addressing mode: ' + S[2], S[3]
#------------------------------------------------------------------------------
def _and(S):
ind2 = S[2][0] == '(' # S[2] is indirect
m2plus = re.search('\+', S[2])
if S[2] in Z80Regs8:
# and e
print '\tand\t' + 'Reg' + S[2].upper()
elif ind2 and m2plus:
# and (ix+1bh)
reg, offset = GetRegOffset(S[2])
print '\tldy\t' + '#' + offset
print '\tand\t' + '(Reg' + reg.upper() + '),y'
else:
# and 3fh
const = GetConst(S[2])
print '\tand\t' + '#' + const
#------------------------------------------------------------------------------
def cp(S):
ind2 = S[2][0] == '(' # S[2] is indirect
m2plus = re.search('\+', S[2])
if ind2 and m2plus:
# cp (ix+10h)
reg, offset = GetRegOffset(S[2])
print '\t+CP_INDIRECT_OFFSET\t' + 'Reg' + reg.upper() + ', ' + offset
elif not ind2:
const = GetConst(S[2])
print '\tcmp\t' + '#' + const
else:
print 'CP error: unsupported addressing mode: ' + S[2]
#------------------------------------------------------------------------------
def dec(S):
ind2 = S[2][0] == '(' # S[2] is indirect
m2plus = re.search('\+', S[2])
if S[2] in Z80Regs8:
print '\tdec\t' + 'Reg' + S[2].upper()
elif S[2] in Z80Regs16:
# dec hl
reg = GetAddr16(S[2])
print '\t+DECW\t' + 'Reg' + reg.upper()
elif ind2 and m2plus:
# dec (ix+11h)
reg, offset = GetRegOffset(S[2])
if reg == '':
return
print '\t+DEC_INDIRECT_OFFSET\t' + 'Reg' + reg.upper() + ', ' + offset
else:
print ';DEC error: unsupported addressing mode: ' + S[2]
#------------------------------------------------------------------------------
def inc(S):
ind2 = S[2][0] == '(' # S[2] is indirect
if S[2] in Z80Regs8:
print '\tinc\t' + 'Reg' + S[2].upper()
return
#
if ind2:
# inc (hl)
reg = GetIndirectAddr16(S[2])
else:
# inc hl
reg = GetAddr16(S[2])
if reg not in Z80Regs16:
print 'INC error: Illegal Z80 reg: ' + reg
elif ind2:
print '\t+INC_INDIRECT\t' + 'Reg' + reg.upper()
else:
print '\t+INCW\t' + 'Reg' + reg.upper()
#------------------------------------------------------------------------------
def jp(S):
if S[3] == '':
print '\tjmp\t' + S[2]
return
if S[2] == 'z':
print '\t+JP_Z\t' + S[3]
elif S[2] == 'nz':
print '\t+JP_NZ\t' + S[3]
elif S[2] == 'c':
print '\t+JP_C\t' + S[3]
elif S[2] == 'nc':
print '\t+JP_NC\t' + S[3]
else:
print ';JP error: unsupported cc: ' + S[2]
#------------------------------------------------------------------------------
def jr(S):
if S[3] == '':
print '\tjmp\t' + S[2]
return
if S[2] == 'z':
print '\tbeq\t' + S[3]
elif S[2] == 'nz':
print '\tbne\t' + S[3]
elif S[2] == 'c':
print '\tbcc\t' + S[3] # C inverted
elif S[2] == 'nc':
print '\tbcs\t' + S[3] # C inverted
else:
print 'JR error: unsupported cc: ' + S[2]
#------------------------------------------------------------------------------
def ld(S):
m2 = S[2] in Z80Regs8
m3 = S[3] in Z80Regs8
m2plus = re.search('\+', S[2])
m3plus = re.search('\+', S[3])
len2 = len(S[2])
len3 = len(S[3])
ind2 = S[2][0] == '(' # S[2] is indirect
ind3 = S[3][0] == '(' # S[3] is indirect
if m2 and m3:
# ld c,a
print '\t+LD\t' + 'Reg' + S[2].upper() + ', ' + 'Reg' + S[3].upper()
return
elif m2 and not ind3:
# ld c,80h
const = GetConst(S[3])
print '\t+LD_REG_IMM\t' + 'Reg' + S[2].upper() + ', ' + const
return
elif m2 and ind3 and len3 == len('(xx)'):
# ld a,(hl)
reg = S[3][1:3] # Middle 2 chars
if reg not in Z80Regs16:
print 'Illegal Z80 reg: ' + reg
return
print '\t+LD_REG_INDIRECT\t' + 'Reg' + S[2].upper() + ', ' + 'Reg' + reg.upper()
return
elif m2 and ind3 and m3plus:
# ld h,(ix+15h)
reg, offset = GetRegOffset(S[3])
if reg == '':
return
print '\t+LD_REG_INDIRECT_OFFSET\t' + 'Reg' + S[2].upper() + ', ' + 'Reg' + reg.upper() + ', ' + offset
return
elif m2 and ind3:
# ld a,(0f1fdh)
# ld a,(lf1fd)
abs = GetIndirectAddr16(S[3])
print '\t+LD_REG_INDIRECT_ABS\t' + 'Reg' + S[2].upper() + ', ' + abs
return
elif S[2] in Z80Regs16 and ind3:
# ld hl,(lf1f6)
# ld hl,(0f1f6h)
src = GetIndirectAddr16(S[3])
print '\t+LDW_INDIRECT\t' + 'Reg' + S[2].upper() + ', ' + src
return
elif S[2] in Z80Regs16:
# ld ix,lf214
# ld hl,0008h
const = GetAddr16(S[3])
print '\t+LDW\t' + 'Reg' + S[2].upper() + ', ' + const
return
elif ind2 and m2plus and m3:
# ld (ix+19h),a
reg, offset = GetRegOffset(S[2])
if reg == '':
return
print '\t+LD_INDIRECT_OFFSET\t' + 'Reg' + reg.upper() + ', ' + offset + ', ' + 'Reg' + S[3].upper()
return
elif ind2 and m2plus and not m3:
# ld (ix+19h),01h
reg, offset = GetRegOffset(S[2])
if reg == '':
return
const = GetConst(S[3])
print '\t+LD_INDIRECT_OFFSET_IMM\t' + 'Reg' + reg.upper() + ', ' + offset + ', ' + const
return
elif ind2 and m3:
# ld (hl),a
# ld (0f1fch),a
# ld (lf1fc),a
Addr16 = GetIndirectAddr16(S[2])
if Addr16 in Z80Regs16:
print '\t+LD_INDIRECT\t' + 'Reg' + Addr16.upper() + ', ' + 'Reg' + S[3].upper()
else:
print '\t+LD_INDIRECT_ABS\t' + Addr16 + ', ' + 'Reg' + S[3].upper()
return
elif ind2 and not m3:
# ld (hl),00h
# ld (0f1f6h),hl
# ld (lf1f6h),hl
Addr16 = GetIndirectAddr16(S[2])
const = GetConst(S[3])
if Addr16 in Z80Regs16:
print '\t+LD_INDIRECT_IMM\t' + 'Reg' + Addr16.upper() + ', ' + const
elif const in Z80Regs16:
print '\t+LDW_INDIRECT\t' + Addr16 + ', ' + 'Reg' + const.upper()
else:
print 'Illegal Z80 reg: ' + Addr16
return
#
print 'LD error: No match for ' + S[2], S[3]
#------------------------------------------------------------------------------
def orr(S):
if S[2] in Z80Regs8:
# or l
print '\tora\t' + 'Reg' + S[2].upper()
else:
# or 38h
const = GetConst(S[2])
print '\tora\t' + '#' + const
#------------------------------------------------------------------------------
def pop(S):
if S[2] in Z80Regs16:
# pop de
print '\t+POP16\t' + 'Reg' + S[2].upper()
else:
print 'POP error: unsupported addressing mode'
#------------------------------------------------------------------------------
def push(S):
if S[2] in Z80Regs16:
# push de
print '\t+PUSH16\t' + 'Reg' + S[2].upper()
else:
print 'PUSH error: unsupported addressing mode'
#------------------------------------------------------------------------------
def sbc(S):
if S[2] in Z80Regs16 and S[3] in Z80Regs16:
# sbc hl,bc
print '\t+SBCW\t' + 'Reg' + S[2].upper() + ', ' + 'Reg' + S[3].upper()
else:
print 'SBC error: unsupported addressing mode'
#------------------------------------------------------------------------------
def sub(S):
ind2 = S[2][0] == '(' # S[2] is indirect
if S[2] in Z80Regs8:
# sub l
print '\tsbc\t' + 'Reg' + S[2].upper() + '\t; CARRY possibly wrong'
elif ind2:
# sub (hl)
reg = GetIndirectAddr16(S[2])
if reg not in Z80Regs16:
print 'DEC error: Illegal Z80 reg: ' + Addr16
return
print '\t+SUB_INDIRECT\t' + 'Reg' + reg.upper()
else:
# sub 80h
const = GetConst(S[2])
print '\tsec\t' + '\t; CARRY possibly wrong'
print '\tsbc\t' + '#' + const
#------------------------------------------------------------------------------
def ret(S):
if S[2] == '':
print '\trts'
elif S[2] == 'z':
print '\t+RET_Z\t' + S[3]
elif S[2] == 'nz':
print '\t+RET_NZ\t' + S[3]
elif S[2] == 'c':
print '\t+RET_C\t' + S[3]
elif S[2] == 'nc':
print '\t+RET_NC\t' + S[3]
else:
print ';RET error: unsupported cc: ' + S[2]
print ''
#------------------------------------------------------------------------------
def xor(S):
ind2 = S[2][0] == '(' # S[2] is indirect
if S[2] in Z80Regs8:
print '\t+LD_REG_IMM\t' + 'Reg' + S[2].upper() + ', 0' + '\t; xor ' + S[2]
# elif ind2:
# reg = GetIndirectAddr16(S[2])
else:
print 'XOR error: unsupported addressing mode'
#==============================================================================
def Process(S):
if S[0] != '':
print S[0]
if S[1] == '':
return 1 # No opcode
elif S[1] == 'nop':
return 0 # Assume this is data section
elif S[1] == 'adc':
adc(S)
elif S[1] == 'add':
add(S)
elif S[1] == 'and':
_and(S)
elif S[1] == 'call':
print '\tjsr\t' + S[2]
elif S[1] == 'dec':
dec(S)
elif S[1] == 'cp':
cp(S)
elif S[1] == 'inc':
inc(S)
elif S[1] == 'jp':
jp(S)
elif S[1] == 'jr':
jr(S)
elif S[1] == 'ld':
ld(S)
elif S[1] == 'ldi':
print '\t+LDI'
elif S[1] == 'or':
orr(S)
elif S[1] == 'pop':
pop(S)
elif S[1] == 'push':
push(S)
elif S[1] == 'ret':
ret(S)
elif S[1] == 'sbc':
sbc(S)
elif S[1] == 'sub':
sub(S)
elif S[1] == 'xor':
xor(S)
else:
s = ';\t'
for i in range(len(S)):
s = s + S[i]
s = s + '\t; ** Unknown opcode **'
print s
return 1
#------------------------------------------------------------------------------
def hdr_code():
print ';ACME 0.85'
print ''
print '!cpu 6502 ; Compatible with all Apple2\'s'
print '!to \"TEST\", plain'
print '!sl \"TEST.labels\"'
print '*=$6000'
print ''
print '!source \"..\\Common\\Z80-Macros.a\"'
print '!source \"..\\Common\\ZP-Macros.a\"'
print '!source \"..\\Common\\AppleDefs.a\"'
print '!source \"..\\Common\\MockingboardDefs.a\"'
print ''
print ';------------------------------------------------------------------------------'
print ''
print '!zone code'
print ''
#------------------------------------------------------------------------------
def hdr_data():
print ''
print ';------------------------------------------------------------------------------'
print ''
print '!zone data'
print ''
#------------------------------------------------------------------------------
def help():
print 'ConvertZ80 v1.0.0'
print ''
print 'Usage: ConvertZ80.py <z80.asm>'
#------------------------------------------------------------------------------
def main():
if len(sys.argv) < 2:
help()
return
hFileIn = open(sys.argv[1], 'r')
#if len(sys.argv) >= 3:
# hFileOut = open(sys.argv[2], 'w')
hdr_code()
n = 0
while n < 1000:
szLine = GetLine(hFileIn)
if szLine == '':
break
Split = re.split('\s+|,', szLine)
if Process(Split) == 0:
break
n = n + 1
hdr_data()
hFileIn.close()
#hFileOut.close()
#------------------------------------------------------------------------------
main()