Ejemplo n.º 1
0
    def fix_addresses(self, statements, this_index):
        """
        Once all of the statements have been translated, all of the addresses
        must be 'fixed'. In particular, branch operations need to know how
        many statements they need to skip ahead or behind, and the address
        at the target statement. This function calculates what the target
        of a branch, jump or subroutine call needs to go to, and inserts
        it in the code package for the assembled instruction.

        :param statements: the full set of statements that make up the proram
        :param this_index: the index that this instruction occurs at
        """
        if self.operand.is_type(OperandType.RELATIVE):
            base_value = 0x101 if self.instruction.is_short_branch else 0x10001
            branch_index = self.code_pkg.additional.int
            size_hint = 2 if self.instruction.is_short_branch else 4
            length = 0
            if branch_index < this_index:
                length = 1
                for statement in statements[branch_index:this_index + 1]:
                    length += statement.code_pkg.size
                self.code_pkg.additional = NumericValue(base_value - length,
                                                        size_hint=size_hint)
            else:
                for statement in statements[this_index + 1:branch_index]:
                    length += statement.code_pkg.size
                self.code_pkg.additional = NumericValue(length,
                                                        size_hint=size_hint)
            return

        if self.operand.value.is_type(ValueType.ADDRESS):
            self.code_pkg.additional = statements[
                self.operand.value.int].code_pkg.address
Ejemplo n.º 2
0
 def test_save_file_works_correct(self):
     cassette_file = CassetteFile(NumericValue(0x1234), NumericValue(0x5678))
     raw_bytes = [0x02]
     expected = [
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x3C, 0x00, 0x0F, 0x74, 0x65, 0x73, 0x74, 0x66, 0x69, 0x6C, 0x65, 0x02, 0x00, 0x00, 0x12,
         0x34, 0x56, 0x78, 0x85, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x3C, 0x01, 0x01, 0x02, 0x04, 0x55, 0x55, 0x3C, 0xFF, 0x00,
         0xFF, 0x55
     ]
     cassette_file.host_file = MockFile()
     cassette_file.save_file("testfile", raw_bytes)
     self.assertEqual(expected, [value for value in cassette_file.host_file.value])
Ejemplo n.º 3
0
 def test_save_file_works_correct(self):
     cassette_file = CassetteFile()
     raw_bytes = [0x02]
     expected = [
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x3C, 0x00, 0x0F, 0x74, 0x65, 0x73, 0x74, 0x66, 0x69, 0x6C, 0x65, 0x02, 0x00, 0x00, 0x12,
         0x34, 0x56, 0x78, 0x85, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
         0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x3C, 0x01, 0x01, 0x02, 0x04, 0x55, 0x55, 0x3C, 0xFF, 0x00,
         0xFF, 0x55
     ]
     cassette_file.host_file = MockFile()
     coco_file = CoCoFile(
         name="testfile",
         load_addr=NumericValue(0x1234),
         exec_addr=NumericValue(0x5678),
         data=raw_bytes
     )
     cassette_file.save_to_host_file(coco_file)
     self.assertEqual(expected, [value for value in cassette_file.host_file.value])
Ejemplo n.º 4
0
    def test_numeric_from_character_literal_word_character_is_correct(self):
        for char_val in range(65, 91):
            result = NumericValue("'{}".format(chr(char_val)))
            self.assertEqual(char_val, result.int)

        for char_val in range(97, 123):
            result = NumericValue("'{}".format(chr(char_val)))
            self.assertEqual(char_val, result.int)
Ejemplo n.º 5
0
 def test_get_binary_array_all_correct(self):
     statement1 = Statement("    JMP $FFFF")
     statement1.code_pkg.op_code = NumericValue("$DEAD")
     statement1.code_pkg.post_byte = NumericValue("$BEEF")
     statement1.code_pkg.additional = NumericValue("$CAFE")
     program = Program()
     program.statements = [statement1]
     self.assertEqual([0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE], program.get_binary_array())
Ejemplo n.º 6
0
 def test_append_header_correct(self):
     name = "testfile"
     expected = [0x55, 0x3C, 0x00, 0x0F, 0x74, 0x65, 0x73, 0x74, 0x66, 0x69, 0x6C, 0x65, 0x02, 0xFF, 0x00, 0x12,
                 0x34, 0x56, 0x78, 0x84, 0x55]
     buffer = []
     cassette_file = CassetteFile(NumericValue(0x1234), NumericValue(0x5678))
     cassette_file.append_header(buffer, name, CassetteFileType.OBJECT_FILE, CassetteDataType.ASCII)
     self.assertEqual(expected, buffer)
Ejemplo n.º 7
0
    def fix_pcr_relative_addresses(self, statements, this_index):
        """
        Once all of the statements have been translated, then we need to
        check whether program counter relative indexed statements can
        be 8-bit, or if they must be 16-bit. This operation changes the
        size of a code package depending on how many steps away a statement
        is. To calculate the relative offset, we use a cheat - since we
        don't yet know how big any of the PCR statements are, we count the
        size of each instruction between the PCR statement using the code
        package's max_size. This tells us potentially how large the statements
        will be. If they are bigger than an 8-bit value, then we can default
        to a 16-bit offset. There may be edge cases where this heuristic may fail,
        most notably when there is a PCR statement that has not yet been resolved
        to be 8-bit, and would change the max_size calculation to be a valid
        8-bit offset value instead.

        :param statements: the full set of statements that make up the program
        :param this_index: the index that this instruction occurs at
        """
        if not self.code_pkg.additional_needs_resolution or not self.code_pkg.post_byte_choices:
            return

        if self.operand.left.is_address_expression():
            relative_index = self.operand.left.extract_address_index_from_expression(
            )
        else:
            relative_index = self.code_pkg.additional.int

        if relative_index > this_index:
            total_size = 0
            raw_post_byte = self.code_pkg.post_byte.int
            for x in range(this_index, relative_index):
                total_size += statements[x].code_pkg.max_size
            if total_size <= 255:
                self.code_pkg.size += 1
                raw_post_byte |= self.code_pkg.post_byte_choices[0]
            else:
                self.code_pkg.size += 2
                raw_post_byte |= self.code_pkg.post_byte_choices[1]
            self.code_pkg.post_byte = NumericValue(raw_post_byte)
        else:
            total_size = 0
            raw_post_byte = self.code_pkg.post_byte.int
            for x in range(relative_index, this_index):
                total_size += statements[x].code_pkg.max_size
            if total_size <= 255:
                self.code_pkg.size += 1
                raw_post_byte |= self.code_pkg.post_byte_choices[0]
            else:
                self.code_pkg.size += 2
                raw_post_byte |= self.code_pkg.post_byte_choices[1]
            self.code_pkg.post_byte = NumericValue(raw_post_byte)
Ejemplo n.º 8
0
    def resolve_symbols(self, symbol_table):
        """
        Given a symbol table, searches the operands for any symbols, and resolves
        them with values from the symbol table. Returns a (possibly) new Operand
        class type as a result of symbol resolution.

        :param symbol_table: the symbol table to search
        :return: self, or a new Operand class type with a resolved value
        """
        if self.is_type(OperandType.EXPRESSION):
            return self.resolve_expression(symbol_table)

        if not self.value.is_type(ValueType.SYMBOL):
            return self

        symbol = self.get_symbol(self.value.ascii(), symbol_table)

        if symbol.is_type(ValueType.ADDRESS):
            self.value = AddressValue(symbol.int)
            if self.type == OperandType.UNKNOWN:
                return ExtendedOperand(self.operand_string,
                                       self.instruction,
                                       value=self.value)
            return self

        if symbol.is_type(ValueType.NUMERIC):
            self.value = copy(symbol)
            if self.value.hex_len() == 2:
                return DirectOperand(self.operand_string,
                                     self.instruction,
                                     value=self.value)
            return ExtendedOperand(self.operand_string,
                                   self.instruction,
                                   value=self.value)
Ejemplo n.º 9
0
 def translate(self):
     code_pkg = CodePackage()
     code_pkg.op_code = NumericValue(self.instruction.mode.rel)
     if self.value.is_type(ValueType.ADDRESS):
         code_pkg.additional = self.value
     code_pkg.size = self.instruction.mode.rel_sz
     return code_pkg
Ejemplo n.º 10
0
 def test_numeric_raises_exception_on_invalid_strings(self):
     with self.assertRaises(ValueTypeError) as context:
         NumericValue("this is not a valid string")
     self.assertEqual(
         "[this is not a valid string] is not valid integer, character literal, or hex value",
         str(context.exception)
     )
Ejemplo n.º 11
0
 def translate(self):
     return CodePackage(
         op_code=NumericValue(self.instruction.mode.rel),
         additional=self.value if self.value.is_address() else NoneValue(),
         size=self.instruction.mode.rel_sz,
         max_size=self.instruction.mode.rel_sz,
     )
Ejemplo n.º 12
0
 def translate(self):
     if not self.instruction.mode.ext:
         raise ValueError(
             "Instruction [{}] does not support extended addressing".format(
                 self.instruction.mnemonic))
     return CodePackage(op_code=NumericValue(self.instruction.mode.ext),
                        additional=self.value,
                        size=self.instruction.mode.ext_sz)
Ejemplo n.º 13
0
 def translate(self):
     if not self.instruction.mode.inh:
         raise OperandTypeError("Instruction [{}] requires an operand".format(self.instruction.mnemonic))
     return CodePackage(
         op_code=NumericValue(self.instruction.mode.inh),
         size=self.instruction.mode.inh_sz,
         max_size=self.instruction.mode.inh_sz,
     )
Ejemplo n.º 14
0
 def translate(self):
     if not self.instruction.mode.dir:
         raise OperandTypeError(
             "Instruction [{}] does not support direct addressing".format(self.instruction.mnemonic)
         )
     return CodePackage(
         op_code=NumericValue(self.instruction.mode.dir),
         additional=self.value,
         size=self.instruction.mode.dir_sz,
         max_size=self.instruction.mode.dir_sz,
     )
Ejemplo n.º 15
0
    def translate(self):
        if self.instruction.mnemonic == "FCB":
            return CodePackage(additional=NumericValue(self.value.int, size_hint=2), size=1, max_size=1)

        if self.instruction.mnemonic == "FDB":
            return CodePackage(additional=NumericValue(self.value.int, size_hint=4), size=2, max_size=2)

        if self.instruction.mnemonic == "RMB":
            return CodePackage(
                additional=NumericValue(0, size_hint=self.value.int*2),
                size=self.value.int,
                max_size=self.value.int,
            )

        if self.instruction.mnemonic == "ORG":
            return CodePackage(address=self.value)

        if self.instruction.mnemonic == "FCC":
            return CodePackage(additional=self.value, size=self.value.byte_len(), max_size=self.value.byte_len())

        return CodePackage()
Ejemplo n.º 16
0
    def set_address(self, address):
        """
        This function sets the address where this statement should be located
        in memory. If the address is not already set, it will set the address
        and return the address that was set. If the address was already set
        (for example, in an ORG operation), it will return that address
        instead.

        :param address: the address to set for the statement
        :return: the address that was set or returned
        """
        if not self.code_pkg.address.is_type(ValueType.NONE):
            return self.code_pkg.address.int
        self.code_pkg.address = NumericValue(address)
        return self.code_pkg.address.int
Ejemplo n.º 17
0
    def resolve_expression(self, symbol_table):
        """
        Attempts to resolve the expression contained in the operand using the
        symbol table supplied. Returns a (possibly) new Operand class type as a
        result of symbol resolution.

        :param symbol_table: the symbol table to use for resolution
        :return: self, or a new Operand class type with a resolved value
        """
        if self.left.is_type(ValueType.SYMBOL):
            self.left = self.get_symbol(self.left.ascii(), symbol_table)

        if self.right.is_type(ValueType.SYMBOL):
            self.right = self.get_symbol(self.right.ascii(), symbol_table)

        if self.right.is_type(ValueType.NUMERIC) and self.left.is_type(
                ValueType.NUMERIC):
            left = self.left.int
            right = self.right.int
            if self.operation == "+":
                self.value = NumericValue("{}".format(left + right))
            if self.operation == "-":
                self.value = NumericValue("{}".format(left - right))
            if self.operation == "*":
                self.value = NumericValue("{}".format(int(left * right)))
            if self.operation == "/":
                self.value = NumericValue("{}".format(int(left / right)))
            if self.value.hex_len() == 2:
                return DirectOperand(self.operand_string,
                                     self.instruction,
                                     value=self.value)
            return ExtendedOperand(self.operand_string,
                                   self.instruction,
                                   value=self.value)

        raise ValueError("[{}] unresolved expression".format(
            self.operand_string))
Ejemplo n.º 18
0
    def translate(self):
        if not self.instruction.mode.ind:
            raise ValueError(
                "Instruction [{}] does not support indexed addressing".format(
                    self.instruction.mnemonic))
        raw_post_byte = 0x00
        size = self.instruction.mode.ind_sz
        additional = NoneValue()

        # Determine register (if any)
        if "X" in self.right:
            raw_post_byte |= 0x00
        if "Y" in self.right:
            raw_post_byte |= 0x20
        if "U" in self.right:
            raw_post_byte |= 0x40
        if "S" in self.right:
            raw_post_byte |= 0x60

        if self.left == "":
            raw_post_byte |= 0x80
            if "-" in self.right or "+" in self.right:
                if "+" in self.right:
                    raw_post_byte |= 0x00
                if "++" in self.right:
                    raw_post_byte |= 0x01
                if "-" in self.right:
                    raw_post_byte |= 0x02
                if "--" in self.right:
                    raw_post_byte |= 0x03
            else:
                raw_post_byte |= 0x04

        elif self.left == "A" or self.left == "B" or self.left == "D":
            raw_post_byte |= 0x80
            if self.left == "A":
                raw_post_byte |= 0x06
            if self.left == "B":
                raw_post_byte |= 0x05
            if self.left == "D":
                raw_post_byte |= 0x0B

        else:
            if "+" in self.right or "-" in self.right:
                raise ValueError("[{}] invalid indexed expression".format(
                    self.operand_string))
            if type(self.left) == str:
                self.left = NumericValue(self.left)
            if self.left.is_type(ValueType.ADDRESS):
                raise ValueError(
                    "[{}] cannot translate address in left hand side".format(
                        self.operand_string))
            numeric = self.left
            if numeric.byte_len() == 2:
                size += 2
                if "PC" in self.right:
                    raw_post_byte |= 0x8D
                    additional = numeric
                else:
                    raw_post_byte |= 0x89
                    additional = numeric
            elif numeric.byte_len() == 1:
                if "PC" in self.right:
                    raw_post_byte |= 0x8C
                    additional = numeric
                    size += 1
                else:
                    if numeric.int <= 0x1F:
                        raw_post_byte |= numeric.int
                    else:
                        raw_post_byte |= 0x88
                        additional = numeric
                        size += 1

        return CodePackage(op_code=NumericValue(self.instruction.mode.ind),
                           post_byte=NumericValue(raw_post_byte),
                           additional=additional,
                           size=size)
Ejemplo n.º 19
0
class IndexedOperand(Operand):
    def __init__(self, operand_string, instruction):
        super().__init__(instruction)
        self.type = OperandType.INDEXED
        self.operand_string = operand_string
        self.right = ""
        self.left = ""
        if "," not in operand_string or instruction.is_string_define:
            raise ValueError(
                "[{}] is not an indexed value".format(operand_string))
        if len(operand_string.split(",")) != 2:
            raise ValueError(
                "[{}] incorrect number of commas in indexed value".format(
                    operand_string))
        self.left, self.right = operand_string.split(",")

    def resolve_symbols(self, symbol_table):
        if self.left != "":
            if self.left != "A" and self.left != "B" and self.left != "D":
                self.left = Value.create_from_str(self.left, self.instruction)
                if self.left.is_type(ValueType.SYMBOL):
                    self.left = self.get_symbol(self.left.ascii(),
                                                symbol_table)
        return self

    def translate(self):
        if not self.instruction.mode.ind:
            raise ValueError(
                "Instruction [{}] does not support indexed addressing".format(
                    self.instruction.mnemonic))
        raw_post_byte = 0x00
        size = self.instruction.mode.ind_sz
        additional = NoneValue()

        # Determine register (if any)
        if "X" in self.right:
            raw_post_byte |= 0x00
        if "Y" in self.right:
            raw_post_byte |= 0x20
        if "U" in self.right:
            raw_post_byte |= 0x40
        if "S" in self.right:
            raw_post_byte |= 0x60

        if self.left == "":
            raw_post_byte |= 0x80
            if "-" in self.right or "+" in self.right:
                if "+" in self.right:
                    raw_post_byte |= 0x00
                if "++" in self.right:
                    raw_post_byte |= 0x01
                if "-" in self.right:
                    raw_post_byte |= 0x02
                if "--" in self.right:
                    raw_post_byte |= 0x03
            else:
                raw_post_byte |= 0x04

        elif self.left == "A" or self.left == "B" or self.left == "D":
            raw_post_byte |= 0x80
            if self.left == "A":
                raw_post_byte |= 0x06
            if self.left == "B":
                raw_post_byte |= 0x05
            if self.left == "D":
                raw_post_byte |= 0x0B

        else:
            if "+" in self.right or "-" in self.right:
                raise ValueError("[{}] invalid indexed expression".format(
                    self.operand_string))
            if type(self.left) == str:
                self.left = NumericValue(self.left)
            if self.left.is_type(ValueType.ADDRESS):
                raise ValueError(
                    "[{}] cannot translate address in left hand side".format(
                        self.operand_string))
            numeric = self.left
            if numeric.byte_len() == 2:
                size += 2
                if "PC" in self.right:
                    raw_post_byte |= 0x8D
                    additional = numeric
                else:
                    raw_post_byte |= 0x89
                    additional = numeric
            elif numeric.byte_len() == 1:
                if "PC" in self.right:
                    raw_post_byte |= 0x8C
                    additional = numeric
                    size += 1
                else:
                    if numeric.int <= 0x1F:
                        raw_post_byte |= numeric.int
                    else:
                        raw_post_byte |= 0x88
                        additional = numeric
                        size += 1

        return CodePackage(op_code=NumericValue(self.instruction.mode.ind),
                           post_byte=NumericValue(raw_post_byte),
                           additional=additional,
                           size=size)
Ejemplo n.º 20
0
class Operand(ABC):
    def __init__(self, instruction, value=None):
        self.type = OperandType.UNKNOWN
        self.operand_string = ""
        self.instruction = instruction
        self.requires_resolution = False
        self.value = value if value else NoneValue(None)
        self.left = NoneValue(None)
        self.right = NoneValue(None)
        self.operation = ""

    @classmethod
    def create_from_str(cls, operand_string, instruction):
        try:
            return PseudoOperand(operand_string, instruction)
        except ValueError:
            pass

        try:
            return SpecialOperand(operand_string, instruction)
        except ValueError:
            pass

        try:
            return RelativeOperand(operand_string, instruction)
        except ValueError:
            pass

        try:
            return InherentOperand(operand_string, instruction)
        except ValueError:
            pass

        try:
            return ImmediateOperand(operand_string, instruction)
        except ValueError:
            pass

        try:
            return DirectOperand(operand_string, instruction)
        except ValueError:
            pass

        try:
            return ExtendedOperand(operand_string, instruction)
        except ValueError:
            pass

        try:
            return ExtendedIndexedOperand(operand_string, instruction)
        except ValueError:
            pass

        try:
            return IndexedOperand(operand_string, instruction)
        except ValueError:
            pass

        try:
            return ExpressionOperand(operand_string, instruction)
        except ValueError:
            pass

        try:
            return UnknownOperand(operand_string, instruction)
        except ValueError:
            pass

        raise ValueError("[{}] unknown operand type".format(operand_string))

    def is_type(self, operand_type):
        """
        Returns True if the type of this operand class is the type being compared.

        :param operand_type: the OperandType to check
        :return: True if the OperandType values match, False otherwise
        """
        return self.type == operand_type

    def resolve_symbols(self, symbol_table):
        """
        Given a symbol table, searches the operands for any symbols, and resolves
        them with values from the symbol table. Returns a (possibly) new Operand
        class type as a result of symbol resolution.

        :param symbol_table: the symbol table to search
        :return: self, or a new Operand class type with a resolved value
        """
        if self.is_type(OperandType.EXPRESSION):
            return self.resolve_expression(symbol_table)

        if not self.value.is_type(ValueType.SYMBOL):
            return self

        symbol = self.get_symbol(self.value.ascii(), symbol_table)

        if symbol.is_type(ValueType.ADDRESS):
            self.value = AddressValue(symbol.int)
            if self.type == OperandType.UNKNOWN:
                return ExtendedOperand(self.operand_string,
                                       self.instruction,
                                       value=self.value)
            return self

        if symbol.is_type(ValueType.NUMERIC):
            self.value = copy(symbol)
            if self.value.hex_len() == 2:
                return DirectOperand(self.operand_string,
                                     self.instruction,
                                     value=self.value)
            return ExtendedOperand(self.operand_string,
                                   self.instruction,
                                   value=self.value)

    def resolve_expression(self, symbol_table):
        """
        Attempts to resolve the expression contained in the operand using the
        symbol table supplied. Returns a (possibly) new Operand class type as a
        result of symbol resolution.

        :param symbol_table: the symbol table to use for resolution
        :return: self, or a new Operand class type with a resolved value
        """
        if self.left.is_type(ValueType.SYMBOL):
            self.left = self.get_symbol(self.left.ascii(), symbol_table)

        if self.right.is_type(ValueType.SYMBOL):
            self.right = self.get_symbol(self.right.ascii(), symbol_table)

        if self.right.is_type(ValueType.NUMERIC) and self.left.is_type(
                ValueType.NUMERIC):
            left = self.left.int
            right = self.right.int
            if self.operation == "+":
                self.value = NumericValue("{}".format(left + right))
            if self.operation == "-":
                self.value = NumericValue("{}".format(left - right))
            if self.operation == "*":
                self.value = NumericValue("{}".format(int(left * right)))
            if self.operation == "/":
                self.value = NumericValue("{}".format(int(left / right)))
            if self.value.hex_len() == 2:
                return DirectOperand(self.operand_string,
                                     self.instruction,
                                     value=self.value)
            return ExtendedOperand(self.operand_string,
                                   self.instruction,
                                   value=self.value)

        raise ValueError("[{}] unresolved expression".format(
            self.operand_string))

    @staticmethod
    def get_symbol(symbol_label, symbol_table):
        if symbol_label not in symbol_table:
            raise ValueError("[{}] not in symbol table".format(symbol_label))
        return symbol_table[symbol_label]

    @abstractmethod
    def translate(self):
        """
Ejemplo n.º 21
0
    def translate(self):
        if not self.instruction.mode.ind:
            raise ValueError(
                "Instruction [{}] does not support indexed addressing".format(
                    self.instruction.mnemonic))
        size = self.instruction.mode.ind_sz

        if not type(self.value) == str and self.value.is_type(
                ValueType.ADDRESS):
            size += 2
            return CodePackage(op_code=NumericValue(self.instruction.mode.ind),
                               post_byte=NumericValue(0x9F),
                               additional=self.value,
                               size=size)

        if not type(self.value) == str and self.value.is_type(
                ValueType.NUMERIC):
            size += 2
            return CodePackage(op_code=NumericValue(self.instruction.mode.ind),
                               post_byte=NumericValue(0x9F),
                               additional=self.value,
                               size=size)

        raw_post_byte = 0x80
        additional = NoneValue()

        if "X" in self.right:
            raw_post_byte |= 0x00
        if "Y" in self.right:
            raw_post_byte |= 0x20
        if "U" in self.right:
            raw_post_byte |= 0x40
        if "S" in self.right:
            raw_post_byte |= 0x60

        if self.left == "":
            if "-" in self.right or "+" in self.right:
                if self.right == "X+" or self.right == "Y+" or self.right == "U+" or self.right == "S+":
                    raise ValueError(
                        "[{}] not allowed as an extended indirect value".
                        format(self.right))
                if self.right == "-X" or self.right == "-Y" or self.right == "-U" or self.right == "-S":
                    raise ValueError(
                        "[{}] not allowed as an extended indirect value".
                        format(self.right))
                if "++" in self.right:
                    raw_post_byte |= 0x11
                if "--" in self.right:
                    raw_post_byte |= 0x13
            else:
                raw_post_byte |= 0x14

        elif self.left == "A" or self.left == "B" or self.left == "D":
            if self.left == "A":
                raw_post_byte |= 0x16
            if self.left == "B":
                raw_post_byte |= 0x15
            if self.left == "D":
                raw_post_byte |= 0x1B

        else:
            if "+" in self.right or "-" in self.right:
                raise ValueError("[{}] invalid indexed expression".format(
                    self.operand_string))
            if type(self.left) == str:
                self.left = NumericValue(self.left)
            if self.left.is_type(ValueType.ADDRESS):
                raise ValueError(
                    "[{}] cannot translate address in left hand side".format(
                        self.operand_string))
            numeric = self.left
            if numeric.byte_len() == 2:
                size += 2
                if "PC" in self.right:
                    raw_post_byte |= 0x9D
                    additional = numeric
                else:
                    raw_post_byte |= 0x99
                    additional = numeric
            elif numeric.byte_len() == 1:
                size += 1
                if "PC" in self.right:
                    raw_post_byte |= 0x9C
                    additional = numeric
                else:
                    raw_post_byte |= 0x98
                    additional = numeric

        return CodePackage(op_code=NumericValue(self.instruction.mode.ind),
                           post_byte=NumericValue(raw_post_byte),
                           additional=additional,
                           size=size)
Ejemplo n.º 22
0
class ExtendedIndexedOperand(Operand):
    def __init__(self, operand_string, instruction, value=None):
        super().__init__(instruction)
        self.type = OperandType.EXTENDED_INDIRECT
        self.operand_string = operand_string
        self.left = None
        self.right = None
        if value is not None:
            self.value = value
            return
        match = EXTENDED_INDIRECT_REGEX.match(self.operand_string)
        if not match:
            raise ValueError(
                "[{}] is not an extended indexed value".format(operand_string))
        parsed_value = match.group("value")
        if "," not in parsed_value:
            self.value = Value.create_from_str(parsed_value, self.instruction)
        elif len(parsed_value.split(",")) == 2:
            self.left, self.right = parsed_value.split(",")
        else:
            raise ValueError(
                "[{}] incorrect number of commas in extended indexed value".
                format(operand_string))

    def resolve_symbols(self, symbol_table):
        if not self.value.is_type(ValueType.NONE) and self.value.is_type(
                ValueType.SYMBOL):
            self.value = self.get_symbol(self.value.ascii(), symbol_table)
            return self

        if self.left and self.left != "":
            if self.left != "A" and self.left != "B" and self.left != "D":
                self.left = Value.create_from_str(self.left, self.instruction)
                if self.left.is_type(ValueType.SYMBOL):
                    self.left = self.get_symbol(self.left.ascii(),
                                                symbol_table)
        return self

    def translate(self):
        if not self.instruction.mode.ind:
            raise ValueError(
                "Instruction [{}] does not support indexed addressing".format(
                    self.instruction.mnemonic))
        size = self.instruction.mode.ind_sz

        if not type(self.value) == str and self.value.is_type(
                ValueType.ADDRESS):
            size += 2
            return CodePackage(op_code=NumericValue(self.instruction.mode.ind),
                               post_byte=NumericValue(0x9F),
                               additional=self.value,
                               size=size)

        if not type(self.value) == str and self.value.is_type(
                ValueType.NUMERIC):
            size += 2
            return CodePackage(op_code=NumericValue(self.instruction.mode.ind),
                               post_byte=NumericValue(0x9F),
                               additional=self.value,
                               size=size)

        raw_post_byte = 0x80
        additional = NoneValue()

        if "X" in self.right:
            raw_post_byte |= 0x00
        if "Y" in self.right:
            raw_post_byte |= 0x20
        if "U" in self.right:
            raw_post_byte |= 0x40
        if "S" in self.right:
            raw_post_byte |= 0x60

        if self.left == "":
            if "-" in self.right or "+" in self.right:
                if self.right == "X+" or self.right == "Y+" or self.right == "U+" or self.right == "S+":
                    raise ValueError(
                        "[{}] not allowed as an extended indirect value".
                        format(self.right))
                if self.right == "-X" or self.right == "-Y" or self.right == "-U" or self.right == "-S":
                    raise ValueError(
                        "[{}] not allowed as an extended indirect value".
                        format(self.right))
                if "++" in self.right:
                    raw_post_byte |= 0x11
                if "--" in self.right:
                    raw_post_byte |= 0x13
            else:
                raw_post_byte |= 0x14

        elif self.left == "A" or self.left == "B" or self.left == "D":
            if self.left == "A":
                raw_post_byte |= 0x16
            if self.left == "B":
                raw_post_byte |= 0x15
            if self.left == "D":
                raw_post_byte |= 0x1B

        else:
            if "+" in self.right or "-" in self.right:
                raise ValueError("[{}] invalid indexed expression".format(
                    self.operand_string))
            if type(self.left) == str:
                self.left = NumericValue(self.left)
            if self.left.is_type(ValueType.ADDRESS):
                raise ValueError(
                    "[{}] cannot translate address in left hand side".format(
                        self.operand_string))
            numeric = self.left
            if numeric.byte_len() == 2:
                size += 2
                if "PC" in self.right:
                    raw_post_byte |= 0x9D
                    additional = numeric
                else:
                    raw_post_byte |= 0x99
                    additional = numeric
            elif numeric.byte_len() == 1:
                size += 1
                if "PC" in self.right:
                    raw_post_byte |= 0x9C
                    additional = numeric
                else:
                    raw_post_byte |= 0x98
                    additional = numeric

        return CodePackage(op_code=NumericValue(self.instruction.mode.ind),
                           post_byte=NumericValue(raw_post_byte),
                           additional=additional,
                           size=size)
Ejemplo n.º 23
0
 def test_symbol_byte_len_correct_when_resolved(self):
     result = SymbolValue('symbol')
     result.resolved = True
     result.value = NumericValue("$AB")
     self.assertEqual(1, result.byte_len())
Ejemplo n.º 24
0
 def test_expression_symbol_left_resolves_correctly(self):
     symbol_table = {"VAR": NumericValue("$FE", mode=ExplicitAddressingMode.DIRECT)}
     result = ExpressionValue("VAR+1")
     result = result.resolve(symbol_table)
     self.assertEqual(result.hex(), "FF")
Ejemplo n.º 25
0
    def translate(self):
        code_pkg = CodePackage()
        code_pkg.op_code = NumericValue(self.instruction.mode.imm)
        code_pkg.size = self.instruction.mode.imm_sz
        code_pkg.post_byte = 0x00

        if self.instruction.mnemonic == "PSHS" or self.instruction.mnemonic == "PULS":
            if not self.operand_string:
                raise ValueError("one or more registers must be specified")

            registers = self.operand_string.split(",")
            for register in registers:
                if register not in REGISTERS:
                    raise ValueError("[{}] unknown register".format(register))

                code_pkg.post_byte |= 0x06 if register == "D" else 0x00
                code_pkg.post_byte |= 0x01 if register == "CC" else 0x00
                code_pkg.post_byte |= 0x02 if register == "A" else 0x00
                code_pkg.post_byte |= 0x04 if register == "B" else 0x00
                code_pkg.post_byte |= 0x08 if register == "DP" else 0x00
                code_pkg.post_byte |= 0x10 if register == "X" else 0x00
                code_pkg.post_byte |= 0x20 if register == "Y" else 0x00
                code_pkg.post_byte |= 0x40 if register == "U" else 0x00
                code_pkg.post_byte |= 0x80 if register == "PC" else 0x00

        if self.instruction.mnemonic == "EXG" or self.instruction.mnemonic == "TFR":
            registers = self.operand_string.split(",")
            if len(registers) != 2:
                raise ValueError("[{}] requires exactly 2 registers".format(
                    self.instruction.mnemonic))

            if registers[0] not in REGISTERS:
                raise ValueError("[{}] unknown register".format(registers[0]))

            if registers[1] not in REGISTERS:
                raise ValueError("[{}] unknown register".format(registers[1]))

            code_pkg.post_byte |= 0x00 if registers[0] == "D" else 0x00
            code_pkg.post_byte |= 0x00 if registers[1] == "D" else 0x00

            code_pkg.post_byte |= 0x10 if registers[0] == "X" else 0x00
            code_pkg.post_byte |= 0x01 if registers[1] == "X" else 0x00

            code_pkg.post_byte |= 0x20 if registers[0] == "Y" else 0x00
            code_pkg.post_byte |= 0x02 if registers[1] == "Y" else 0x00

            code_pkg.post_byte |= 0x30 if registers[0] == "U" else 0x00
            code_pkg.post_byte |= 0x03 if registers[1] == "U" else 0x00

            code_pkg.post_byte |= 0x40 if registers[0] == "S" else 0x00
            code_pkg.post_byte |= 0x04 if registers[1] == "S" else 0x00

            code_pkg.post_byte |= 0x50 if registers[0] == "PC" else 0x00
            code_pkg.post_byte |= 0x05 if registers[1] == "PC" else 0x00

            code_pkg.post_byte |= 0x80 if registers[0] == "A" else 0x00
            code_pkg.post_byte |= 0x08 if registers[1] == "A" else 0x00

            code_pkg.post_byte |= 0x90 if registers[0] == "B" else 0x00
            code_pkg.post_byte |= 0x09 if registers[1] == "B" else 0x00

            code_pkg.post_byte |= 0xA0 if registers[0] == "CC" else 0x00
            code_pkg.post_byte |= 0x0A if registers[1] == "CC" else 0x00

            code_pkg.post_byte |= 0xB0 if registers[0] == "DP" else 0x00
            code_pkg.post_byte |= 0x0B if registers[1] == "DP" else 0x00

            if code_pkg.post_byte not in \
                    [
                        0x01, 0x10, 0x02, 0x20, 0x03, 0x30, 0x04, 0x40,
                        0x05, 0x50, 0x12, 0x21, 0x13, 0x31, 0x14, 0x41,
                        0x15, 0x51, 0x23, 0x32, 0x24, 0x42, 0x25, 0x52,
                        0x34, 0x43, 0x35, 0x53, 0x45, 0x54, 0x89, 0x98,
                        0x8A, 0xA8, 0x8B, 0xB8, 0x9A, 0xA9, 0x9B, 0xB9,
                        0xAB, 0xBA, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
                        0x88, 0x99, 0xAA, 0xBB
                    ]:
                raise ValueError("[{}] of [{}] to [{}] not allowed".format(
                    self.instruction.mnemonic, registers[0], registers[1]))

        code_pkg.post_byte = NumericValue(code_pkg.post_byte)
        return code_pkg
Ejemplo n.º 26
0
 def test_value_high_value_zero_when_length_less_than_two(self):
     result = NumericValue("$0123", size_hint=1)
     self.assertEqual(result.high_byte(), 0x00)
Ejemplo n.º 27
0
 def test_value_low_value_correct(self):
     result = NumericValue("$1223")
     self.assertEqual(result.low_byte(), 0x23)
Ejemplo n.º 28
0
 def test_value_high_value_correct_when_length_is_two(self):
     result = NumericValue("$0123")
     self.assertEqual(result.high_byte(), 0x01)
Ejemplo n.º 29
0
 def test_value_low_value_zero_when_length_zero(self):
     result = NumericValue("$0123", size_hint=0)
     self.assertEqual(result.low_byte(), 0x00)
Ejemplo n.º 30
0
 def test_value_low_value_correct_when_length_less_or_equal_to_two(self):
     result = NumericValue("$23")
     self.assertEqual(result.low_byte(), 0x23)