Beispiel #1
0
 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 
Beispiel #2
0
 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
Beispiel #3
0
 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) 
Beispiel #4
0
 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 
Beispiel #5
0
 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]
Beispiel #6
0
 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)
Beispiel #7
0
 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
Beispiel #8
0
 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 
Beispiel #9
0
 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
Beispiel #10
0
 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
Beispiel #11
0
 def test_size16_negative(self):
     self.assertEquals(vm.SWORD_MIN, vm.size16(vm.SWORD_MIN)) 
Beispiel #12
0
 def test_size16(self):
     self.assertEquals(0xffff, vm.size16(0xffff)) 
Beispiel #13
0
    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