def _resolve(self, uref): """ Resolve the given unresolved reference. Get the symbol's value or re-evaluate an expression and place that value in the reference's address. """ if uref.expr is None: value = self.meta.lookup(uref.ref) else: value = uref.expr.eval(self.meta) if uref.type == REFERENCE_VALUE: self.mem[uref.address] = vm.size8(value) elif uref.type == REFERENCE_ABSOLUTE: self.mem[uref.address::2] = vm.size16(value) elif uref.type == REFERENCE_ZERO_PAGE: self.mem[uref.address] = vm.size8(value) elif uref.type == REFERENCE_RELATIVE: abs_address = vm.size16(value) # Branch is relative to PC after opcode and displacement # have been consumed. Since abs_address points to where # the displacement should go, add one to this value. rel_address = abs_address - (uref.address + 1) assert_branch_displacement(rel_address) self.mem[uref.address] = vm.twos_forward(rel_address) else: assert False
def _getitem_single(self, index): """ Notifies listeners for each byte load and calls abstract _load """ value = self._load(vm.size16(index)) [listener(index, value) for listener in self.load_listeners] return value
def r(self, address=None): if address is None: address = self.meta['PROGRAM_START'] address = vm.size16(self.meta[address]) self.cpu.push2(self.meta['MONITOR'] - 1) istart(self.comp, address) if self.cpu.exit != x6502.EXIT_MONITOR: print str(self.cpu)
def map(self, block, address, name): """ Maps the *block* to the given *address* and assigns it with *name*. If the *name* is already in use, a :class:`ValueException` is raised. Raises an :class:`OverflowError` if the address is not in the allowable range. """ if name in self._block_by_name: raise ValueError('Block with name {} already exists'.format(name)) self._blocks += [(block, vm.size16(address))] self._block_by_name[name] = block
def _setitem_single(self, index, value): """ Notifies listeners for each byte store and calls abstract _load. Emits warning if read only. """ if self.read_only: raise ReadOnlyError('Write {} to read-only location {}' .format(vm.hex8(value), vm.hex16(index))) else: self._store(vm.size16(index), value) [listener(index, value) for listener in self.store_listeners]
def label(self, name, address=None): """ Defines a the label, *name*, at *address*. If *address* is not specified, the current position of the assembler is used. Raises an :class:`OverflowError` if the address is out of range. """ if address is None: address = self.position self._check_meta() resolved = self.meta.define_label(name, vm.size16(address)) map(self._resolve, resolved)
def load(self): """ Loads a byte from the current position and advances the position by one. If *increment_first* is ``True``, the position is advanced before loading the byte. Raises an :class:`OverflowError` if the :attr:`position` is invalid. """ if self.increment_first: self.position += 1 value = self.mem[vm.size16(self.position)] if not self.increment_first: self.position += 1 return value
def load2(self): """ Loads a word from the current position and advances the position by two. If *increment_first* is ``True``, the position is advanced before loading the word. Raises an :class:`OverflowError` if the :attr:`position` is invalid. """ if self.increment_first: self.position += 1 value = self.mem[vm.size16(self.position)::2] if self.increment_first: self.position += 1 else: self.position += 2 return value
def define_label(self, name, address, reserved=False): """ Defines a label, *name*, for *address*. Raises a :class:`SymbolConflictError` if an alias or label with the same name is already defined. Raises a :class:`OverflowError` if *address* is not a 16-bit value. If *reserved* is ``True``, the alias cannot be removed once added. If this definition resolves references, a list of addresses where unresolved references exist is returned, otherwise an empty list is returned. """ address = vm.size16(address) resolvable = self._check_symbol(name, reserved) self.labels[name] = address self.addresses[address].add(name) return resolvable
def next(self): """ Description """ d = Disassembled() d.address = vm.size16(self.position) d.labels = self.meta.get_labels(d.address) d.remarks = self.meta.get_remarks(d.address) d.argument = self.meta.get_argument(d.address) d.data = self.meta.get_data(d.address) if d.data is not None: self.position = d.data.address + d.data.length return d opcode = self.pc.load() if opcode in self._opcodes: i = self._opcodes[opcode] else: op = '?{:02X}'.format(opcode) i = x6502.Instruction(opcode, op, am.IMP, None) d.instruction = i if i.addressing_mode in AM_ADDRESS_16: arg = self.pc.load2() d.bytes = [opcode, vm.lb(arg), vm.hb(arg)] elif (i.addressing_mode in AM_ADDRESS_8 or i.addressing_mode in (am.REL, am.IMM)): arg = self.pc.load() if i.addressing_mode == am.REL and d.argument is None: # Branch is displacement after consuming bytes, therefore # add two. d.argument = vm.hex16(d.address + vm.twos_inverse(arg) + 2) d.bytes = [opcode, arg] elif i.addressing_mode in AM_NO_ARGUMENT: d.bytes = [opcode] else: assert False return d
def test_size16_negative(self): self.assertEquals(vm.SWORD_MIN, vm.size16(vm.SWORD_MIN))
def test_size16(self): self.assertEquals(0xffff, vm.size16(0xffff))
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