Example #1
0
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
Example #2
0
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
Example #3
0
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 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()
Example #5
0
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()
Example #6
0
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()
Example #7
0
def GetOperand():
    """
    Get an operand. This can get complicated.
    Operand can be:
    Index =  0: #
    Index =  1: SHORT
    Index =  2: LONG
    Index =  3: (X)
    Index =  4: (SHORT,X)
    Index =  5: (LONG,X)
    Index =  6: (Y)
    Index =  7: (SHORT,Y)
    Index =  8: (LONG,Y)
    Index =  9: [SHORT]
    Index = 10: [LONG.W]
    Index = 10: {LONG}
    Index = 11: ([SHORT],X)
    Index = 12: ([LONG.W],X)
    Index = 12: ({LONG},X)
    Index = 13: ([SHORT],Y)
    Index = 14: ([LONG.W],Y)
    Index = 14: ({LONG},Y)
    Index = 15: A
    Index = 16: X
    Index = 17: Y
    Index = 18: S
    """

    global Asm

    pntr = dec.Asm.Parse_Pointer

    operand = assem.GetWord().upper()
    if operand == 'A':
        return (15, 0)
    if operand == 'X':
        return (16, 0)
    if operand == 'Y':
        return (17, 0)
    if operand == 'S':
        return (18, 0)
    if operand == '(X)':
        return (3, 0)
    if operand == '(Y)':
        return (6, 0)

    dec.Asm.Parse_Pointer = pntr

    # ----------

    if operand[0] in '#/=\\':
        # Immediate value
        mode = assem.NowChar(True)
        value = assem.EvalExpr()
        if mode == '#':
            return (0, value[0])
        if mode == '/':
            return (0, value[0] >> 8)
        if mode == '=':
            return (0, value[0] >> 16)
        return (0, value[0] >> 24)

# ----------

    if operand[0:2] == '([':
        # Some form of Indexed Indirect mode

        assem.IncParsePointer()
        assem.IncParsePointer()

        pntr = dec.Asm.Parse_Pointer
        line = dec.Asm.Parse_Line
        operand = assem.GetWord('', '', ']').upper()
        endpnt = dec.Asm.Parse_Pointer
        dec.Asm.Parse_Pointer = pntr
        short = True
        if operand[-2:] == '.W':
            short = False
            dec.Asm.Parse_Line = line[:endpnt - 2] + ' '

        value = assem.EvalExpr()
        dec.Asm.Parse_Line = line
        dec.Asm.Parse_Pointer = endpnt

        if assem.NowChar(True) != ']':
            errors.DoError('badoper', False)

        if not assem.MoreParameters():
            errors.DoError('missoper', False)

        nowchar = assem.NowChar(True).upper()
        if nowchar == 'X':
            xymode = 11
        elif nowchar == 'Y':
            xymode = 13
        else:
            xymode = 11
            errors.DoError('badoper', False)

        if assem.NowChar(True) != ')':
            errors.DoError('badoper', False)

        if dec.Asm.Pass == 2 and (value[0] >> 8 != 0):
            errors.DoError('range', False)

        if short:
            return (xymode + 0, value[0])
        else:
            return (xymode + 1, value[0])

# ----------

    if operand[0:2] == '({':
        # Indexed Indirect long mode

        assem.IncParsePointer()
        assem.IncParsePointer()
        value = assem.EvalExpr()
        if assem.NowChar(True) != '}':
            errors.DoError('badoper', False)

        if not assem.MoreParameters():
            errors.DoError('missoper', False)

        nowchar = assem.NowChar(True).upper()
        if nowchar == 'X':
            xymode = 12
        elif nowchar == 'Y':
            xymode = 14
        else:
            xymode = 12
            errors.DoError('badoper', False)

        if assem.NowChar(True) != ')':
            errors.DoError('badoper', False)

        if dec.Asm.Pass == 2 and (value[0] >> 8 != 0):
            errors.DoError('range', False)

        return (xymode, value[0])

# ----------

    if operand[0] == '(':
        # Some form of indexed mode.
        # It can be short or long, followed by ,X) or ,Y)

        assem.IncParsePointer()

        prefix = ''
        if operand[0] in '<>':
            # It's forced long or short
            prefix = assem.NowChar(True)

        value = assem.EvalExpr()

        if prefix == '<':
            short = True
            if dec.Asm.Pass == 2 and (value[0] >> 8) != 0:
                errors.DoError('range', False)
        elif prefix == '>' or value[1]:
            short = False
        else:
            short = False
            if (value[0] >> 8) == 0:
                short = True

        if not assem.MoreParameters():
            errors.DoError('missoper', False)

        nowchar = assem.NowChar(True).upper()
        if nowchar == 'X':
            xymode = 4
        elif nowchar == 'Y':
            xymode = 7
        else:
            xymode = 4
            errors.DoError('badoper', False)

        if assem.NowChar(True) != ')':
            errors.DoError('badoper', False)

        if short:
            return (xymode + 0, value[0])
        else:
            return (xymode + 1, value[0])

# ----------

    if operand[0] == '[':
        # Some form of indirect mode, could be [short] or [long.w]

        assem.IncParsePointer()
        pntr = dec.Asm.Parse_Pointer
        line = dec.Asm.Parse_Line
        operand = assem.GetWord('', '', ']').upper()
        endpnt = dec.Asm.Parse_Pointer
        dec.Asm.Parse_Pointer = pntr
        short = True
        if operand[-2:] == '.W':
            short = False
            dec.Asm.Parse_Line = line[:endpnt - 2] + ' '

        value = assem.EvalExpr()
        dec.Asm.Parse_Line = line
        dec.Asm.Parse_Pointer = endpnt

        if assem.NowChar(True) != ']':
            errors.DoError('badoper', False)

        if dec.Asm.Pass == 2 and (value[0] >> 8 != 0):
            errors.DoError('range', False)

        if short:
            return (9, value[0])
        else:
            return (10, value[0])

# ----------

    if operand[0] == '{':
        # Indirect LONG mode

        assem.IncParsePointer()
        value = assem.EvalExpr()
        if assem.NowChar(True) != '}':
            errors.DoError('badoper', False)

        if dec.Asm.Pass == 2 and (value[0] >> 8 != 0):
            errors.DoError('range', False)

        return (10, value[0])

# ----------

# Here only short or long mode option left.
# Must decide whether to use short or long, depending on address size

    prefix = ''
    if operand[0] in '<>':
        # It's forced long or short
        prefix = assem.NowChar(True)

    value = assem.EvalExpr()

    if prefix == '<':
        short = True
        if dec.Asm.Pass == 2 and (value[0] >> 8) != 0:
            errors.DoError('range', False)
    elif prefix == '>' or value[1]:
        short = False
    else:
        short = False
        if (value[0] >> 8) == 0:
            short = True

    if short:
        return (1, value[0])
    else:
        return (2, value[0])
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()
def Bits():
    """
    Bit instructions
    - A
    - Direct
    - [X]
    """

    global Asm

    if MissingOperand():
        return

    if assem.NowChar() == '#':
        # This is optional
        assem.IncParsePointer()

    bit = assem.EvalExpr()[0]

    if not assem.MoreParameters():
        errors.DoError('missoper', False)
        return

    param = dec.Asm.Parse_Line[dec.Asm.Parse_Pointer:dec.Asm.Parse_Pointer+2]\
        .upper()

    if param == 'A ':
        # Second operand is A
        opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][0]
        if opcode == 0:
            errors.DoError('badoper', False)
            return
        else:
            assem.IncParsePointer()
            target.CodeByte(opcode + bit)
            dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][0]

    elif assem.NowChar() == '[':
        # Secnd parameter should be [X]
        opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][2]
        if opcode == 0:
            errors.DoError('badoper', False)
            return
        else:
            assem.GetWord()
            target.CodeByte(opcode + bit)
            dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][2]

    else:
        # Second parameter is Direct
        direct = assem.EvalExpr()[0]
        opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][1]
        target.CodeByte(opcode + bit)
        target.CodeByte(direct)
        dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][1]

        if dec.Asm.Pass == 2 and (direct < 0 or direct > 255):
            errors.DoError('range', False)

    if dec.Asm.Pass == 2 and (bit < 0 or bit > 7):
        errors.DoError('range', False)

    NoMore()
def Multiple():
    """
    Multiple operand instructions
    - #
    - Direct
    - [X]
    - [#,X]
    - X,#
    - Direct,#
    - Direct,Direct
    """

    global Asm

    if MissingOperand():
        return

    param = dec.Asm.Parse_Line[dec.Asm.Parse_Pointer:dec.Asm.Parse_Pointer+2]\
        .upper()

    if param == 'A,':
        # First operand is A
        assem.NowChar(True)
        assem.MoreParameters()

        if assem.NowChar() in '#/=\\':
            # It is direct mode
            opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][0]
            if opcode == 0:
                errors.DoError('badoper', False)
            else:
                prefix = assem.NowChar(True)

                value = assem.EvalExpr()[0]

                if prefix == '/':
                    value = value >> 8
                elif prefix == '=':
                    value = value >> 16
                elif prefix == '\\':
                    value = value >> 24

                target.CodeByte(opcode)
                target.CodeByte(value)
                dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][0]

        elif assem.NowChar() == '[':
            # It's some kind of indexed mode
            assem.IncParsePointer()

            param = dec.Asm.Parse_Line[dec.Asm.
                                       Parse_Pointer:dec.Asm.Parse_Pointer +
                                       2].upper()
            if param == 'X]':
                # Non offset indexed mode
                opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][2]
                if opcode == 0:
                    errors.DoError('badoper', False)
                else:
                    target.CodeByte(opcode)
                    dec.Asm.Timing =\
                        dec.Asm.Instructions[dec.Asm.Mnemonic][2][2]
                    dec.Asm.Parse_Pointer = dec.Asm.Parse_Pointer + 2
            else:
                # Must be offset indexed mode
                opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][3]
                if opcode == 0:
                    errors.DoError('badoper', False)
                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][3]
                    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:
            # Second parameter must be direct mode
            opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][1]
            if opcode == 0:
                errors.DoError('badoper', False)
            else:
                value = assem.EvalExpr()[0]
                target.CodeByte(opcode)
                target.CodeByte(value)
                dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][1]
                if dec.Asm.Pass == 2 and (value < 0 or value > 255):
                    errors.DoError('range', False)

    elif param == 'X,':
        # First operand is X
        assem.NowChar(True)
        assem.MoreParameters()
        opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][4]
        if opcode == 0:
            errors.DoError('badoper', False)
        else:
            prefix = assem.NowChar(True)

            value = assem.EvalExpr()[0]

            if prefix == '/':
                value = value >> 8
            elif prefix == '=':
                value = value >> 16
            elif prefix == '\\':
                value = value >> 24

            target.CodeByte(opcode)
            target.CodeWord(value)
            dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][4]

    else:
        # Must be direct mode

        parm1 = assem.EvalExpr()[0]

        if not assem.MoreParameters():
            errors.DoError('missoper', False)

        if assem.NowChar() in '#/=\\':
            # Second parameter is immediate
            opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][5]
            if opcode == 0:
                errors.DoError('badoper', False)
            else:
                prefix = assem.NowChar(True)
                parm2 = assem.EvalExpr()[0]

                if prefix == '/':
                    parm2 = parm2 >> 8
                elif prefix == '=':
                    parm2 = parm2 >> 16
                elif prefix == '\\':
                    parm2 = parm2 >> 24

                if dec.Asm.Pass == 2 and (parm1 < 0 or parm1 > 255):
                    errors.DoError('range', False)
                target.CodeByte(opcode)
                target.CodeByte(parm1)
                target.CodeByte(parm2)
                dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][5]

        else:
            # Second operand should be direct now
            opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][6]
            if opcode == 0:
                errors.DoError('badoper', False)
            else:
                parm2 = assem.EvalExpr()[0]
                if dec.Asm.Pass == 2 and (parm1 < 0 or parm1 > 255 or parm2 < 0
                                          or parm2 > 255):
                    errors.DoError('range', False)
                target.CodeByte(opcode)
                target.CodeByte(parm2)
                target.CodeByte(parm1)
                dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][6]

    NoMore()
Example #11
0
def H6301(index):

    """
    Handle immediate boolean instructions, only known to the Hitachi 6301
    """

    global Asm

    if index != 4:
        # These instructions only exist in the 6301
        errors.DoError('badopco', False)
        return

    if MissingOperand():
        return

    prefix = assem.NowChar(True)
    if prefix not in '#/=\\':
        errors.DoError('badoper', False)
        return

    value = assem.EvalExpr()

    if prefix == '#':
        oper1 = value[0]
    elif prefix == '/':
        oper1 = value[0] >> 8
    elif prefix == '=':
        oper1 = value[0] >> 16
    else:
        oper1 = value[0] >> 24

    if not assem.MoreParameters():
        errors.DoError('missoper', False)
        return

    prefix = ''
    if assem.NowChar() == '<':
        # Only forced ZP prefix allowed today
        assem.IncParsePointer()
        prefix = '<'

    value = assem.EvalExpr()

    if dec.Asm.Pass == 2 and prefix == '':
        if value[0] >> 8 != 0:
            errors.DoError('range', False)

    opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][0]
    timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][0]
    if assem.MoreParameters():
        if assem.NowChar(True).upper() != 'X':
            errors.DoError('badoper', False)
        opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][1]
        timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][1]

    target.CodeByte(opcode)
    target.CodeByte(oper1)
    target.CodeByte(value[0])
    dec.Asm.Timing = timing

    NoMore()
Example #12
0
def Multi():
    """
    Handle all other mnemonics of the 6502 instructionset.
    Each addressing mode has a separate entry in the opcode tupple.
    If the opcode is 0x00 the particular instruction is not available
    on the selected model.
    If the cycle length is '0' the particular addressing mode is not
    supported.
    The model is selected by calling either the 6502 overlay, or the
    65c02 or 65sc02 overlays.
    """

    global Asm, sweet16

    if modelindex == 2 and (dec.Asm.Mnemonic in ('STZ', 'TRB', 'TSB')):
        errors.DoError('badopco', False)
        return

    instructions = dec.Asm.Instructions[dec.Asm.Mnemonic][1]
    ctimes = dec.Asm.Instructions[dec.Asm.Mnemonic][modelindex]
    operandbegin = dec.Asm.Parse_Pointer

    # Does implied addressing exist for this instruction?
    optional = dec.Asm.Optional
    pointer = dec.Asm.Parse_Pointer
    if instructions[0] != 0 and ctimes[0] != '0':
        if optional and \
                (dec.Asm.Parse_Line[operandbegin:operandbegin+2].upper() ==
                 "A "):
            optional = False
        if optional is False:
            # No operand followed, use implied addressing mode
            dec.Asm.Timing = ctimes[0]
            target.CodeByte(instructions[0])
            return

    if MissingOperand():
        return

    # There are two compound instructions, save prefix for them first
    if dec.Asm.Mnemonic == 'ADD':
        target.CodeByte(0x18)
    if dec.Asm.Mnemonic == 'SUB':
        target.CodeByte(0x38)

    nowchar = assem.NowChar().upper()

    # Is it immediate addressing mode?
    if nowchar in '#/=\\':
        if instructions[1] == 0 or ctimes[1] == '0':
            errors.DoError('badoper', False)
            return
        prefix = assem.NowChar(True)
        value = assem.EvalExpr()
        dec.Asm.Timing = ctimes[1]
        if prefix == '#':
            operand = value[0]
        elif prefix == '/':
            operand = value[0] >> 8
        elif prefix == '=':
            operand = value[0] >> 16
        else:
            operand = value[0] >> 24
        target.CodeByte(instructions[1])
        target.CodeByte(operand)
        NoMore()
        return

    # Is it some kind if indirect mode?
    if nowchar == '(':
        assem.IncParsePointer()
        value = assem.EvalExpr()
        if assem.NowChar() == ')':
            # It must be (ZP),Y mode now, or is it JMP (IND) ?
            # On the CMOS models it can also be (ZP)
            assem.IncParsePointer()
            if assem.MoreParameters():
                # It must be (zp),y now
                opcode = instructions[5]
                if (opcode != 0) and (assem.NowChar(True).upper() == 'Y'):
                    dec.Asm.Timing = ctimes[5]
                    target.CodeByte(opcode)
                    target.CodeByte(value[0])
                    if dec.Asm.Pass == 2 and ((value[0] >> 8) != 0):
                        errors.DoError('range', False)
                    NoMore()
                    return
                else:
                    errors.DoError('badoper', False)

            else:
                # It is (zp), or (abs) in case of JMP now
                opcode = instructions[10]
                dec.Asm.Timing = ctimes[10]
                if dec.Asm.Mnemonic == "JMP":
                    # It's JMP (IND)
                    target.CodeByte(opcode)
                    target.CodeWord(value[0])
                    if dec.Asm.Pass == 2 and ((value[0] >> 16) != 0):
                        errors.DoError('range', False)
                    if ((value[0] & 255) == 255) and modelindex == 2:
                        # Give warning to user about the 6502 JMP (IND) bug
                        errors.DoWarning('6502bug', False)
                    NoMore()
                    return
                else:
                    # It's (zp) now
                    if ctimes[10] == 0:
                        errors.DoError('badoper', False)
                        return
                    target.CodeByte(opcode)
                    target.CodeByte(value[0])
                    if dec.Asm.Pass == 2 and ((value[0] >> 8) != 0):
                        errors.DoError('range', False)
                    NoMore()
                    return
            return

        # It must be (ZP,X) mode now
        opcode = instructions[4]
        if (opcode != 0 and ctimes[4] != '0') and assem.MoreParameters() \
                and (assem.NowChar(True).upper() == 'X') and \
                (assem.NowChar(True).upper() == ')'):
            dec.Asm.Timing = ctimes[4]
            target.CodeByte(opcode)
            if dec.Asm.Mnemonic == "JMP":
                target.CodeWord(value[0])
                if dec.Asm.Pass == 2 and ((value[0] >> 16) != 0):
                    errors.DoError('range', False)
            else:
                target.CodeByte(value[0])
                if dec.Asm.Pass == 2 and ((value[0] >> 8) != 0):
                    errors.DoError('range', False)
            NoMore()
        else:
            errors.DoError('badoper', False)
        return

    # May now be ZP, ABS, ZP,X ABS,X ZP,Y or ABS,Y

    if nowchar in '<>':
        # Forced ZP or ABS prefix given
        prefix = nowchar
        assem.IncParsePointer()
    else:
        prefix = ''  # We have no preference, let the assembler decide

    value = assem.EvalExpr()
    if prefix == '':
        if value[1]:
            # A forward referenced label is used, force absolute mode
            prefix = '>'
        else:
            # Now decide if ZP is still possible
            if (value[0] >> 8) == 0:
                prefix = '<'
            else:
                prefix = '>'

    if not (assem.MoreParameters()):
        # It's normal ZP or ABS addressing mode
        if prefix == '<':
            index = 2
        else:
            index = 3
    else:
        # It's ZP or ABS indexed with X or Y now
        nowchar = assem.NowChar(True).upper()
        if nowchar == 'X':
            index = 6
        elif nowchar == 'Y':
            index = 8
        else:
            errors.DoError('badoper', False)
            return
        if prefix == '>':
            index = index + 1

    if prefix == '<' and instructions[index] == 0:
        # ZP wanted, but doesn't exist, use ABS instead
        prefix = '>'
        index = index + 1

    if instructions[index] == 0 or ctimes[index] == '0':
        errors.DoError('badoper', False)
        return

    target.CodeByte(instructions[index])
    dec.Asm.Timing = ctimes[index]

    if prefix == '<':
        target.CodeByte(value[0])
        address = value[0] >> 8
    else:
        target.CodeWord(value[0])
        address = value[0] >> 16

    if dec.Asm.Mnemonic == 'JSR':
        # See if it's JSR SWEET16
        if dec.Asm.Parse_Line[operandbegin:operandbegin+8].upper() == \
                'SWEET16 ':
            sweet16 = True

    if dec.Asm.Pass == 2 and address != 0:
        errors.DoError('range', False)
    NoMore()
    return
Example #13
0
def Math():
    """
    Handle the math instructions.
    """

    global Asm

    if MissingOperand():
        # We need parameters
        return

    pntr = dec.Asm.Parse_Pointer
    par1 = assem.GetWord().upper()

    if par1 == 'C':
        # Handle bit math instruction
        if not assem.MoreParameters():
            # We need 2 parameters
            errors.DoError('missoper', False)
            return
        opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][6]
        dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][6]
        if assem.NowChar() == '/':
            # It's inverse bit mode
            assem.IncParsePointer()
            opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][7]
            dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][7]
        par2 = GetBit()

        if opcode == 0:
            # Opcode doesn't exist
            errors.DoError('badoper', False)
        else:
            # Opcode does exist, save it to the target, with operand
            target.CodeByte(opcode)
            target.CodeByte(par2)

        NoMore()
        return

    dec.Asm.Parse_Pointer = pntr
    par1 = GetRegDir()
    if not assem.MoreParameters():
        # We need 2 parameters
        errors.DoError('missoper', False)
        return
    par2 = GetRegDir()

    if par1[1] == 2:
        # First operand can't be register, translate it to direct address
        par1 = (dec.Asm.RB8051 * 8 + par1[0], 0)

    if par1[1] == 0:
        # First operand is a direct address
        if par2[1] == 1:
            # DIR,A
            opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][4]
            dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][4]
            if opcode == 0:
                # Opcode doesn't exist
                errors.DoError('badoper', False)
            else:
                # Opcode does exist, save it with operand
                target.CodeByte(opcode)
                target.CodeByte(par1[0])

        elif par2[1] == 8:
            # DIR,#
            opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][5]
            dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][5]
            if opcode == 0:
                # Opcode doesn't exist
                errors.DoError('badoper', False)
            else:
                # Opcode does exist, save it with operands
                target.CodeByte(opcode)
                target.CodeByte(par1[0])
                target.CodeByte(par2[0])

        else:
            # Everything else is illegal
            errors.DoError('badoper', False)

    elif par1[1] == 1:
        # First operand is A
        if par2[1] == 0:
            # A,DIR
            opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][1]
            dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][1]
            target.CodeByte(opcode)
            target.CodeByte(par2[0])

        elif par2[1] == 2:
            # A,Rn
            opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][0]
            dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][0]
            target.CodeByte(opcode + par2[0])

        elif par2[1] == 3:
            # A,@Ri
            opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][2]
            dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][2]
            target.CodeByte(opcode + par2[0])

        elif par2[1] == 8:
            # A,#
            opcode = dec.Asm.Instructions[dec.Asm.Mnemonic][1][3]
            dec.Asm.Timing = dec.Asm.Instructions[dec.Asm.Mnemonic][2][3]
            if opcode == 0:
                # Opcode doesn't exist
                errors.DoError('badoper', False)
            else:
                # Opcode does exist, save it with operand
                target.CodeByte(opcode)
                target.CodeByte(par2[0])

        else:
            # Illegal second parameter
            errors.DoError('badoper', False)

    else:
        # Illegal first parameter
        errors.DoError('badoper', False)

    NoMore()
Example #14
0
def GetRegDir():
    """
    Return a tupple with a value and register mode.
    The value may not always have a true meaningm, in which case it's value
    must be 0.
    Mode = 0:   Direct addressing mode (value[0] is direct address)
    Mode = 1:   A mode (value[0] has no meaning)
    Mode = 2:   R0..R7 mode (value[0] is register number 0..7)
    Mode = 3:   @R0..@R1 mode (value[0] is register number 0..1)
    Mode = 4:   DPTR mode (value[0] has no meaning)
    Mode = 5:   @A+PC mode (value[0] has no meaning)
    Mode = 6:   @A+DPTR mode (value[0] has no meaning)
    Mode = 7:   @DPTR mode (value[0] has no meaning)
    Mode = 8:   # immediate mode (value[0] is the immediate value)
    """

    global Asm

    value = GetReg()
    register = value[0]
    mode = value[1]

    if mode != 0:
        # A valid register was found, don't bother looking any further
        return (register, mode)

    prefix = assem.NowChar()

    if prefix in '@<>':
        # Is it an indirect indicator or a forced direct or register mode
        assem.IncParsePointer()

    value = assem.EvalExpr()

    if prefix == '<':
        # Forced register mode
        if dec.Asm.Pass == 2 and (value[0] >> 5) != 0:
            # Value may not be bigger than 4 * 8 - 1 or negative
            errors.DoError('range', False)

        # Any other value is truncated to register size (forced mode)
        register = value[0] & 7
        # Indicate register mode
        mode = 2
        return (register, mode)

    if prefix == '>':
        # Forced direct mode
        if dec.Asm.Pass == 2 and (value[0] >> 8 != 0):
            # Value may not be more than 0xFF or negative
            errors.DoError('range', False)
        return (value[0], 0)  # Indicate direct mode

    if prefix == '@':
        # Only @R0 or @R1 allowed now, regardless of forward referencing
        register = value[0] & 0x1F
        if dec.Asm.Pass == 2:
            if (value[0] >> 5) != 0:
                # Value is a lot bigger than any register could be
                errors.DoError('range', False)
            if (register >> 3) != dec.Asm.RB8051:
                # Address is not a member of the current register bank
                errors.DoError('range', False)
            if (register & 6) != 0:
                # Only register 0 and 1 allowed being used as index
                errors.DoError('range', False)

        register = value[0] & 1
        mode = 3  # Indicate @ mode

    # Now can only be direct mode or normal register mode
    if dec.Asm.Pass == 2 and (value[0] >> 8 != 0):
        # Value is more than direct mode allows, or negative
        errors.DoError('range', False)

    if not value[1]:
        # No forward referenced label was used, so value is know in both passes
        if value[0] >> 5 != 0:
            # Value is too big to be a register
            register = value[0]
            # Indicate direct mode
            mode = 0
        else:
            # Compare bank of direct address with current bank
            if dec.Asm.RB8051 == (value[0] >> 3):
                # Same bank! Make it a real register
                register = value[0] & 7
                # Indicate register mode
                mode = 2
            else:
                # Not the same bank, use direct mode now
                register = value[0]
                # Indicate direct mode
                mode = 0
    else:
        # Forward referenced label was used, be on the safe side,
        # use direct mode
        register = value[0]
        # Indicate direct mode
        mode = 0

    return (register, mode)
Example #15
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
    PS: the P of the pointers is optional

    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:
            # We now allow omitting P for numbered registers
            dec.Asm.Parse_Pointer -= 1
            reg = assem.NowChar(True).upper()
            if reg not in "0123":
                # It can't be a register
                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)