Exemplo n.º 1
0
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
Exemplo n.º 2
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()
Exemplo n.º 3
0
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()
Exemplo n.º 4
0
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)
Exemplo n.º 5
0
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()
Exemplo n.º 6
0
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()
Exemplo n.º 7
0
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)
Exemplo n.º 8
0
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
Exemplo n.º 9
0
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)
Exemplo n.º 10
0
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)
Exemplo n.º 11
0
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)
Exemplo n.º 12
0
def DoMnemonic():

    if dec.Cross.Name == "":
        errors.DoError("nocross", True)
    else:
        dec.Cross.Mnemonic()
Exemplo n.º 13
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
    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