def test_size8s_low(self): self.assertEquals(-128, vm.size8s(-128))
def test_size8s_high(self): self.assertEquals(255, vm.size8s(255))
def assemble(self, *args): """ To assemble an instruction, call the object with the :class:`instruction <mach8.instruction.Instruction>` and the argument (if necessary). Example:: a = Assembler(mem, position=0x4000) _; a(lda_imm, 0x42) Call the object with a string to create a label at the current address. Forward references allowed. Example:: _; a(jmp_abs, 'skip_brk') _; a(brk) _; a('skip_brk') _; a(nop) Use :mod:`expressions <mach8.expressions>` for enhanced disassembly display:: _; a(lda_imm, 9 + 2) # Disassembles to lda #$0B _; a(lda_imm, add(9, 2)) # Disassembles to lda #[9 + 2] Returns the address where the instruction was assembled. Note: Any reference to a label or alias that does not exist is considered to be an unresolved reference and will be entered in as a zero until resolved. Invoking :meth:`verify` will raise a :class:`SymbolUnresolvedError` if there are any outstanding unresolved references. """ instruction_address = self.position if len(args) == 0: return instruction_address # Label definition if isinstance(args[0], str): if len(args) != 1: raise TypeError('Expected 1 argument but received {:d}' .format(len(args))) label = args[0] self.label(label) return inst = args[0] required_args = 1 if inst.addressing_mode in AM_NO_ARGUMENT else 2 if len(args) != required_args: raise TypeError('Expected {:d} arguments but received {:d}' .format(required_args, len(args))) self._check_meta() if inst.addressing_mode in AM_ADDRESS_16: self.meta.clear(instruction_address + 1, instruction_address + 3) address = self.meta.add_reference(args[1], instruction_address, REFERENCE_ABSOLUTE) address = vm.size16(address) self._pc.store(inst.opcode) self._pc.store2(address) elif inst.addressing_mode in AM_ADDRESS_8: self.meta.clear(instruction_address + 1, instruction_address + 2) address = self.meta.add_reference(args[1], instruction_address, REFERENCE_ZERO_PAGE) address = vm.size8(address) self._pc.store(inst.opcode) self._pc.store(address) elif inst.addressing_mode == am.IMM: self.meta.clear(instruction_address + 1, instruction_address + 2) value = self.meta.add_reference(args[1], instruction_address, REFERENCE_VALUE) value = vm.size8s(value) self._pc.store(inst.opcode) self._pc.store(vm.mask8(value)) elif inst.addressing_mode in AM_NO_ARGUMENT: self._pc.store(inst.opcode) elif inst.addressing_mode == am.REL: self.meta.clear(instruction_address + 1, instruction_address + 2) abs_address = self.meta.add_reference(args[1], instruction_address, REFERENCE_RELATIVE) if self.meta.lookup(args[1], default=None) is not None: # Branch is relative to PC after instruction has been consumed. # Since we have not yet 'consumed' it, the PC has to be # adjusted by two (opcode and offset) rel_address = abs_address - (self.position + 2) assert_branch_displacement(rel_address) # TODO: Cleanup address = rel_address & vm.BITS8 else: address = 0 self._pc.store(inst.opcode) self._pc.store(address) else: raise ValueError('Invalid instruction: ' + str(inst)) self._new_position = True