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 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 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 RegPair(): global Asm if MissingOperand(): return registers = 'BDHS' if dec.Asm.Mnemonic in ('POP', 'PUSH'): registers = 'BDHP' reg = registers.find(assem.NowChar(True).upper()) if reg < 0: errors.DoError('badoper', False) return if reg == 3: wrong = False if dec.Asm.Mnemonic in ('POP', 'PUSH'): if assem.NowChar(True).upper() != 'S': wrong = True else: if assem.NowChar(True).upper() != 'W': wrong = True else: if assem.NowChar(True).upper() != 'P': wrong = True if wrong: errors.DoError('badoper', False) return target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1] + (reg << 4)) NoMore()
def Immediate(): global Asm if MissingOperand(): 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 WriteOpcode(dec.Asm.Instructions[dec.Asm.Mnemonic][1]) WriteOperand(val) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] 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 ImmediateNibl(): """ Immediate Nibble instructions (test included in mnemonic) data """ global Asm if MissingOperand(): 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 target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1] + (val & 15)) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] NoMore()
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 Jumps(): global Asm if MissingOperand(): return if assem.NowChar() == '@': # It is an indirect jump reg1 = GetReg() if reg1[0] == '@rr' or reg1[0] == '@R': target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1][1]) target.CodeByte(reg1[1]) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][1] if reg1[1] & 1 != 0: errors.DoError('range', False) else: errors.DoError('badoper', False) else: # It's not an indirect jump if dec.Asm.Mnemonic == 'CALL': # It's a CALL instruction opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][0] dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][0] else: # It's JP instruction conditions = {'F': 0x00, 'C': 0x70, 'NC': 0xF0, 'Z': 0x60, 'NZ': 0xE0, 'PL': 0xD0, 'MI': 0x50, 'OV': 0x40, 'NOV': 0xC0, 'EQ': 0x60, 'NE': 0xE0, 'GE': 0x90, 'LT': 0x10, 'GT': 0xA0, 'LE': 0x20, 'UGE': 0xF0, 'ULT': 0x70, 'UGT': 0xB0, 'ULE': 0x30} pointer = dec.Asm.Parse_Pointer cond = assem.GetWord().upper() if cond in conditions and assem.NowChar() == ',': # A legal condition code was given opcode = conditions[cond] + 13 dec.Asm.Timing = '10+' if not assem.MoreParameters(): errors.DoError('missoper', False) return else: # No condition was given dec.Asm.Parse_Pointer = pointer dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][0] opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][0] dest = assem.EvalExpr() target.CodeByte(opcode) target.CodeWord(dest[0]) if dec.Asm.Pass == 2 and (dest[0] >> 16) != 0: errors.DoError('range', False) NoMore()
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 GetIndex(): """ Get an index register. Legal index registers are X, Y and Z. These register may be pre-decremented or post-incremented. Function returns a tupple: incdec: 0=unchanged, 1=post-increment, 2=pre-decement index: X, Y, or Z offset: 6-bit offset in range from 0 to 63 """ global Asm index = assem.NowChar(True).upper() if index == ' ': # Mmm, missing operand errors.DoError('missoper', False) return (0, 'Z', 0) # Return dummy values incdec = 0 if index == '-': # Pre-decrement incdec = 2 index = assem.NowChar(True).upper() if index not in ('X', 'Y', 'Z'): # It's none of the legal index registers errors.DoError('badoper', False) return (0, 'Z', 0) # Return dummy values if incdec == 0: # It's not pre-decrement, so it may be post-incrment if assem.NowChar() == '+': incdec = 1 assem.NowChar(True) offset = 0 if dec.Asm.Mnemonic in ('LDD', 'STD') and incdec == 1: # An offset q must follow if index == 'X': # LDD X+q doesn't exist errors.DoError('badoper', False) offset = assem.EvalExpr()[0] if dec.Asm.Pass == 2 and (offset < 0 or offset > 63): # Check range only in pass 2 errors.DoError('range', False) offset = 0 # Split all the bits to fit the opcode gaps. offset = (offset & 7) + ((offset & 0x18) << 7) + ((offset & 0x20) << 8) return (incdec, index, offset)
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 Pairs(): """ Handle paired operand instructions. """ global Asm if MissingOperand(): return reg1 = assem.GetWord().upper() if not assem.MoreParameters(): errors.DoError('missoper', False) return if assem.NowChar() == ' ': errors.DoError('missoper', False) return if assem.NowChar() in '#/=\\': reg2 = '#' else: reg2 = assem.GetWord().upper() operand = reg1 + ',' + reg2 operands = dec.Asm.Instructions[dec.Asm.Mnemonic][1] opcodes = dec.Asm.Instructions[dec.Asm.Mnemonic][2] times = dec.Asm.Instructions[dec.Asm.Mnemonic][3] if operand in operands: index = 0 for t in operands: if t == operand: break index = index + 1 target.CodeByte(opcodes[index]) dec.Asm.Timing = times[index] if reg2 == '#': prefix = assem.NowChar(True) value = assem.EvalExpr() if prefix == '#': target.CodeByte(value[0]) elif prefix == '/': target.CodeByte(value[0] >> 8) elif prefix == '=': target.CodeByte(value[0] >> 16) else: target.CodeByte(value[0] >> 24) else: errors.DoError('badoper', 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 Immediate(): global Asm if MissingOperand(): return opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] dest = GetReg() if dest[0] > 5: errors.DoError('badoper', False) return if len(opcode[dest[0]]) == 0: errors.DoError('badoper', False) return if not assem.MoreParameters(): errors.DoError('missoper', False) return if assem.NowChar() in '#/=\\': prefix = assem.NowChar(True) else: prefix = '#' value = assem.EvalExpr() for i in range(0, len(opcode[dest[0]]), 2): byte = opcode[dest[0]][i:i + 2] if byte == 'XX': target.CodeByte(dest[1]) else: target.CodeByte(int(byte, 16)) if prefix == '#': data = value[0] elif prefix == '/': data = value[0] >> 8 elif prefix == '=': data = value[0] >> 16 else: data = value[0] >> 24 target.CodeByte(data) dec.Asm.Timing = timing[dest[0]] NoMore()
def MviInst(): global Asm if MissingOperand(): return registers = 'ABCDEHLM' reg1 = registers.find(assem.NowChar(True).upper()) if reg1 < 0: errors.DoError('badoper', False) return if reg1 == 7: # timing is different if first operand is M dec.Asm.Timing = '9' if not assem.MoreParameters(): errors.DoError('missoper', False) return if assem.NowChar() == ' ': errors.DoError('missoper', False) 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 NoMore() opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] + (reg1 << 3) target.CodeByte(opcode) target.CodeByte(byte)
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 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 Multiply(): global Asm if MissingOperand(): return operand1 = assem.GetWord().upper() if operand1 not in 'XY': errors.DoError('badoper', False) return if not assem.MoreParameters(): errors.DoError('missoper', False) return if assem.NowChar(True).upper() != 'A': errors.DoError('badoper', False) return if operand1 == 'X': target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1][0]) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][0] else: target.CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][1][1]) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][1] NoMore()
def Pseudo(): global Asm ptr = GetPtr() if ptr > 0: # Legal pointer used if assem.NowChar(True) == ",": # A parameter is following dest = assem.EvalExpr()[0] - 1 # LDI /DEST WriteOpcode(0xC4) WriteOperand((dest >> 8) & 255) # XPAH PTR WriteOpcode(0x34 + ptr) # LDI #DEST WriteOpcode(0xC4) WriteOperand(dest & 255) # XPAL PTR WriteOpcode(0x30 + ptr) # XPPC PTR WriteOpcode(0x3C + ptr) else: # PC or P0 not allowed errors.DoError('badoper', False) return NoMore()
def Math(): global Asm timing = dec.Asm.Timing.split(':') if MissingOperand(): return registers = 'BCDEHLMA' reg = registers.find(assem.NowChar(True).upper()) if reg == 6: dec.Asm.Timing = timing[1] else: dec.Asm.Timing = timing[0] if dec.Asm.Mnemonic in ('DCR', 'INR'): reg = reg << 3 if reg < 0: errors.DoError('badoper', False) return NoMore() target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1] + reg)
def XchdInst(): """ Handle the XCHD instruction. """ global Asm if MissingOperand(): # No parameters return dec.Asm.Timing = '1' if assem.NowChar(True).upper() != 'A': # First paramter must be an A errors.DoError('badoper', False) return if not assem.MoreParameters(): # Only one parameter given errors.DoError('missoper', False) return par2 = GetReg() if par2[1] != 3: # Second parameter may only be @Ri errors.DoError('badoper', False) return target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1] + par2[0]) 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 MovInst(): global Asm if MissingOperand(): return registers = 'ABCDEHLM' reg1 = registers.find(assem.NowChar(True).upper()) if reg1 < 0: errors.DoError('badoper', False) return if reg1 == 7: # timing is different if first operand is M dec.Asm.Timing = '7' if not assem.MoreParameters(): errors.DoError('missoper', False) return if assem.NowChar() == ' ': errors.DoError('missoper', False) return reg2 = registers.find(assem.NowChar(True).upper()) if reg2 < 0: errors.DoError('badoper', False) return if reg1 == 7 and reg2 == 7: # mov m,m is not allowed, that his the hlt instruction errors.DoError('badoper', False) return if reg2 == 7: # timing is different if second operand is M dec.Asm.Timing = '8' NoMore() opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] + (reg1 << 3) + reg2 target.CodeByte(opcode)
def DirID(): """ Set the ID words. These ID words are usually stored directly behind the program memory, or directly behind the EEPROM memory if that is present. The SB-Assembler only checks that the Configuration word is stored beyond the program memory. """ global Asm, Cross if dec.Asm.Memory != 0: # The .ID directive can only be used in program memory errors.DoError(dec.Cross.Name + 'codemem', False) return if dec.Asm.PH_Address <= dec.Asm.Max_Address: # We're still in program memory. We can't have that errors.DoError(dec.Cross.Name + 'progmem', False) return if assem.NowChar() == '#': # Ignore the # symbol assem.NowChar(True) id = assem.EvalExpr()[0] # Temporarily raise program limit limit = dec.Asm.Max_Address dec.Asm.Max_Address = 0x0FFF # Save the ID, one nibble at a time target.SaveByte(id & 0x000F) target.SaveByte(0) target.SaveByte((id >> 4) & 0x000F) target.SaveByte(0) target.SaveByte((id >> 8) & 0x000F) target.SaveByte(0) target.SaveByte((id >> 12) & 0x000F) target.SaveByte(0) # Restore original limit dec.Asm.Max_Address = limit NoMore()
def MovInst(): global Asm timing = dec.Asm.Timing.split(':') if MissingOperand(): return registers = 'BCDEHLMA' reg1 = registers.find(assem.NowChar(True).upper()) if reg1 < 0: errors.DoError('badoper', False) return if not assem.MoreParameters(): errors.DoError('missoper', False) return if assem.NowChar() == ' ': errors.DoError('missoper', False) return reg2 = registers.find(assem.NowChar(True).upper()) if reg2 < 0: errors.DoError('badoper', False) return if reg1 == 6 and reg2 == 6: # mov m,m is not allowed, that's the hlt instruction errors.DoError('badoper', False) return NoMore() opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] + (reg1 << 3) + reg2 if reg1 == 6 or reg2 == 6: dec.Asm.Timing = timing[1] else: dec.Asm.Timing = timing[0] target.CodeByte(opcode)
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 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 DirCW(): """ Set the Configuration word. This Configuration word is usually stored at the last location in memory, which is word address $0FFF (or byte addresses ($1FFE and $1FFF). Programming devices expect that word to be there. The SB-Assembler only checks that the Configuration word is stored beyond the program memory. """ global Asm, Cross if dec.Asm.Memory != 0: # The .CW directive can only be used in program memory errors.DoError(dec.Cross.Name + 'codemem', False) return if dec.Asm.PH_Address <= dec.Asm.Max_Address: # We're still in program memory. We can't have that errors.DoError(dec.Cross.Name + 'progmem', False) return if assem.NowChar() == '#': # Ignore the # symbol assem.NowChar(True) config = assem.EvalExpr()[0] if dec.Asm.Pass == 2 and (config < 0 or config > 0x0FFF): # Only 12 bits allowed errors.DoError('range', False) # Temporarily raise program limit limit = dec.Asm.Max_Address dec.Asm.Max_Address = 0x0FFF # Bypass the RETLW pointer target.SaveByte(config & 0xFF) target.SaveByte((config >> 8) & 0x0F) # Restore original limit dec.Asm.Max_Address = limit NoMore()
def LdaxStax(): global Asm if MissingOperand(): return reg = assem.NowChar(True).upper() if reg == 'B': opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] elif reg == 'D': opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] + (1 << 4) else: errors.DoError('badoper', False) return NoMore() target.CodeByte(opcode)