Esempio n. 1
0
def decodeMOV(tokenList: List[tokens.Token], section: nodes.Node.Section,
              invert: bool) -> Tuple[nodes.Node, List[tokens.Token]]:
    if len(tokenList) == 0:
        return generateToFewTokensError(
            -1, f"{'MOVN' if invert else 'MOV'} instruction"), []
    dest, *tokenList = tokenList
    if len(tokenList) < 2:
        return generateToFewTokensError(
            dest.line, f"{'MOVN' if invert else 'MOV'} instruction"), []
    if not isinstance(dest, tokens.Register):
        # Wrong token, generate an error
        return generateUnexpectedTokenError(
            dest.line, dest.contents,
            "a register"), advanceToNewline(tokenList)
    separator, *tokenList = tokenList
    if isinstance(separator, tokens.Separator) and separator.contents == ",":
        src, *tokenList = tokenList
        if isinstance(src, tokens.Register):

            def movReg(
                state: programState.ProgramState
            ) -> Tuple[programState.ProgramState, Union[programState.RunError,
                                                        None]]:
                value, err = state.getReg(src.contents)
                if invert:
                    value = value ^ 0xFFFF_FFFF
                state.setReg(dest.contents, value)
                return state, err

            return nodes.InstructionNode(section, dest.line, movReg), tokenList
        elif isinstance(src, tokens.ImmediateValue):
            # check 8 bits
            if src.value > 0xFF:
                return generateImmediateOutOfRangeError(
                    src.line, src.value, 0xFF), tokenList

            def movImmed(
                state: programState.ProgramState
            ) -> Tuple[programState.ProgramState, Union[programState.RunError,
                                                        None]]:
                if invert:
                    value = src.value ^ 0xFFFF_FFFF
                else:
                    value = src.value
                state.setReg(dest.contents, value)
                return state, None

            return nodes.InstructionNode(section, dest.line,
                                         movImmed), tokenList
        else:
            # Wrong token, generate an error
            return generateUnexpectedTokenError(
                src.line, src.contents,
                "a register or an immediate value"), advanceToNewline(
                    tokenList)
    else:
        # Wrong token, generate an error
        return generateUnexpectedTokenError(separator.line, separator.contents,
                                            "','"), advanceToNewline(tokenList)
Esempio n. 2
0
def decodePOP(
        tokenList: List[tokens.Token],
        section: nodes.Node.Section) -> Tuple[nodes.Node, List[tokens.Token]]:
    line = tokenList[0].line

    regs, tokenList = getRegisterList(tokenList, "POP")

    if isinstance(regs, nodes.ErrorNode):
        return regs, tokenList
    regs = list(reversed(regs))

    def pop(
        state: programState.ProgramState
    ) -> Tuple[programState.ProgramState, Union[programState.RunError, None]]:
        if len(regs) == 0:
            return state, None
        # head, *tail = registers

        address, _ = state.getReg("SP")
        # check address is in 0...stacksize
        if address > (state.getLabelAddress("__STACKSIZE")) or address < 0:
            return state, programState.RunError(
                "All stack entries have been pop'ed already",
                programState.RunError.ErrorType.Error)
        for reg in regs:
            err = state.loadRegister(address, 32, False, reg)
            address += 4
            if err is not None:
                return state, err
        state.setReg("SP", address)
        return state, None

    return nodes.InstructionNode(section, line, pop), tokenList
Esempio n. 3
0
def decodePUSH(
        tokenList: List[tokens.Token],
        section: nodes.Node.Section) -> Tuple[nodes.Node, List[tokens.Token]]:
    line = tokenList[0].line

    regs, tokenList = getRegisterList(tokenList, "PUSH")

    if isinstance(regs, nodes.ErrorNode):
        return regs, tokenList

    def push(
        state: programState.ProgramState
    ) -> Tuple[programState.ProgramState, Union[programState.RunError, None]]:
        if len(regs) == 0:
            return state, None
        # head, *tail = registers

        address, _ = state.getReg("SP")
        # check address is in 0...stacksize
        if address > (state.getLabelAddress("__STACKSIZE")) or address < 0:
            return state, programState.RunError(
                "Stack overflow", programState.RunError.ErrorType.Error)

        for reg in regs:
            address -= 4
            err = state.storeRegister(address, reg, 32)
            if err is not None:
                return state, err
        state.setReg("SP", address)
        return state, None

    return nodes.InstructionNode(section, line, push), tokenList
Esempio n. 4
0
def decodeTST(section: nodes.Node.Section, line: int, arg1: str, arg2: Union[int, str], arg3: Union[int, str, None]) -> nodes.Node:
    if arg3 is not None:
        return instructionsUtils.generateUnexpectedTokenError(line, (", " + arg3) if isinstance(arg3, str) else (', #' + str(arg3)), "End of line")

    if isinstance(arg2, int):
        arg2 = arg2 & 0XFFFFFFFF
        # check 8 bits
        if arg2 > 0xFF:
            return instructionsUtils.generateImmediateOutOfRangeError(line, arg2, 0xFF)

    def run(state: programState.ProgramState) -> Tuple[programState.ProgramState, Union[programState.RunError, None]]:
        a, err = state.getReg(arg1)
        if isinstance(arg2, str):
            if err is None:
                b, err = state.getReg(arg2)
            else:
                b, _ = state.getReg(arg2)
        else:
            b = arg2 & 0XFFFFFFFF

        out = a & b

        n = bool((out >> 31) & 1)
        z = out == 0

        # state.setReg(arg1, out)
        state.setALUState(programState.StatusRegister(n, z, False, False))

        return state, None
    return nodes.InstructionNode(section, line, run)
Esempio n. 5
0
def decodeROR(section: nodes.Node.Section, line: int, arg1: str, arg2: Union[int, str], arg3: Union[int, str, None]) -> nodes.Node:
    if arg3 is None:
        return instructionsUtils.generateUnexpectedTokenError(line, "End of line", "a register")

    def run(state: programState.ProgramState) -> Tuple[programState.ProgramState, Union[programState.RunError, None]]:
        a, err = state.getReg(arg2)
        if isinstance(arg3, str):
            if err is None:
                b, err = state.getReg(arg3)
            else:
                b, _ = state.getReg(arg3)
        else:
            b = arg3 & 0XFFFFFFFF

        bMod32 = b & 31
        out = (a >> bMod32) | (a << (32 - bMod32))
        out32 = out & 0xFFFF_FFFF

        if b == 0:
            c = state.status.C  # The C flag is unaffected if the shift value is 0 - ARM docs
        else:
            c = bool((a >> (bMod32-1)) & 1)  # Get last bit shifted out

        n = bool((out32 >> 31) & 1)
        z = out32 == 0

        state.setReg(arg1, out32)
        state.setALUState(programState.StatusRegister(n, z, c, False))

        return state, err
    return nodes.InstructionNode(section, line, run)
Esempio n. 6
0
def decodeBIC(section: nodes.Node.Section, line: int, arg1: str, arg2: Union[int, str], arg3: Union[int, str, None]) -> nodes.Node:
    if arg3 is None:
        # move arg2 to arg3 and copy arg1 to arg2
        arg3 = arg2
        arg2 = arg1

    if isinstance(arg3, int):
        arg3 = arg3 & 0XFFFFFFFF
        if arg3 > 0xFF:
            return instructionsUtils.generateImmediateOutOfRangeError(line, arg3, 0xFF)

    def run(state: programState.ProgramState) -> Tuple[programState.ProgramState, Union[programState.RunError, None]]:
        a, err = state.getReg(arg2)
        if isinstance(arg3, str):
            if err is None:
                b, err = state.getReg(arg3)
            else:
                b, _ = state.getReg(arg3)
        else:
            b = arg3 & 0XFFFFFFFF

        out = a & (b ^ 0xFFFF_FFFF)  # out = a & ! b

        n = bool((out >> 31) & 1)
        z = out == 0

        state.setReg(arg1, out)
        state.setALUState(programState.StatusRegister(n, z, False, False))

        return state, err
    return nodes.InstructionNode(section, line, run)
Esempio n. 7
0
def decodeBLX(tokenList: List[tokens.Token], section: nodes.Node.Section,
              link: bool) -> Tuple[nodes.Node, List[tokens.Token]]:
    if len(tokenList) == 0:
        return generateToFewTokensError(-1, "BL instruction"), []
    label, *tokenList = tokenList
    if isinstance(label, tokens.Register):

        def branchTo(
            state: programState.ProgramState
        ) -> Tuple[programState.ProgramState, Union[programState.RunError,
                                                    None]]:
            if link:
                # Save return address in LR
                state.setReg("LR", state.getReg("PC")[0])

            address, err = state.getReg(label.contents)
            # Subtract 4 because we will add 4 to the address later in the run loop and we need to start at address and not address+4
            state.setReg("PC", address - 4)
            state.hasReturned = False
            return state, err

        return nodes.InstructionNode(section, label.line, branchTo), tokenList
    else:
        # Wrong token, generate an error
        return generateUnexpectedTokenError(
            label.line, label.contents, "a label"), advanceToNewline(tokenList)
Esempio n. 8
0
def decodeBranch(
    tokenList: List[tokens.Token], section: nodes.Node.Section,
    condition: Callable[[programState.StatusRegister], bool]
) -> Tuple[nodes.Node, List[tokens.Token]]:
    if len(tokenList) == 0:
        return generateToFewTokensError(-1, "Branch instruction"), []
    label, *tokenList = tokenList
    if isinstance(label, tokens.Label):

        def branchTo(
            state: programState.ProgramState
        ) -> Tuple[programState.ProgramState, Union[programState.RunError,
                                                    None]]:
            if condition(state.status):
                address: Union[int,
                               programState.RunError] = state.getLabelAddress(
                                   label.contents)
                if isinstance(address, programState.RunError):
                    return state, address
                else:
                    # Subtract 4 because we will add 4 to the address later in the run loop and we need to start at address and not address+4
                    state.setReg("PC", address - 4)
            return state, None

        return nodes.InstructionNode(section, label.line, branchTo), tokenList
    else:
        # Wrong token, generate an error
        return generateUnexpectedTokenError(
            label.line, label.contents, "a label"), advanceToNewline(tokenList)
Esempio n. 9
0
def decodeCMN(section: nodes.Node.Section, line: int, arg1: str, arg2: Union[int, str], arg3: Union[int, str, None]) -> nodes.Node:
    if arg3 is not None:
        return instructionsUtils.generateUnexpectedTokenError(line, (", " + arg3) if isinstance(arg3, str) else (', #' + str(arg3)), "End of line")

    if isinstance(arg2, int):
        arg2 = arg2 & 0XFFFFFFFF
        # check 8 bits
        if arg2 > 0xFF:
            return instructionsUtils.generateImmediateOutOfRangeError(line, arg2, 0xFF)

    def run(state: programState.ProgramState) -> Tuple[programState.ProgramState, Union[programState.RunError, None]]:
        a = state.getReg(arg1)
        if isinstance(arg2, str):
            b = state.getReg(arg2)
        else:
            b = arg2 & 0XFFFFFFFF

        out = a + b
        out32 = out & 0xFFFFFFFF
        bit31 = (out32 >> 31) & 1

        signA = (a >> 31) & 1
        signB = (b >> 31) & 1

        v = signA == signB and signB != bit31
        c = bool((out >> 32) & 1)
        n = bool((out >> 31) & 1)
        z = out32 == 0

        # state.setReg(arg1, out32)
        state.setALUState(programState.StatusRegister(n, z, c, v))

        return state, None
    return nodes.InstructionNode(section, line, run)
Esempio n. 10
0
def decodeLSR(section: nodes.Node.Section, line: int, arg1: str, arg2: Union[int, str], arg3: Union[int, str, None]) -> nodes.Node:
    if arg3 is None:
        return instructionsUtils.generateUnexpectedTokenError(line, "End of line", "a register")

    if isinstance(arg3, int):
        arg3 = arg3 & 0XFFFFFFFF
        if arg3 > 32:
            return instructionsUtils.generateImmediateOutOfRangeError(line, arg3, 33)

    def run(state: programState.ProgramState) -> Tuple[programState.ProgramState, Union[programState.RunError, None]]:
        a = state.getReg(arg2)
        if isinstance(arg3, str):
            b = state.getReg(arg3)
            if b > 32:
                return state, programState.RunError(f"Shift value is out of range: value must be below 33 but is {b}", programState.RunError.ErrorType.Error)
        else:
            b = arg3

        out = a >> b
        out32 = out & 0xFFFF_FFFF

        if b == 0:
            c = state.status.C  # The C flag is unaffected if the shift value is 0 - ARM docs
        else:
            c = bool((a >> (b-1)) & 1)  # Get last bit shifted out
        n = bool((out32 >> 31) & 1)
        z = out32 == 0

        state.setReg(arg1, out32)
        state.setALUState(programState.StatusRegister(n, z, c, False))

        return state, None
    return nodes.InstructionNode(section, line, run)
Esempio n. 11
0
def decodeADC(section: nodes.Node.Section, line: int, arg1: str, arg2: Union[int, str], arg3: Union[int, str, None]) -> nodes.Node:
    if arg3 is None:
        # move arg2 to arg3 and copy arg1 to arg2
        arg3 = arg2
        arg2 = arg1

    if isinstance(arg3, int):
        arg3 = arg3 & 0XFFFFFFFF
        if arg1.upper() == arg2.upper():
            if arg1.upper() == "SP":
                # check 7 bits
                if arg3 > 0b0111_1111:
                    return instructionsUtils.generateImmediateOutOfRangeError(line, arg3, 0b0111_1111)
                else:
                    # multiple by 4
                    arg3 *= 4
            else:
                # check 8 bits
                if arg3 > 0xFF:
                    return instructionsUtils.generateImmediateOutOfRangeError(line, arg3, 0xFF)
        else:
            if arg2.upper() == "SP":  # arg1 can't be SP when arg2 is because arg1.upper() == arg2.upper() returned False
                # check 8 bits
                if arg3 > 0xFF:
                    return instructionsUtils.generateImmediateOutOfRangeError(line, arg3, 0xFF)
                else:
                    # multiple by 4
                    arg3 *= 4
            # check 3 bits
            if arg3 > 0b0111:
                return instructionsUtils.generateImmediateOutOfRangeError(line, arg3, 0b0111)

    def run(state: programState.ProgramState) -> Tuple[programState.ProgramState, Union[programState.RunError, None]]:
        a = state.getReg(arg2)
        if isinstance(arg3, str):
            b = state.getReg(arg3)
        else:
            b = arg3 & 0XFFFFFFFF

        # subtract one more if carry is set
        if state.status.C:
            b += 1

        out = a + b
        out32 = out & 0xFFFFFFFF
        bit31 = (out32 >> 31) & 1

        signA = (a >> 31) & 1
        signB = (b >> 31) & 1

        v = signA == signB and signB != bit31
        c = bool((out >> 32) & 1)
        n = bool((out >> 31) & 1)
        z = out32 == 0

        state.setReg(arg1, out32)
        state.setALUState(programState.StatusRegister(n, z, c, v))

        return state, None
    return nodes.InstructionNode(section, line, run)
Esempio n. 12
0
def decodeSUB(section: nodes.Node.Section, line: int, arg1: str, arg2: Union[int, str], arg3: Union[int, str, None]) -> nodes.Node:
    if arg3 is None:
        # move arg2 to arg3 and copy arg1 to arg2
        arg3 = arg2
        arg2 = arg1

    if isinstance(arg3, int):
        arg3 = arg3 & 0XFFFFFFFF
        if arg1.upper() == arg2.upper():
            if arg1.upper() == "SP":
                # check 7 bits
                if arg3 > 0b0111_1111:
                    return instructionsUtils.generateImmediateOutOfRangeError(line, arg3, 0b0111_1111)
                else:
                    # multiple by 4
                    arg3 *= 4
            else:
                # check 8 bits
                if arg3 > 0xFF:
                    return instructionsUtils.generateImmediateOutOfRangeError(line, arg3, 0xFF)
        else:
            # check 3 bits
            if arg3 > 0b0111:
                return instructionsUtils.generateImmediateOutOfRangeError(line, arg3, 0b0111)

    def run(state: programState.ProgramState) -> Tuple[programState.ProgramState, Union[programState.RunError, None]]:
        a, err = state.getReg(arg2)
        if isinstance(arg3, str):
            if err is None:
                b, err = state.getReg(arg3)
            else:
                b, _ = state.getReg(arg3)
        else:
            b = arg3 & 0XFFFFFFFF

        minusB = ((~b)+1) & 0xFFFFFFFF
        out = a + minusB
        out32 = out & 0xFFFFFFFF
        bit31 = (out32 >> 31) & 1

        signA = (a >> 31) & 1
        signB = (minusB >> 31) & 1

        v = signA == signB and signB != bit31
        c = bool((out >> 32) & 1)
        n = bool((out >> 31) & 1)
        z = out32 == 0

        state.setReg(arg1, out32)
        state.setALUState(programState.StatusRegister(n, z, c, v))

        return state, err
    return nodes.InstructionNode(section, line, run)
Esempio n. 13
0
def decodeMUL(section: nodes.Node.Section, line: int, arg1: str, arg2: Union[int, str], arg3: Union[int, str, None]) -> nodes.Node:
    if arg3 is None:
        return instructionsUtils.generateUnexpectedTokenError(line, "End of line", "a register")
    if isinstance(arg3, int):
        return instructionsUtils.generateUnexpectedTokenError(line, f'#{arg3}', "a register")

    def run(state: programState.ProgramState) -> Tuple[programState.ProgramState, Union[programState.RunError, None]]:
        a = state.getReg(arg2)
        b = state.getReg(arg3)

        out32 = (a * b) & 0xFFFFFFFF

        n = bool((out32 >> 31) & 1)
        z = out32 == 0

        state.setReg(arg1, out32)
        state.setALUState(programState.StatusRegister(n, z, state.status.C, state.status.V))

        return state, None
    return nodes.InstructionNode(section, line, run)
Esempio n. 14
0
def decodeSTR(tokenList: List[tokens.Token], section: nodes.Node.Section,
              bitSize: int) -> Tuple[nodes.Node, List[tokens.Token]]:
    if len(tokenList) == 0:
        return instructionsUtils.generateToFewTokensError(
            -1, "STR instruction"), []
    src, *tokenList = tokenList
    if len(tokenList) < 2:
        return instructionsUtils.generateToFewTokensError(
            src.line, "STR instruction"), []
    if not isinstance(src, tokens.Register):
        # Wrong token, generate an error
        return instructionsUtils.generateUnexpectedTokenError(
            src.line, src.contents, "a register or an immediate value"
        ), instructionsUtils.advanceToNewline(tokenList)
    separator, *tokenList = tokenList
    if isinstance(separator, tokens.Separator) and separator.contents == ",":
        separator, *tokenList = tokenList
        if isinstance(separator,
                      tokens.Separator) and separator.contents == "[":
            if len(tokenList) < 2:
                return instructionsUtils.generateToFewTokensError(
                    src.line, "STR instruction"), []
            dest1, *tokenList = tokenList
            if not isinstance(dest1, tokens.Register):
                # Wrong token, generate an error
                return instructionsUtils.generateUnexpectedTokenError(
                    dest1.line, dest1.contents,
                    "a register"), instructionsUtils.advanceToNewline(
                        tokenList)
            separator, *tokenList = tokenList
            if isinstance(separator,
                          tokens.Separator) and separator.contents == "]":

                def strOneReg(
                    state: programState.ProgramState
                ) -> Tuple[programState.ProgramState, Union[
                        programState.RunError, None]]:
                    adr, err = state.getReg(dest1.contents)
                    newState: Union[
                        None, programState.RunError] = state.storeRegister(
                            adr, src.contents, bitSize)
                    return state, err if newState is None else newState

                return nodes.InstructionNode(section, src.line,
                                             strOneReg), tokenList
            elif isinstance(separator,
                            tokens.Separator) and separator.contents == ",":
                if len(tokenList) < 2:
                    return instructionsUtils.generateToFewTokensError(
                        src.line, "STR instruction"), []
                dest2, separator, *tokenList = tokenList
                if isinstance(separator,
                              tokens.Separator) and separator.contents != "]":
                    return instructionsUtils.generateUnexpectedTokenError(
                        separator.line, separator.contents,
                        "']'"), instructionsUtils.advanceToNewline(tokenList)
                if isinstance(dest2, tokens.Register):

                    def strDualReg(
                        state: programState.ProgramState
                    ) -> Tuple[programState.ProgramState, Union[
                            programState.RunError, None]]:
                        adr1, err = state.getReg(dest1.contents)
                        if err is None:
                            adr2, err = state.getReg(dest2.contents)
                        else:
                            adr2, _ = state.getReg(dest2.contents)
                        newState: Union[
                            None, programState.RunError] = state.storeRegister(
                                adr1 + adr2, src.contents, bitSize)
                        return state, err if newState is None else newState

                    return nodes.InstructionNode(section, src.line,
                                                 strDualReg), tokenList
                elif isinstance(dest2, tokens.ImmediateValue):
                    dest2: tokens.ImmediateValue = dest2
                    value: int = dest2.value
                    # check bit length - 5 bits or 8 for full word relative to SP or PC
                    dest1Text = dest1.contents.upper()
                    if dest1Text == "SP" or dest1Text == "PC":
                        if bitSize == 32:
                            if value > 0xFF:
                                return instructionsUtils.generateImmediateOutOfRangeError(
                                    dest2.line, value, 0xFF), tokenList
                            else:
                                value = 4 + (value * 4)
                        else:
                            return nodes.ErrorNode(
                                f"\033[31m"  # red color
                                f"File \"$fileName$\", line {dest2.line}\n"
                                f"\tSyntax error: Cannot only store a full word relative to PC or LR"
                                f"\033[0m\n"), tokenList
                    else:
                        if value > 0b0001_1111:
                            return instructionsUtils.generateImmediateOutOfRangeError(
                                dest2.line, value, 0b0111_1111), tokenList
                        else:
                            # multiple by 4
                            if bitSize == 32:
                                value *= 4
                            elif bitSize == 16:
                                value *= 2

                    def strRegImmed(
                        state: programState.ProgramState
                    ) -> Tuple[programState.ProgramState, Union[
                            programState.RunError, None]]:
                        adr, err = state.getReg(dest1.contents)
                        newState: Union[
                            None, programState.RunError] = state.storeRegister(
                                adr + value, src.contents, bitSize)
                        return state, err if newState is None else newState

                    return nodes.InstructionNode(section, src.line,
                                                 strRegImmed), tokenList
                else:
                    # Wrong token, generate an error
                    return instructionsUtils.generateUnexpectedTokenError(
                        dest2.line, dest2.contents,
                        "a register or an immediate value"
                    ), instructionsUtils.advanceToNewline(tokenList)
            else:
                # Wrong token, generate an error
                return instructionsUtils.generateUnexpectedTokenError(
                    separator.line, separator.contents,
                    "']' or ','"), instructionsUtils.advanceToNewline(
                        tokenList)
        else:
            # Wrong token, generate an error
            return instructionsUtils.generateUnexpectedTokenError(
                separator.line, separator.contents,
                "'['"), instructionsUtils.advanceToNewline(tokenList)
    else:
        # Wrong token, generate an error
        return instructionsUtils.generateUnexpectedTokenError(
            separator.line, separator.contents,
            "','"), instructionsUtils.advanceToNewline(tokenList)
Esempio n. 15
0
def decodeLDR(tokenList: List[tokens.Token], section: nodes.Node.Section,
              bitSize: int,
              sign_extend: bool) -> Tuple[nodes.Node, List[tokens.Token]]:
    if len(tokenList) == 0:
        return instructionsUtils.generateToFewTokensError(
            -1, "LDR instruction"), []
    dest, *tokenList = tokenList
    if len(tokenList) < 2:
        return instructionsUtils.generateToFewTokensError(
            dest.line, "LDR instruction"), []
    if not isinstance(dest, tokens.Register):
        # Wrong token, generate an error
        return instructionsUtils.generateUnexpectedTokenError(
            dest.line, dest.contents, "a register or an immediate value"
        ), instructionsUtils.advanceToNewline(tokenList)
    separator, *tokenList = tokenList
    if isinstance(separator, tokens.Separator) and separator.contents == ",":
        separator, *tokenList = tokenList
        if isinstance(
                separator, tokens.LoadImmediateValue
        ) and not sign_extend:  # sign extend is not supported for this syntax
            value: int = separator.value & 0xFFFFFFFF

            def ldrImmed(
                state: programState.ProgramState
            ) -> Tuple[programState.ProgramState, Union[programState.RunError,
                                                        None]]:
                state.setReg(dest.contents, value)
                return state, None

            return nodes.InstructionNode(section, dest.line,
                                         ldrImmed), tokenList
        elif isinstance(
                separator, tokens.LoadLabel
        ) and not sign_extend:  # sign extend is not supported for this syntax
            label: tokens.LoadLabel = separator

            def ldrLabel(
                state: programState.ProgramState
            ) -> Tuple[programState.ProgramState, Union[programState.RunError,
                                                        None]]:
                val: Union[int, programState.RunError] = state.getLabelAddress(
                    label.label)
                if isinstance(val, programState.RunError):
                    return state, val
                else:
                    state.setReg(dest.contents, val)
                    return state, None

            return nodes.InstructionNode(section, dest.line,
                                         ldrLabel), tokenList
        elif isinstance(separator,
                        tokens.Separator) and separator.contents == "[":
            if len(tokenList) < 2:
                return instructionsUtils.generateToFewTokensError(
                    dest.line, "LDR instruction"), []
            src1, *tokenList = tokenList
            if not isinstance(src1, tokens.Register):
                # Wrong token, generate an error
                return instructionsUtils.generateUnexpectedTokenError(
                    src1.line, src1.contents,
                    "a register"), instructionsUtils.advanceToNewline(
                        tokenList)
            separator, *tokenList = tokenList
            if isinstance(separator,
                          tokens.Separator) and separator.contents == "]":

                def ldrOneReg(
                    state: programState.ProgramState
                ) -> Tuple[programState.ProgramState, Union[
                        programState.RunError, None]]:
                    adr, loadErr = state.getReg(src1.contents)
                    err: Union[None,
                               programState.RunError] = state.loadRegister(
                                   adr, bitSize, sign_extend, dest.contents)
                    return state, loadErr if err is None else err

                return nodes.InstructionNode(section, dest.line,
                                             ldrOneReg), tokenList
            elif isinstance(separator,
                            tokens.Separator) and separator.contents == ",":
                if len(tokenList) < 2:
                    return instructionsUtils.generateToFewTokensError(
                        dest.line, "LDR instruction"), []
                src2, separator, *tokenList = tokenList
                if isinstance(separator,
                              tokens.Separator) and separator.contents != "]":
                    return instructionsUtils.generateUnexpectedTokenError(
                        separator.line, separator.contents,
                        "']'"), instructionsUtils.advanceToNewline(tokenList)
                if isinstance(src2, tokens.Register):

                    def ldrDualReg(
                        state: programState.ProgramState
                    ) -> Tuple[programState.ProgramState, Union[
                            programState.RunError, None]]:
                        adr1, loadErr = state.getReg(src1.contents)
                        if loadErr is None:
                            adr2, loadErr = state.getReg(src2.contents)
                        else:
                            adr2, _ = state.getReg(src2.contents)
                        err: Union[None,
                                   programState.RunError] = state.loadRegister(
                                       adr1 + adr2, bitSize, sign_extend,
                                       dest.contents)
                        return state, loadErr if err is None else err

                    return nodes.InstructionNode(section, dest.line,
                                                 ldrDualReg), tokenList
                elif isinstance(src2, tokens.ImmediateValue):
                    src2: tokens.ImmediateValue = src2
                    value: int = src2.value
                    # check bit length - 5 bits or 8 for full word relative to SP or PC
                    src1Text = src1.contents.upper()
                    if src1Text == "SP" or src1Text == "PC":
                        if bitSize == 32:
                            if value > 0xFF:
                                return instructionsUtils.generateImmediateOutOfRangeError(
                                    src2.line, value, 0xFF), tokenList
                            else:
                                value = 4 + (value * 4)
                        else:
                            return nodes.ErrorNode(
                                f"\033[31m"  # red color
                                f"File \"$fileName$\", line {src2.line}\n"
                                f"\tSyntax error: Cannot only load a full word relative to PC or LR"
                                f"\033[0m\n"), tokenList
                    else:
                        if value > 0b0001_1111:
                            return instructionsUtils.generateImmediateOutOfRangeError(
                                src2.line, value, 0b0111_1111), tokenList
                        else:
                            # multiple by 4
                            if bitSize == 32:
                                value *= 4
                            elif bitSize == 16:
                                value *= 2

                    def ldrRegImmed(
                        state: programState.ProgramState
                    ) -> Tuple[programState.ProgramState, Union[
                            programState.RunError, None]]:
                        adr, loadErr = state.getReg(src1.contents)
                        err: Union[None,
                                   programState.RunError] = state.loadRegister(
                                       adr + value, bitSize, sign_extend,
                                       dest.contents)
                        return state, loadErr if err is None else err

                    return nodes.InstructionNode(section, dest.line,
                                                 ldrRegImmed), tokenList
                else:
                    # Wrong token, generate an error
                    return instructionsUtils.generateUnexpectedTokenError(
                        src2.line, src2.contents,
                        "a register or an immediate value"
                    ), instructionsUtils.advanceToNewline(tokenList)
            else:
                # Wrong token, generate an error
                return instructionsUtils.generateUnexpectedTokenError(
                    separator.line, separator.contents,
                    "']' or ','"), instructionsUtils.advanceToNewline(
                        tokenList)
        else:
            # Wrong token, generate an error
            return instructionsUtils.generateUnexpectedTokenError(
                separator.line, separator.contents,
                "'['"), instructionsUtils.advanceToNewline(tokenList)
    else:
        # Wrong token, generate an error
        return instructionsUtils.generateUnexpectedTokenError(
            separator.line, separator.contents,
            "','"), instructionsUtils.advanceToNewline(tokenList)
Esempio n. 16
0
def decodeExtend(tokenList: List[tokens.Token], section: nodes.Node.Section,
                 signed: bool,
                 halfWord: bool) -> Tuple[nodes.Node, List[tokens.Token]]:
    if halfWord:
        if signed:
            instrName = "SXTH"
        else:
            instrName = "UXTH"
    else:
        if signed:
            instrName = "SXTB"
        else:
            instrName = "UXTB"
    if len(tokenList) == 0:
        return generateToFewTokensError(-1, f"{instrName} instruction"), []
    dest, *tokenList = tokenList
    if len(tokenList) < 2:
        return generateToFewTokensError(dest.line,
                                        f"{instrName} instruction"), []
    if not isinstance(dest, tokens.Register):
        # Wrong token, generate an error
        return generateUnexpectedTokenError(
            dest.line, dest.contents,
            "a register"), advanceToNewline(tokenList)
    separator, *tokenList = tokenList
    if isinstance(separator, tokens.Separator) and separator.contents == ",":
        src, *tokenList = tokenList
        if isinstance(src, tokens.Register):

            def movReg(
                state: programState.ProgramState
            ) -> Tuple[programState.ProgramState, Union[programState.RunError,
                                                        None]]:
                value, err = state.getReg(src.contents)
                if halfWord:
                    if signed:
                        if (value & 0b1000_0000_0000_0000
                            ) == 0b1000_0000_0000_0000:
                            value |= 0xFFFF_0000  # Set upper half-word when sign bit is set
                        else:
                            value &= 0xFFFF
                    else:
                        value &= 0xFFFF
                else:
                    if signed:
                        if (value & 0b1000_0000) == 0b1000_0000:
                            value |= 0xFFFF_FF00  # Set upper three bytes when sign bit is set
                        else:
                            value &= 0xFF
                    else:
                        value &= 0xFF

                state.setReg(dest.contents, value)
                return state, err

            return nodes.InstructionNode(section, dest.line, movReg), tokenList
        else:
            # Wrong token, generate an error
            return generateUnexpectedTokenError(
                src.line, src.contents,
                "a register"), advanceToNewline(tokenList)
    else:
        # Wrong token, generate an error
        return generateUnexpectedTokenError(separator.line, separator.contents,
                                            "','"), advanceToNewline(tokenList)