JensDiemer

<style> hr { margin: 150px; } </style>

08.2013 - Warum?

Apple ][ (6502 CPU) Emulator in Python:

Andere Emulatoren in Python:

  • ZX Spectrum Emulator (pyZX)
  • NES Emulator (spyn)
  • Atari 2600 (pyTari)

Vorhandene Dragon32 / CoCo Emulatoren:


Wie baut man einen Emulator?

Emulation vs. Simulation

Emulation: Der original, unmodifizierte ROM machinen code wird ausgeführt
Simulation: Man ahmt die Ausgabe und das verhalten nach.


Wie emuliert man eine CPU?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
""" Pseudo Python code ! """

class CPU(object):
    RESET_VECTOR = 0xfffe
    
    def __init__(self):
        self.memory = [0x00, 0x00, 0x00, ...]
        self.program_counter = self.RESET_VECTOR
        ...
    
    def run(self):
        while True:
            opcode = self.memory[self.program_counter]
            self.program_counter += 1
            self.interpretate_opcode(opcode)

    def interpretate_opcode(self, opcode):
        if opcode == 0x01:
            self.op_inc_a()
        elif opcode == 0x02:
            self.op_dec_a()
        ...

    def op_inc_a(self):
        self.register_A += 1

    def op_dec_a(self):
        self.register_A -= 1

    ...

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
""" Pseudo Python code ! """

class Memory(object):
    RAM_END = 0x7FFF # 32KB 
    
    def __init__(self):
        self.ram = RAM(size=32768) # 32KB RAM
        self.rom = ROM(rom_file="dragon32.rom") # 16KB ROM

        self.callbacks = {
            0xff00: read_keyboard_matrix_row,
            0xff02: read_keyboard_matrix_column,
        }

    def read_byte(self, address):
        if address in self.callbacks:
            return self.callbacks[address]
        
        if address < self.RAM_END:
            return self.ram.read_byte(address)
        else:
            return self.rom.read_byte(address)


class CPU(object):
    IRQ_VECTOR = 0xfff8
    RESET_VECTOR = 0xfffe
    
    def __init__(self):
        self.memory = Memory()
        self.running = True
        ...
    
    def reset(self):
        self.cpu_cycles = 0
        self.program_counter = self.RESET_VECTOR
        self.register_A = 0
        ...
    
    def run(self):
        while self.running:
            opcode = self.read_pc_byte()
            self.interpretate_opcode(opcode)
            if self.cpu_cycles>1000:
                self.sync_periphery()

    def read_pc_byte(self):
        self.cpu_cycles += 1
        byte = self.memory.read_byte(self.program_counter)
        self.program_counter += 1
        return byte

    def interpretate_opcode(self, opcode):
        if opcode == 0x01:
            self.op_inc_a()
        elif opcode == 0x02:
            self.op_inc_m()
        ...

    def op_inc_a(self):
        self.cpu_cycles += 1
        self.register_A += 1

    def op_inc_m(self):
        effective_address = self.read_pc_byte()
        byte = self.memory.read_byte(effective_address)
        byte += byte & 0xff
        self.memory.write_byte(effective_address, byte)

    ...


Informationen sammeln

6809 Instruction Set:

generiert:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
INC: {'condition code': 'H - Not affected.\n...
     'description': 'Adds to the operand.\n...
     'instr_desc': 'Increment accumulator or memory location',
     'mnemonic': {INC: {'HNZVC': '-aaa-',
                      'desc': 'M = M + 1',
                      'needs_ea': True,
                      'ops': {0xc: {'addr_mode': DIRECT,
                                  'bytes': 2,
                                  'cycles': 6},
                             0x6c: {'addr_mode': INDEXED,
                                   'bytes': 2,
                                   'cycles': 6},
                             0x7c: {'addr_mode': EXTENDED,
                                   'bytes': 3,
                                   'cycles': 7}},
                      'read_from_memory': BYTE,
                      'register': None,
                      'write_to_memory': BYTE},
                 'INCA': {'HNZVC': '-aaa-',
                         'desc': 'A = A + 1',
                         'needs_ea': False,
                         'ops': {0x4c: {'addr_mode': INHERENT,
                                      'bytes': 1,
                                      'cycles': 2}},
                         'read_from_memory': None,
                         'register': REG_A,
                         'write_to_memory': None},
                 'INCB': {'HNZVC': '-aaa-',
                         'desc': 'B = B + 1',