def NewOrgSet(memory): """ Handle flushing of the current target line. We possibly have to close an unformatted target file as well. Possible parameter values are 0 for code memory and 2 for EEPROM memory """ if dec.Asm.Pass == 2: # Only during pass 2 if memory == 0: # In code memory if dec.Asm.Code_Tformat != '': # A targetfile is open FlushTarget(0) if dec.Asm.Code_Tformat in ('BIN', 'HEX'): # It's an unformattedtext target file if dec.Asm.Code_Tfile.tell() != 0: # Unformatted target file is not empty CloseTarget(0) errors.DoWarning('tclosed', True) else: # It's EEPROM or RAM section if dec.Asm.Eeprom_Tformat != '': # A target file is open FlushTarget(2) if dec.Asm.Eeprom_Tformat in ('BIN', 'HEX'): # It'sn unformatted target file if dec.Asm.Eeprom_Tfile.tell() != 0: # Unformatted target file is not empty CloseTarget(2) errors.DoWarning('tclosed', True)
def CrossMnemonic(): """ Instructions have to start on an even byte location, so we'll do a boundary sync first. Then we'll check if the given directive is known to us. Depending on the chosen family some directives may not be valid. Parse the mnemonic if it is valid. """ global Asm target.BoundarySync() if dec.Asm.AVR_Family == 0: # AVR Family not specified, assume XMega family errors.DoWarning(dec.Cross.Name + 'nofamily', False) dec.Asm.AVR_Family = 4 if dec.Asm.Mnemonic in dec.Asm.Instructions: if not (FamilyCheck(dec.Asm.Instructions[dec.Asm.Mnemonic][1], dec.Asm.Instructions[dec.Asm.Mnemonic][2])): # Opcode not supported by this family errors.DoError('badopco', False) else: # Opcode is supported by this family, do it dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][4] func = dec.Asm.Instructions[dec.Asm.Mnemonic][0] func() else: errors.DoError('badopco', False)
def Immediate(): """ Immediate operand instructions. Instructions optionally accept the traditional # / = and \ prefixes. Only the RETLW instruction will accept multiple operatnds, which are stored sequentially in program memory. """ global Asm opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] if opcode == 0x0C00: # Operand field may be empty for RETLW instruction if dec.Asm.Parse_Pointer == 0 or dec.Asm.Optional is False: # No parameter is following CodeWord(opcode) return while True: prefix = '#' if assem.NowChar() in '#/=\\': # A prefix is given, let's get it prefix = assem.NowChar(True) value = assem.EvalExpr()[0] if dec.Asm.Mnemonic == "BANKSEL": # BANKSEL is the same as MOVLB with modified operand value = (value // 256) & 0x0F if not dec.Flags.ErrorInLine: # No error in this line, let's continue if prefix == '#': # Keep lower byte value = value & 0xFF elif prefix == '/': # Keep 2nd lower byte value = (value >> 8) & 0xFF elif prefix == '=': # Keep 2nd upper byte value = (value >> 16) & 0xFF else: # Keep upper byte value = (value >> 24) & 0xFF if opcode == 0x0100: # MOVLB range is limited to 4 bits value = value & 0x0F CodeWord(opcode + value) if not assem.MoreParameters(): # No more parameters break if opcode != 0x0C00: # Only the RETLW instruction allows multiple literal bytes errors.DoWarning('extrign', False)
def NoMore(): """ No more operands shoudl follow. Raise a warning if more parameters follow. """ if assem.MoreParameters(): errors.DoWarning('extrign', False)
def IncPP(): """ Increment the Program Pointer. """ global Asm dec.Asm.Fraction = dec.Asm.Fraction + 1 if dec.Asm.Fraction >= dec.Asm.PP_TA_Factor: dec.Asm.PP_Address = dec.Asm.PP_Address + 1 dec.Asm.PH_Address = dec.Asm.PH_Address + 1 dec.Asm.Fraction = 0 if not dec.Flags.DummyMode: if dec.Asm.Pass == 2 and (not dec.Asm.Code_Twrap) and\ dec.Asm.TA_Address > dec.Asm.Code_Tmaxadd: dec.Asm.Code_Twrap = True # True because will only happen in pass 2 errors.DoWarning('trange', True) dec.Asm.TA_Address = dec.Asm.TA_Address & dec.MAX32 dec.Asm.TA_Address = dec.Asm.TA_Address + 1 if dec.Asm.Code_Tformat in ('INT', 'INS'): if (dec.Asm.TA_Address & 0xFFFF) == 0: # Segment changed! Flush current line before change of segment FlushTarget(0)
def NoMore(): """ No more parameters are expected. Raise a warning if more paramters are found anyway. """ if assem.MoreParameters(): errors.DoWarning('extrign', False)
def NoMore(): """ A useful function which tests if no more parameters are given when we don't expect any more at the end of the operand parsing. """ if assem.MoreParameters(): errors.DoWarning('extrign', False)
def NoMore(): """ This must be the end of the line. Raise an error if it's not. Or a warning if more parameters follow. """ if assem.MoreParameters(): errors.DoWarning('extrign', False)
def Immediate(): """ Immediate operand instructions. Instructions optionally accept the traditional # / = and \ prefixes. Only GOTO and CALL don't, they are only tolerant to the # prefix Only the RETLW instruction will accept multiple operatnds, which are stored sequentially in program memory. """ global Asm opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] if opcode == 0x3400: # Operand field may be empty for RETLW instruction if dec.Asm.Parse_Pointer == 0 or dec.Asm.Optional is False: # No parameter is following CodeWord(opcode) return while True: prefix = '#' if assem.NowChar() in '#/=\\': # A prefix is given, let's get it prefix = assem.NowChar(True) value = assem.EvalExpr() if not dec.Flags.ErrorInLine: # No error in this line, let's continue if opcode == 0x2000 or opcode == 0x2800: # Allow 11 bits of operand for GOTO CodeWord(opcode + (value[0] & 0x7FF)) if prefix != '#': # Only the default prefix is allowed errors.DoError('badoper', False) elif prefix == '#': # Save opcode and lower byte CodeWord(opcode + (value[0] & 0xFF)) elif prefix == '/': # Save opcode and 2nd lower byte CodeWord(opcode + ((value[0] >> 8) & 0xFF)) elif prefix == '=': # Save opcode and 2nd upper byte CodeWord(opcode + ((value[0] >> 16) & 0xFF)) else: # Save opcode and upper byte CodeWord(opcode + ((value[0] >> 24) & 0xFF)) if not assem.MoreParameters(): # No more parameters break if opcode != 0x3400: # Only the RETLW instruction allows multiple literal bytes errors.DoWarning('extrign', False)
def CodeLong(value, list=True): """ Save a long to the target file. Give a warning only once if the byte is not written to code memory! This is the routine to be used by crosses to save a code long. """ if dec.Asm.Memory != 0 and not dec.Flags.CodeWarn and dec.Asm.Pass == 2: dec.Flags.CodeWarn = True errors.DoWarning('notcode', True) SaveLong(value, list)
def CodeWord(data, list="True"): """ Write the code word to the target file. We can't rely on target.CodeWord because that would change everything into RETLW instructions. """ if dec.Asm.Memory != 0 and not dec.Flags.CodeWarn and dec.Asm.Pass == 2: dec.Flags.CodeWarn = True errors.DoWarning('notcode', True) target.SaveByte(data & 0xFF, list) target.SaveByte((data >> 8) & 0xFF, list)
def WriteOpcode(data): """ Normally an Opcode byte can just be written to memory. However when the Opcde byte is written to the beginning of the page, the assembler assumes that you have crossed a page boundary and it will give you a warning. Crossing a page boundary is perfectly legal, as long as you know what you're doing. """ global Asm if dec.Asm.Pass == 2: if ((dec.Asm.BOL_Address) & 4095) == 0: errors.DoWarning(dec.Cross.Name + 'pagebeg', True) target.CodeByte(data)
def Absolute(): global Asm if MissingOperand(): return value = assem.EvalExpr() if dec.Asm.Pass == 2 or (not value[1]): # Test range only if in pass 2, or pass 1 if not forward referenced if value[0] > dec.Asm.Max_Address or value[0] < 0: # It's a range error, simply ignore everything which doesn't fit errors.DoError('range', False) target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1]) target.CodeWord(value[0]) if value[2] == 2: errors.DoWarning('eeprom') NoMore()
def CodeWord(data, list="True"): """ Write the code word to the target file. We don't have to anythong special for the PIC16. We only need to do a boundary sync first. """ if dec.Asm.Memory != 0 and not dec.Flags.CodeWarn and dec.Asm.Pass == 2: # It's useless to store program code in EEPROM or RAM memory dec.Flags.CodeWarn = True errors.DoWarning('notcode', True) if dec.Asm.Memory == 0: # OK, we're in code memory if (dec.Asm.PH_Address % 2) != 0: # We're at an odd address. Let's save a padding byte target.SaveByte(0, False) dec.Asm.BOL_Address = dec.Asm.PH_Address dec.Asm.List_Address = dec.Asm.PH_Address target.SaveByte(data & 0xFF, list) target.SaveByte((data >> 8) & 0xFF, list)
def CrossInit(): global Asm, Flags, avrdirlist assem.CheckVersions(crossversion, minversion) # Tupple consists of these fields: # - Function to be called # - 8=Xmega, 4=Mega, 2=AVR, 1=Tiny # - 128=XMEGA, 64=Enhanced 4M, 32=Enhanced 128k, 16=Enhanced 8k, # 8-Classic 128k, 4=Classic 8k, 2=Minimal, 1=Reduced # - Opcode # - Tiniming dec.Asm.Instructions = { 'ADC': (RegReg, 0b00001111, 0b01111111, 0x1C00, '1'), 'ADD': (RegReg, 0b00001111, 0b01111111, 0x0C00, '1'), 'AND': (RegReg, 0b00001111, 0b01111111, 0x2000, '1'), 'CP': (RegReg, 0b00001111, 0b01111111, 0x1400, '1'), 'CPC': (RegReg, 0b00001111, 0b01111111, 0x0400, '1'), 'CPSE': (RegReg, 0b00001111, 0b01111111, 0x1000, '1/2/3'), 'EOR': (RegReg, 0b00001111, 0b01111111, 0x2400, '1'), 'FMUL': (RegReg, 0b00001100, 0b01110000, 0x0308, '2'), 'FMULS': (RegReg, 0b00001100, 0b01110000, 0x0380, '2'), 'FMULSU': (RegReg, 0b00001100, 0b01110000, 0x0388, '2'), 'MOV': (RegReg, 0b00001111, 0b01111111, 0x2C00, '1'), 'MOVW': (RegReg, 0b00001100, 0b01110000, 0x0100, '1'), 'MUL': (RegReg, 0b00001100, 0b01110000, 0x9C00, '1'), 'MULS': (RegReg, 0b00001100, 0b01110000, 0x0200, '1'), 'MULSU': (RegReg, 0b00001100, 0b01110000, 0x0300, '1'), 'OR': (RegReg, 0b00001111, 0b01111111, 0x2800, '1'), 'SBC': (RegReg, 0b00001111, 0b01111111, 0x0800, '1'), 'SUB': (RegReg, 0b00001111, 0b01111111, 0x1800, '1'), 'ADIW': (RegImm, 0b00001110, 0b01111100, 0x9600, '1'), 'ANDI': (RegImm, 0b00001111, 0b01111111, 0x7000, '1'), 'CBR': (RegImm, 0b00001111, 0b01111111, 0x7000, '1'), 'CPI': (RegImm, 0b00001111, 0b01111111, 0x3000, '1'), 'LDI': (RegImm, 0b00001111, 0b01111111, 0xE000, '1'), 'ORI': (RegImm, 0b00001111, 0b01111111, 0x6000, '1'), 'SBCI': (RegImm, 0b00001111, 0b01111111, 0x4000, '1'), 'SBIW': (RegImm, 0b00001110, 0b01111100, 0x9700, '2'), 'SBR': (RegImm, 0b00001111, 0b01111111, 0x6000, '1'), 'SUBI': (RegImm, 0b00001111, 0b01111111, 0x5000, '1'), 'ASR': (RegOnly, 0b00001111, 0b01111111, 0x9405, '1'), 'CLR': (RegOnly, 0b00001111, 0b01111111, 0x2400, '1'), 'COM': (RegOnly, 0b00001111, 0b01111111, 0x9400, '1'), 'DEC': (RegOnly, 0b00001111, 0b01111111, 0x940A, '1'), 'INC': (RegOnly, 0b00001111, 0b01111111, 0x9403, '1'), 'LAC': (RegOnly, 0b00001000, 0b00000000, 0x9206, '2'), 'LAS': (RegOnly, 0b00001000, 0b00000000, 0x9205, '2'), 'LAT': (RegOnly, 0b00001000, 0b00000000, 0x9207, '2'), 'LSL': (RegOnly, 0b00001111, 0b01111111, 0x0C00, '1'), 'LSR': (RegOnly, 0b00001111, 0b01111111, 0x9406, '1'), 'NEG': (RegOnly, 0b00001111, 0b01111111, 0x9401, '1'), 'POP': (RegOnly, 0b00001111, 0b01111101, 0x900F, '2'), 'PUSH': (RegOnly, 0b00001111, 0b01111101, 0x920F, '1/2'), 'ROL': (RegOnly, 0b00001111, 0b01111111, 0x1C00, '1'), 'ROR': (RegOnly, 0b00001111, 0b01111111, 0x9407, '1'), 'SER': (RegOnly, 0b00001111, 0b01111111, 0xEF0F, '1'), 'SWAP': (RegOnly, 0b00001111, 0b01111111, 0x9402, '1'), 'TST': (RegOnly, 0b00001111, 0b01111111, 0x2000, '1'), 'XCH': (RegOnly, 0b00001000, 0b00000000, 0x9204, '2'), 'BRBC': (RelJmp, 0b00001111, 0b01111111, 0xF400, '1/2'), 'BRBS': (RelJmp, 0b00001111, 0b01111111, 0xF000, '1/2'), 'BRCC': (RelJmp, 0b00001111, 0b01111111, 0xF400, '1/2'), 'BRCS': (RelJmp, 0b00001111, 0b01111111, 0xF000, '1/2'), 'BREQ': (RelJmp, 0b00001111, 0b01111111, 0xF001, '1/2'), 'BRGE': (RelJmp, 0b00001111, 0b01111111, 0xF404, '1/2'), 'BRHC': (RelJmp, 0b00001111, 0b01111111, 0xF405, '1/2'), 'BRHS': (RelJmp, 0b00001111, 0b01111111, 0xF005, '1/2'), 'BRID': (RelJmp, 0b00001111, 0b01111111, 0xF407, '1/2'), 'BRIE': (RelJmp, 0b00001111, 0b01111111, 0xF007, '1/2'), 'BRLO': (RelJmp, 0b00001111, 0b01111111, 0xF000, '1/2'), 'BRLT': (RelJmp, 0b00001111, 0b01111111, 0xF004, '1/2'), 'BRMI': (RelJmp, 0b00001111, 0b01111111, 0xF002, '1/2'), 'BRNE': (RelJmp, 0b00001111, 0b01111111, 0xF401, '1/2'), 'BRPL': (RelJmp, 0b00001111, 0b01111111, 0xF402, '1/2'), 'BRSH': (RelJmp, 0b00001111, 0b01111111, 0xF400, '1/2'), 'BRTC': (RelJmp, 0b00001111, 0b01111111, 0xF406, '1/2'), 'BRTS': (RelJmp, 0b00001111, 0b01111111, 0xF006, '1/2'), 'BRVC': (RelJmp, 0b00001111, 0b01111111, 0xF403, '1/2'), 'BRVS': (RelJmp, 0b00001111, 0b01111111, 0xF003, '1/2'), 'RCALL': (RelJmp, 0b00001111, 0b01111111, 0xD000, '2/3/4'), 'RJMP': (RelJmp, 0b00001111, 0b01111111, 0xC000, '2'), 'CALL': (CallJmp, 0b00001110, 0b01111000, 0x940E, '3/4/5'), 'JMP': (CallJmp, 0b00001110, 0b01111000, 0x940C, '3'), 'BLD': (BitInst, 0b00001111, 0b01111111, 0xF800, '1'), 'BST': (BitInst, 0b00001111, 0b01111111, 0xFA00, '1'), 'SBRC': (BitInst, 0b00001111, 0b01111111, 0xFC00, '1/2/3'), 'SBRS': (BitInst, 0b00001111, 0b01111111, 0xFE00, '1/2/3'), 'CBI': (IOBits, 0b00001111, 0b01111111, 0x9800, '1/2'), 'SBI': (IOBits, 0b00001111, 0b01111111, 0x9A00, '1/2'), 'SBIC': (IOBits, 0b00001111, 0b01111111, 0x9900, '2/3/4*'), 'SBIS': (IOBits, 0b00001111, 0b01111111, 0x9B00, '2/3/4*'), # reduced LD has less addressing modes 'LD': (LDIndexed, 0b00001111, 0b01111111, 1, '1/2/3'), 'LDD': (LDIndexed, 0b00001110, 0b01111100, 0, '1/2/3'), # reduced ST has less addressing modes 'ST': (STIndexed, 0b00001111, 0b01111111, 1, '1/2'), 'STD': (STIndexed, 0b00001110, 0b01111100, 0, '1/2'), # tiny & reduced LDS and STS have different bit pattern 'LDS': (LdsSts, 0b00001111, 0b01111101, 0x9000, '2/3'), 'STS': (LdsSts, 0b00001111, 0b01111101, 0x9200, '2'), 'ELPM': (ELpm, 0b00001110, 0b01111000, 0x95D8, '3'), 'LPM': (ELpm, 0b00001110, 0b01110110, 0x95C8, '3'), 'SPM': (Spm, 0b00001100, 0b01110000, 0x95E8, '*'), 'IN': (InOut, 0b00001111, 0b01111111, 0xB000, '1'), 'OUT': (InOut, 0b00001111, 0b01111111, 0xB800, '1'), 'BCLR': (Sreg, 0b00001111, 0b01111111, 0x9488, '1'), 'BSET': (Sreg, 0b00001111, 0b01111111, 0x9408, '1'), 'DES': (Des, 0b00001000, 0b00000000, 0x940B, '1/2'), 'BREAK': (Inherent, 0b00001101, 0b01100001, 0x9598, '1'), 'CLC': (Inherent, 0b00001111, 0b01111111, 0x9488, '1'), 'CLH': (Inherent, 0b00001111, 0b01111111, 0x94D8, '1'), 'CLI': (Inherent, 0b00001111, 0b01111111, 0x94F8, '1'), 'CLN': (Inherent, 0b00001111, 0b01111111, 0x94A8, '1'), 'CLS': (Inherent, 0b00001111, 0b01111111, 0x94C8, '1'), 'CLT': (Inherent, 0b00001111, 0b01111111, 0x94E8, '1'), 'CLV': (Inherent, 0b00001111, 0b01111111, 0x94B8, '1'), 'CLZ': (Inherent, 0b00001111, 0b01111111, 0x9498, '1'), 'EICALL': (Inherent, 0b00001100, 0b01000000, 0x9519, '3/4*'), 'EIJMP': (Inherent, 0b00001100, 0b01000000, 0x9419, '2'), 'ICALL': (Inherent, 0b00001111, 0b01111100, 0x9509, '2/3/4*'), 'IJMP': (Inherent, 0b00001111, 0b01111100, 0x9409, '2'), 'NOP': (Inherent, 0b00001111, 0b01111111, 0x0000, '1'), 'RET': (Inherent, 0b00001111, 0b01111111, 0x9508, '4/5*'), 'RETI': (Inherent, 0b00001111, 0b01111111, 0x9518, '4/5*'), 'SEC': (Inherent, 0b00001111, 0b01111111, 0x9408, '1'), 'SEH': (Inherent, 0b00001111, 0b01111111, 0x9458, '1'), 'SEI': (Inherent, 0b00001111, 0b01111111, 0x9478, '1'), 'SEN': (Inherent, 0b00001111, 0b01111111, 0x9428, '1'), 'SES': (Inherent, 0b00001111, 0b01111111, 0x9448, '1'), 'SET': (Inherent, 0b00001111, 0b01111111, 0x9468, '1'), 'SEV': (Inherent, 0b00001111, 0b01111111, 0x9438, '1'), 'SEZ': (Inherent, 0b00001111, 0b01111111, 0x9418, '1'), 'SLEEP': (Inherent, 0b00001111, 0b01111111, 0x9588, '1'), 'WDR': (Inherent, 0b00001111, 0b01111111, 0x95A8, '1') } length = 0 for i in dec.Asm.Instructions: if len(dec.Asm.Instructions[i][4]) > length: length = len(dec.Asm.Instructions[i][4]) dec.Asm.Timing_Length = length dec.Asm.Memory = 0 if dec.Asm.Pass == 1: sys.stdout.write('Loaded ' + dec.Cross.Name[2:] + ' overlay version ' + crossversion + dec.EOL) dec.Asm.Max_Address = (1 << 22) - 1 # Change target factor to 2 if dec.Asm.PP_TA_Factor != 2: if dec.Asm.PP_Address != dec.Asm.TA_Address or\ dec.Asm.PP_Address != dec.Asm.PH_Address: # Oops, this is complicated. Let's warn the programmer errors.DoWarning('taconfusion', True) # Set the instruction size and double the target address dec.Asm.PP_TA_Factor = 2 dec.Asm.TA_Address *= 2 dec.Flags.BigEndian = False dec.Asm.AVR_Family = 0 errors.Error_List[dec.Cross.Name + 'nofamily'] =\ 'AVR Family not set. Assuming XMega family.' # Fill dictionary with all available directive handlers for i in dir(cravr): if len(i) == 5 and i[:3] == 'Dir': avrdirlist[i[-2:]] = eval(i) return
def Stack(): """ Handle Push and Pull instructions. Any number from of registers and register pairs may be pushed and pulled by one instruction, all separated by a comma. A warning is issued if you specify a particular register more than once. """ global Asm if MissingOperand(): return registers = { 'CC': 1, 'CCR': 1, 'A': 2, 'B': 4, 'D': 6, 'A:B': 6, 'DP': 8, 'DPR': 8, 'X': 16, 'Y': 32, 'U': 64, 'US': 64, 'S': 64, 'SP': 64, 'PC': 128 } stack = dec.Asm.Mnemonic[-1] postbyte = 0 doubled = False while True: reg = assem.GetWord().upper() if reg in registers: if reg == stack: # S may not be used in PSHS and PULS # U may not be used in PSHU and PULU errors.DoError('badoper', False) return bits = registers[reg] if (postbyte & bits) != 0: doubled = True postbyte = postbyte | bits else: errors.DoError('badoper', False) return if not assem.MoreParameters(): break if doubled: errors.DoWarning('6809double', False) count = 0 for i in range(0, 8): if (postbyte & (1 << i)) != 0: if i > 3: count = count + 2 else: count = count + 1 target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1]) target.CodeByte(postbyte) dec.Asm.Timing = str(dec.Asm.Instructions[dec.Asm.Mnemonic][2] + count)
def CrossInit(): global Asm, Flags, Cross assem.CheckVersions(crossversion, minversion) dec.Asm.Instructions = { 'ADDLW': (Immediate, 0x3E00, '1'), 'ANDLW': (Immediate, 0x3900, '1'), 'CALL': (Immediate, 0x2000, '2'), 'GOTO': (Immediate, 0x2800, '2'), 'IORLW': (Immediate, 0x3800, '1'), 'MOVLB': (Immediate, 0x0020, '1'), 'MOVLP': (Immediate, 0x3180, '1'), 'MOVLW': (Immediate, 0x3000, '1'), 'RETLW': (Immediate, 0x3400, '2'), 'SUBLW': (Immediate, 0x3C00, '1'), 'XORLW': (Immediate, 0x3A00, '1'), 'B': (Immediate, 0x2800, '2'), 'BANKSEL': (Immediate, 0x0020, '1'), 'BRW': (Implied, 0x000B, '2'), 'CALLW': (Implied, 0x000A, '2'), 'CLRWDT': (Implied, 0x0064, '1'), 'OPTION': (Implied, 0x0062, '1'), 'RESET': (Implied, 0x0001, '1'), 'RETFIE': (Implied, 0x0009, '2'), 'RETURN': (Implied, 0x0008, '2'), 'SLEEP': (Implied, 0x0063, '1'), 'CLRW': (Implied, 0x0100, '1'), 'NOP': (Implied, 0x0000, '1'), 'CLRC': (Implied, 0x1003, '1'), 'CLRDC': (Implied, 0x1083, '1'), 'CLRZ': (Implied, 0x1103, '1'), 'SETC': (Implied, 0x1403, '1'), 'SETDC': (Implied, 0x1483, '1'), 'SETZ': (Implied, 0x1503, '1'), 'SKPC': (Implied, 0x1C03, '1-2'), 'SKPDC': (Implied, 0x1C83, '1-2'), 'SKPNC': (Implied, 0x1803, '1-2'), 'SKPNDC': (Implied, 0x1883, '1-2'), 'SKPNZ': (Implied, 0x1903, '1-2'), 'SKPZ': (Implied, 0x1D03, '1-2'), 'BRA': (Relative, 0x3200, '2'), 'CLRF': (FileOnly, 0x0180, '1'), 'MOVWF': (FileOnly, 0x0080, '1'), 'TRIS': (FileOnly, 0x0060, '1'), 'MOVFW': (FileOnly, 0x0800, '1'), 'TSTF': (FileOnly, 0x0880, '1'), 'ADDWF': (FileW, 0x0700, '1'), 'ADDWFC': (FileW, 0x3D00, '1'), 'ANDWF': (FileW, 0x0500, '1'), 'ASRF': (FileW, 0x3700, '1'), 'LSLF': (FileW, 0x3500, '1'), 'LSRF': (FileW, 0x3600, '1'), 'COMF': (FileW, 0x0900, '1'), 'DECF': (FileW, 0x0300, '1'), 'DECFSZ': (FileW, 0x0B00, '1-2'), 'INCF': (FileW, 0x0A00, '1'), 'INCFSZ': (FileW, 0x0F00, '1-2'), 'IORWF': (FileW, 0x0400, '1'), 'MOVF': (FileW, 0x0800, '1'), 'RLF': (FileW, 0x0D00, '1'), 'RRF': (FileW, 0x0C00, '1'), 'SUBWF': (FileW, 0x0200, '1'), 'SUBWFB': (FileW, 0x3B00, '1'), 'SWAPF': (FileW, 0x0E00, '1'), 'XORWF': (FileW, 0x0600, '1'), 'BCF': (FileBit, 0x1000, '1'), 'BSF': (FileBit, 0x1400, '1'), 'BTFSC': (FileBit, 0x1800, '1-2'), 'BTFSS': (FileBit, 0x1C00, '1-2'), 'ADDFSR': (Compiler, (0x3100, 0x3100), '1'), 'MOVIW': (Compiler, (0x0010, 0x3F00), '1'), 'MOVWI': (Compiler, (0x0018, 0x3F80), '1'), 'BC': (Branches, 0x1803, '2-3'), 'BDC': (Branches, 0x1883, '2-3'), 'BNC': (Branches, 0x1C03, '2-3'), 'BNDC': (Branches, 0x1C83, '2-3'), 'BNZ': (Branches, 0x1D03, '2-3'), 'BZ': (Branches, 0x1903, '2-3'), 'ADDCF': (Pseudo, 0x1803, 0x0A00, '2'), 'ADDDCF': (Pseudo, 0x1883, 0x0A00, '2'), 'NEGF': (Pseudo, 0x0980, 0x0A00, '2'), 'SUBCF': (Pseudo, 0x1803, 0x0300, '2'), 'SUBDCF': (Pseudo, 0x1883, 0x0300, '2'), 'LCALL': (Long, 0x2000), 'LGOTO': (Long, 0x2800) } dec.Asm.Timing_Length = 3 dec.Asm.Memory = 0 # Select code memory as default if dec.Asm.Pass == 1: sys.stdout.write('Loaded ' + dec.Cross.Name[2:] + ' overlay version ' + crossversion + dec.EOL) dec.Asm.Max_Address = 0x0400 - 1 dec.Flags.BigEndian = False # Change target factor to 2 if dec.Asm.PP_TA_Factor != 2: if dec.Asm.PP_Address != dec.Asm.TA_Address or dec.Asm.PP_Address !=\ dec.Asm.PH_Address: # Oops, this is complicated. Let's warn the programmer errors.DoWarning('taconfusion', True) # Set the instruction size and double the target address dec.Asm.PP_TA_Factor = 2 dec.Asm.TA_Address *= 2 dec.Asm.TablePic14 = -1 errors.Error_List[dec.Cross.Name + 'tcrossed'] =\ 'Table crossed page boundary' errors.Error_List[dec.Cross.Name + 'codemem'] =\ 'Directive only allowed within Code memory' errors.Error_List[dec.Cross.Name + 'progmem'] =\ 'Directive only allowed beyond program memory' dec.Cross.SaveByte = eval('SaveByte')
def Multi(): """ Handle all other mnemonics of the 6502 instructionset. Each addressing mode has a separate entry in the opcode tupple. If the opcode is 0x00 the particular instruction is not available on the selected model. If the cycle length is '0' the particular addressing mode is not supported. The model is selected by calling either the 6502 overlay, or the 65c02 or 65sc02 overlays. """ global Asm, sweet16 if modelindex == 2 and (dec.Asm.Mnemonic in ('STZ', 'TRB', 'TSB')): errors.DoError('badopco', False) return instructions = dec.Asm.Instructions[dec.Asm.Mnemonic][1] ctimes = dec.Asm.Instructions[dec.Asm.Mnemonic][modelindex] operandbegin = dec.Asm.Parse_Pointer # Does implied addressing exist for this instruction? optional = dec.Asm.Optional pointer = dec.Asm.Parse_Pointer if instructions[0] != 0 and ctimes[0] != '0': if optional and \ (dec.Asm.Parse_Line[operandbegin:operandbegin+2].upper() == "A "): optional = False if optional is False: # No operand followed, use implied addressing mode dec.Asm.Timing = ctimes[0] target.CodeByte(instructions[0]) return if MissingOperand(): return # There are two compound instructions, save prefix for them first if dec.Asm.Mnemonic == 'ADD': target.CodeByte(0x18) if dec.Asm.Mnemonic == 'SUB': target.CodeByte(0x38) nowchar = assem.NowChar().upper() # Is it immediate addressing mode? if nowchar in '#/=\\': if instructions[1] == 0 or ctimes[1] == '0': errors.DoError('badoper', False) return prefix = assem.NowChar(True) value = assem.EvalExpr() dec.Asm.Timing = ctimes[1] if prefix == '#': operand = value[0] elif prefix == '/': operand = value[0] >> 8 elif prefix == '=': operand = value[0] >> 16 else: operand = value[0] >> 24 target.CodeByte(instructions[1]) target.CodeByte(operand) NoMore() return # Is it some kind if indirect mode? if nowchar == '(': assem.IncParsePointer() value = assem.EvalExpr() if assem.NowChar() == ')': # It must be (ZP),Y mode now, or is it JMP (IND) ? # On the CMOS models it can also be (ZP) assem.IncParsePointer() if assem.MoreParameters(): # It must be (zp),y now opcode = instructions[5] if (opcode != 0) and (assem.NowChar(True).upper() == 'Y'): dec.Asm.Timing = ctimes[5] target.CodeByte(opcode) target.CodeByte(value[0]) if dec.Asm.Pass == 2 and ((value[0] >> 8) != 0): errors.DoError('range', False) NoMore() return else: errors.DoError('badoper', False) else: # It is (zp), or (abs) in case of JMP now opcode = instructions[10] dec.Asm.Timing = ctimes[10] if dec.Asm.Mnemonic == "JMP": # It's JMP (IND) target.CodeByte(opcode) target.CodeWord(value[0]) if dec.Asm.Pass == 2 and ((value[0] >> 16) != 0): errors.DoError('range', False) if ((value[0] & 255) == 255) and modelindex == 2: # Give warning to user about the 6502 JMP (IND) bug errors.DoWarning('6502bug', False) NoMore() return else: # It's (zp) now if ctimes[10] == 0: errors.DoError('badoper', False) return target.CodeByte(opcode) target.CodeByte(value[0]) if dec.Asm.Pass == 2 and ((value[0] >> 8) != 0): errors.DoError('range', False) NoMore() return return # It must be (ZP,X) mode now opcode = instructions[4] if (opcode != 0 and ctimes[4] != '0') and assem.MoreParameters() \ and (assem.NowChar(True).upper() == 'X') and \ (assem.NowChar(True).upper() == ')'): dec.Asm.Timing = ctimes[4] target.CodeByte(opcode) if dec.Asm.Mnemonic == "JMP": target.CodeWord(value[0]) if dec.Asm.Pass == 2 and ((value[0] >> 16) != 0): errors.DoError('range', False) else: target.CodeByte(value[0]) if dec.Asm.Pass == 2 and ((value[0] >> 8) != 0): errors.DoError('range', False) NoMore() else: errors.DoError('badoper', False) return # May now be ZP, ABS, ZP,X ABS,X ZP,Y or ABS,Y if nowchar in '<>': # Forced ZP or ABS prefix given prefix = nowchar assem.IncParsePointer() else: prefix = '' # We have no preference, let the assembler decide value = assem.EvalExpr() if prefix == '': if value[1]: # A forward referenced label is used, force absolute mode prefix = '>' else: # Now decide if ZP is still possible if (value[0] >> 8) == 0: prefix = '<' else: prefix = '>' if not (assem.MoreParameters()): # It's normal ZP or ABS addressing mode if prefix == '<': index = 2 else: index = 3 else: # It's ZP or ABS indexed with X or Y now nowchar = assem.NowChar(True).upper() if nowchar == 'X': index = 6 elif nowchar == 'Y': index = 8 else: errors.DoError('badoper', False) return if prefix == '>': index = index + 1 if prefix == '<' and instructions[index] == 0: # ZP wanted, but doesn't exist, use ABS instead prefix = '>' index = index + 1 if instructions[index] == 0 or ctimes[index] == '0': errors.DoError('badoper', False) return target.CodeByte(instructions[index]) dec.Asm.Timing = ctimes[index] if prefix == '<': target.CodeByte(value[0]) address = value[0] >> 8 else: target.CodeWord(value[0]) address = value[0] >> 16 if dec.Asm.Mnemonic == 'JSR': # See if it's JSR SWEET16 if dec.Asm.Parse_Line[operandbegin:operandbegin+8].upper() == \ 'SWEET16 ': sweet16 = True if dec.Asm.Pass == 2 and address != 0: errors.DoError('range', False) NoMore() return
def SaveByte(value, list=True): """ Save a byte to the current open target file. We ignore all bits which don't belong to the byte. """ global Asm, Flags value = value & 255 # Ignore irrelevant bits. if list: listing.ListByte(value) if dec.Asm.Memory == 0: # In code memory # Check if byte is still within address limit if (dec.Asm.Pass == 2) and (not dec.Asm.Code_Wrap) and\ (dec.Asm.PP_Address > dec.Asm.Max_Address): dec.Asm.Code_Wrap = True # True because will only happen in pass 2 errors.DoWarning('maxaddr', True) if (dec.Asm.Pass == 2) and (dec.Asm.Code_Tformat != '') and\ (not dec.Flags.DummyMode): if len(dec.Asm.Code_Tbuffer) == 0: dec.Asm.Code_Tbuffer.append(dec.Asm.TA_Address) dec.Asm.Code_Tbuffer.append(value) if len(dec.Asm.Code_Tbuffer) > dec.Asm.Code_Tlength: FlushTarget(0) IncPP() elif dec.Asm.Memory == 1: # In RAM memory # No need to save the byte to RAM memory! dec.Asm.RM_Address = dec.Asm.RM_Address + 1 elif dec.Asm.Memory == 2: # In EEPROM memory if (dec.Asm.Pass == 2) and (dec.Asm.Eeprom_Tformat != ''): if len(dec.Asm.Eeprom_Tbuffer) == 0: dec.Asm.Eeprom_Tbuffer.append(dec.Asm.EM_Address) dec.Asm.Eeprom_Tbuffer.append(value) if len(dec.Asm.Eeprom_Tbuffer) > dec.Asm.Eeprom_Tlength: FlushTarget(2) if dec.Asm.Pass == 2 and (not dec.Asm.Eeprom_Twrap) and\ dec.Asm.EM_Address > dec.Asm.Eeprom_Tmaxadd: dec.Asm.Eeprom_Twrap = True # True because will only happen in pass 2 errors.DoWarning('trange', True) dec.Asm.EM_Address = dec.Asm.EM_Address & ((1 << 32) - 1) dec.Asm.EM_Address = dec.Asm.EM_Address + 1 if dec.Asm.Eeprom_Tformat in ('INT', 'INS'): if (dec.Asm.EM_Address & 65535) == 0: # Segment changed! Flush current line before change of segment FlushTarget(2) if dec.Asm.Memory == 0: # Code address is not always incremented by 1 dec.Asm.List_Address = dec.Asm.PH_Address else: dec.Asm.List_Address = dec.Asm.List_Address + 1
def Immediate(): """ Immediate operand instructions. Instructions optionally accept the traditional # / = and \ prefixes. Only GOTO and CALL don't, they are only tolerant to the # prefix No range checking is done, other than that CALL desitnation bit-8 is not allowed to be 1. Only the RETLW instruction will accept multiple operatnds, which are stored sequentially in program memory. RETLW also allows no operands, which loads 0 in W. """ global Asm opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] if opcode == 0x800: # Operand field may be empty for RETLW instruction if dec.Asm.Parse_Pointer == 0 or dec.Asm.Optional is False: # No parameter is following CodeWord(opcode) return while True: prefix = '#' if assem.NowChar() in '#/=\\': # A prefix is given, let's get it prefix = assem.NowChar(True) value = assem.EvalExpr() if not dec.Flags.ErrorInLine: # No error in this line, let's continue if opcode == 0xA00: # Allow 9 bits of operand for GOTO CodeWord(opcode + (value[0] & 0x1FF)) if prefix != '#': # Only the default prefix is allowed errors.DoError('badoper', False) elif prefix == '#': # Save opcode and lower byte CodeWord(opcode + (value[0] & 0xFF)) elif prefix == '/': # Save opcode and 2nd lower byte CodeWord(opcode + ((value[0] >> 8) & 0xFF)) elif prefix == '=': # Save opcode and 2nd upper byte CodeWord(opcode + ((value[0] >> 16) & 0xFF)) else: # Save opcode and upper byte CodeWord(opcode + ((value[0] >> 24) & 0xFF)) if opcode == 0x900: # It's a CALL instruction if prefix != '#': # Only allow # prefix (as it's the default) errors.DoError("badoper", False) if dec.Asm.Pass == 2 and (value[0] & 0x100) != 0: # Range error errors.DoError("range", False) if not assem.MoreParameters(): # No more parameters break if opcode != 0x800: # Only the RETLW instruction allows multiple literal bytes errors.DoWarning('extrign', False)
def GetDisplacement(opcode, allowauto): """ Expected parameters: opcode The basic opcode, can be modified before saving allowauto Flag indicating if @ mode is allowed Expected operands: @(Px) Offset = relative 0 and x can be 1 to 3 @E(Px) Offset = relative E-reg and x can be 1 to 3 @expr(Px) Offset = relative expr and x can be 1 to 3 (Px) Offset = relative 0 and x can be 0 to 3 or C E Offset = relative E-reg and reg PC E(Px) Offset = relative E-reg and x can be 0 to 3 or C expr(Px) Offset = relative expr and x can be 0 to 3 or C expr Offset = absolute expr and register is assumed PC PS: the P of the pointers is optional Not allowed: @(PC) or @(P0) @E(PC) or @E(P0) @expr(PC) or @expr(P0) The opcode can be modified the m flag (Auto indexed mode flag) and or the pointer before it is save to the target file. The assembler will not warn you about page crossings for the EA of the instruction. It's the programmer's responsibility to keep data tables from crossing page boundaries. The page wrap may even be done deliberately. Absolute addressing is only allowed for PC relative addressing mode, where the (PC) or (P0) part of the operand is omitted. The formula to calculate the offset is : DEST-PC-1 Except for jump instructions where it is: DEST-PC-2 Fortunately the jump instructions are the only ones which start with a J. """ global Asm if MissingOperand(): return offset = 0 forward = False error = False absolute = False reg = '0' autoindex = False eregister = False if allowauto: # auto-indexed addressing is allowed if assem.NowChar() == '@': # It is iato indexed addressing opcode = opcode + 4 assem.IncParsePointer() # Point at char following @ autoindex = True parseptr = dec.Asm.Parse_Pointer # Remember current parse pointer if assem.NowChar() != '(': # Some sort of offset is given if assem.GetWord(endchars="( ") == 'E': # It is E register offset = -128 eregister = True else: # It's not the E register, restore pointer dec.Asm.Parse_Pointer = parseptr if offset == 0: # Offset was not E-register # Offset can be a displacement or an abosulte value express = assem.EvalExpr() offset = express[0] forward = express[1] # This can't be an if, because we may have parsed the offset already if assem.NowChar() == '(': # A pointer register is given (offset would be relative now) assem.IncParsePointer() if assem.NowChar(True).upper() == 'P': # Still going good reg = assem.NowChar(True).upper() else: # We now allow omitting P for numbered registers dec.Asm.Parse_Pointer -= 1 reg = assem.NowChar(True).upper() if reg not in "0123": # It can't be a register error = True if assem.NowChar(True) != ')': # Something's wrong error = True if not error: # No error found yet if reg == 'C': reg = '0' if reg < '0' or reg > '3': # Something's wrong error = True if reg == '0' and autoindex: # P0 is not allowed together with auto indexed mode error = True if not error: # No error occurred, we know everything now opcode = opcode + int(reg) else: # An error did occur error = True else: # No register given, assuming PC, addressing is absolute now if not eregister: # The offset was not the E register # Now we have to calculate the real offset offset = offset - dec.Asm.BOL_Address - 1 absolute = True if dec.Asm.Mnemonic[0].upper() == "J": # An extra offset for Jump instructions offset = offset - 1 if autoindex and reg == '0': # Auto indexing doesn't allow the PC register error = True if error: # An error has occurred, tell us about it errors.DoError("badoper", False) NoMore() if dec.Asm.Pass == 2 and not forward: # Only test range in pass 2 if offset < -128 or offset > 127: # Range error errors.DoError('range', False) if offset == -128 and absolute: # Offset calculated to -128, are you sure! errors.DoWarning(dec.Cross.Name + 'offset', True) WriteOpcode(opcode) WriteOperand(offset)
def NoMore(): if assem.MoreParameters(): errors.DoWarning('extrign', False)
def Immediate(): """ Immediate operand instructions. Instructions optionally accept the traditional # / = and \ prefixes. Only GOTO and CALL don't, they are only tolerant to the # prefix Only the RETLW instruction will accept multiple operatnds, which are stored sequentially in program memory. """ global Asm opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] if opcode == 0x3400: # Operand field may be empty for RETLW instruction if dec.Asm.Parse_Pointer == 0 or dec.Asm.Optional is False: # No parameter is following CodeWord(opcode) return while True: prefix = '#' if assem.NowChar() in '#/=\\': # A prefix is given, let's get it prefix = assem.NowChar(True) value = assem.EvalExpr()[0] if not dec.Flags.ErrorInLine: # No error in this line, let's continue if dec.Asm.Mnemonic == "BANKSEL": # BANKSEL is the same as MOVLB with modified operand value = (value // 128) & 0x1F if opcode == 0x2000 or opcode == 0x2800: # Allow 11 bits of operand for GOTO literal = value & 0x7FF if prefix != '#': # Only the default prefix is allowed errors.DoError('badoper', False) elif prefix == '#': # Save opcode and lower byte literal = value & 0xFF elif prefix == '/': # Save opcode and 2nd lower byte literal = (value >> 8) & 0xFF elif prefix == '=': # Save opcode and 2nd upper byte literal = (value >> 16) & 0xFF else: # Save opcode and upper byte literal = (value >> 24) & 0xFF if opcode == 0x0020: # It's MOVLB, limit literal to 5 bits if dec.Asm.Pass == 2 and (literal < 0 or literal > 0x1F): # Range error errors.DoError('range', False) literal = literal & 0x1F if opcode == 0x3180: # It's MOVLP, limit literal to 7 bits if dec.Asm.Pass == 2 and (literal < 0 or literal > 0x7F): # Range error errors.DoError('range', False) literal = literal & 0x7F # Save opcode + literal to target CodeWord(opcode + literal) if not assem.MoreParameters(): # No more parameters break if opcode != 0x3400: # Only the RETLW instruction allows multiple literal bytes errors.DoWarning('extrign', False) else: # There's an error in the line, simply save a dummy and quit loop CodeWord(opcode) break
def CrossInit(): global Asm, Flags, Cross assem.CheckVersions(crossversion, minversion) dec.Asm.Instructions = { 'RETLW' : (Immediate, 0x800, '2'), 'CALL' : (Immediate, 0x900, '2'), 'GOTO' : (Immediate, 0xA00, '2'), 'B' : (Immediate, 0xA00, '2'), 'MOVLW' : (Immediate, 0xC00, '1'), 'IORLW' : (Immediate, 0xD00, '1'), 'ANDLW' : (Immediate, 0xE00, '1'), 'XORLW' : (Immediate, 0xF00, '1'), 'CLRW' : (Implied, 0x040, '1'), 'CLRWDT': (Implied, 0x004, '1'), 'NOP' : (Implied, 0x000, '1'), 'OPTION': (Implied, 0x002, '1'), 'SLEEP' : (Implied, 0x003, '1'), 'CLRC' : (Implied, 0x403, '1'), 'CLRDC' : (Implied, 0x423, '1'), 'CLRZ' : (Implied, 0x443, '1'), 'SETC' : (Implied, 0x503, '1'), 'SETDC' : (Implied, 0x523, '1'), 'SETZ' : (Implied, 0x543, '1'), 'SKPC' : (Implied, 0x703, '1-2'), 'SKPDC' : (Implied, 0x723, '1-2'), 'SKPNC' : (Implied, 0x603, '1-2'), 'SKPNDC': (Implied, 0x623, '1-2'), 'SKPNZ' : (Implied, 0x643, '1-2'), 'SKPZ' : (Implied, 0x743, '1-2'), 'CLRF' : (FileOnly, 0x060, '1'), 'MOVWF' : (FileOnly, 0x020, '1'), 'TRIS' : (FileOnly, 0x000, '1'), 'MOVFW' : (FileOnly, 0x200, '1'), 'TSTF' : (FileOnly, 0x220, '1'), 'ADDWF' : (FileW, 0x1C0, '1'), 'ANDWF' : (FileW, 0x140, '1'), 'COMF' : (FileW, 0x240, '1'), 'DECF' : (FileW, 0x0C0, '1'), 'DECFSZ': (FileW, 0x2C0, '1-2'), 'INCF' : (FileW, 0x280, '1'), 'INCFSZ': (FileW, 0x3C0, '1-2'), 'IORWF' : (FileW, 0x100, '1'), 'MOVF' : (FileW, 0x200, '1'), 'RLF' : (FileW, 0x340, '1'), 'RRF' : (FileW, 0x300, '1'), 'SUBWF' : (FileW, 0x080, '1'), 'SWAPF' : (FileW, 0x380, '1'), 'XORWF' : (FileW, 0x180, '1'), 'BCF' : (FileBit, 0x400 , '1'), 'BSF' : (FileBit, 0x500 , '1'), 'BTFSC' : (FileBit, 0x600 , '1-2'), 'BTFSS' : (FileBit, 0x700 , '1-2'), 'BC' : (Branches, 0x603, '2-3'), 'BDC' : (Branches, 0x623, '2-3'), 'BNC' : (Branches, 0x703, '2-3'), 'BNDC' : (Branches, 0x723, '2-3'), 'BNZ' : (Branches, 0x743, '2-3'), 'BZ' : (Branches, 0x643, '2-3'), 'ADDCF' : (Pseudo, 0x603, 0x280, '2'), 'ADDDCF': (Pseudo, 0x623, 0x280, '2'), 'NEGF' : (Pseudo, 0x260, 0x280, '2'), 'SUBCF' : (Pseudo, 0x603, 0x0C0, '2'), 'SUBDCF': (Pseudo, 0x623, 0x0C0, '2'), 'LCALL' : (Long, 0x900), 'LGOTO' : (Long, 0xA00) } dec.Asm.Timing_Length = 3 dec.Asm.Memory = 0 # Select code memory as default if dec.Asm.Pass == 1: sys.stdout.write('Loaded ' + dec.Cross.Name[2:] + ' overlay version ' + crossversion + dec.EOL) dec.Asm.Max_Address = 511 dec.Flags.BigEndian = False # Change target factor to 2 if dec.Asm.PP_TA_Factor != 2: if dec.Asm.PP_Address != dec.Asm.TA_Address or dec.Asm.PP_Address !=\ dec.Asm.PH_Address: # Oops, this is complicated. Let's warn the programmer errors.DoWarning('taconfusion', True) # Set the instruction size and double the target address dec.Asm.PP_TA_Factor = 2 dec.Asm.TA_Address *= 2 dec.Asm.TablePic12 = -1 errors.Error_List[dec.Cross.Name + 'tcrossed'] =\ 'Table crossed page boundary' errors.Error_List[dec.Cross.Name + 'codemem'] =\ 'Directive only allowed within Code memory' errors.Error_List[dec.Cross.Name + 'progmem'] =\ 'Directive only allowed beyond program memory' dec.Cross.SaveByte = eval('SaveByte')