def GetOneParameter(): global Asm parameter = "" if assem.NowChar() == ",": # It is an empty parameter return parameter endmark = assem.NowChar() if endmark in "'\"": # Start of literal string assem.IncParsePointer() while assem.NowChar() != endmark: # Get parameter until end mark singlechar = assem.NowChar(True) if singlechar == "\\": # Escaping, include the Escape symbol in parameter parameter = parameter + singlechar # And add the Escaped character too singlechar = assem.NowChar(True) parameter = parameter + singlechar assem.IncParsePointer() # Increment past endmark return parameter else: # Get parameter until space or comma while not assem.NowChar() in " ,": # Can never be beyond end line! parameter = parameter + assem.NowChar() assem.IncParsePointer() return parameter
def GetParameters(): global Asm parameters = [] if dec.Asm.Parse_Pointer == 0 or assem.NowChar() in dec.COMMENT2: # No operand field or operand field is only comment return parameters while True: parameter = GetOneParameter() parameters.append(parameter) if assem.NowChar() == " ": # End of parameter list break if assem.NowChar(True) == ",": # Something more follows if assem.NowChar() == " ": # A space followed the comma. We allow one space for # readability assem.IncParsePointer() if assem.NowChar() in " ;": # Nothing else follows, save final empty parameter parameters.append("") break return parameters
def Branch(): global Asm if MissingOperand(): return conditions = {'C': 1, 'NC': 2, 'Z': 3, 'NZ': 4} pointer = dec.Asm.Parse_Pointer condition = assem.GetWord().upper() if dec.Asm.Mnemonic == 'JR' and condition in conditions and\ assem.NowChar(True) == ',': index = conditions[condition] if assem.NowChar() == " ": # Allow a space to follow a comma assem.IncParsePointer() else: dec.Asm.Parse_Pointer = pointer index = 0 value = assem.EvalExpr() offset = value[0] - dec.Asm.BOL_Address - 2 if dec.Asm.Pass == 2 and (offset < -128 or offset > 127): errors.DoError('range', False) Code(dec.Asm.Instructions[dec.Asm.Mnemonic][1][index]) target.CodeByte(offset) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][index] NoMore()
def Jumps(): """ Jump instructions - Absolute - [#,X] """ global Asm if MissingOperand(): return if assem.NowChar() == '[': # Should be [#,X] now assem.IncParsePointer() opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][1] if opcode == 0: errors.DoError('badoper', False) return else: if assem.NowChar() == '#': # Ignore leading # assem.IncParsePointer() value = assem.EvalExpr()[0] target.CodeByte(opcode) target.CodeByte(value) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][1] if not assem.MoreParameters(): errors.DoError('missoper', False) if dec.Asm.Parse_Line[dec.Asm.Parse_Pointer:dec.Asm.Parse_Pointer + 3].upper() != 'X] ': errors.DoError('badoper', False) return else: # Must be absolute now dest = assem.EvalExpr()[0] target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1][0]) target.CodeWord(dest) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][1] if dec.Asm.Pass == 2 and (dest < dec.Ace_Minjmp or dest > dec.Ace_Maxjmp): errors.DoError('range', False) NoMore()
def Jumps(): global Asm if MissingOperand(): return conditions = { 'NZ': 0, 'Z': 1, 'NC': 2, 'C': 3, 'PO': 4, 'PE': 5, 'P': 6, 'M': 7 } pointer = dec.Asm.Parse_Pointer condition = assem.GetWord().upper() if condition in conditions and assem.NowChar(True) == ',': # Conditional jump or call if assem.NowChar() == " ": # Allow a space to follow a comma assem.IncParsePointer() value = assem.EvalExpr() Code(dec.Asm.Instructions[dec.Asm.Mnemonic][1][1] + (conditions[condition] << 3)) target.CodeWord(value[0]) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][1] if dec.Asm.Pass == 2 and ((value[0] >> 16) != 0): errors.DoErrors('range', False) elif condition == '(HL)': # (HL) Code(dec.Asm.Instructions[dec.Asm.Mnemonic][1][2]) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][2] elif condition == '(IX)': # (IX) Code(dec.Asm.Instructions[dec.Asm.Mnemonic][1][3]) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][3] elif condition == '(IY)': # (IY) Code(dec.Asm.Instructions[dec.Asm.Mnemonic][1][4]) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][3] else: # Non conditional dec.Asm.Parse_Pointer = pointer value = assem.EvalExpr() Code(dec.Asm.Instructions[dec.Asm.Mnemonic][1][0]) target.CodeWord(value[0]) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][0] NoMore()
def Sweet16(): """ Handle remaining Sweet16 instructions. They all expect a register number, some accept an indirect register number. Only the SET instruction also expects a 16 bit target address. Registers are numbered from 0 to 15. If you want to use R0 to R15 instead assign labels to the 16 register numbers. """ global Asm if MissingOperand(): return if assem.NowChar() == '@': assem.IncParsePointer() opcode = Sweet16_Mnemonics[dec.Asm.Mnemonic][2] else: opcode = Sweet16_Mnemonics[dec.Asm.Mnemonic][1] if opcode == 0: errors.DoError('badopco', False) return value = assem.EvalExpr() if dec.Asm.Pass == 2 and (value[0] >> 4) != 0: errors.DoError('range', False) opcode = opcode + (value[0] & 15) target.CodeByte(opcode) if dec.Asm.Mnemonic == 'SET': if assem.MoreParameters(): value = assem.EvalExpr() target.CodeWord(value[0]) else: errors.DoError('missoper', False) NoMore()
def GetOperand(): """ Get an operand. This can get complicated. Operand can be: Index = 0: # Index = 1: SHORT Index = 2: LONG Index = 3: (X) Index = 4: (SHORT,X) Index = 5: (LONG,X) Index = 6: (Y) Index = 7: (SHORT,Y) Index = 8: (LONG,Y) Index = 9: [SHORT] Index = 10: [LONG.W] Index = 10: {LONG} Index = 11: ([SHORT],X) Index = 12: ([LONG.W],X) Index = 12: ({LONG},X) Index = 13: ([SHORT],Y) Index = 14: ([LONG.W],Y) Index = 14: ({LONG},Y) Index = 15: A Index = 16: X Index = 17: Y Index = 18: S """ global Asm pntr = dec.Asm.Parse_Pointer operand = assem.GetWord().upper() if operand == 'A': return (15, 0) if operand == 'X': return (16, 0) if operand == 'Y': return (17, 0) if operand == 'S': return (18, 0) if operand == '(X)': return (3, 0) if operand == '(Y)': return (6, 0) dec.Asm.Parse_Pointer = pntr # ---------- if operand[0] in '#/=\\': # Immediate value mode = assem.NowChar(True) value = assem.EvalExpr() if mode == '#': return (0, value[0]) if mode == '/': return (0, value[0] >> 8) if mode == '=': return (0, value[0] >> 16) return (0, value[0] >> 24) # ---------- if operand[0:2] == '([': # Some form of Indexed Indirect mode assem.IncParsePointer() assem.IncParsePointer() pntr = dec.Asm.Parse_Pointer line = dec.Asm.Parse_Line operand = assem.GetWord('', '', ']').upper() endpnt = dec.Asm.Parse_Pointer dec.Asm.Parse_Pointer = pntr short = True if operand[-2:] == '.W': short = False dec.Asm.Parse_Line = line[:endpnt - 2] + ' ' value = assem.EvalExpr() dec.Asm.Parse_Line = line dec.Asm.Parse_Pointer = endpnt if assem.NowChar(True) != ']': errors.DoError('badoper', False) if not assem.MoreParameters(): errors.DoError('missoper', False) nowchar = assem.NowChar(True).upper() if nowchar == 'X': xymode = 11 elif nowchar == 'Y': xymode = 13 else: xymode = 11 errors.DoError('badoper', False) if assem.NowChar(True) != ')': errors.DoError('badoper', False) if dec.Asm.Pass == 2 and (value[0] >> 8 != 0): errors.DoError('range', False) if short: return (xymode + 0, value[0]) else: return (xymode + 1, value[0]) # ---------- if operand[0:2] == '({': # Indexed Indirect long mode assem.IncParsePointer() assem.IncParsePointer() value = assem.EvalExpr() if assem.NowChar(True) != '}': errors.DoError('badoper', False) if not assem.MoreParameters(): errors.DoError('missoper', False) nowchar = assem.NowChar(True).upper() if nowchar == 'X': xymode = 12 elif nowchar == 'Y': xymode = 14 else: xymode = 12 errors.DoError('badoper', False) if assem.NowChar(True) != ')': errors.DoError('badoper', False) if dec.Asm.Pass == 2 and (value[0] >> 8 != 0): errors.DoError('range', False) return (xymode, value[0]) # ---------- if operand[0] == '(': # Some form of indexed mode. # It can be short or long, followed by ,X) or ,Y) assem.IncParsePointer() prefix = '' if operand[0] in '<>': # It's forced long or short prefix = assem.NowChar(True) value = assem.EvalExpr() if prefix == '<': short = True if dec.Asm.Pass == 2 and (value[0] >> 8) != 0: errors.DoError('range', False) elif prefix == '>' or value[1]: short = False else: short = False if (value[0] >> 8) == 0: short = True if not assem.MoreParameters(): errors.DoError('missoper', False) nowchar = assem.NowChar(True).upper() if nowchar == 'X': xymode = 4 elif nowchar == 'Y': xymode = 7 else: xymode = 4 errors.DoError('badoper', False) if assem.NowChar(True) != ')': errors.DoError('badoper', False) if short: return (xymode + 0, value[0]) else: return (xymode + 1, value[0]) # ---------- if operand[0] == '[': # Some form of indirect mode, could be [short] or [long.w] assem.IncParsePointer() pntr = dec.Asm.Parse_Pointer line = dec.Asm.Parse_Line operand = assem.GetWord('', '', ']').upper() endpnt = dec.Asm.Parse_Pointer dec.Asm.Parse_Pointer = pntr short = True if operand[-2:] == '.W': short = False dec.Asm.Parse_Line = line[:endpnt - 2] + ' ' value = assem.EvalExpr() dec.Asm.Parse_Line = line dec.Asm.Parse_Pointer = endpnt if assem.NowChar(True) != ']': errors.DoError('badoper', False) if dec.Asm.Pass == 2 and (value[0] >> 8 != 0): errors.DoError('range', False) if short: return (9, value[0]) else: return (10, value[0]) # ---------- if operand[0] == '{': # Indirect LONG mode assem.IncParsePointer() value = assem.EvalExpr() if assem.NowChar(True) != '}': errors.DoError('badoper', False) if dec.Asm.Pass == 2 and (value[0] >> 8 != 0): errors.DoError('range', False) return (10, value[0]) # ---------- # Here only short or long mode option left. # Must decide whether to use short or long, depending on address size prefix = '' if operand[0] in '<>': # It's forced long or short prefix = assem.NowChar(True) value = assem.EvalExpr() if prefix == '<': short = True if dec.Asm.Pass == 2 and (value[0] >> 8) != 0: errors.DoError('range', False) elif prefix == '>' or value[1]: short = False else: short = False if (value[0] >> 8) == 0: short = True if short: return (1, value[0]) else: return (2, value[0])
def Multi(): """ Handle multiple operand type instructions - Immediate mode - Direct page mode - Extended mode - 0,X mode - Direct,X mode - Extended,X mode """ global Asm if MissingOperand(): return if assem.NowChar() in '#/=\\': # It is direct addressing mode prefix = assem.NowChar(True) opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][0] if opcode == 0: errors.DoError('badoper', False) return value = assem.EvalExpr()[0] if prefix == '/': value = value >> 8 elif prefix == '=': value = value >> 16 elif prefix == '\\': value = value >> 24 Code(opcode) target.CodeByte(value) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][0] NoMore() return if assem.NowChar() == ',': # zero offset indexed mode value = 0 length = 0 assem.MoreParameters() indexreg = assem.GetWord().upper() if indexreg == 'X': # Use 0 offset X mode index = 3 else: errors.DoError('badoper', False) return elif dec.Asm.Parse_Line[dec.Asm.Parse_Pointer:dec.Asm.Parse_Pointer+2]\ .upper() == 'X ': # Zero offset indexed X mode value = 0 length = 0 index = 3 assem.IncParsePointer() else: # Can be direct mode, extended mode or offset,indexed mode from here prefix = '' if assem.NowChar() in '<>': prefix = assem.NowChar(True) dest = assem.EvalExpr() value = dest[0] if assem.MoreParameters(): # Handle indexed mode indexreg = assem.GetWord().upper() if indexreg == 'X': index = 4 else: errors.DoError('badoper', False) return if prefix == '>': # Forced extended mode if dec.Asm.Instructions[dec.Asm.Mnemonic][1][index + 1] == 0: # Extended mode doesn't exist, use direct mode instead length = 1 else: index = index + 1 length = 2 elif prefix == '<': # Forced direct mode length = 1 else: # Let the assembler deside whether it's direct or extended if dest[1]: # Forward referenced label used, use extended if dec.Asm.Instructions[dec.Asm.Mnemonic][1][index + 1] == 0: # Extended mode doesn't exist, use direct mode instead length = 1 else: length = 2 index = index + 1 else: if value == 0 and index == 4: # 0 offset and X index, use special opcode if it exists if dec.Asm.Instructions[dec.Asm.Mnemonic][1][index-1]\ == 0: # Sorry, doesn't exist length = 1 else: length = 0 index = index - 1 elif value > 255: # We should use extended indexed mode if dec.Asm.Instructions[dec.Asm.Mnemonic][1][index+1]\ == 0: # But that doesn't exist errors.DoError('range', False) return index = index + 1 length = 2 else: # We can use Direct mode length = 1 else: # Direct or extended mode if prefix == '>': # Forced extended mode if dec.Asm.Instructions[dec.Asm.Mnemonic][1][2] == 0: # Extended mode doesn't exist, use direct mode instead index = 1 length = 1 else: # Extended mode exists, feel free to use it index = 2 length = 2 elif prefix == '<': # Forced direct mode index = 1 length = 1 else: # Let the assembler deside whether it's direct or extended if dest[1]: # Forward referenced label used, use extended if dec.Asm.Instructions[dec.Asm.Mnemonic][1][2] == 0: # Extended mode doesn't exist, use direct mode instead index = 1 length = 1 else: # Extended mode does exist, feel free to use it index = 2 length = 2 else: if value > 255: index = 2 length = 2 else: index = 1 length = 1 if dec.Asm.Pass == 2 and length == 1: # We are using direct mode, does the value fit? if value >= 255: errors.DoError('range', False) if dec.Asm.Pass == 2 and value < 0: # Negative numbers not allowed errors.DoError('range', False) opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][index] if opcode == 0: errors.DoError('badoper', False) return dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][index] Code(opcode) if length == 1: target.CodeByte(value) elif length == 2: target.CodeWord(value) NoMore()
def Bits(): """ Bit instructions - A - Direct - [X] """ global Asm if MissingOperand(): return if assem.NowChar() == '#': # This is optional assem.IncParsePointer() bit = assem.EvalExpr()[0] if not assem.MoreParameters(): errors.DoError('missoper', False) return param = dec.Asm.Parse_Line[dec.Asm.Parse_Pointer:dec.Asm.Parse_Pointer+2]\ .upper() if param == 'A ': # Second operand is A opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][0] if opcode == 0: errors.DoError('badoper', False) return else: assem.IncParsePointer() target.CodeByte(opcode + bit) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][0] elif assem.NowChar() == '[': # Secnd parameter should be [X] opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][2] if opcode == 0: errors.DoError('badoper', False) return else: assem.GetWord() target.CodeByte(opcode + bit) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][2] else: # Second parameter is Direct direct = assem.EvalExpr()[0] opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][1] target.CodeByte(opcode + bit) target.CodeByte(direct) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][1] if dec.Asm.Pass == 2 and (direct < 0 or direct > 255): errors.DoError('range', False) if dec.Asm.Pass == 2 and (bit < 0 or bit > 7): errors.DoError('range', False) NoMore()
def Multiple(): """ Multiple operand instructions - # - Direct - [X] - [#,X] - X,# - Direct,# - Direct,Direct """ global Asm if MissingOperand(): return param = dec.Asm.Parse_Line[dec.Asm.Parse_Pointer:dec.Asm.Parse_Pointer+2]\ .upper() if param == 'A,': # First operand is A assem.NowChar(True) assem.MoreParameters() if assem.NowChar() in '#/=\\': # It is direct mode opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][0] if opcode == 0: errors.DoError('badoper', False) else: prefix = assem.NowChar(True) value = assem.EvalExpr()[0] if prefix == '/': value = value >> 8 elif prefix == '=': value = value >> 16 elif prefix == '\\': value = value >> 24 target.CodeByte(opcode) target.CodeByte(value) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][0] elif assem.NowChar() == '[': # It's some kind of indexed mode assem.IncParsePointer() param = dec.Asm.Parse_Line[dec.Asm. Parse_Pointer:dec.Asm.Parse_Pointer + 2].upper() if param == 'X]': # Non offset indexed mode opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][2] if opcode == 0: errors.DoError('badoper', False) else: target.CodeByte(opcode) dec.Asm.Timing =\ dec.Asm.Instructions[dec.Asm.Mnemonic][2][2] dec.Asm.Parse_Pointer = dec.Asm.Parse_Pointer + 2 else: # Must be offset indexed mode opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][3] if opcode == 0: errors.DoError('badoper', False) else: if assem.NowChar() == '#': # Ignore leading # assem.IncParsePointer() value = assem.EvalExpr()[0] target.CodeByte(opcode) target.CodeByte(value) dec.Asm.Timing =\ dec.Asm.Instructions[dec.Asm.Mnemonic][2][3] if not assem.MoreParameters(): errors.DoError('missoper', False) if dec.Asm.Parse_Line[dec.Asm. Parse_Pointer:dec.Asm.Parse_Pointer + 3].upper() != 'X] ': errors.DoError('badoper', False) return else: # Second parameter must be direct mode opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][1] if opcode == 0: errors.DoError('badoper', False) else: value = assem.EvalExpr()[0] target.CodeByte(opcode) target.CodeByte(value) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][1] if dec.Asm.Pass == 2 and (value < 0 or value > 255): errors.DoError('range', False) elif param == 'X,': # First operand is X assem.NowChar(True) assem.MoreParameters() opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][4] if opcode == 0: errors.DoError('badoper', False) else: prefix = assem.NowChar(True) value = assem.EvalExpr()[0] if prefix == '/': value = value >> 8 elif prefix == '=': value = value >> 16 elif prefix == '\\': value = value >> 24 target.CodeByte(opcode) target.CodeWord(value) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][4] else: # Must be direct mode parm1 = assem.EvalExpr()[0] if not assem.MoreParameters(): errors.DoError('missoper', False) if assem.NowChar() in '#/=\\': # Second parameter is immediate opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][5] if opcode == 0: errors.DoError('badoper', False) else: prefix = assem.NowChar(True) parm2 = assem.EvalExpr()[0] if prefix == '/': parm2 = parm2 >> 8 elif prefix == '=': parm2 = parm2 >> 16 elif prefix == '\\': parm2 = parm2 >> 24 if dec.Asm.Pass == 2 and (parm1 < 0 or parm1 > 255): errors.DoError('range', False) target.CodeByte(opcode) target.CodeByte(parm1) target.CodeByte(parm2) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][5] else: # Second operand should be direct now opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][6] if opcode == 0: errors.DoError('badoper', False) else: parm2 = assem.EvalExpr()[0] if dec.Asm.Pass == 2 and (parm1 < 0 or parm1 > 255 or parm2 < 0 or parm2 > 255): errors.DoError('range', False) target.CodeByte(opcode) target.CodeByte(parm2) target.CodeByte(parm1) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][6] NoMore()
def H6301(index): """ Handle immediate boolean instructions, only known to the Hitachi 6301 """ global Asm if index != 4: # These instructions only exist in the 6301 errors.DoError('badopco', False) return if MissingOperand(): return prefix = assem.NowChar(True) if prefix not in '#/=\\': errors.DoError('badoper', False) return value = assem.EvalExpr() if prefix == '#': oper1 = value[0] elif prefix == '/': oper1 = value[0] >> 8 elif prefix == '=': oper1 = value[0] >> 16 else: oper1 = value[0] >> 24 if not assem.MoreParameters(): errors.DoError('missoper', False) return prefix = '' if assem.NowChar() == '<': # Only forced ZP prefix allowed today assem.IncParsePointer() prefix = '<' value = assem.EvalExpr() if dec.Asm.Pass == 2 and prefix == '': if value[0] >> 8 != 0: errors.DoError('range', False) opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][0] timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][0] if assem.MoreParameters(): if assem.NowChar(True).upper() != 'X': errors.DoError('badoper', False) opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][1] timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][1] target.CodeByte(opcode) target.CodeByte(oper1) target.CodeByte(value[0]) dec.Asm.Timing = timing NoMore()
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 Math(): """ Handle the math instructions. """ global Asm if MissingOperand(): # We need parameters return pntr = dec.Asm.Parse_Pointer par1 = assem.GetWord().upper() if par1 == 'C': # Handle bit math instruction if not assem.MoreParameters(): # We need 2 parameters errors.DoError('missoper', False) return opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][6] dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][6] if assem.NowChar() == '/': # It's inverse bit mode assem.IncParsePointer() opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][7] dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][7] par2 = GetBit() if opcode == 0: # Opcode doesn't exist errors.DoError('badoper', False) else: # Opcode does exist, save it to the target, with operand target.CodeByte(opcode) target.CodeByte(par2) NoMore() return dec.Asm.Parse_Pointer = pntr par1 = GetRegDir() if not assem.MoreParameters(): # We need 2 parameters errors.DoError('missoper', False) return par2 = GetRegDir() if par1[1] == 2: # First operand can't be register, translate it to direct address par1 = (dec.Asm.RB8051 * 8 + par1[0], 0) if par1[1] == 0: # First operand is a direct address if par2[1] == 1: # DIR,A opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][4] dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][4] if opcode == 0: # Opcode doesn't exist errors.DoError('badoper', False) else: # Opcode does exist, save it with operand target.CodeByte(opcode) target.CodeByte(par1[0]) elif par2[1] == 8: # DIR,# opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][5] dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][5] if opcode == 0: # Opcode doesn't exist errors.DoError('badoper', False) else: # Opcode does exist, save it with operands target.CodeByte(opcode) target.CodeByte(par1[0]) target.CodeByte(par2[0]) else: # Everything else is illegal errors.DoError('badoper', False) elif par1[1] == 1: # First operand is A if par2[1] == 0: # A,DIR opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][1] dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][1] target.CodeByte(opcode) target.CodeByte(par2[0]) elif par2[1] == 2: # A,Rn opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][0] dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][0] target.CodeByte(opcode + par2[0]) elif par2[1] == 3: # A,@Ri opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][2] dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][2] target.CodeByte(opcode + par2[0]) elif par2[1] == 8: # A,# opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][3] dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][3] if opcode == 0: # Opcode doesn't exist errors.DoError('badoper', False) else: # Opcode does exist, save it with operand target.CodeByte(opcode) target.CodeByte(par2[0]) else: # Illegal second parameter errors.DoError('badoper', False) else: # Illegal first parameter errors.DoError('badoper', False) NoMore()
def GetRegDir(): """ Return a tupple with a value and register mode. The value may not always have a true meaningm, in which case it's value must be 0. Mode = 0: Direct addressing mode (value[0] is direct address) Mode = 1: A mode (value[0] has no meaning) Mode = 2: R0..R7 mode (value[0] is register number 0..7) Mode = 3: @R0..@R1 mode (value[0] is register number 0..1) Mode = 4: DPTR mode (value[0] has no meaning) Mode = 5: @A+PC mode (value[0] has no meaning) Mode = 6: @A+DPTR mode (value[0] has no meaning) Mode = 7: @DPTR mode (value[0] has no meaning) Mode = 8: # immediate mode (value[0] is the immediate value) """ global Asm value = GetReg() register = value[0] mode = value[1] if mode != 0: # A valid register was found, don't bother looking any further return (register, mode) prefix = assem.NowChar() if prefix in '@<>': # Is it an indirect indicator or a forced direct or register mode assem.IncParsePointer() value = assem.EvalExpr() if prefix == '<': # Forced register mode if dec.Asm.Pass == 2 and (value[0] >> 5) != 0: # Value may not be bigger than 4 * 8 - 1 or negative errors.DoError('range', False) # Any other value is truncated to register size (forced mode) register = value[0] & 7 # Indicate register mode mode = 2 return (register, mode) if prefix == '>': # Forced direct mode if dec.Asm.Pass == 2 and (value[0] >> 8 != 0): # Value may not be more than 0xFF or negative errors.DoError('range', False) return (value[0], 0) # Indicate direct mode if prefix == '@': # Only @R0 or @R1 allowed now, regardless of forward referencing register = value[0] & 0x1F if dec.Asm.Pass == 2: if (value[0] >> 5) != 0: # Value is a lot bigger than any register could be errors.DoError('range', False) if (register >> 3) != dec.Asm.RB8051: # Address is not a member of the current register bank errors.DoError('range', False) if (register & 6) != 0: # Only register 0 and 1 allowed being used as index errors.DoError('range', False) register = value[0] & 1 mode = 3 # Indicate @ mode # Now can only be direct mode or normal register mode if dec.Asm.Pass == 2 and (value[0] >> 8 != 0): # Value is more than direct mode allows, or negative errors.DoError('range', False) if not value[1]: # No forward referenced label was used, so value is know in both passes if value[0] >> 5 != 0: # Value is too big to be a register register = value[0] # Indicate direct mode mode = 0 else: # Compare bank of direct address with current bank if dec.Asm.RB8051 == (value[0] >> 3): # Same bank! Make it a real register register = value[0] & 7 # Indicate register mode mode = 2 else: # Not the same bank, use direct mode now register = value[0] # Indicate direct mode mode = 0 else: # Forward referenced label was used, be on the safe side, # use direct mode register = value[0] # Indicate direct mode mode = 0 return (register, mode)
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)