def GetDecimal(): """ This one's a bit complex. The value starts with a decimal digit, now it can be any of the below: + Hex if it starts with a 0 and contains only hex digits followed by an H + Octal if it contains only octal digits followed by a Q + Hex first digit is 0 and next character is an x + Binary first digit is 0 and next character is a b + Binary if it contains only 0 or 1 followed by a B, followed by non hexdigit + Decimal otherwise or 1234d Note: 0101b notation might be confusing if followed by a legal hex digit, like 0101ba. This might be a hex value, only if followed by an h eventually. Thus if we check for hex before we check for binary there is no cause for confusion. """ global Asm text = GetWord(string.ascii_uppercase + string.digits) if len(text) == 1: # A one digit value, can't be any simpler than this return int(text) if text[-1] == 'H': # Must be hex 0ABCDH notation! hexval = text[:-1] if TestDigits(hexval, string.hexdigits): return int(hexval, 16) else: errors.DoError('illhex', False) return 0 if text[-1] == 'Q': # Must be octal 0567Q notation! octval = text[:-1] if TestDigits(octval, string.octdigits): return int(octval, 8) else: errors.DoError('illoct', False) return 0 if text[1] == 'X': # It's hex 0xABCD notation! hexval = text[2:] if TestDigits(hexval, string.hexdigits): return int(hexval, 16) else: errors.DoError('illhex', False) return 0 if text[1] == 'B': # It must be binary 0B0101 notation, it can't be hex anymore, # it doesn't end in H binval = text[2:] if TestDigits(binval, '01'): return int(binval, 2) else: errors.DoError('illbin', False) return 0 if text[-1] == 'B': # It must be binary 01010B notation binval = text[:-1] if TestDigits(binval, '01'): return int(binval, 2) else: errors.DoError('illbin', False) return 0 if text[-1] == 'D': # It must be decimal 1234D notation decval = text[:-1] if TestDigits(decval, string.digits): return int(decval) else: errors.DoError('illdec', False) return 0 # all else failed, it must be a decimal now if TestDigits(text, string.digits): return int(text, 10) else: errors.DoError('illdec', False) return 0
def ParseLine(): """ We've got our source line. Now it's time to parse it all. However if we're defining a macro, we take a detour. First we look if it's an empty line or a comment line Then we extract the label field, if any. Then the mnemonic field, and act on its contents. It can be one of three things: A directive, a macro call or a mnemonic. Before executing the lot we also prepare the operand field. """ global Asm, Flags, Label dec.Asm.Parse_Pointer = 0 dec.Asm.New_Label = "" dec.Asm.Mnemonic = "" dec.Asm.List_Line = "" dec.Asm.Timing = "" dec.Asm.List_Byte_Cnt = 0 macrolevel = dec.Asm.Local_Index if dec.Asm.Parse_Line == chr(26) + " ": # Ctrl-Z, end mark for DOS files, ignore it return if dec.Asm.Macro_Def != '': # Defining a Macro, add this line to macro macros.DefineMacro() return if dec.Asm.Cond_False == 0: # Conditional assembly is true. Have to assemble this line # Select memory mode # May have changed by previous line if dec.Asm.Memory == 0: dec.Asm.BOL_Address = dec.Asm.PH_Address dec.Asm.List_Address = dec.Asm.PH_Address elif dec.Asm.Memory == 1: dec.Asm.BOL_Address = dec.Asm.RM_Address dec.Asm.List_Address = dec.Asm.RM_Address else: dec.Asm.BOL_Address = dec.Asm.EM_Address dec.Asm.List_Address = dec.Asm.EM_Address if IsComment(): # Do nothing if this line is empty or a comment line return newlabel = GetLabelName() globlab = string.ascii_uppercase + '_' # Legal begin chars of label if len(newlabel) > 0 and (newlabel[0] in globlab): # New global label defined newglobal = True else: # No new global lable defined newglobal = False if NowChar() == ":": # It's a macro label IncParsePointer() if NowChar() != " ": # Can't be a bare : errors.DoError('illlabel', False) return # Dont' bother to continue dec.Asm.New_Label = newlabel if len(newlabel) > 0: # Do a boundary sync if a label is given target.BoundarySync() dec.Asm.Mnemonic = GetMnemonic() if dec.Asm.Mnemonic == "": # No mnemonic means no operand either dec.Asm.Parse_Pointer = 0 else: # Parse the operand field dec.Asm.Parse_Pointer = FindOperandField() if newglobal and dec.Asm.Mnemonic[:3] != '.SE': # Set last assigned global label name, only when not .SE directive dec.Asm.Last_Global = newlabel # Reset macro indexes dec.Asm.Macro_Number = 0 dec.Asm.Local_Index = 0 DoAssemble() # Got all the ingredients, now put them all together if dec.Asm.New_Label != "": AssignLabel(dec.Asm.New_Label, macrolevel) else: # Conditional assembly is false, accept only .DO, .EL and # .FI directives if IsComment(): # Nothing to do in this line, it's a comment return if NowChar() != " ": # A label is declared here, get it but don't bother about syntax dec.Asm.New_Label = GetWord("", "", " ") dec.Asm.Mnemonic = GetMnemonic() if dec.Asm.Mnemonic != "": if dec.Asm.Mnemonic[:3] in (".DO", ".EL", ".FI"): # These are the only directives of interest now dec.Asm.Parse_Pointer = FindOperandField() DoAssemble()
def LdsSts(): """ Two different versions of these instructions exist. One version applies to most devices (if implemented), the other version only applies to Reduced core processors (ATtiny10, 9, 5 and 4, aka the ATtiny10 family). Syntax for LDS and STS is the same, but have their operands swapped. On the TINY family only the registers 16 to 31 are allowed, and the constant address value ranges from 0 to 127, which is not checked. On all other devices, if implemented, all 32 registers are allowed. And the constant address value ranges from 0 to 64k. Dictionary: function, Xmega+Mega+AVR+TINY, newflags, opcode, cycles """ global Asm if dec.Asm.Mnemonic == 'LDS': # LDS, get register first, then the address reg = GetReg() << 4 if not assem.MoreParameters(): # Oops, only the reigster was given errors.DoError('missoper', False) # Write dummy words target.CodeWord(0) target.CodeWord(0) return value = assem.EvalExpr()[0] else: # STS, get address first, then the register value = assem.EvalExpr()[0] if not assem.MoreParameters(): # Oops, only the address is given errors.DoError('missoper', False) # Write dummy words target.CodeWord(0) target.CodeWord(0) return reg = GetReg() << 4 if dec.Asm.AVR_Family != 1 and dec.Asm.AVR_Family != 5: # Normal behaviour of these instructions target.CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][3] + reg) target.CodeWord(value) else: # ATtiny or Reduced Core behaviour if dec.Asm.Instructions[dec.Asm.Mnemonic][3] == 0x9000: # It's LDS opcode = 0xa000 else: # It's STS opcode = 0xa800 value = (value & 0x0F) + ((value & 0x70) << 4) target.CodeWord(opcode + reg + value) dec.Asm.Timing = '1' NoMore()
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 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: error = True if assem.NowChar(True) != ')': # Something's wrong error = True if not error: # No error found yet if reg == 'C': reg = '0' if reg < '0' or reg > '3': # Something's wrong error = True if reg == '0' and autoindex: # P0 is not allowed together with auto indexed mode error = True if not error: # No error occurred, we know everything now opcode = opcode + int(reg) else: # An error did occur error = True else: # No register given, assuming PC, addressing is absolute now if not eregister: # The offset was not the E register # Now we have to calculate the real offset offset = offset - dec.Asm.BOL_Address - 1 absolute = True if dec.Asm.Mnemonic[0].upper() == "J": # An extra offset for Jump instructions offset = offset - 1 if autoindex and reg == '0': # Auto indexing doesn't allow the PC register error = True if error: # An error has occurred, tell us about it errors.DoError("badoper", False) NoMore() if dec.Asm.Pass == 2 and not forward: # Only test range in pass 2 if offset < -128 or offset > 127: # Range error errors.DoError('range', False) if offset == -128 and absolute: # Offset calculated to -128, are you sure! errors.DoWarning(dec.Cross.Name + 'offset', True) WriteOpcode(opcode) WriteOperand(offset)
def RegReg(): """ Instructions with register source and register destination operands. Some MULx instructions have a limited register scope so they are treated as exceptions. And also the MOVW instruction requires an execption because it uses register pairs instead of plain registers. Dictionary: function, Xmega+Mega+AVR+TINY, newflags, opcode, cycles """ global Asm # Get destination register reg1 = GetReg() if not assem.MoreParameters(): # Only one parameter was given errors.DoError('missoper', False) # Write dummy word target.CodeWord(0) return # Get source register reg2 = GetReg() if ('MUL' in dec.Asm.Mnemonic) and (dec.Asm.Mnemonic != 'MUL'): # MULx instructions have a limited register file scope if dec.Asm.Pass == 1: # Don't test range during pass 1, to ignore forward references # Set dummy registers instead reg1 = 0 reg2 = 0 else: # Pass 2, do the magic reg1 = reg1 - 16 reg2 = reg2 - 16 if reg1 < 0 or reg2 < 0: # Range error errors.DoError('range', False) # Set dummy values reg1 = 0 reg2 = 0 if dec.Asm.Mnemonic != 'MULS': # Only MULS has a bigger scope than the other MUL instructions if reg1 > 7 or reg2 > 7: # Rage error for MULS errors.DoError('range', False) # Set dummy values reg1 = 0 reg2 = 0 reg1 = reg1 << 4 elif dec.Asm.Mnemonic == 'MOVW': # MOV Word. Either register of the register pair can be used reg1 = (reg1 & 0x1E) << (4 - 1) reg2 = (reg2 & 0x1E) >> 1 else: # Any other instruction # Shift destination bits 4 bits to the left reg1 = reg1 << 4 if reg2 > 15: # Move MSB of source to bit 9 reg2 = reg2 - 16 + 512 target.CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][3] + reg1 + reg2) NoMore()
def RegImm(): """ Register, immediate instructions. The first operand must be a register. The second operand is an immediate constant. The # / = and \ prefixes are optional for the immediate operand. # is assumed if no prefix is given. Dictionary: function, Xmega+Mega+AVR+TINY, newflags, opcode, cycles """ global Asm # Get destination register reg = GetReg() if not assem.MoreParameters(): # Only one operand was given errors.DoError('missoper', False) # Write dummy word target.CodeWord(0) return if assem.NowChar() in '#/=\\': # A prefix is given prefix = assem.NowChar(True) else: # Use default prefix if not given prefix = '#' 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.Mnemonic in ('ADIW', 'SBIW'): # These Word sized instructions have limited operand scopes if dec.Asm.Pass == 2: # Don't check range during pass 1, may be forward referenced if reg not in (24, 26, 28, 30): # Only 4 register pairs may be used as destinaion errors.DoError('range', False) reg = (reg << 3) & 0x30 # Don't check value range, only limit it val = (val & 0xF) + ((val & 0x30) << 2) else: # All other instructions if dec.Asm.Pass == 2: # Don't check range during pass 1, may be forward referenced if reg < 16: errors.DoError('range', False) reg = (reg << 4) & 240 val = (val & 0xF) + ((val & 0xF0) << 4) if dec.Asm.Mnemonic == 'CBR': # CBR is a pseudo instruction, K has to be complemented val = val ^ 0xF0F target.CodeWord(dec.Asm.Instructions[dec.Asm.Mnemonic][3] + reg + val) NoMore()
def GetLabelValue(): global Asm memory = 0 if NowChar() in '.:': # It's a local label label = GetLabelName() if len(label) <= 1: label = '' else: if label[0] == '.': # Always use index 000 if it's a local label label = dec.Asm.Last_Global + ':' + label[1:] + '|000' else: label = dec.Asm.Last_Global + label + '|' + str( dec.Asm.Local_Index).zfill(3) else: # It's a global label label = GetLabelName(False) if len(label) > 0: if NowChar() == ':': # It's a global:local reference local = GetLabelName() if len(local) == 1: label = '' else: # Always use index 000 if global:local notation is used # Done for compatibility with version 2 and because you can't reference # macro labels from other global labels anyway. label = label + local + '|000' if label != '': if label in dec.Asm.Symbol_Table: # Label exists, get its data value = dec.Asm.Symbol_Table[label][0] memory = dec.Asm.Symbol_Table[label][4] if dec.Asm.Pass == 1: # Label exists already in pass 1, so it's not forward referenced forward = False else: # See if label already existed during pass 1 forward = dec.Asm.Symbol_Table[label][1] # Increment label's reference counter dec.Asm.Symbol_Table[label][ 3] = dec.Asm.Symbol_Table[label][3] + 1 else: # Label does not exist value = 0 if dec.Asm.Pass == 1: # It's OK for a label not to exist in pass 1 forward = True else: # It's not OK for a label not to exist in pass 2 errors.DoError('undef', False) forward = True else: # Illegal or incomplete label name errors.DoError('illlabel', False) value = 0 forward = False if NowChar() == ":": errors.DoError('illlabel', False) return (value, forward, memory)
def GetReg(): """ Get a register name from R0 to R31. No leading zeroes are allowed. So R01 is not a legal register name. If no register can be found the operand is assumed to be an expression, which should evaluate to a legal register number between 0 and 31. In the legacy naming convention the Tiny family has a limited register range, from 16 to 31. In the new naming convention the Reduced core family has a limited register range, from 16 to 31. """ global Asm # Save pointer in case we need to start all over again pointer = dec.Asm.Parse_Pointer # First try to get a register name reg = assem.GetWord().upper() family = dec.Asm.AVR_Family if reg == '': # Operand was expected but not found errors.DoError('missoper', False) return 0 if (len(reg) == 2 or len(reg) == 3) and reg[0] == 'R': # Can it be a register name? Must be 2 or 3 chars long and start with R reg = reg[1:] if reg.isdigit: # The register number must be numeric of course if len(reg) == 1 or reg[0] != '0': # It is numeric, without a leading 0 register = int(reg) if register >= 0 and register < 32: # OK it is a register if dec.Asm.Pass == 2 and (family == 1 or family == 5) and\ register < 16: # Oops, the Reduced Core family doesn't have # registers 0 to 15 errors.DoError('range', False) register = 16 return register # Operand was not a register, evaluate expression now dec.Asm.Parse_Pointer = pointer value = assem.EvalExpr() register = value[0] if dec.Asm.Pass == 2: # Test range only if in pass 2 if register < 0 or register > 31: # It's a range error, simply ignore everything which doesn't fit errors.DoError('range', False) register = 0 if (family == 1 or family == 5) and register < 16: # The range for the Reduced Core family is 16 to 31 errors.DoError('range', False) register = 16 # Expression evaluated to a register number return register & 31
def GetValue(): """ Get a value. The value might be a label, a constant in 4 different radixes, given in 3 different formats, the current program counter or the pass number. Returns a tuple containing the value and a forward referenced label flag. Returns (0, False, Memory) if an error is encountered in the value """ global Asm, Flags forward = False memory = 0 # Code memory if this remains 0, other if not. negative = False if NowChar() in '-+': # See if sign is given if NowChar(True) == '-': negative = True nowchar = NowChar().upper() if nowchar in string.ascii_uppercase + '.:_': labelval = GetLabelValue() value = labelval[0] if labelval[1]: # Set forward refenced flag (may be set, but may not be cleared) forward = True memory = labelval[2] elif nowchar in string.digits: value = GetDecimal() elif nowchar in "'\"": value = GetAsciiValue() elif nowchar == '$': value = GetHex() elif nowchar == '%': value = GetBin() elif nowchar == '@': value = GetOct() elif nowchar == '*': # Return current location IncParsePointer() value = dec.Asm.BOL_Address elif nowchar == '?': # Return pass number IncParsePointer() value = dec.Asm.Pass - 1 elif nowchar == ' ': # No parameter is given errors.DoError('valerr', False) return (0, False, memory) else: # None of the above! errors.DoError('badoper', False) return (0, False, memory) if negative: value = -value value = value * 1 # Ensure value is a long rangecheck = value >> 32 if rangecheck != 0 and rangecheck != -1: errors.DoError('overflow', False) return (value, forward, memory)
def Calculate(val1, val2, operator): """ Combine two values using the given operator. Accepts the two values to operate on and the operator itself. Returns a tuple containing the new value and a combined forward reference flag. If either value used a forward referenced value the flag will be set. """ value1 = val1[0] value2 = val2[0] forward = val1[1] | val2[1] memory = val1[2] + val2[2] trueval = dec.MINUS_ONE posmask = (1 << 32) - 1 negmask = -1 ^ posmask result = 0 if operator == '+': # Plus result = value1 + value2 elif operator == '-': # Minus result = value1 - value2 elif operator == '*': # Multiply result = value1 * value2 elif operator == '/': # Divide if value2 != 0: result = value1 // value2 else: if dec.Asm.Pass == 2: # Avoid error messages due to forward referenced labels errors.DoError('div0', False) result = 0 elif operator == '\\': # Modulo if value2 != 0: result = value1 % value2 else: if dec.Asm.Pass == 2: # Avoid error messages due to forward referenced labels errors.DoError('div0', False) result = 0 elif operator == '&': # Bitwise and result = value1 & value2 elif operator == '^' or operator == '|': # Bitwise or result = value1 | value2 elif operator == '!': # Bitwise exor result = value1 ^ value2 elif operator == '=': # Equal if value1 == value2: result = trueval else: result = 0 elif operator == '<': # Less than if value1 < value2: result = trueval else: result = 0 elif operator == '>': # Greater than if value1 > value2: result = trueval else: result = 0 elif operator == '<=': # Less than or equal if value1 <= value2: result = trueval else: result = 0 elif operator == '>=': # Greater than or equal if value1 >= value2: result = trueval else: result = 0 elif operator == '<>': # Not equal if value1 != value2: result = trueval else: result = 0 elif operator == '<<': # Shift left if dec.Asm.Pass == 2 and (value2 < 0 or value2 > 31): # Check valid rane in pass 2 because of forward referenced labels errors.DoError('range', false) value2 = 0 result = value1 << value2 elif operator == '>>': # Shift right if not val2[1] and (value2 < 0 or value2 > 63): # Check valid rane in pass 2 because of forward referenced labels errors.DoError('range', false) value2 = 0 result = value1 >> value2 # Limit result to word size if result < 0: result = result | negmask else: result = result & posmask return (result, forward, memory)
def AssignLabel(newlabel, macrolevel): """ Assign a value to a new label. It accepts the name of the new label. Some tests are made to see if the label exists and hasn't changed value. During pass 2 it should still be in sync with pass 1 also. """ global Asm if dec.Asm.Mnemonic[:3] == '.SE': rw = True else: rw = False if newlabel[0] in '.:': # It's a local label, add the last global in front of it # and current macro number behind it if it's a macro label if dec.Asm.Last_Global != '': if newlabel[0] == '.': # Starting with a dot is always index level 000 newlabel = dec.Asm.Last_Global + ':' + newlabel[1:] + '|000' else: # Otherwise it is the current macro level index newlabel = dec.Asm.Last_Global + newlabel + '|' + str( macrolevel).zfill(3) else: errors.DoError('noglobal', False) return if dec.Asm.Pass == 1: if newlabel in dec.Asm.Symbol_Table: # Label already exists. Must be variable or same value now if rw: if dec.Asm.Symbol_Table[newlabel][2]: # Both old and new defs are RW, set new value dec.Asm.Symbol_Table[newlabel][0] = dec.Asm.BOL_Address else: errors.DoError('con2var', False) return else: if dec.Asm.Symbol_Table[newlabel][2]: errors.DoError('var2con', False) return else: # Both old and new defs are RO, value must be the same! if dec.Asm.Symbol_Table[newlabel][0] != dec.Asm.BOL_Address: errors.DoError('extdef', False) return else: # New label doesn't exist yet, add it to symbol table dec.Asm.Symbol_Table[newlabel] = [ dec.Asm.BOL_Address, True, rw, 0, dec.Asm.Memory, dec.Asm.File_Name[-1] ] else: # Pass 2 if newlabel in dec.Asm.Symbol_Table: if dec.Asm.Symbol_Table[newlabel][2]: # It's a variable # Don't bother testing if RW is still in sync # Give stupid users a chance to break the system :-) dec.Asm.Symbol_Table[newlabel][0] = dec.Asm.BOL_Address dec.Asm.Symbol_Table[newlabel][ 1] = False # Label is declared from now on else: # It's a constant if dec.Asm.Symbol_Table[newlabel][0] != dec.Asm.BOL_Address: # Different value from last time! errors.DoError('syncerr', False) else: # Same value as last time! Mark declared dec.Asm.Symbol_Table[newlabel][1] = False else: # Label sould have been there in pass 2, sync error errors.DoError('syncerr', False)
def DoMnemonic(): if dec.Cross.Name == "": errors.DoError("nocross", True) else: dec.Cross.Mnemonic()
def ParseLine(): """ We've got our source line. Now it's time to parse it all. However if we're defining a macro, we take a detour. First we look if it's an empty line or a comment line Then we extract the label field, if any. Then the mnemonic field, and act on its contents. It can be one of three things: A directive, a macro call or a mnemonic. Before executing the lot we also prepare the operand field. """ global Asm, Flags, Label global current_aid_pointer global array_aid, ending_address # JKL dec.Asm.Parse_Pointer = 0 dec.Asm.New_Label = "" dec.Asm.Mnemonic = "" dec.Asm.List_Line = "" dec.Asm.Timing = "" dec.Asm.List_Byte_Cnt = 0 macrolevel = dec.Asm.Local_Index if dec.Asm.Parse_Line == chr(26) + " ": # Ctrl-Z, end mark for DOS files, ignore it return if dec.Asm.Macro_Def != '': # Defining a Macro macros.DefineMacro() return if dec.Asm.Cond_False == 0: # Conditional assembly is ture. Have to assemble this line # Select memory mode # May have changed by previous line if dec.Asm.Memory == 0: dec.Asm.BOL_Address = dec.Asm.PH_Address dec.Asm.List_Address = dec.Asm.PH_Address elif dec.Asm.Memory == 1: dec.Asm.BOL_Address = dec.Asm.RM_Address dec.Asm.List_Address = dec.Asm.RM_Address else: dec.Asm.BOL_Address = dec.Asm.EM_Address dec.Asm.List_Address = dec.Asm.EM_Address if IsComment(): # Do nothing if this line is empty or a comment line return newlabel = GetLabelName() globlab = string.ascii_uppercase + '_' if len(newlabel) > 0 and (newlabel[0] in globlab): # Clear these in case we have to expand a macro on this line dec.Asm.Macro_Number = 0 dec.Asm.Local_Index = 0 dec.Asm.Last_Global = newlabel if NowChar() == ":": IncParsePointer() if NowChar() != " ": errors.DoError('illlabel', False) return # Dont' bother to continue dec.Asm.New_Label = newlabel if len(newlabel) > 0: # Do a boundary sync if a label is given target.BoundarySync() dec.Asm.Mnemonic = GetMnemonic() if dec.Asm.Mnemonic == "": dec.Asm.Parse_Pointer = 0 # No mnemonic means no operand either else: dec.Asm.Parse_Pointer = FindOperandField() DoAssemble() # Got all the ingredients, now put them all together if dec.Asm.New_Label != "": AssignLabel(dec.Asm.New_Label, macrolevel) else: # Conditional assembly is false, accept only .DO, .EL and .FI directives if IsComment(): # Nothing to do in this line, it's a comment return if NowChar() != " ": # A label is declared here, get it but don't bother about syntax dec.Asm.New_Label = GetWord("", "", " ") dec.Asm.Mnemonic = GetMnemonic() #jkl #sys.stdout = sys.__stdout__ if dec.Asm.Mnemonic != "": if dec.Asm.Mnemonic[:3] in (".DO", ".EL", ".FI"): # These are the only directives of interest now dec.Asm.Parse_Pointer = FindOperandField() DoAssemble() #JKL NOX if (len(dec.Asm.List_Line) > 0): #print(str(hex(dec.Asm.BOL_Address)) + " " +dec.Asm.Mnemonic + " " + dec.Asm.List_Line[8:14] + " " + str(dec.Asm.List_Byte_Cnt) + " ") # TODO ADD LABEL HERE, LINK BACK IN TO NEW ADDITIONAL SYMBOL TABLE array_aid[dec.Asm.BOL_Address] = { 'address': dec.Asm.BOL_Address, 'operator': dec.Asm.Mnemonic, 'operand': dec.Asm.List_Line[8:14], 'byte_cnt': dec.Asm.List_Byte_Cnt } print((array_aid[dec.Asm.BOL_Address])) ending_address = dec.Asm.BOL_Address