def BitInst(): """ Bit instructions. These require 2 operands. The first is the register number from 0 to 31. The second is the bit number from 0 to 7. Dictionary: function, Xmega+Mega+AVR+TINY, newflags, opcode, cycles """ global Asm reg = GetReg() << 4 if not assem.MoreParameters(): # Only the register number is given, the bit number is missing errors.DoError('missoper', False) # Write dummy word target.CodeWord(0) return bitno = assem.EvalExpr()[0] if dec.Asm.Pass == 2 and (bitno < 0 or bitno > 7): # Report range error if bit number not between 0 and 7 errors.DoError('range', False) bitno = 0 target.CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][3] + reg + bitno) NoMore()
def CallJmp(): """ CALL and JMP can reach the entire Flash memory. Therefore the constant k is 22 bits wide. The constant is spread over 2 words like this: 1001.010k.kkkk.111k 2.2111. 1 1.0987. 6 kkkk.kkkk.kkkk.kkkk 1111.1100.0000.0000 5432.1098.7654.3210 Dictionary: function, Xmega+Mega+AVR+TINY, newflags, opcode, cycles """ global Asm maxadd = dec.Asm.Max_Address 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] > maxadd: # Are we beyond physical memory? errors.DoError('range', False) destinationl = value[0] & dec.MAX16 destinationh = (value[0] >> 16) & 63 destinationh = ((destinationh & 62) << 3) + (destinationh & 1) target.CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][3] + destinationh) target.CodeWord(destinationl) NoMore()
def Spm(): """ This instruction has only one optional parameter. It is either Z (default) or Z+ Dictionary: function, Xmega+Mega+AVR+TINY, newflags, opcode, cycles """ global Asm if dec.Asm.Parse_Pointer == 0 or not dec.Asm.Optional: # No operand, use defalt Z index target.CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][3]) else: # An operand is given, must be Z or Z+ value = GetIndex() if value[1] != 'Z' or value[0] == 2 or value[2] != 0: # Illegal index register errors.DoError('badoper', False) index = 0 # Dummy mode else: # Legal index register index = value[0] target.CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][3] + (index << 4)) NoMore()
def Load(): global Asm if MissingOperand(): return reg1 = GetReg() if dec.Flags.ErrorInLine: # An error was found in parameter 1, no need to continue return if not assem.MoreParameters(): errors.DoError('missoper', False) return reg2 = GetReg() firstpar = 'LD.' + reg1[0] if firstpar in dec.Asm.Instructions: secpar = dec.Asm.Instructions[firstpar][0] opcode = dec.Asm.Instructions[firstpar][1] timing = dec.Asm.Instructions[firstpar][2] extra = dec.Asm.Instructions[firstpar][3] index = 0 for t in secpar: if t == reg2[0]: # Found 2nd parameter, now let's save it to the target file opc = opcode[index] Code(opc) dec.Asm.Timing = timing[index] if extra[index] == 1: # save one extra byte from operand 2 target.CodeByte(reg2[1]) elif extra[index] == 2: # save two extra bytes from operand 2 target.CodeWord(reg2[1]) elif extra[index] == 3: # save one extra byte from operand 1 target.CodeByte(reg1[1]) elif extra[index] == 4: # save one extra byte from operand 1 and one from operand 2 target.CodeByte(reg1[1]) target.CodeByte(reg2[1]) elif extra[index] == 5: # save two extra bytes from operand 1 target.CodeWord(reg1[1]) NoMore() return index = index + 1 # This type of parameter was not allowed as second parameter errors.DoError('badoper', False) else: # This type of parameter was not allowed as first parameter errors.DoError('badoper', False)
def LDIndexed(): """ LD indexed takes 2 operands. A register number and an index register, which may include a pre-decrement or a post-increment. The Y and Z index registers may also have an offset from the register's base value. The range of this offset is from 0 to 63. Reduced instructionset only has LD Rd,Z. All others are off limits. This is not correctly implemented in the legacy family and cannot be fixed! Dictionary: function, Xmega+Mega+AVR+TINY, newflags, 1 or 0, cycles """ global Asm reg = GetReg() << 4 if not assem.MoreParameters(): # Only the register was given. The index register is missing errors.DoError('missoper', False) target.CodeWord(0) # Write dummy word return value = GetIndex() if value[1] == 'X': # Get the opcode for LD Rn,X if dec.Asm.AVR_Family == 6: # Illegal index register for this minimal core errors.DoError('badoper', False) opcode = 0x900C elif value[1] == 'Y': # Get the opcode for LD(D) Rn,Y and add offset to it if dec.Asm.AVR_Family == 6: # Illegal index register for this minimal core errors.DoError('badoper', False) opcode = 0x8008 + value[2] if value[0] != 0 and len(dec.Asm.Mnemonic) == 2: # Indicated pre-decrement or post-increment opcode opcode = opcode + 0x1000 else: # Get the opcode for LD(D) Rn,Z and add offset to it opcode = 0x8000 + value[2] if value[0] != 0 and len(dec.Asm.Mnemonic) == 2: # Indicate pre-decrement or post-increment opcode if dec.Asm.AVR_Family == 6: # pre-decrement and post-increment not implemented errors.DoError('badoper', False) opcode = opcode + 0x1000 if len(dec.Asm.Mnemonic) == 2: # It's LD, not LDD, add the pre-decrement or post-increment flag to it opcode = opcode + value[0] target.CodeWord(opcode + reg) NoMore()
def STIndexed(): """ ST indexed takes 2 operands. An index register, which may include a pre-decrement or a post-increment, and a register. The Y and Z index registers may also have an offset from the register's base value. The range of this offset is from 0 to 63. Reduced instructionset only has ST Z,Rd. All others are off limits. This is not correctly implemented in the legacy family and cannot be fixed! Dictionary: function, Xmega+Mega+AVR+TINY, newflags, 1 or 0, cycles """ global Asm value = GetIndex() if value[1] == 'X': # Get opcode for ST X,Rn if dec.Asm.AVR_Family == 6: # Illegal index register for this minimal core errors.DoError('badoper', False) opcode = 0x920C elif value[1] == 'Y': # Get opcode for ST(D) Y,Rn and add offset to it if dec.Asm.AVR_Family == 6: # Illegal index register for this minimal core errors.DoError('badoper', False) opcode = 0x8208 + value[2] if value[0] != 0 and len(dec.Asm.Mnemonic) == 2: # Indicated pre-decrement or post-increment opcode opcode = opcode + 0x1000 else: # Get opcode for ST(D) Z,Rn and add offset to it opcode = 0x8200 + value[2] if value[0] != 0 and len(dec.Asm.Mnemonic) == 2: # Indicated pre-decrement or post-increment opcode if dec.Asm.AVR_Family == 6: # pre-decrement and post-increment not implemented errors.DoError('badoper', False) opcode = opcode + 0x1000 if len(dec.Asm.Mnemonic) == 2: # It's ST, not STD, add the pre-decrement or post-increment flag to it opcode = opcode + value[0] if not assem.MoreParameters(): errors.DoError('missoper', False) target.CodeWord(0) # Write dummy word return reg = GetReg() << 4 target.CodeWord(opcode + reg) 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 ELpm(): """ These instructions require two operands. The first one is one of the 32 registers. The second one is either the Z index register, or Z+. Optionally the instruction can also be used without operands. Not all variants may be available on all devices. AT90S1200 doesn't have an LPM instruction at all. Dictionary: function, Xmega+Mega+AVR+TINY, newflags, newflags, opcode, cycles """ global Asm if dec.Asm.Parse_Pointer == 0 or not dec.Asm.Optional: # No operand, use implied addressing mode target.CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][3]) else: if dec.Asm.Mnemonic == 'ELPM': # Get opcode for ELMP opcode = 0x9006 else: # Get opcode for LMP opcode = 0x9004 reg = GetReg() << 4 if not assem.MoreParameters(): # Index register operand is missing errors.DoError('missoper', False) target.CodeWord(0) # Write dummy word return value = GetIndex() if value[1] != 'Z' or value[0] == 2 or value[2] != 0: # Only the Z or Z+ index register is allowed. errors.DoError('badoper', False) reg = 0 # Dummy register index = 0 # and dummy mode else: # Legal index register index = value[0] target.CodeWord(opcode + reg + index) NoMore()
def Branch(): global Asm if MissingOperand(): return operand = GetOperand() if operand[0] == 1 or operand[0] == 2: # Branch relative offset = operand[1] - 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][0]) target.CodeByte(offset) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][0] elif operand[0] == 9: # Branch [indirect] target.CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][1][1]) target.CodeByte(operand[1]) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][1] else: errors.DoError('badoper', False) return NoMore()
def LBranch(): """ Handle long branch instructions. Displacement is destinaiton - current address - 3 in case 3 byte long instruction Displacement is destinaiton - current address - 4 in case 4 byte long instruction """ global Asm if MissingOperand(): return opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] value = assem.EvalExpr() offset = value[0] - dec.Asm.BOL_Address - 3 if opcode > 255: # It's a 2 byte opcode offset = offset - 1 target.CodeByte(opcode >> 8) target.CodeByte(opcode) target.CodeWord(offset) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] NoMore()
def Stack(): global Asm if MissingOperand(): return operand = assem.GetWord().upper() if operand == 'A': index = 0 elif operand == 'X': index = 1 elif operand == 'Y': index = 2 elif operand == 'CC': index = 3 else: errors.DoError('badoper', False) return opcode = (dec.Asm.Instructions[dec.Asm.Mnemonic][1][index]) if opcode > 255: target.CodeWord(opcode) else: target.CodeByte(opcode) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][index] 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 RegOnly(): """ These instructions require only one register. CRL, LSL, ROL and TST are acutally pseudo instructions. They require the single operand to be used twice, both as source and destinatio. The SER instruction has a limited register span. Dictionary: function, Xmega+Mega+AVR+TINY, newflags, opcode, cycles """ global Asm reg = GetReg() if dec.Asm.Mnemonic in ('CLR', 'LSL', 'ROL', 'TST'): # These are acutally pseudo instructions, requiring the operand # to be used as source and destination for the original instruction reg1 = reg << 4 if reg > 15: reg = reg - 16 + 512 reg = reg + reg1 elif dec.Asm.Mnemonic == 'SER': if dec.Asm.Pass == 2 and reg < 16: # This one has a limited register span errors.DoError('range', False) reg = (reg & 0xF) << 4 else: # All others are normal reg = reg << 4 target.CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][3] + reg) NoMore()
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 InOut(): """ These instructions require two operands. A register from 0 to 31 and an I/O address from 0 to 63. The IN and OUT instructions have their operand order swapped. Dictionary: function, Xmega+Mega+AVR+TINY, newflags, opcode, cycles """ global Asm if dec.Asm.Mnemonic == 'IN': # Get register operand first, then I/O location reg = GetReg() << 4 if not assem.MoreParameters(): # Oops only register is given errors.DoError('missoper', False) target.CodeWord(0) # Write dummy word return value = assem.EvalExpr()[0] else: # Get I/O location first, then register value = assem.EvalExpr()[0] if not assem.MoreParameters(): # Oops, only I/O location given errors.DoError('missoper', False) target.CodeWord(0) # Write dummy word return reg = GetReg() << 4 if dec.Asm.Pass == 2 and (value < 0 or value > 63): # Check I/O address range in pass 2 only errors.DoError('range', False) value = 0 ioreg = (value & 15) + ((value & 48) << 5) target.CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][3] + reg + ioreg) NoMore()
def Inherent(): """ These instructions don't need an operand. Can't be any easier. Dictionary: function, Xmega+Mega+AVR+TINY, newflags, opcode, cycles """ global Asm target.CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][3])
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 IOBits(): """ I/O instructions. Operate on the lower 32 I/O addresses. Requires two operands. I/O address, from 0 to 31. And bit number from 0 to 7. Dictionary: function, Xmega+Mega+AVR+TINY, newflags, opcode, cycles """ global Asm ioreg = assem.EvalExpr()[0] if dec.Asm.Pass == 2 and (ioreg < 0 or ioreg > 31): # Check range of I/O register in pass 2 only errors.DoError('range', False) ioreg = 0 ioreg = ioreg << 3 if not assem.MoreParameters(): # Only the I/O register is given. The bit number is missing errors.DoError('missoper', False) # Write dummy word target.CodeWord(0) return bitno = assem.EvalExpr()[0] if dec.Asm.Pass == 2 and (bitno < 0 or bitno > 7): # Check range of bit number in pass 2 only errors.DoError('range', False) bitno = 0 target.CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][3] + ioreg + bitno) NoMore()
def SaveAll(prebyte, opcode, operand): if opcode == 0: errors.DoError('badoper', False) return if prebyte != 0: target.CodeByte(prebyte) target.CodeByte(opcode) if operand[0] in (0, 1, 4, 7, 9, 10, 11, 12, 13, 14): target.CodeByte(operand[1]) elif operand[0] in (2, 5, 8): target.CodeWord(operand[1]) 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 dest = assem.EvalExpr() target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1]) target.CodeWord(dest[0]) dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2] if dec.Asm.Pass == 2 and (dest[0] >> 14) != 0: errors.DoError('range', False) NoMore()
def Sreg(): """ These instructions require only a bit number from 0 to 7. Dictionary: function, Xmega+Mega+AVR+TINY, newflags, opcode, cycles """ global Asm sregbit = assem.EvalExpr()[0] if dec.Asm.Pass == 2 and (sregbit < 0 or sregbit > 7): # Outside the legal range errors.DoError('range', False) sregbit = 0 target.CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][3] + (sregbit << 4)) NoMore()
def Des(): """ This instruction requires an operand in the range of 0 to 15. Dictionary: function, Xmega+Mega+AVR+TINY, newflags, opcode, cycles """ global Asm value = assem.EvalExpr()[0] if dec.Asm.Pass == 2 and (value < 0 or value > 15): # Outside the legal range errors.DoError('range', False) value = 0 target.CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][3] + (value << 4)) 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 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 Jumps(): global Asm if dec.Asm.Mnemonic == 'CPE': # This mnemonics may or may not have an address as operand # Depending on the 1972 or 1976 syntax if not dec.Asm.Optional: # No parameter was following within 10 spaces target.CodeByte(0xBC) dec.Asm.Timing = "5" return dest = assem.EvalExpr() target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1]) target.CodeWord(dest[0]) if dec.Asm.Pass == 2 and (dest[0] >> 14) != 0: errors.DoError('range', False) NoMore()
def InOut(): global Asm if MissingOperand(): return value = assem.EvalExpr() if dec.Flags.ErrorInLine: # Save 2 dummy bytes if an error was given target.CodeWord(0) else: # No error was found, no danger of getting sync error if dec.Asm.Pass == 2 or (not value[1]): # Test range in pass 2 or when not forward referenced if value[0] > dec.MAX8 or value[0] < 0: # Report error, but ignore everthing which doesn't fit errors.DoError('range', False) target.CodeByte(dec.Asm.Instructions[dec.Asm.Mnemonic][1]) target.CodeByte(value[0]) NoMore()
def Accu(): global Asm if MissingOperand(): return if GetOperand()[0] != 15: errors.DoError('badoper', False) return if not assem.MoreParameters(): errors.DoError('missoper', False) return operand = GetOperand() if operand[0] > 14: errors.DoError('badoper', False) return opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][operand[0]] timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][operand[0]] prebyte = opcode // 256 opcbyte = opcode % 256 if prebyte != 0: target.CodeByte(prebyte) target.CodeByte(opcbyte) if operand[0] in (0, 1, 4, 7, 9, 10, 11, 12, 13, 14): target.CodeByte(operand[1]) elif operand[0] in (2, 5, 8): target.CodeWord(operand[1]) dec.Asm.Timing = timing NoMore()
def Immediate(): global Asm if MissingOperand(): return if dec.Asm.Mnemonic == 'LXI': registers = 'BDHS' reg = registers.find(assem.NowChar(True).upper()) if reg < 0: errors.DoError('badoper', False) return if reg == 3: # It was S, so next char must be a P to finish SP if assem.NowChar(True).upper() != 'P': errors.DoError('badoper', False) return opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] + (reg << 4) if not assem.MoreParameters(): errors.DoError('missoper', False) elif dec.Asm.Mnemonic == 'MVI': registers = 'BCDEHLMA' reg = registers.find(assem.NowChar(True).upper()) timing = dec.Asm.Timing.split(':') if reg == 6: dec.Asm.Timing = timing[1] else: dec.Asm.Timing = timing[0] if reg < 0: errors.DoError('badoper', False) return opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] + (reg << 3) if not assem.MoreParameters(): errors.DoError('missoper', False) else: opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1] prefix = '' if assem.NowChar() in '#/=\\': prefix = assem.NowChar(True) value = assem.EvalExpr() if not dec.Flags.ErrorInLine: target.CodeByte(opcode) if dec.Asm.Mnemonic == 'LXI': if prefix in ' #': target.CodeWord(value[0]) elif prefix == '/': target.CodeWord(value[0] >> 8) elif prefix == '=': target.CodeWord(value[0] >> 16) else: target.CodeWord(value[0] >> 24) else: if prefix in ' #': target.CodeByte(value[0]) elif prefix == '/': target.CodeByte(value[0] >> 8) elif prefix == '=': target.CodeByte(value[0] >> 16) else: target.CodeByte(value[0] >> 24) NoMore()
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()