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 ' #------------------------------------------------------------------------------ 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()