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
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])
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])
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)
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())
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)
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)
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
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) )
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, )
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)
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, )
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, )
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()
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))
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
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)
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)
def test_numeric_from_character_literal_raises_on_invalid_character_literal(self): with self.assertRaises(ValueTypeError) as context: NumericValue("'~") self.assertEqual("['~] is not valid integer, character literal, or hex value", str(context.exception))
def test_numeric_from_16_bit_binary_string_is_correct(self): result = NumericValue("%1010101010101010") self.assertEqual(43690, result.int)
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
def test_value_low_value_correct(self): result = NumericValue("$1223") self.assertEqual(result.low_byte(), 0x23)
def test_value_low_value_correct_when_length_less_or_equal_to_two(self): result = NumericValue("$23") self.assertEqual(result.low_byte(), 0x23)
def test_value_low_value_zero_when_length_zero(self): result = NumericValue("$0123", size_hint=0) self.assertEqual(result.low_byte(), 0x00)
def test_value_high_value_correct_when_length_is_two(self): result = NumericValue("$0123") self.assertEqual(result.high_byte(), 0x01)
def test_value_high_value_zero_when_length_less_than_two(self): result = NumericValue("$0123", size_hint=1) self.assertEqual(result.high_byte(), 0x00)
def test_numeric_from_binary_string_throws_exception_when_too_long(self): with self.assertRaises(ValueTypeError) as context: NumericValue("%10101010101010101") self.assertEqual("binary pattern 10101010101010101 must be 8 or 16 bits long", str(context.exception))
def test_symbol_str_correct_when_resolved(self): result = SymbolValue('symbol') result.resolved = True result.value = NumericValue("$AB") self.assertEqual("AB", str(result))
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())
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")