def FileOnly(): """ These instructions only require a file register as operand. No range checking is done. When access bank selector is missing the assembler will determine the access bank or BSR mode for you. The access bank selector may only be either 0 or 1. """ global Asm opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] value = assem.EvalExpr()[0] if assem.MoreParameters(): # Good, the access bank selector is given. That's easy accessbank = assem.EvalExpr()[0] if dec.Asm.Pass == 2 and (accessbank < 0 or accessbank > 1): # Oops, this is not good errors.DoError('range', False) else: # Now we have to decide accessbank = 0 if value >= dec.Asm.AccessBank18 and value <\ (dec.Asm.AccessBank18 + 0xF00): # Outside of access bank range. Use BSR mode instead accessbank = 1 accessbank = (accessbank & 1) << 8 CodeWord(opcode + (value & 0x0FF) + accessbank) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] NoMore()
def FileFile(): """ MOVFF instruction. Moves a file register to a file register. Both can be addressed directly with 12-bits. Source or destination can be the W register, if the WREG SFR is used. The PCL, TOSU, TOSH and TOSL can't be used as destination. A range error is reported if you do use these. No other range checking is done though. """ global Asm source = assem.EvalExpr()[0] & 0xFFF if not assem.MoreParameters(): # Missing 2nd operand errors.DoError('missoper', False) dest = 0 else: dest = assem.EvalExpr()[0] & 0xFFF CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][1] + source) CodeWord(0xF000 + dest) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] if dec.Asm.Pass == 2 and dest in [0xFF9, 0xFFD, 0xFFE, 0xFFF]: # PCL, TOSL, TOSH and TOSU can't be used as destination errors.DoError('range', False) NoMore()
def Bits(): """ Handle Bit instructions Both bit set/clr as well as branch bit set/clr instructions are handled by this routine. """ global Asm if MissingOperand(): return bitno = assem.EvalExpr()[0] opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] + ((bitno & 7)) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] if not assem.MoreParameters(): # We expected more parameters errors.DoError('missoper', False) return param = dec.Asm.Parse_Line[dec.Asm.Parse_Pointer:dec.Asm.Parse_Pointer+2]\ .upper() if param in ('A,', 'X,', 'Y,', 'A ', 'X ', 'Y '): assem.NowChar(True) if param[0] == 'A': mem = 255 elif param[0] == 'X': mem = 128 else: mem = 129 else: mem = assem.EvalExpr()[0] if dec.Asm.Mnemonic[1] == 'R': # It's a branch instruction if not assem.MoreParameters(): # We expected more parameters errors.DoError('missoper', False) return dest = assem.EvalExpr()[0] offset = dest - dec.Asm.BOL_Address - 3 target.CodeByte(opcode) target.CodeByte(mem) target.CodeByte(offset) if dec.Asm.Pass == 2 and (offset < -128 or offset > +127): errors.DoError('range', False) else: # It wasn't a branch instruction target.CodeByte(opcode) target.CodeByte(mem) if dec.Asm.Pass == 2: if (bitno < 0 or bitno > 7) or (mem < 0 or mem > 255): errors.DoError('range', False) NoMore()
def Lfsr(): """ File one of the 4 File select register pointers with a 12 bit file register address. File register number is not range checked. """ global Asm opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] pointer = assem.EvalExpr()[0] if not assem.MoreParameters(): # Missing operand errors.DoError('missoper', False) register = 0 else: # Get the operand register = assem.EvalExpr()[0] if dec.Asm.Pass == 2 and (pointer < 0 or pointer > 3): # Range error errors.DoError('range', False) pointer = pointer & 3 CodeWord(opcode + (pointer << 4) + ((register >> 8) & 0xF)) CodeWord(0xF000 + (register & 0xFF)) NoMore()
def GetDest(filereg): """ Get the destination for register file instructions. It can either accept W or F or nothing. Or it can accept any expression as long as it returns 0 or 1. Only when a destination is given the optional access bank selector can also be given. If not, the assembler will pick the proper access bank mode for you. """ global Asm dest = 0x200 if assem.MoreParameters(): # Direction is specified temp = dec.Asm.Parse_Pointer direction = assem.GetWord().upper() if direction == "W": # Direction towards W register dest = 0 elif direction == "F": # Direction towards File register dest = 0x200 else: # Neither W nor F. Must be an expression now dec.Asm.Parse_Pointer = temp dest = assem.EvalExpr()[0] if dec.Asm.Pass == 2 and (dest < 0 or dest > 1): # That's a range error! errors.DoError('range', False) dest = (dest & 1) * 0x200 if assem.MoreParameters(): # Good, the access bank selector is given. That's easy accessbank = assem.EvalExpr()[0] if dec.Asm.Pass == 2 and (accessbank < 0 or accessbank > 1): # Oops, this is not good errors.DoError('range', False) else: # Now we have to decide accessbank = 0 if filereg >= dec.Asm.AccessBank18 and filereg <\ (dec.Asm.AccessBank18 + 0xF00): # Outside of access bank range. Use BSR mode instead accessbank = 1 else: # Direction was not specified, so access bank select is also automatic accessbank = 0 if filereg >= dec.Asm.AccessBank18 and filereg <\ (dec.Asm.AccessBank18 + 0xF00): # Outside of access bank range. Use BSR mode instead accessbank = 1 dest += (accessbank & 1) << 8 return dest
def Conditional(): """ Conditional instructions reg,dest con,dest """ global Asm if MissingOperand(): return val = assem.EvalExpr()[0] if not assem.MoreParameters(): errors.DoError('missoper', False) return dest = assem.EvalExpr()[0] if dec.Asm.Pass == 2: if (val < 0 or val > 15): # Range error errors.DoError('range', False) # !!!! isz on last 2 locations of page causes jump to next page. Strange but # true according to page 3-42 target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1] + (val & 15)) target.CodeByte(dest) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] NoMore()
def FileBit(): """ File register and bit operations. Only the bit address is being range checked. """ global Asm opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] filereg = assem.EvalExpr()[0] if assem.MoreParameters(): # Oh, good, something else is following bit = assem.EvalExpr()[0] if dec.Asm.Pass == 2 and (bit < 0 or bit > 7): # Illegal bit number errors.DoError('range', False) bit = bit & 0x07 else: # Oops, missing operand errors.DoError('missoper', False) bit = 0 CodeWord(opcode + (filereg & 0x7F) + (bit << 7)) NoMore()
def PointerData(): """ Pointer pair with data instructions pointer,data """ global Asm MissingOperand() parsepointer = dec.Asm.Parse_Pointer pointer = -1 pntr = assem.GetWord().upper() if len(pntr) == 2 and pntr[1] == "P": # It might as well be a poiner pair if pntr[0] >= '0' and pntr[0] <= '7': # It sure is pointer = int(pntr[0]) * 2 if pointer == -1: # It wasn't a pointer, so it must be an expression now dec.Asm.Parse_Pointer = parsepointer pointer = assem.EvalExpr()[0] if not assem.MoreParameters(): errors.DoError('missoper', False) return prefix = '#' if assem.NowChar() in '#/=\\': prefix = assem.NowChar(True) value = assem.EvalExpr() if prefix == '#': val = value[0] & 255 elif prefix == '/': val = (value[0] >> 8) & 255 elif prefix == '=': val = (value[0] >> 16) & 255 else: val = (value[0] >> 24) & 255 if dec.Asm.Pass == 2: # Range check only in pass 2 if pointer < 0 or pointer > 15 or pointer % 2 == 1: # Range error errors.DoError('range', False) target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1] + pointer) target.CodeByte(val) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] NoMore()
def RelJmp(): """ Relative addressing mode. Most instructions have an offset range from -64 to +63, counted from the begin of line address + 1. Only the RCALL and RJMP instructions have a range between 2048 and +2047. BRBC and BRBS als require a bit number to specified as first operand. Dictionary: function, Xmega+Mega+AVR+TINY, newflags, opcode, cycles """ global Asm if dec.Asm.Mnemonic in ('BRBC', 'BRBS'): # Get bit number first value = assem.EvalExpr() bit = value[0] if dec.Asm.Pass == 2 and (bit < 0 or bit > 7): # Test range of bit number (0 to 7) errors.DoError('range', False) bit = bit & 7 if not assem.MoreParameters(): # Only bit number was given errors.DoError('missoper', False) else: # All other instructions don't require a bit number bit = 0 value = assem.EvalExpr() if dec.Asm.Pass == 2 or (not value[1]): # Check range only when in pass 2 and no forward referenced label used if value[0] < 0 or value[0] > dec.Asm.Max_Address: # Are we beyond physical memory? errors.DoError('range', False) offset = value[0] - dec.Asm.BOL_Address - 1 if dec.Asm.Mnemonic in ('RCALL', 'RJMP'): # RCALL and RCJMP have an extended range if dec.Asm.Pass == 2 and (offset < -2048 or offset > 2047): # Out of range errors.DoError('range', False) offset = offset & 0xFFF else: # All other relative jump instructions have a limited range if dec.Asm.Pass == 2 and (offset < -64 or offset > 63): # Out of range errors.DoError('range', False) offset = (offset & 0x7F) << 3 target.CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][3] + offset + bit) 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 Move(): global Asm if MissingOperand(): return param = dec.Asm.Parse_Line[dec.Asm.Parse_Pointer:dec.Asm.Parse_Pointer+2]\ .upper() if param in ('A,', 'X,', 'Y,'): assem.NowChar(True) if param == 'A,': dest = 255 elif param == 'X,': dest = 128 else: dest = 129 else: dest = assem.EvalExpr()[0] if not assem.MoreParameters(): # We expected more parameters errors.DoError('missoper', False) return prefix = assem.NowChar(True) if prefix not in '#/=\\': 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(dec.Asm.Instructions[dec.Asm.Mnemonic][1]) target.CodeByte(dest) target.CodeByte(value) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] if dest < 0 or dest > 255: errors.DoError('range', False) NoMore()
def GetBit(): """ Legal bit addresses are: Direct addresses from 020H.0 to 02FH.7 SFR addresses which can be devided by 8, followed by .0 to .7 If the address is not followed by .0 to .7 it is handled as a normal address, in which case its value should be below 256. """ global Asm pntr = dec.Asm.Parse_Pointer par1 = assem.GetWord().upper() regbit = 0 if len(par1) > 2 and par1[-2] == '.' and par1[-1] in '01234567': # operand.bit notation. Hide bit number temporarily bitno = int(par1[-1]) parseline = dec.Asm.Parse_Line dec.Asm.Parse_Line = parseline[:dec.Asm.Parse_Pointer - 2] + ' ' dec.Asm.Parse_Pointer = pntr value = assem.EvalExpr() dec.Asm.Parse_Line = parseline dec.Asm.Parse_Pointer = dec.Asm.Parse_Pointer + 2 if dec.Asm.Pass == 2: # Only check rage during pass 2 if value[0] in range(0x20, 0x30): # In RAM area regbit = ((value[0] & 15) << 3) + bitno elif value[0] in range(0x80, 0xFF, 8): # In SFR area regbit = value[0] + bitno else: # Not in legal area errors.DoError('range', False) else: # No operand.bit notation, evaluate normally dec.Asm.Parse_Pointer = pntr value = assem.EvalExpr() regbit = value[0] if dec.Asm.Pass == 2 and (value[0] >> 8) != 0: # Value not between 0 to 255 errors.DoError('range', False) return regbit
def Immediate2(): """ RLDI instruction with immediate operand. First operand is the register to be loaded. Second operand is the immediate 16 bit data. May be prefixed by one of the immediate prefixes. """ global Asm if MissingOperand(): return # Get register register = assem.EvalExpr()[0] if dec.Asm.Pass == 2: # Don't check range in pass 1 as label may be forward referenced if register < 0 or register > 15: register = 0 if not assem.MoreParameters(): errors.DoError('missoper', False) return prefix = '#' if assem.NowChar() in '#/=\\': prefix = assem.NowChar(True) value = assem.EvalExpr()[0] if prefix == '#': val = value & 0xFFFF elif prefix == '/': val = (value >> 8) & 0xFFFF elif prefix == '=': val = (value >> 16) & 0xFFFF else: val = (value >> 24) & 0xFFFF target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1] >> 8) target.CodeByte((dec.Asm.Instructions[dec.Asm.Mnemonic][1] & 0xFF) + register) target.CodeByte(val >> 8) target.CodeByte(val & 0xFF) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] NoMore()
def Relative(): global Asm if MissingOperand(): return opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] value = assem.EvalExpr()[0] offset = value - dec.Asm.BOL_Address - 1 if dec.Asm.Pass == 2 and (offset < -32 or offset > 31): errors.DoError('range', False) if dec.Asm.Pass == 2: if offset < 0: offset = offset * -1 else: opcode = opcode + 32 else: offset = 0 offset = (offset & 63) target.CodeByte(opcode + offset) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] NoMore()
def DirMS(): """ Set program memory size. It's only used to warn you when the program memory is full. Setting the memory size to 0 disables memory size checkking. This is useful for saving ID, Config and EERPOM data. """ global Asm size = assem.EvalExpr() if size[1]: # A forward referenced label was used errors.DoError('forwref', False) else: # Not a forward refereced label if size[0] == 0: # Set memory size to infinity and beyond dec.Asm.Max_Address = 0x100000000 else: # Not infinite size if size[0] > 0x200000 or size[0] < 1024: # That's a range error errors.DoError('range', False) dec.Asm.Max_Address = size[0] - 1 NoMore()
def BranchBit(): """ Handle the bit test branch instructions. """ global Asm if MissingOperand(): # We need operands return dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] par1 = GetBit() if not assem.MoreParameters(): # Oops only one operand given errors.DoError('missoper', False) return value = assem.EvalExpr() offset = value[0] - dec.Asm.BOL_Address - 3 if dec.Asm.Pass == 2 and (offset < -128 or offset > 127): # Out of range errors.DoError('range', False) target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1]) target.CodeByte(par1) target.CodeByte(offset) NoMore()
def Returns(): """ The return instructions will now take an optional parameter, which controls whether some registers are copied from their shadow registers (1), or not (0). The default is 0. """ global Asm opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] if dec.Asm.Parse_Pointer == 0 or dec.Asm.Optional is False: # No parameter is following CodeWord(opcode) else: # Optional parameter given flag = assem.EvalExpr()[0] CodeWord(opcode + (flag & 1)) if dec.Asm.Pass == 2 and (flag < 0 or flag > 1): # Range error errors.DoError('range', False) NoMore()
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 RegArg(): """ Expecting a register as parameter. A valid range from 0 to 15 is only checked in pass 2. """ global Asm if MissingOperand(): return opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] value = assem.EvalExpr()[0] if dec.Asm.Pass == 2: # Don't check range in pass 1 as label may be forward referenced if value < 0 or value > 15: value = 0 errors.DoError('range', False) if value == 0 and opcode == 0: # LDN 0 is not allowed errors.DoError('range', False) if opcode == 0x60 or opcode == 0x68: # OUT and INP instruction have a restricted range if value < 1 or value > 7: value = 0 errors.DoError('range', False) target.CodeByte(opcode + value) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] NoMore()
def Restart(): global Asm if MissingOperand(): return value = assem.EvalExpr() if dec.Flags.ErrorInLine: # Save dummy bute to keep passes in sync target.CodeByte(0) else: # No errors were found vector = value[0] if value[1] and dec.Asm.Pass == 1: # Don't bother about range in case of forward referenced in pass 1 vector = 0 if vector > 8: if vector not in (16, 24, 32, 40, 48, 56): errors.DoError('range', False) vector = 0 if vector > 7: vector = vector >> 3 target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1] + (vector << 3)) NoMore()
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] 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 Branch(index): """ Handle branch instructions. Displacement is destinaiton - current address - 2 """ global Asm dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][index] if dec.Asm.Timing == 0: errros.DoError('badopco', False) return if MissingOperand(): return 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) target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1]) target.CodeByte(offset) NoMore()
def GetReg(): global Asm pointer = dec.Asm.Parse_Pointer register = assem.GetWord().upper() if register == 'A': return (1, 0xFF) elif register == "X": return (2, 0x80) elif register == "Y": return (3, 0x81) elif register == "V": return (4, 0x82) elif register == "W": return (5, 0x83) elif register == "(X)": return (6, 0) elif register == "(Y)": return (7, 0) else: dec.Asm.Parse_Pointer = pointer value = assem.EvalExpr()[0] if dec.Asm.Pass == 2 and (value > 255 or value < 0): errors.DoError('range', False) value = value & 255 return (0, value)
def BitInst(): global Asm if MissingOperand(): return opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] bitno = assem.EvalExpr()[0] if dec.Asm.Pass == 2 and (bitno > 7 or bitno < 0): assem.DoError('range', False) bitno = bitno & 7 if not assem.MoreParameters(): errors.DoError('missoper', False) return datareg = GetReg() if datareg[0] > 5: assem.DoError('badoper', False) datareg = datareg[1] target.CodeByte(opcode + BitSwap(bitno)) target.CodeByte(datareg) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] NoMore()
def Immediate(): global Asm if MissingOperand(): return prefix = assem.NowChar() if prefix in '#/=\\': prefix = assem.NowChar(True) else: prefix = '#' value = assem.EvalExpr() if prefix == '#': byte = value[0] elif prefix == '/': byte = value[0] >> 8 elif prefix == '=': byte = value[0] >> 16 else: byte = value[0] >> 24 target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1]) target.CodeByte(byte) NoMore()
def Pseudo(): """ Pseudo instructions, or compound instructions. These instructions combine a bit test on the status register and an INCF """ global Asm opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][3] value = assem.EvalExpr()[0] if opcode == 0x0980: # NEGF needs to add the file address CodeWord(opcode + (value & 0x7F)) else: # Not NEGF CodeWord(opcode) opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][2] dest = GetDest() CodeWord(opcode + (value & 0x7F) + dest) NoMore()
def Immediate(): """ Immediate operand. May be prefixed by one of the immediate prefixes. """ global Asm if MissingOperand(): return prefix = '#' if assem.NowChar() in '#/=\\': prefix = assem.NowChar(True) value = assem.EvalExpr()[0] if prefix == '#': val = value & 255 elif prefix == '/': val = (value >> 8) & 255 elif prefix == '=': val = (value >> 16) & 255 else: val = (value >> 24) & 255 if dec.Asm.Instructions[dec.Asm.Mnemonic][1] > 0xFF: # It's a 2 byte instruction target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1] >> 8) target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1]) target.CodeByte(val) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] NoMore()
def Long(): """ Pseudo instructions to make jumping across page boundaries easier. These instructions require the maximum memory size to be set correctly using the dedicated .MS directive. With this information the assembler will only use the minimum number of required memory bank select bits. I deliberately don't load PCLATH directly, because that would destroy the contents of the W register. Instead I clear PCLATH first, then set only the bits necessary to select the required bank. """ global Asm opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] timing = '2' dest = assem.EvalExpr()[0] if dec.Asm.Max_Address >= 2048: # There are multible banks # We now have MOVLP to load PCLATH CodeWord(0x3180 + ((dest >> 8) & 0x78)) timing = '3' dec.Asm.Timing = timing CodeWord(opcode + (dest & 0x07FF)) NoMore()
def Branch(): """ Branching is simply done by copying the second byte of the instruction to PCL. Therefore the destination is always on the same page as the second byte of the branch instruction. """ global Asm if MissingOperand(): return value = assem.EvalExpr()[0] if dec.Asm.Instructions[dec.Asm.Mnemonic][1] > 0xFF: # It's a 2 byte instruction target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1] >> 8) offset = 2 else: offset = 1 if dec.Asm.Pass == 2: # Don't check range in pass 1 as label may be forward referenced page = (dec.Asm.BOL_Address + offset) >> 8 destpage = value >> 8 if page != destpage: # Destination not on the same page errors.DoError('range', False) target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1]) target.CodeByte(value) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] NoMore()
def GetDest(): """ Get the destination for register file instructions. It can either accept W or F or nothing. Or it can accept any expression as long as it returns 0 or 1 """ global Asm dest = 0x80 if assem.MoreParameters(): # Direction is specified temp = dec.Asm.Parse_Pointer direction = assem.GetWord().upper() if direction == "W": # Direction towards W register dest = 0 elif direction == "F": # Direction towards File register dest = 0x80 else: # Neither W nor F. Must be an expression now dec.Asm.Parse_Pointer = temp dest = assem.EvalExpr()[0] if dec.Asm.Pass == 2 and (dest < 0 or dest > 1): # That's a range error! errors.DoError('range', False) dest = (dest & 1) * 0x80 return dest