diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/applepy.py b/applepy.py index 6f6e69a..479de65 100644 --- a/applepy.py +++ b/applepy.py @@ -5,16 +5,12 @@ import numpy import pygame +import struct +import subprocess import sys import time -def signed(x): - if x > 0x7F: - x = x - 0x100 - return x - - class Display: characters = [ @@ -286,33 +282,10 @@ class Speaker: sound = pygame.sndarray.make_sound(sample_array) sound.play() self.reset() - - -class ROM: - def __init__(self, start, size): - self.start = start - self.end = start + size - 1 - self._mem = [0x00] * size - - def load(self, address, data): - for offset, datum in enumerate(data): - self._mem[address - self.start + offset] = datum - - def load_file(self, address, filename): - with open(filename) as f: - for offset, datum in enumerate(f.read()): - self._mem[address - self.start + offset] = ord(datum) - - def read_byte(self, address): - assert self.start <= address <= self.end - return self._mem[address - self.start] - - -class RAM(ROM): - - def write_byte(self, address, value): - self._mem[address] = value + def update(self, cycle): + if self.buffer and (cycle - self.last_toggle) > self.CHECK_INTERVAL: + self.play() class SoftSwitches: @@ -352,474 +325,41 @@ class SoftSwitches: return 0x00 -class Memory: - - def __init__(self, options=None, display=None, speaker=None): +class Apple2: + + def __init__(self, options, display, speaker): self.display = display self.speaker = speaker - self.rom = ROM(0xD000, 0x3000) - - if options: - self.rom.load_file(0xD000, options.rom) - - self.ram = RAM(0x0000, 0xC000) - - if options and options.ram: - self.ram.load_file(0x0000, options.ram) - self.softswitches = SoftSwitches(display, speaker) - - def load(self, address, data): - if address < 0xC000: - self.ram.load(address, data) - - def read_byte(self, cycle, address): - if address < 0xC000: - return self.ram.read_byte(address) - elif address < 0xD000: - return self.softswitches.read_byte(cycle, address) - else: - return self.rom.read_byte(address) - - def read_word(self, cycle, address): - return self.read_byte(cycle, address) + (self.read_byte(cycle + 1, address + 1) << 8) - - def read_word_bug(self, cycle, address): - if address % 0x100 == 0xFF: - return self.read_byte(cycle, address) + (self.read_byte(cycle + 1, address & 0xFF00) << 8) - else: - return self.read_word(cycle, address) - - def write_byte(self, address, value): - if address < 0xC000: - self.ram.write_byte(address, value) - if 0x400 <= address < 0x800 and self.display: - self.display.update(address, value) - if 0x2000 <= address < 0x5FFF and self.display: - self.display.update(address, value) - - def update(self, cycle): - if self.speaker and self.speaker.buffer and (cycle - self.speaker.last_toggle) > self.speaker.CHECK_INTERVAL: - self.speaker.play() + args = [ + sys.executable, + "cpu6502.py", + "--rom", options.rom, + ] + if options.ram: + args.extend([ + "--ram", options.ram, + ]) + self.core = subprocess.Popen( + args=args, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + ) -class Disassemble: - def __init__(self, cpu, memory): - self.cpu = cpu - self.memory = memory - - self.setup_ops() - - def setup_ops(self): - self.ops = [None] * 0x100 - self.ops[0x00] = ("BRK", ) - self.ops[0x01] = ("ORA", self.indirect_x_mode) - self.ops[0x05] = ("ORA", self.zero_page_mode) - self.ops[0x06] = ("ASL", self.zero_page_mode) - self.ops[0x08] = ("PHP", ) - self.ops[0x09] = ("ORA", self.immediate_mode) - self.ops[0x0A] = ("ASL", ) - self.ops[0x0D] = ("ORA", self.absolute_mode) - self.ops[0x0E] = ("ASL", self.absolute_mode) - self.ops[0x10] = ("BPL", self.relative_mode) - self.ops[0x11] = ("ORA", self.indirect_y_mode) - self.ops[0x15] = ("ORA", self.zero_page_x_mode) - self.ops[0x16] = ("ASL", self.zero_page_x_mode) - self.ops[0x18] = ("CLC", ) - self.ops[0x19] = ("ORA", self.absolute_y_mode) - self.ops[0x1D] = ("ORA", self.absolute_x_mode) - self.ops[0x1E] = ("ASL", self.absolute_x_mode) - self.ops[0x20] = ("JSR", self.absolute_mode) - self.ops[0x21] = ("AND", self.indirect_x_mode) - self.ops[0x24] = ("BIT", self.zero_page_mode) - self.ops[0x25] = ("AND", self.zero_page_mode) - self.ops[0x26] = ("ROL", self.zero_page_mode) - self.ops[0x28] = ("PLP", ) - self.ops[0x29] = ("AND", self.immediate_mode) - self.ops[0x2A] = ("ROL", ) - self.ops[0x2C] = ("BIT", self.absolute_mode) - self.ops[0x2D] = ("AND", self.absolute_mode) - self.ops[0x2E] = ("ROL", self.absolute_mode) - self.ops[0x30] = ("BMI", self.relative_mode) - self.ops[0x31] = ("AND", self.indirect_y_mode) - self.ops[0x35] = ("AND", self.zero_page_x_mode) - self.ops[0x36] = ("ROL", self.zero_page_x_mode) - self.ops[0x38] = ("SEC", ) - self.ops[0x39] = ("AND", self.absolute_y_mode) - self.ops[0x3D] = ("AND", self.absolute_x_mode) - self.ops[0x3E] = ("ROL", self.absolute_x_mode) - self.ops[0x40] = ("RTI", ) - self.ops[0x41] = ("EOR", self.indirect_x_mode) - self.ops[0x45] = ("EOR", self.zero_page_mode) - self.ops[0x46] = ("LSR", self.zero_page_mode) - self.ops[0x48] = ("PHA", ) - self.ops[0x49] = ("EOR", self.immediate_mode) - self.ops[0x4A] = ("LSR", ) - self.ops[0x4C] = ("JMP", self.absolute_mode) - self.ops[0x4D] = ("EOR", self.absolute_mode) - self.ops[0x4E] = ("LSR", self.absolute_mode) - self.ops[0x50] = ("BVC", self.relative_mode) - self.ops[0x51] = ("EOR", self.indirect_y_mode) - self.ops[0x55] = ("EOR", self.zero_page_x_mode) - self.ops[0x56] = ("LSR", self.zero_page_x_mode) - self.ops[0x58] = ("CLI", ) - self.ops[0x59] = ("EOR", self.absolute_y_mode) - self.ops[0x5D] = ("EOR", self.absolute_x_mode) - self.ops[0x5E] = ("LSR", self.absolute_x_mode) - self.ops[0x60] = ("RTS", ) - self.ops[0x61] = ("ADC", self.indirect_x_mode) - self.ops[0x65] = ("ADC", self.zero_page_mode) - self.ops[0x66] = ("ROR", self.zero_page_mode) - self.ops[0x68] = ("PLA", ) - self.ops[0x69] = ("ADC", self.immediate_mode) - self.ops[0x6A] = ("ROR", ) - self.ops[0x6C] = ("JMP", self.indirect_mode) - self.ops[0x6D] = ("ADC", self.absolute_mode) - self.ops[0x6E] = ("ROR", self.absolute_mode) - self.ops[0x70] = ("BVS", self.relative_mode) - self.ops[0x71] = ("ADC", self.indirect_y_mode) - self.ops[0x75] = ("ADC", self.zero_page_x_mode) - self.ops[0x76] = ("ROR", self.zero_page_x_mode) - self.ops[0x78] = ("SEI", ) - self.ops[0x79] = ("ADC", self.absolute_y_mode) - self.ops[0x7D] = ("ADC", self.absolute_x_mode) - self.ops[0x7E] = ("ROR", self.absolute_x_mode) - self.ops[0x81] = ("STA", self.indirect_x_mode) - self.ops[0x84] = ("STY", self.zero_page_mode) - self.ops[0x85] = ("STA", self.zero_page_mode) - self.ops[0x86] = ("STX", self.zero_page_mode) - self.ops[0x88] = ("DEY", ) - self.ops[0x8A] = ("TXA", ) - self.ops[0x8C] = ("STY", self.absolute_mode) - self.ops[0x8D] = ("STA", self.absolute_mode) - self.ops[0x8E] = ("STX", self.absolute_mode) - self.ops[0x90] = ("BCC", self.relative_mode) - self.ops[0x91] = ("STA", self.indirect_y_mode) - self.ops[0x94] = ("STY", self.zero_page_x_mode) - self.ops[0x95] = ("STA", self.zero_page_x_mode) - self.ops[0x96] = ("STX", self.zero_page_y_mode) - self.ops[0x98] = ("TYA", ) - self.ops[0x99] = ("STA", self.absolute_y_mode) - self.ops[0x9A] = ("TXS", ) - self.ops[0x9D] = ("STA", self.absolute_x_mode) - self.ops[0xA0] = ("LDY", self.immediate_mode) - self.ops[0xA1] = ("LDA", self.indirect_x_mode) - self.ops[0xA2] = ("LDX", self.immediate_mode) - self.ops[0xA4] = ("LDY", self.zero_page_mode) - self.ops[0xA5] = ("LDA", self.zero_page_mode) - self.ops[0xA6] = ("LDX", self.zero_page_mode) - self.ops[0xA8] = ("TAY", ) - self.ops[0xA9] = ("LDA", self.immediate_mode) - self.ops[0xAA] = ("TAX", ) - self.ops[0xAC] = ("LDY", self.absolute_mode) - self.ops[0xAD] = ("LDA", self.absolute_mode) - self.ops[0xAE] = ("LDX", self.absolute_mode) - self.ops[0xB0] = ("BCS", self.relative_mode) - self.ops[0xB1] = ("LDA", self.indirect_y_mode) - self.ops[0xB4] = ("LDY", self.zero_page_x_mode) - self.ops[0xB5] = ("LDA", self.zero_page_x_mode) - self.ops[0xB6] = ("LDX", self.zero_page_y_mode) - self.ops[0xB8] = ("CLV", ) - self.ops[0xB9] = ("LDA", self.absolute_y_mode) - self.ops[0xBA] = ("TSX", ) - self.ops[0xBC] = ("LDY", self.absolute_x_mode) - self.ops[0xBD] = ("LDA", self.absolute_x_mode) - self.ops[0xBE] = ("LDX", self.absolute_y_mode) - self.ops[0xC0] = ("CPY", self.immediate_mode) - self.ops[0xC1] = ("CMP", self.indirect_x_mode) - self.ops[0xC4] = ("CPY", self.zero_page_mode) - self.ops[0xC5] = ("CMP", self.zero_page_mode) - self.ops[0xC6] = ("DEC", self.zero_page_mode) - self.ops[0xC8] = ("INY", ) - self.ops[0xC9] = ("CMP", self.immediate_mode) - self.ops[0xCA] = ("DEX", ) - self.ops[0xCC] = ("CPY", self.absolute_mode) - self.ops[0xCD] = ("CMP", self.absolute_mode) - self.ops[0xCE] = ("DEC", self.absolute_mode) - self.ops[0xD0] = ("BNE", self.relative_mode) - self.ops[0xD1] = ("CMP", self.indirect_y_mode) - self.ops[0xD5] = ("CMP", self.zero_page_x_mode) - self.ops[0xD6] = ("DEC", self.zero_page_x_mode) - self.ops[0xD8] = ("CLD", ) - self.ops[0xD9] = ("CMP", self.absolute_y_mode) - self.ops[0xDD] = ("CMP", self.absolute_x_mode) - self.ops[0xDE] = ("DEC", self.absolute_x_mode) - self.ops[0xE0] = ("CPX", self.immediate_mode) - self.ops[0xE1] = ("SBC", self.indirect_x_mode) - self.ops[0xE4] = ("CPX", self.zero_page_mode) - self.ops[0xE5] = ("SBC", self.zero_page_mode) - self.ops[0xE6] = ("INC", self.zero_page_mode) - self.ops[0xE8] = ("INX", ) - self.ops[0xE9] = ("SBC", self.immediate_mode) - self.ops[0xEA] = ("NOP", ) - self.ops[0xEC] = ("CPX", self.absolute_mode) - self.ops[0xED] = ("SBC", self.absolute_mode) - self.ops[0xEE] = ("INC", self.absolute_mode) - self.ops[0xF0] = ("BEQ", self.relative_mode) - self.ops[0xF1] = ("SBC", self.indirect_y_mode) - self.ops[0xF5] = ("SBC", self.zero_page_x_mode) - self.ops[0xF6] = ("INC", self.zero_page_x_mode) - self.ops[0xF8] = ("SED", ) - self.ops[0xF9] = ("SBC", self.absolute_y_mode) - self.ops[0xFD] = ("SBC", self.absolute_x_mode) - self.ops[0xFE] = ("INC", self.absolute_x_mode) - - def absolute_mode(self, pc): - a = self.memory.read_word(pc + 1) - return "$%04X [%04X] = %02X" % (a, a, self.memory.read_word(a)) - - def absolute_x_mode(self, pc): - a = self.memory.read_word(pc + 1) - e = a + self.cpu.x_index - return "$%04X,X [%04X] = %02X" % (a, e, self.memory.read_byte(e)) - - def absolute_y_mode(self, pc): - a = self.memory.read_word(pc + 1) - e = a + self.cpu.y_index - return "$%04X,Y [%04X] = %02X" % (a, e, self.memory.read_byte(e)) - - def immediate_mode(self, pc): - return "#$%02X" % (self.memory.read_byte(pc + 1)) - - def indirect_mode(self, pc): - a = self.memory.read_word(pc + 1) - return "($%04X) [%04X] = %02X" % (a, a, self.memory.read_word(a)) - - def indirect_x_mode(self, pc): - z = self.memory.read_byte(pc + 1) - a = self.memory.read_word((z + self.cpu.x_index) % 0x100) - return "($%02X,X) [%04X] = %02X" % (z, a, self.memory.read_byte(a)) - - def indirect_y_mode(self, pc): - z = self.memory.read_byte(pc + 1) - a = self.memory.read_word(z) + self.cpu.y_index - return "($%02X),Y [%04X] = %02X" % (z, a, self.memory.read_byte(a)) - - def relative_mode(self, pc): - return "$%04X" % (pc + signed(self.memory.read_byte(pc + 1) + 2)) - - def zero_page_mode(self, pc): - a = self.memory.read_byte(pc + 1) - return "$%02X [%04X] = %02X" % (a, a, self.memory.read_byte(a)) - - def zero_page_x_mode(self, pc): - z = self.memory.read_byte(pc + 1) - a = (z + self.cpu.x_index) % 0x100 - return "$%02X,X [%04X] = %02X" % (z, a, self.memory.read_byte(a)) - - def zero_page_y_mode(self, pc): - z = self.memory.read_byte(pc + 1) - a = (z + self.cpu.y_index) % 0x100 - return "$%02X,Y [%04X] = %02X" % (z, a, self.memory.read_byte(a)) - - def disasm(self, pc): - op = self.memory.read_byte(pc) - info = self.ops[op] - s = "%02X %s" % (pc, info[0]) - if len(info) > 1: - s += " " + info[1](pc) - return s - - -class CPU: - - STACK_PAGE = 0x100 - RESET_VECTOR = 0xFFFC - - def __init__(self, memory): - self.memory = memory - self.disassemble = Disassemble(self, memory) - - self.accumulator = 0x00 - self.x_index = 0x00 - self.y_index = 0x00 - - self.carry_flag = 0 - self.zero_flag = 0 - self.interrupt_disable_flag = 0 - self.decimal_mode_flag = 0 - self.break_flag = 1 - self.overflow_flag = 0 - self.sign_flag = 0 - - self.stack_pointer = 0xFF - - self.cycles = 0 - - self.setup_ops() - self.reset() - - def setup_ops(self): - self.ops = [None] * 0x100 - self.ops[0x00] = lambda: self.BRK() - self.ops[0x01] = lambda: self.ORA(self.indirect_x_mode()) - self.ops[0x05] = lambda: self.ORA(self.zero_page_mode()) - self.ops[0x06] = lambda: self.ASL(self.zero_page_mode()) - self.ops[0x08] = lambda: self.PHP() - self.ops[0x09] = lambda: self.ORA(self.immediate_mode()) - self.ops[0x0A] = lambda: self.ASL() - self.ops[0x0D] = lambda: self.ORA(self.absolute_mode()) - self.ops[0x0E] = lambda: self.ASL(self.absolute_mode()) - self.ops[0x10] = lambda: self.BPL(self.relative_mode()) - self.ops[0x11] = lambda: self.ORA(self.indirect_y_mode()) - self.ops[0x15] = lambda: self.ORA(self.zero_page_x_mode()) - self.ops[0x16] = lambda: self.ASL(self.zero_page_x_mode()) - self.ops[0x18] = lambda: self.CLC() - self.ops[0x19] = lambda: self.ORA(self.absolute_y_mode()) - self.ops[0x1D] = lambda: self.ORA(self.absolute_x_mode()) - self.ops[0x1E] = lambda: self.ASL(self.absolute_x_mode(rmw=True)) - self.ops[0x20] = lambda: self.JSR(self.absolute_mode()) - self.ops[0x21] = lambda: self.AND(self.indirect_x_mode()) - self.ops[0x24] = lambda: self.BIT(self.zero_page_mode()) - self.ops[0x25] = lambda: self.AND(self.zero_page_mode()) - self.ops[0x26] = lambda: self.ROL(self.zero_page_mode()) - self.ops[0x28] = lambda: self.PLP() - self.ops[0x29] = lambda: self.AND(self.immediate_mode()) - self.ops[0x2A] = lambda: self.ROL() - self.ops[0x2C] = lambda: self.BIT(self.absolute_mode()) - self.ops[0x2D] = lambda: self.AND(self.absolute_mode()) - self.ops[0x2E] = lambda: self.ROL(self.absolute_mode()) - self.ops[0x30] = lambda: self.BMI(self.relative_mode()) - self.ops[0x31] = lambda: self.AND(self.indirect_y_mode()) - self.ops[0x35] = lambda: self.AND(self.zero_page_x_mode()) - self.ops[0x36] = lambda: self.ROL(self.zero_page_x_mode()) - self.ops[0x38] = lambda: self.SEC() - self.ops[0x39] = lambda: self.AND(self.absolute_y_mode()) - self.ops[0x3D] = lambda: self.AND(self.absolute_x_mode()) - self.ops[0x3E] = lambda: self.ROL(self.absolute_x_mode(rmw=True)) - self.ops[0x40] = lambda: self.RTI() - self.ops[0x41] = lambda: self.EOR(self.indirect_x_mode()) - self.ops[0x45] = lambda: self.EOR(self.zero_page_mode()) - self.ops[0x46] = lambda: self.LSR(self.zero_page_mode()) - self.ops[0x48] = lambda: self.PHA() - self.ops[0x49] = lambda: self.EOR(self.immediate_mode()) - self.ops[0x4A] = lambda: self.LSR() - self.ops[0x4C] = lambda: self.JMP(self.absolute_mode()) - self.ops[0x4D] = lambda: self.EOR(self.absolute_mode()) - self.ops[0x4E] = lambda: self.LSR(self.absolute_mode()) - self.ops[0x50] = lambda: self.BVC(self.relative_mode()) - self.ops[0x51] = lambda: self.EOR(self.indirect_y_mode()) - self.ops[0x55] = lambda: self.EOR(self.zero_page_x_mode()) - self.ops[0x56] = lambda: self.LSR(self.zero_page_x_mode()) - self.ops[0x58] = lambda: self.CLI() - self.ops[0x59] = lambda: self.EOR(self.absolute_y_mode()) - self.ops[0x5D] = lambda: self.EOR(self.absolute_x_mode()) - self.ops[0x5E] = lambda: self.LSR(self.absolute_x_mode(rmw=True)) - self.ops[0x60] = lambda: self.RTS() - self.ops[0x61] = lambda: self.ADC(self.indirect_x_mode()) - self.ops[0x65] = lambda: self.ADC(self.zero_page_mode()) - self.ops[0x66] = lambda: self.ROR(self.zero_page_mode()) - self.ops[0x68] = lambda: self.PLA() - self.ops[0x69] = lambda: self.ADC(self.immediate_mode()) - self.ops[0x6A] = lambda: self.ROR() - self.ops[0x6C] = lambda: self.JMP(self.indirect_mode()) - self.ops[0x6D] = lambda: self.ADC(self.absolute_mode()) - self.ops[0x6E] = lambda: self.ROR(self.absolute_mode()) - self.ops[0x70] = lambda: self.BVS(self.relative_mode()) - self.ops[0x71] = lambda: self.ADC(self.indirect_y_mode()) - self.ops[0x75] = lambda: self.ADC(self.zero_page_x_mode()) - self.ops[0x76] = lambda: self.ROR(self.zero_page_x_mode()) - self.ops[0x78] = lambda: self.SEI() - self.ops[0x79] = lambda: self.ADC(self.absolute_y_mode()) - self.ops[0x7D] = lambda: self.ADC(self.absolute_x_mode()) - self.ops[0x7E] = lambda: self.ROR(self.absolute_x_mode(rmw=True)) - self.ops[0x81] = lambda: self.STA(self.indirect_x_mode()) - self.ops[0x84] = lambda: self.STY(self.zero_page_mode()) - self.ops[0x85] = lambda: self.STA(self.zero_page_mode()) - self.ops[0x86] = lambda: self.STX(self.zero_page_mode()) - self.ops[0x88] = lambda: self.DEY() - self.ops[0x8A] = lambda: self.TXA() - self.ops[0x8C] = lambda: self.STY(self.absolute_mode()) - self.ops[0x8D] = lambda: self.STA(self.absolute_mode()) - self.ops[0x8E] = lambda: self.STX(self.absolute_mode()) - self.ops[0x90] = lambda: self.BCC(self.relative_mode()) - self.ops[0x91] = lambda: self.STA(self.indirect_y_mode(rmw=True)) - self.ops[0x94] = lambda: self.STY(self.zero_page_x_mode()) - self.ops[0x95] = lambda: self.STA(self.zero_page_x_mode()) - self.ops[0x96] = lambda: self.STX(self.zero_page_y_mode()) - self.ops[0x98] = lambda: self.TYA() - self.ops[0x99] = lambda: self.STA(self.absolute_y_mode(rmw=True)) - self.ops[0x9A] = lambda: self.TXS() - self.ops[0x9D] = lambda: self.STA(self.absolute_x_mode(rmw=True)) - self.ops[0xA0] = lambda: self.LDY(self.immediate_mode()) - self.ops[0xA1] = lambda: self.LDA(self.indirect_x_mode()) - self.ops[0xA2] = lambda: self.LDX(self.immediate_mode()) - self.ops[0xA4] = lambda: self.LDY(self.zero_page_mode()) - self.ops[0xA5] = lambda: self.LDA(self.zero_page_mode()) - self.ops[0xA6] = lambda: self.LDX(self.zero_page_mode()) - self.ops[0xA8] = lambda: self.TAY() - self.ops[0xA9] = lambda: self.LDA(self.immediate_mode()) - self.ops[0xAA] = lambda: self.TAX() - self.ops[0xAC] = lambda: self.LDY(self.absolute_mode()) - self.ops[0xAD] = lambda: self.LDA(self.absolute_mode()) - self.ops[0xAE] = lambda: self.LDX(self.absolute_mode()) - self.ops[0xB0] = lambda: self.BCS(self.relative_mode()) - self.ops[0xB1] = lambda: self.LDA(self.indirect_y_mode()) - self.ops[0xB4] = lambda: self.LDY(self.zero_page_x_mode()) - self.ops[0xB5] = lambda: self.LDA(self.zero_page_x_mode()) - self.ops[0xB6] = lambda: self.LDX(self.zero_page_y_mode()) - self.ops[0xB8] = lambda: self.CLV() - self.ops[0xB9] = lambda: self.LDA(self.absolute_y_mode()) - self.ops[0xBA] = lambda: self.TSX() - self.ops[0xBC] = lambda: self.LDY(self.absolute_x_mode()) - self.ops[0xBD] = lambda: self.LDA(self.absolute_x_mode()) - self.ops[0xBE] = lambda: self.LDX(self.absolute_y_mode()) - self.ops[0xC0] = lambda: self.CPY(self.immediate_mode()) - self.ops[0xC1] = lambda: self.CMP(self.indirect_x_mode()) - self.ops[0xC4] = lambda: self.CPY(self.zero_page_mode()) - self.ops[0xC5] = lambda: self.CMP(self.zero_page_mode()) - self.ops[0xC6] = lambda: self.DEC(self.zero_page_mode()) - self.ops[0xC8] = lambda: self.INY() - self.ops[0xC9] = lambda: self.CMP(self.immediate_mode()) - self.ops[0xCA] = lambda: self.DEX() - self.ops[0xCC] = lambda: self.CPY(self.absolute_mode()) - self.ops[0xCD] = lambda: self.CMP(self.absolute_mode()) - self.ops[0xCE] = lambda: self.DEC(self.absolute_mode()) - self.ops[0xD0] = lambda: self.BNE(self.relative_mode()) - self.ops[0xD1] = lambda: self.CMP(self.indirect_y_mode()) - self.ops[0xD5] = lambda: self.CMP(self.zero_page_x_mode()) - self.ops[0xD6] = lambda: self.DEC(self.zero_page_x_mode()) - self.ops[0xD8] = lambda: self.CLD() - self.ops[0xD9] = lambda: self.CMP(self.absolute_y_mode()) - self.ops[0xDD] = lambda: self.CMP(self.absolute_x_mode()) - self.ops[0xDE] = lambda: self.DEC(self.absolute_x_mode(rmw=True)) - self.ops[0xE0] = lambda: self.CPX(self.immediate_mode()) - self.ops[0xE1] = lambda: self.SBC(self.indirect_x_mode()) - self.ops[0xE4] = lambda: self.CPX(self.zero_page_mode()) - self.ops[0xE5] = lambda: self.SBC(self.zero_page_mode()) - self.ops[0xE6] = lambda: self.INC(self.zero_page_mode()) - self.ops[0xE8] = lambda: self.INX() - self.ops[0xE9] = lambda: self.SBC(self.immediate_mode()) - self.ops[0xEA] = lambda: self.NOP() - self.ops[0xEC] = lambda: self.CPX(self.absolute_mode()) - self.ops[0xED] = lambda: self.SBC(self.absolute_mode()) - self.ops[0xEE] = lambda: self.INC(self.absolute_mode()) - self.ops[0xF0] = lambda: self.BEQ(self.relative_mode()) - self.ops[0xF1] = lambda: self.SBC(self.indirect_y_mode()) - self.ops[0xF5] = lambda: self.SBC(self.zero_page_x_mode()) - self.ops[0xF6] = lambda: self.INC(self.zero_page_x_mode()) - self.ops[0xF8] = lambda: self.SED() - self.ops[0xF9] = lambda: self.SBC(self.absolute_y_mode()) - self.ops[0xFD] = lambda: self.SBC(self.absolute_x_mode()) - self.ops[0xFE] = lambda: self.INC(self.absolute_x_mode(rmw=True)) - - def reset(self): - self.program_counter = self.read_word(self.RESET_VECTOR) - def run(self): update_cycle = 0 quit = False while not quit: - self.cycles += 2 # all instructions take this as a minimum - op = self.read_pc_byte() - func = self.ops[op] - if func is None: - print "UNKNOWN OP" - print hex(self.program_counter - 1) - print hex(op) - break + op = self.core.stdout.read(8) + cycle, rw, addr, val = struct.unpack("= 1024: - self.memory.display.flash() + self.display.flash() pygame.display.flip() - self.memory.update(self.cycles) + if self.speaker: + self.speaker.update(cycle) update_cycle = 0 - def test_run(self, start, end): - self.program_counter = start - while True: - self.cycles += 2 # all instructions take this as a minimum - if self.program_counter == end: - break - op = self.read_pc_byte() - func = self.ops[op] - if func is None: - print "UNKNOWN OP" - print hex(self.program_counter - 1) - print hex(op) - break - else: - self.ops[op]() - - #### - - def get_pc(self, inc=1): - pc = self.program_counter - self.program_counter += inc - return pc - - def read_byte(self, address): - return self.memory.read_byte(self.cycles, address) - - def read_word(self, address): - return self.memory.read_word(self.cycles, address) - - def read_word_bug(self, address): - return self.memory.read_word_bug(self.cycles, address) - - def read_pc_byte(self): - return self.read_byte(self.get_pc()) - - def read_pc_word(self): - return self.read_word(self.get_pc(2)) - - #### - - def status_from_byte(self, status): - self.carry_flag = [0, 1][0 != status & 1] - self.zero_flag = [0, 1][0 != status & 2] - self.interrupt_disable_flag = [0, 1][0 != status & 4] - self.decimal_mode_flag = [0, 1][0 != status & 8] - self.break_flag = [0, 1][0 != status & 16] - self.overflow_flag = [0, 1][0 != status & 64] - self.sign_flag = [0, 1][0 != status & 128] - - def status_as_byte(self): - return self.carry_flag | self.zero_flag << 1 | self.interrupt_disable_flag << 2 | self.decimal_mode_flag << 3 | self.break_flag << 4 | 1 << 5 | self.overflow_flag << 6 | self.sign_flag << 7 - - #### - - def push_byte(self, byte): - self.memory.write_byte(self.STACK_PAGE + self.stack_pointer, byte) - self.stack_pointer = (self.stack_pointer - 1) % 0x100 - - def pull_byte(self): - self.stack_pointer = (self.stack_pointer + 1) % 0x100 - return self.read_byte(self.STACK_PAGE + self.stack_pointer) - - def push_word(self, word): - hi, lo = divmod(word, 0x100) - self.push_byte(hi) - self.push_byte(lo) - - def pull_word(self): - s = self.STACK_PAGE + self.stack_pointer + 1 - self.stack_pointer += 2 - return self.read_word(s) - - #### - - def immediate_mode(self): - return self.get_pc() - - def absolute_mode(self): - self.cycles += 2 - return self.read_pc_word() - - def absolute_x_mode(self, rmw=False): - if rmw: - self.cycles += 1 - return self.absolute_mode() + self.x_index - - def absolute_y_mode(self, rmw=False): - if rmw: - self.cycles += 1 - return self.absolute_mode() + self.y_index - - def zero_page_mode(self): - self.cycles += 1 - return self.read_pc_byte() - - def zero_page_x_mode(self): - self.cycles += 1 - return (self.zero_page_mode() + self.x_index) % 0x100 - - def zero_page_y_mode(self): - self.cycles += 1 - return (self.zero_page_mode() + self.y_index) % 0x100 - - def indirect_mode(self): - self.cycles += 2 - return self.read_word_bug(self.absolute_mode()) - - def indirect_x_mode(self): - self.cycles += 4 - return self.read_word_bug((self.read_pc_byte() + self.x_index) % 0x100) - - def indirect_y_mode(self, rmw=False): - if rmw: - self.cycles += 4 - else: - self.cycles += 3 - return self.read_word_bug(self.read_pc_byte()) + self.y_index - - def relative_mode(self): - pc = self.get_pc() - return pc + 1 + signed(self.read_byte(pc)) - - #### - - def update_nz(self, value): - value = value % 0x100 - self.zero_flag = [0, 1][(value == 0)] - self.sign_flag = [0, 1][((value & 0x80) != 0)] - return value - - def update_nzc(self, value): - self.carry_flag = [0, 1][(value > 0xFF)] - return self.update_nz(value) - - #### - - # LOAD / STORE - - def LDA(self, operand_address): - self.accumulator = self.update_nz(self.read_byte(operand_address)) - - def LDX(self, operand_address): - self.x_index = self.update_nz(self.read_byte(operand_address)) - - def LDY(self, operand_address): - self.y_index = self.update_nz(self.read_byte(operand_address)) - - def STA(self, operand_address): - self.memory.write_byte(operand_address, self.accumulator) - - def STX(self, operand_address): - self.memory.write_byte(operand_address, self.x_index) - - def STY(self, operand_address): - self.memory.write_byte(operand_address, self.y_index) - - # TRANSFER - - def TAX(self): - self.x_index = self.update_nz(self.accumulator) - - def TXA(self): - self.accumulator = self.update_nz(self.x_index) - - def TAY(self): - self.y_index = self.update_nz(self.accumulator) - - def TYA(self): - self.accumulator = self.update_nz(self.y_index) - - def TSX(self): - self.x_index = self.update_nz(self.stack_pointer) - - def TXS(self): - self.stack_pointer = self.x_index - - # SHIFTS / ROTATES - - def ASL(self, operand_address=None): - if operand_address is None: - self.accumulator = self.update_nzc(self.accumulator << 1) - else: - self.cycles += 2 - self.memory.write_byte(operand_address, self.update_nzc(self.read_byte(operand_address) << 1)) - - def ROL(self, operand_address=None): - if operand_address is None: - a = self.accumulator << 1 - if self.carry_flag: - a = a | 0x01 - self.accumulator = self.update_nzc(a) - else: - self.cycles += 2 - m = self.read_byte(operand_address) << 1 - if self.carry_flag: - m = m | 0x01 - self.memory.write_byte(operand_address, self.update_nzc(m)) - - def ROR(self, operand_address=None): - if operand_address is None: - if self.carry_flag: - self.accumulator = self.accumulator | 0x100 - self.carry_flag = self.accumulator % 2 - self.accumulator = self.update_nz(self.accumulator >> 1) - else: - self.cycles += 2 - m = self.read_byte(operand_address) - if self.carry_flag: - m = m | 0x100 - self.carry_flag = m % 2 - self.memory.write_byte(operand_address, self.update_nz(m >> 1)) - - def LSR(self, operand_address=None): - if operand_address is None: - self.carry_flag = self.accumulator % 2 - self.accumulator = self.update_nz(self.accumulator >> 1) - else: - self.cycles += 2 - self.carry_flag = self.read_byte(operand_address) % 2 - self.memory.write_byte(operand_address, self.update_nz(self.read_byte(operand_address) >> 1)) - - # JUMPS / RETURNS - - def JMP(self, operand_address): - self.cycles -= 1 - self.program_counter = operand_address - - def JSR(self, operand_address): - self.cycles += 2 - self.push_word(self.program_counter - 1) - self.program_counter = operand_address - - def RTS(self): - self.cycles += 4 - self.program_counter = self.pull_word() + 1 - - # BRANCHES - - def BCC(self, operand_address): - if not self.carry_flag: - self.cycles += 1 - self.program_counter = operand_address - - def BCS(self, operand_address): - if self.carry_flag: - self.cycles += 1 - self.program_counter = operand_address - - def BEQ(self, operand_address): - if self.zero_flag: - self.cycles += 1 - self.program_counter = operand_address - - def BNE(self, operand_address): - if not self.zero_flag: - self.cycles += 1 - self.program_counter = operand_address - - def BMI(self, operand_address): - if self.sign_flag: - self.cycles += 1 - self.program_counter = operand_address - - def BPL(self, operand_address): - if not self.sign_flag: - self.cycles += 1 - self.program_counter = operand_address - - def BVC(self, operand_address): - if not self.overflow_flag: - self.cycles += 1 - self.program_counter = operand_address - - def BVS(self, operand_address): - if self.overflow_flag: - self.cycles += 1 - self.program_counter = operand_address - - # SET / CLEAR FLAGS - - def CLC(self): - self.carry_flag = 0 - - def CLD(self): - self.decimal_mode_flag = 0 - - def CLI(self): - self.interrupt_disable_flag = 0 - - def CLV(self): - self.overflow_flag = 0 - - def SEC(self): - self.carry_flag = 1 - - def SED(self): - self.decimal_mode_flag = 1 - - def SEI(self): - self.interrupt_disable_flag = 1 - - # INCREMENT / DECREMENT - - def DEC(self, operand_address): - self.cycles += 2 - self.memory.write_byte(operand_address, self.update_nz(self.read_byte(operand_address) - 1)) - - def DEX(self): - self.x_index = self.update_nz(self.x_index - 1) - - def DEY(self): - self.y_index = self.update_nz(self.y_index - 1) - - def INC(self, operand_address): - self.cycles += 2 - self.memory.write_byte(operand_address, self.update_nz(self.read_byte(operand_address) + 1)) - - def INX(self): - self.x_index = self.update_nz(self.x_index + 1) - - def INY(self): - self.y_index = self.update_nz(self.y_index + 1) - - # PUSH / PULL - - def PHA(self): - self.cycles += 1 - self.push_byte(self.accumulator) - - def PHP(self): - self.cycles += 1 - self.push_byte(self.status_as_byte()) - - def PLA(self): - self.cycles += 2 - self.accumulator = self.update_nz(self.pull_byte()) - - def PLP(self): - self.cycles += 2 - self.status_from_byte(self.pull_byte()) - - # LOGIC - - def AND(self, operand_address): - self.accumulator = self.update_nz(self.accumulator & self.read_byte(operand_address)) - - def ORA(self, operand_address): - self.accumulator = self.update_nz(self.accumulator | self.read_byte(operand_address)) - - def EOR(self, operand_address): - self.accumulator = self.update_nz(self.accumulator ^ self.read_byte(operand_address)) - - # ARITHMETIC - - def ADC(self, operand_address): - # @@@ doesn't handle BCD yet - assert not self.decimal_mode_flag - - a2 = self.accumulator - a1 = signed(a2) - m2 = self.read_byte(operand_address) - m1 = signed(m2) - - # twos complement addition - result1 = a1 + m1 + self.carry_flag - - # unsigned addition - result2 = a2 + m2 + self.carry_flag - - self.accumulator = self.update_nzc(result2) - - # perhaps this could be calculated from result2 but result1 is more intuitive - self.overflow_flag = [0, 1][(result1 > 127) | (result1 < -128)] - - def SBC(self, operand_address): - # @@@ doesn't handle BCD yet - assert not self.decimal_mode_flag - - a2 = self.accumulator - a1 = signed(a2) - m2 = self.read_byte(operand_address) - m1 = signed(m2) - - # twos complement subtraction - result1 = a1 - m1 - [1, 0][self.carry_flag] - - # unsigned subtraction - result2 = a2 - m2 - [1, 0][self.carry_flag] - - self.accumulator = self.update_nz(result2) - self.carry_flag = [0, 1][(result2 >= 0)] - - # perhaps this could be calculated from result2 but result1 is more intuitive - self.overflow_flag = [0, 1][(result1 > 127) | (result1 < -128)] - - # BIT - - def BIT(self, operand_address): - value = self.read_byte(operand_address) - self.sign_flag = ((value >> 7) % 2) # bit 7 - self.overflow_flag = ((value >> 6) % 2) # bit 6 - self.zero_flag = [0, 1][((self.accumulator & value) == 0)] - - # COMPARISON - - def CMP(self, operand_address): - result = self.accumulator - self.read_byte(operand_address) - self.carry_flag = [0, 1][(result >= 0)] - self.update_nz(result) - - def CPX(self, operand_address): - result = self.x_index - self.read_byte(operand_address) - self.carry_flag = [0, 1][(result >= 0)] - self.update_nz(result) - - def CPY(self, operand_address): - result = self.y_index - self.read_byte(operand_address) - self.carry_flag = [0, 1][(result >= 0)] - self.update_nz(result) - - # SYSTEM - - def NOP(self): - pass - - def BRK(self): - self.cycles += 5 - self.push_word(self.program_counter + 1) - self.push_byte(self.status_as_byte()) - self.program_counter = self.read_word(0xFFFE) - self.break_flag = 1 - - def RTI(self): - self.cycles += 4 - self.status_from_byte(self.pull_byte()) - self.program_counter = self.pull_word() - - - # @@@ IRQ - # @@@ NMI - def usage(): print >>sys.stderr, "ApplePy - an Apple ][ emulator in Python" @@ -1329,7 +429,6 @@ if __name__ == "__main__": options = get_options() display = Display() speaker = None if options.quiet else Speaker() - mem = Memory(options, display, speaker) - - cpu = CPU(mem) - cpu.run() + + apple = Apple2(options, display, speaker) + apple.run() diff --git a/applepy_curses.py b/applepy_curses.py new file mode 100644 index 0000000..8b234e6 --- /dev/null +++ b/applepy_curses.py @@ -0,0 +1,91 @@ +# ApplePy - an Apple ][ emulator in Python +# James Tauber / http://jtauber.com/ +# originally written 2001, updated 2011 + + +import curses +import struct +import subprocess +import sys + + +kbd = 0 + + +def write_screen(win, address, value): + base = address - 0x400 + hi, lo = divmod(base, 0x80) + row_group, column = divmod(lo, 0x28) + row = hi + 8 * row_group + + # skip if writing to row group 3 + if row_group == 3: + return + + c = chr(0x20 + ((value + 0x20) % 0x40)) + + if value < 0x40: + attr = curses.A_DIM + elif value < 0x80: + attr = curses.A_REVERSE + elif value < 0xA0: + attr = curses.A_UNDERLINE + else: + attr = curses.A_DIM + + try: + win.addch(row, column, c, attr) + except curses.error: + pass + + +def read(addr, val): + global kbd + if addr == 0xC000: + return kbd + elif addr == 0xC010: + kbd = kbd & 0x7F + return 0x00 + + +def write(win, addr, val): + if 0x400 <= addr <= 0x800: + write_screen(win, addr, val) + + +def run(win): + global kbd + p = subprocess.Popen( + args=[sys.executable, "cpu6502.py"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + win.clear() + curses.noecho() + win.nodelay(True) + while True: + op = p.stdout.read(8) + cycle, rw, addr, val = struct.unpack(" 0x7F: + x = x - 0x100 + return x + + +class ROM: + + def __init__(self, start, size): + self.start = start + self.end = start + size - 1 + self._mem = [0x00] * size + + def load(self, address, data): + for offset, datum in enumerate(data): + self._mem[address - self.start + offset] = datum + + def load_file(self, address, filename): + with open(filename) as f: + for offset, datum in enumerate(f.read()): + self._mem[address - self.start + offset] = ord(datum) + + def read_byte(self, address): + assert self.start <= address <= self.end + return self._mem[address - self.start] + + +class RAM(ROM): + + def write_byte(self, address, value): + self._mem[address] = value + + +class Memory: + + def __init__(self, options=None, use_stdio=True): + self.use_stdio = use_stdio + self.rom = ROM(0xD000, 0x3000) + + if options: + self.rom.load_file(0xD000, options.rom) + + self.ram = RAM(0x0000, 0xC000) + + if options and options.ram: + self.ram.load_file(0x0000, options.ram) + + def load(self, address, data): + if address < 0xC000: + self.ram.load(address, data) + + def read_byte(self, cycle, address): + if address < 0xC000: + return self.ram.read_byte(address) + elif address < 0xD000: + return self.bus_read(cycle, address) + else: + return self.rom.read_byte(address) + + def read_word(self, cycle, address): + return self.read_byte(cycle, address) + (self.read_byte(cycle + 1, address + 1) << 8) + + def read_word_bug(self, cycle, address): + if address % 0x100 == 0xFF: + return self.read_byte(cycle, address) + (self.read_byte(cycle + 1, address & 0xFF00) << 8) + else: + return self.read_word(cycle, address) + + def write_byte(self, cycle, address, value): + if address < 0xC000: + self.ram.write_byte(address, value) + if 0x400 <= address < 0x800 or 0x2000 <= address < 0x5FFF: + self.bus_write(cycle, address, value) + + def bus_read(self, cycle, address): + if not self.use_stdio: + return 0 + op = struct.pack(" 1: + s += " " + info[1](pc) + return s + + +class CPU: + + STACK_PAGE = 0x100 + RESET_VECTOR = 0xFFFC + + def __init__(self, memory): + self.memory = memory + self.disassemble = Disassemble(self, memory) + + self.accumulator = 0x00 + self.x_index = 0x00 + self.y_index = 0x00 + + self.carry_flag = 0 + self.zero_flag = 0 + self.interrupt_disable_flag = 0 + self.decimal_mode_flag = 0 + self.break_flag = 1 + self.overflow_flag = 0 + self.sign_flag = 0 + + self.stack_pointer = 0xFF + + self.cycles = 0 + + self.setup_ops() + self.reset() + + def setup_ops(self): + self.ops = [None] * 0x100 + self.ops[0x00] = lambda: self.BRK() + self.ops[0x01] = lambda: self.ORA(self.indirect_x_mode()) + self.ops[0x05] = lambda: self.ORA(self.zero_page_mode()) + self.ops[0x06] = lambda: self.ASL(self.zero_page_mode()) + self.ops[0x08] = lambda: self.PHP() + self.ops[0x09] = lambda: self.ORA(self.immediate_mode()) + self.ops[0x0A] = lambda: self.ASL() + self.ops[0x0D] = lambda: self.ORA(self.absolute_mode()) + self.ops[0x0E] = lambda: self.ASL(self.absolute_mode()) + self.ops[0x10] = lambda: self.BPL(self.relative_mode()) + self.ops[0x11] = lambda: self.ORA(self.indirect_y_mode()) + self.ops[0x15] = lambda: self.ORA(self.zero_page_x_mode()) + self.ops[0x16] = lambda: self.ASL(self.zero_page_x_mode()) + self.ops[0x18] = lambda: self.CLC() + self.ops[0x19] = lambda: self.ORA(self.absolute_y_mode()) + self.ops[0x1D] = lambda: self.ORA(self.absolute_x_mode()) + self.ops[0x1E] = lambda: self.ASL(self.absolute_x_mode(rmw=True)) + self.ops[0x20] = lambda: self.JSR(self.absolute_mode()) + self.ops[0x21] = lambda: self.AND(self.indirect_x_mode()) + self.ops[0x24] = lambda: self.BIT(self.zero_page_mode()) + self.ops[0x25] = lambda: self.AND(self.zero_page_mode()) + self.ops[0x26] = lambda: self.ROL(self.zero_page_mode()) + self.ops[0x28] = lambda: self.PLP() + self.ops[0x29] = lambda: self.AND(self.immediate_mode()) + self.ops[0x2A] = lambda: self.ROL() + self.ops[0x2C] = lambda: self.BIT(self.absolute_mode()) + self.ops[0x2D] = lambda: self.AND(self.absolute_mode()) + self.ops[0x2E] = lambda: self.ROL(self.absolute_mode()) + self.ops[0x30] = lambda: self.BMI(self.relative_mode()) + self.ops[0x31] = lambda: self.AND(self.indirect_y_mode()) + self.ops[0x35] = lambda: self.AND(self.zero_page_x_mode()) + self.ops[0x36] = lambda: self.ROL(self.zero_page_x_mode()) + self.ops[0x38] = lambda: self.SEC() + self.ops[0x39] = lambda: self.AND(self.absolute_y_mode()) + self.ops[0x3D] = lambda: self.AND(self.absolute_x_mode()) + self.ops[0x3E] = lambda: self.ROL(self.absolute_x_mode(rmw=True)) + self.ops[0x40] = lambda: self.RTI() + self.ops[0x41] = lambda: self.EOR(self.indirect_x_mode()) + self.ops[0x45] = lambda: self.EOR(self.zero_page_mode()) + self.ops[0x46] = lambda: self.LSR(self.zero_page_mode()) + self.ops[0x48] = lambda: self.PHA() + self.ops[0x49] = lambda: self.EOR(self.immediate_mode()) + self.ops[0x4A] = lambda: self.LSR() + self.ops[0x4C] = lambda: self.JMP(self.absolute_mode()) + self.ops[0x4D] = lambda: self.EOR(self.absolute_mode()) + self.ops[0x4E] = lambda: self.LSR(self.absolute_mode()) + self.ops[0x50] = lambda: self.BVC(self.relative_mode()) + self.ops[0x51] = lambda: self.EOR(self.indirect_y_mode()) + self.ops[0x55] = lambda: self.EOR(self.zero_page_x_mode()) + self.ops[0x56] = lambda: self.LSR(self.zero_page_x_mode()) + self.ops[0x58] = lambda: self.CLI() + self.ops[0x59] = lambda: self.EOR(self.absolute_y_mode()) + self.ops[0x5D] = lambda: self.EOR(self.absolute_x_mode()) + self.ops[0x5E] = lambda: self.LSR(self.absolute_x_mode(rmw=True)) + self.ops[0x60] = lambda: self.RTS() + self.ops[0x61] = lambda: self.ADC(self.indirect_x_mode()) + self.ops[0x65] = lambda: self.ADC(self.zero_page_mode()) + self.ops[0x66] = lambda: self.ROR(self.zero_page_mode()) + self.ops[0x68] = lambda: self.PLA() + self.ops[0x69] = lambda: self.ADC(self.immediate_mode()) + self.ops[0x6A] = lambda: self.ROR() + self.ops[0x6C] = lambda: self.JMP(self.indirect_mode()) + self.ops[0x6D] = lambda: self.ADC(self.absolute_mode()) + self.ops[0x6E] = lambda: self.ROR(self.absolute_mode()) + self.ops[0x70] = lambda: self.BVS(self.relative_mode()) + self.ops[0x71] = lambda: self.ADC(self.indirect_y_mode()) + self.ops[0x75] = lambda: self.ADC(self.zero_page_x_mode()) + self.ops[0x76] = lambda: self.ROR(self.zero_page_x_mode()) + self.ops[0x78] = lambda: self.SEI() + self.ops[0x79] = lambda: self.ADC(self.absolute_y_mode()) + self.ops[0x7D] = lambda: self.ADC(self.absolute_x_mode()) + self.ops[0x7E] = lambda: self.ROR(self.absolute_x_mode(rmw=True)) + self.ops[0x81] = lambda: self.STA(self.indirect_x_mode()) + self.ops[0x84] = lambda: self.STY(self.zero_page_mode()) + self.ops[0x85] = lambda: self.STA(self.zero_page_mode()) + self.ops[0x86] = lambda: self.STX(self.zero_page_mode()) + self.ops[0x88] = lambda: self.DEY() + self.ops[0x8A] = lambda: self.TXA() + self.ops[0x8C] = lambda: self.STY(self.absolute_mode()) + self.ops[0x8D] = lambda: self.STA(self.absolute_mode()) + self.ops[0x8E] = lambda: self.STX(self.absolute_mode()) + self.ops[0x90] = lambda: self.BCC(self.relative_mode()) + self.ops[0x91] = lambda: self.STA(self.indirect_y_mode(rmw=True)) + self.ops[0x94] = lambda: self.STY(self.zero_page_x_mode()) + self.ops[0x95] = lambda: self.STA(self.zero_page_x_mode()) + self.ops[0x96] = lambda: self.STX(self.zero_page_y_mode()) + self.ops[0x98] = lambda: self.TYA() + self.ops[0x99] = lambda: self.STA(self.absolute_y_mode(rmw=True)) + self.ops[0x9A] = lambda: self.TXS() + self.ops[0x9D] = lambda: self.STA(self.absolute_x_mode(rmw=True)) + self.ops[0xA0] = lambda: self.LDY(self.immediate_mode()) + self.ops[0xA1] = lambda: self.LDA(self.indirect_x_mode()) + self.ops[0xA2] = lambda: self.LDX(self.immediate_mode()) + self.ops[0xA4] = lambda: self.LDY(self.zero_page_mode()) + self.ops[0xA5] = lambda: self.LDA(self.zero_page_mode()) + self.ops[0xA6] = lambda: self.LDX(self.zero_page_mode()) + self.ops[0xA8] = lambda: self.TAY() + self.ops[0xA9] = lambda: self.LDA(self.immediate_mode()) + self.ops[0xAA] = lambda: self.TAX() + self.ops[0xAC] = lambda: self.LDY(self.absolute_mode()) + self.ops[0xAD] = lambda: self.LDA(self.absolute_mode()) + self.ops[0xAE] = lambda: self.LDX(self.absolute_mode()) + self.ops[0xB0] = lambda: self.BCS(self.relative_mode()) + self.ops[0xB1] = lambda: self.LDA(self.indirect_y_mode()) + self.ops[0xB4] = lambda: self.LDY(self.zero_page_x_mode()) + self.ops[0xB5] = lambda: self.LDA(self.zero_page_x_mode()) + self.ops[0xB6] = lambda: self.LDX(self.zero_page_y_mode()) + self.ops[0xB8] = lambda: self.CLV() + self.ops[0xB9] = lambda: self.LDA(self.absolute_y_mode()) + self.ops[0xBA] = lambda: self.TSX() + self.ops[0xBC] = lambda: self.LDY(self.absolute_x_mode()) + self.ops[0xBD] = lambda: self.LDA(self.absolute_x_mode()) + self.ops[0xBE] = lambda: self.LDX(self.absolute_y_mode()) + self.ops[0xC0] = lambda: self.CPY(self.immediate_mode()) + self.ops[0xC1] = lambda: self.CMP(self.indirect_x_mode()) + self.ops[0xC4] = lambda: self.CPY(self.zero_page_mode()) + self.ops[0xC5] = lambda: self.CMP(self.zero_page_mode()) + self.ops[0xC6] = lambda: self.DEC(self.zero_page_mode()) + self.ops[0xC8] = lambda: self.INY() + self.ops[0xC9] = lambda: self.CMP(self.immediate_mode()) + self.ops[0xCA] = lambda: self.DEX() + self.ops[0xCC] = lambda: self.CPY(self.absolute_mode()) + self.ops[0xCD] = lambda: self.CMP(self.absolute_mode()) + self.ops[0xCE] = lambda: self.DEC(self.absolute_mode()) + self.ops[0xD0] = lambda: self.BNE(self.relative_mode()) + self.ops[0xD1] = lambda: self.CMP(self.indirect_y_mode()) + self.ops[0xD5] = lambda: self.CMP(self.zero_page_x_mode()) + self.ops[0xD6] = lambda: self.DEC(self.zero_page_x_mode()) + self.ops[0xD8] = lambda: self.CLD() + self.ops[0xD9] = lambda: self.CMP(self.absolute_y_mode()) + self.ops[0xDD] = lambda: self.CMP(self.absolute_x_mode()) + self.ops[0xDE] = lambda: self.DEC(self.absolute_x_mode(rmw=True)) + self.ops[0xE0] = lambda: self.CPX(self.immediate_mode()) + self.ops[0xE1] = lambda: self.SBC(self.indirect_x_mode()) + self.ops[0xE4] = lambda: self.CPX(self.zero_page_mode()) + self.ops[0xE5] = lambda: self.SBC(self.zero_page_mode()) + self.ops[0xE6] = lambda: self.INC(self.zero_page_mode()) + self.ops[0xE8] = lambda: self.INX() + self.ops[0xE9] = lambda: self.SBC(self.immediate_mode()) + self.ops[0xEA] = lambda: self.NOP() + self.ops[0xEC] = lambda: self.CPX(self.absolute_mode()) + self.ops[0xED] = lambda: self.SBC(self.absolute_mode()) + self.ops[0xEE] = lambda: self.INC(self.absolute_mode()) + self.ops[0xF0] = lambda: self.BEQ(self.relative_mode()) + self.ops[0xF1] = lambda: self.SBC(self.indirect_y_mode()) + self.ops[0xF5] = lambda: self.SBC(self.zero_page_x_mode()) + self.ops[0xF6] = lambda: self.INC(self.zero_page_x_mode()) + self.ops[0xF8] = lambda: self.SED() + self.ops[0xF9] = lambda: self.SBC(self.absolute_y_mode()) + self.ops[0xFD] = lambda: self.SBC(self.absolute_x_mode()) + self.ops[0xFE] = lambda: self.INC(self.absolute_x_mode(rmw=True)) + + def reset(self): + self.program_counter = self.read_word(self.RESET_VECTOR) + + def run(self): + while True: + self.cycles += 2 # all instructions take this as a minimum + op = self.read_pc_byte() + func = self.ops[op] + if func is None: + print "UNKNOWN OP" + print hex(self.program_counter - 1) + print hex(op) + break + else: + self.ops[op]() + + def test_run(self, start, end): + self.program_counter = start + while True: + self.cycles += 2 # all instructions take this as a minimum + if self.program_counter == end: + break + op = self.read_pc_byte() + func = self.ops[op] + if func is None: + print "UNKNOWN OP" + print hex(self.program_counter - 1) + print hex(op) + break + else: + self.ops[op]() + + #### + + def get_pc(self, inc=1): + pc = self.program_counter + self.program_counter += inc + return pc + + def read_byte(self, address): + return self.memory.read_byte(self.cycles, address) + + def read_word(self, address): + return self.memory.read_word(self.cycles, address) + + def read_word_bug(self, address): + return self.memory.read_word_bug(self.cycles, address) + + def read_pc_byte(self): + return self.read_byte(self.get_pc()) + + def read_pc_word(self): + return self.read_word(self.get_pc(2)) + + def write_byte(self, address, value): + self.memory.write_byte(self.cycles, address, value) + + #### + + def status_from_byte(self, status): + self.carry_flag = [0, 1][0 != status & 1] + self.zero_flag = [0, 1][0 != status & 2] + self.interrupt_disable_flag = [0, 1][0 != status & 4] + self.decimal_mode_flag = [0, 1][0 != status & 8] + self.break_flag = [0, 1][0 != status & 16] + self.overflow_flag = [0, 1][0 != status & 64] + self.sign_flag = [0, 1][0 != status & 128] + + def status_as_byte(self): + return self.carry_flag | self.zero_flag << 1 | self.interrupt_disable_flag << 2 | self.decimal_mode_flag << 3 | self.break_flag << 4 | 1 << 5 | self.overflow_flag << 6 | self.sign_flag << 7 + + #### + + def push_byte(self, byte): + self.write_byte(self.STACK_PAGE + self.stack_pointer, byte) + self.stack_pointer = (self.stack_pointer - 1) % 0x100 + + def pull_byte(self): + self.stack_pointer = (self.stack_pointer + 1) % 0x100 + return self.read_byte(self.STACK_PAGE + self.stack_pointer) + + def push_word(self, word): + hi, lo = divmod(word, 0x100) + self.push_byte(hi) + self.push_byte(lo) + + def pull_word(self): + s = self.STACK_PAGE + self.stack_pointer + 1 + self.stack_pointer += 2 + return self.read_word(s) + + #### + + def immediate_mode(self): + return self.get_pc() + + def absolute_mode(self): + self.cycles += 2 + return self.read_pc_word() + + def absolute_x_mode(self, rmw=False): + if rmw: + self.cycles += 1 + return self.absolute_mode() + self.x_index + + def absolute_y_mode(self, rmw=False): + if rmw: + self.cycles += 1 + return self.absolute_mode() + self.y_index + + def zero_page_mode(self): + self.cycles += 1 + return self.read_pc_byte() + + def zero_page_x_mode(self): + self.cycles += 1 + return (self.zero_page_mode() + self.x_index) % 0x100 + + def zero_page_y_mode(self): + self.cycles += 1 + return (self.zero_page_mode() + self.y_index) % 0x100 + + def indirect_mode(self): + self.cycles += 2 + return self.read_word_bug(self.absolute_mode()) + + def indirect_x_mode(self): + self.cycles += 4 + return self.read_word_bug((self.read_pc_byte() + self.x_index) % 0x100) + + def indirect_y_mode(self, rmw=False): + if rmw: + self.cycles += 4 + else: + self.cycles += 3 + return self.read_word_bug(self.read_pc_byte()) + self.y_index + + def relative_mode(self): + pc = self.get_pc() + return pc + 1 + signed(self.read_byte(pc)) + + #### + + def update_nz(self, value): + value = value % 0x100 + self.zero_flag = [0, 1][(value == 0)] + self.sign_flag = [0, 1][((value & 0x80) != 0)] + return value + + def update_nzc(self, value): + self.carry_flag = [0, 1][(value > 0xFF)] + return self.update_nz(value) + + #### + + # LOAD / STORE + + def LDA(self, operand_address): + self.accumulator = self.update_nz(self.read_byte(operand_address)) + + def LDX(self, operand_address): + self.x_index = self.update_nz(self.read_byte(operand_address)) + + def LDY(self, operand_address): + self.y_index = self.update_nz(self.read_byte(operand_address)) + + def STA(self, operand_address): + self.write_byte(operand_address, self.accumulator) + + def STX(self, operand_address): + self.write_byte(operand_address, self.x_index) + + def STY(self, operand_address): + self.write_byte(operand_address, self.y_index) + + # TRANSFER + + def TAX(self): + self.x_index = self.update_nz(self.accumulator) + + def TXA(self): + self.accumulator = self.update_nz(self.x_index) + + def TAY(self): + self.y_index = self.update_nz(self.accumulator) + + def TYA(self): + self.accumulator = self.update_nz(self.y_index) + + def TSX(self): + self.x_index = self.update_nz(self.stack_pointer) + + def TXS(self): + self.stack_pointer = self.x_index + + # SHIFTS / ROTATES + + def ASL(self, operand_address=None): + if operand_address is None: + self.accumulator = self.update_nzc(self.accumulator << 1) + else: + self.cycles += 2 + self.write_byte(operand_address, self.update_nzc(self.read_byte(operand_address) << 1)) + + def ROL(self, operand_address=None): + if operand_address is None: + a = self.accumulator << 1 + if self.carry_flag: + a = a | 0x01 + self.accumulator = self.update_nzc(a) + else: + self.cycles += 2 + m = self.read_byte(operand_address) << 1 + if self.carry_flag: + m = m | 0x01 + self.write_byte(operand_address, self.update_nzc(m)) + + def ROR(self, operand_address=None): + if operand_address is None: + if self.carry_flag: + self.accumulator = self.accumulator | 0x100 + self.carry_flag = self.accumulator % 2 + self.accumulator = self.update_nz(self.accumulator >> 1) + else: + self.cycles += 2 + m = self.read_byte(operand_address) + if self.carry_flag: + m = m | 0x100 + self.carry_flag = m % 2 + self.write_byte(operand_address, self.update_nz(m >> 1)) + + def LSR(self, operand_address=None): + if operand_address is None: + self.carry_flag = self.accumulator % 2 + self.accumulator = self.update_nz(self.accumulator >> 1) + else: + self.cycles += 2 + self.carry_flag = self.read_byte(operand_address) % 2 + self.write_byte(operand_address, self.update_nz(self.read_byte(operand_address) >> 1)) + + # JUMPS / RETURNS + + def JMP(self, operand_address): + self.cycles -= 1 + self.program_counter = operand_address + + def JSR(self, operand_address): + self.cycles += 2 + self.push_word(self.program_counter - 1) + self.program_counter = operand_address + + def RTS(self): + self.cycles += 4 + self.program_counter = self.pull_word() + 1 + + # BRANCHES + + def BCC(self, operand_address): + if not self.carry_flag: + self.cycles += 1 + self.program_counter = operand_address + + def BCS(self, operand_address): + if self.carry_flag: + self.cycles += 1 + self.program_counter = operand_address + + def BEQ(self, operand_address): + if self.zero_flag: + self.cycles += 1 + self.program_counter = operand_address + + def BNE(self, operand_address): + if not self.zero_flag: + self.cycles += 1 + self.program_counter = operand_address + + def BMI(self, operand_address): + if self.sign_flag: + self.cycles += 1 + self.program_counter = operand_address + + def BPL(self, operand_address): + if not self.sign_flag: + self.cycles += 1 + self.program_counter = operand_address + + def BVC(self, operand_address): + if not self.overflow_flag: + self.cycles += 1 + self.program_counter = operand_address + + def BVS(self, operand_address): + if self.overflow_flag: + self.cycles += 1 + self.program_counter = operand_address + + # SET / CLEAR FLAGS + + def CLC(self): + self.carry_flag = 0 + + def CLD(self): + self.decimal_mode_flag = 0 + + def CLI(self): + self.interrupt_disable_flag = 0 + + def CLV(self): + self.overflow_flag = 0 + + def SEC(self): + self.carry_flag = 1 + + def SED(self): + self.decimal_mode_flag = 1 + + def SEI(self): + self.interrupt_disable_flag = 1 + + # INCREMENT / DECREMENT + + def DEC(self, operand_address): + self.cycles += 2 + self.write_byte(operand_address, self.update_nz(self.read_byte(operand_address) - 1)) + + def DEX(self): + self.x_index = self.update_nz(self.x_index - 1) + + def DEY(self): + self.y_index = self.update_nz(self.y_index - 1) + + def INC(self, operand_address): + self.cycles += 2 + self.write_byte(operand_address, self.update_nz(self.read_byte(operand_address) + 1)) + + def INX(self): + self.x_index = self.update_nz(self.x_index + 1) + + def INY(self): + self.y_index = self.update_nz(self.y_index + 1) + + # PUSH / PULL + + def PHA(self): + self.cycles += 1 + self.push_byte(self.accumulator) + + def PHP(self): + self.cycles += 1 + self.push_byte(self.status_as_byte()) + + def PLA(self): + self.cycles += 2 + self.accumulator = self.update_nz(self.pull_byte()) + + def PLP(self): + self.cycles += 2 + self.status_from_byte(self.pull_byte()) + + # LOGIC + + def AND(self, operand_address): + self.accumulator = self.update_nz(self.accumulator & self.read_byte(operand_address)) + + def ORA(self, operand_address): + self.accumulator = self.update_nz(self.accumulator | self.read_byte(operand_address)) + + def EOR(self, operand_address): + self.accumulator = self.update_nz(self.accumulator ^ self.read_byte(operand_address)) + + # ARITHMETIC + + def ADC(self, operand_address): + # @@@ doesn't handle BCD yet + assert not self.decimal_mode_flag + + a2 = self.accumulator + a1 = signed(a2) + m2 = self.read_byte(operand_address) + m1 = signed(m2) + + # twos complement addition + result1 = a1 + m1 + self.carry_flag + + # unsigned addition + result2 = a2 + m2 + self.carry_flag + + self.accumulator = self.update_nzc(result2) + + # perhaps this could be calculated from result2 but result1 is more intuitive + self.overflow_flag = [0, 1][(result1 > 127) | (result1 < -128)] + + def SBC(self, operand_address): + # @@@ doesn't handle BCD yet + assert not self.decimal_mode_flag + + a2 = self.accumulator + a1 = signed(a2) + m2 = self.read_byte(operand_address) + m1 = signed(m2) + + # twos complement subtraction + result1 = a1 - m1 - [1, 0][self.carry_flag] + + # unsigned subtraction + result2 = a2 - m2 - [1, 0][self.carry_flag] + + self.accumulator = self.update_nz(result2) + self.carry_flag = [0, 1][(result2 >= 0)] + + # perhaps this could be calculated from result2 but result1 is more intuitive + self.overflow_flag = [0, 1][(result1 > 127) | (result1 < -128)] + + # BIT + + def BIT(self, operand_address): + value = self.read_byte(operand_address) + self.sign_flag = ((value >> 7) % 2) # bit 7 + self.overflow_flag = ((value >> 6) % 2) # bit 6 + self.zero_flag = [0, 1][((self.accumulator & value) == 0)] + + # COMPARISON + + def CMP(self, operand_address): + result = self.accumulator - self.read_byte(operand_address) + self.carry_flag = [0, 1][(result >= 0)] + self.update_nz(result) + + def CPX(self, operand_address): + result = self.x_index - self.read_byte(operand_address) + self.carry_flag = [0, 1][(result >= 0)] + self.update_nz(result) + + def CPY(self, operand_address): + result = self.y_index - self.read_byte(operand_address) + self.carry_flag = [0, 1][(result >= 0)] + self.update_nz(result) + + # SYSTEM + + def NOP(self): + pass + + def BRK(self): + self.cycles += 5 + self.push_word(self.program_counter + 1) + self.push_byte(self.status_as_byte()) + self.program_counter = self.read_word(0xFFFE) + self.break_flag = 1 + + def RTI(self): + self.cycles += 4 + self.status_from_byte(self.pull_byte()) + self.program_counter = self.pull_word() + + + # @@@ IRQ + # @@@ NMI + + +def usage(): + print >>sys.stderr, "ApplePy - an Apple ][ emulator in Python" + print >>sys.stderr, "James Tauber / http://jtauber.com/" + print >>sys.stderr + print >>sys.stderr, "Usage: cpu6502.py [options]" + print >>sys.stderr + print >>sys.stderr, " -R, --rom ROM file to use (default A2ROM.BIN)" + print >>sys.stderr, " -r, --ram RAM file to load (default none)" + sys.exit(1) + + +def get_options(): + class Options: + def __init__(self): + self.rom = "A2ROM.BIN" + self.ram = None + + options = Options() + a = 1 + while a < len(sys.argv): + if sys.argv[a].startswith("-"): + if sys.argv[a] in ("-R", "--rom"): + a += 1 + options.rom = sys.argv[a] + elif sys.argv[a] in ("-r", "--ram"): + a += 1 + options.ram = sys.argv[a] + else: + usage() + else: + usage() + a += 1 + + return options + + +if __name__ == "__main__": + if sys.stdout.isatty(): + print "ApplePy cpu core" + print "Run applepy.py instead" + sys.exit(0) + + options = get_options() + mem = Memory(options) + + cpu = CPU(mem) + cpu.run() diff --git a/tests.py b/tests.py index 11fa2f4..3d8dedd 100644 --- a/tests.py +++ b/tests.py @@ -1,11 +1,11 @@ import unittest -from applepy import Memory, CPU +from cpu6502 import Memory, CPU class TestMemory(unittest.TestCase): def setUp(self): - self.memory = Memory() + self.memory = Memory(use_stdio=False) def test_load(self): self.memory.load(0x1000, [0x01, 0x02, 0x03]) @@ -14,9 +14,9 @@ class TestMemory(unittest.TestCase): self.assertEqual(self.memory.read_byte(None, 0x1002), 0x03) def test_write(self): - self.memory.write_byte(0x1000, 0x11) - self.memory.write_byte(0x1001, 0x12) - self.memory.write_byte(0x1002, 0x13) + self.memory.write_byte(None, 0x1000, 0x11) + self.memory.write_byte(None, 0x1001, 0x12) + self.memory.write_byte(None, 0x1002, 0x13) self.assertEqual(self.memory.read_byte(None, 0x1000), 0x11) self.assertEqual(self.memory.read_byte(None, 0x1001), 0x12) self.assertEqual(self.memory.read_byte(None, 0x1002), 0x13) @@ -25,7 +25,7 @@ class TestMemory(unittest.TestCase): class TestLoadStoreOperations(unittest.TestCase): def setUp(self): - self.memory = Memory() + self.memory = Memory(use_stdio=False) self.cpu = CPU(self.memory) self.memory.load(0x1000, [0x00, 0x01, 0x7F, 0x80, 0xFF]) @@ -114,7 +114,7 @@ class TestLoadStoreOperations(unittest.TestCase): class TestRegisterTransferOperations(unittest.TestCase): def setUp(self): - self.memory = Memory() + self.memory = Memory(use_stdio=False) self.cpu = CPU(self.memory) def test_TAX(self): @@ -189,7 +189,7 @@ class TestRegisterTransferOperations(unittest.TestCase): class TestStackOperations(unittest.TestCase): def setUp(self): - self.memory = Memory() + self.memory = Memory(use_stdio=False) self.cpu = CPU(self.memory) def test_TSX(self): @@ -237,11 +237,11 @@ class TestStackOperations(unittest.TestCase): class TestLogicalOperations(unittest.TestCase): def setUp(self): - self.memory = Memory() + self.memory = Memory(use_stdio=False) self.cpu = CPU(self.memory) def test_AND(self): - self.memory.write_byte(0x1000, 0x37) + self.memory.write_byte(None, 0x1000, 0x37) self.cpu.accumulator = 0x34 self.cpu.AND(0x1000) self.assertEqual(self.cpu.accumulator, 0x34) @@ -254,7 +254,7 @@ class TestLogicalOperations(unittest.TestCase): self.assertEqual(self.cpu.sign_flag, 0) def test_EOR(self): - self.memory.write_byte(0x1000, 0x37) + self.memory.write_byte(None, 0x1000, 0x37) self.cpu.accumulator = 0x34 self.cpu.EOR(0x1000) self.assertEqual(self.cpu.accumulator, 0x03) @@ -272,7 +272,7 @@ class TestLogicalOperations(unittest.TestCase): self.assertEqual(self.cpu.sign_flag, 0) def test_ORA(self): - self.memory.write_byte(0x1000, 0x37) + self.memory.write_byte(None, 0x1000, 0x37) self.cpu.accumulator = 0x34 self.cpu.ORA(0x1000) self.assertEqual(self.cpu.accumulator, 0x37) @@ -290,31 +290,31 @@ class TestLogicalOperations(unittest.TestCase): self.assertEqual(self.cpu.sign_flag, 0) def test_BIT(self): - self.memory.write_byte(0x1000, 0x00) + self.memory.write_byte(None, 0x1000, 0x00) self.cpu.accumulator = 0x00 self.cpu.BIT(0x1000) self.assertEqual(self.cpu.overflow_flag, 0) self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 1) - self.memory.write_byte(0x1000, 0x40) + self.memory.write_byte(None, 0x1000, 0x40) self.cpu.accumulator = 0x00 self.cpu.BIT(0x1000) self.assertEqual(self.cpu.overflow_flag, 1) self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 1) - self.memory.write_byte(0x1000, 0x80) + self.memory.write_byte(None, 0x1000, 0x80) self.cpu.accumulator = 0x00 self.cpu.BIT(0x1000) self.assertEqual(self.cpu.overflow_flag, 0) self.assertEqual(self.cpu.sign_flag, 1) self.assertEqual(self.cpu.zero_flag, 1) - self.memory.write_byte(0x1000, 0xC0) + self.memory.write_byte(None, 0x1000, 0xC0) self.cpu.accumulator = 0x00 self.cpu.BIT(0x1000) self.assertEqual(self.cpu.overflow_flag, 1) self.assertEqual(self.cpu.sign_flag, 1) self.assertEqual(self.cpu.zero_flag, 1) - self.memory.write_byte(0x1000, 0xC0) + self.memory.write_byte(None, 0x1000, 0xC0) self.cpu.accumulator = 0xC0 self.cpu.BIT(0x1000) self.assertEqual(self.cpu.overflow_flag, 1) @@ -325,7 +325,7 @@ class TestLogicalOperations(unittest.TestCase): class TestArithmeticOperations(unittest.TestCase): def setUp(self): - self.memory = Memory() + self.memory = Memory(use_stdio=False) self.cpu = CPU(self.memory) def test_ADC_without_BCD(self): @@ -335,7 +335,7 @@ class TestArithmeticOperations(unittest.TestCase): # 1 + 1 = 2 (C = 0; V = 0) self.cpu.carry_flag = 0 self.cpu.accumulator = 0x01 - self.memory.write_byte(0x1000, 0x01) + self.memory.write_byte(None, 0x1000, 0x01) self.cpu.ADC(0x1000) self.assertEqual(self.cpu.accumulator, 0x02) self.assertEqual(self.cpu.carry_flag, 0) @@ -344,7 +344,7 @@ class TestArithmeticOperations(unittest.TestCase): # 1 + -1 = 0 (C = 1; V = 0) self.cpu.carry_flag = 0 self.cpu.accumulator = 0x01 - self.memory.write_byte(0x1000, 0xFF) + self.memory.write_byte(None, 0x1000, 0xFF) self.cpu.ADC(0x1000) self.assertEqual(self.cpu.accumulator, 0x00) self.assertEqual(self.cpu.carry_flag, 1) @@ -353,7 +353,7 @@ class TestArithmeticOperations(unittest.TestCase): # 127 + 1 = 128 (C = 0; V = 1) self.cpu.carry_flag = 0 self.cpu.accumulator = 0x7F - self.memory.write_byte(0x1000, 0x01) + self.memory.write_byte(None, 0x1000, 0x01) self.cpu.ADC(0x1000) self.assertEqual(self.cpu.accumulator, 0x80) # @@@ self.assertEqual(self.cpu.carry_flag, 0) @@ -362,7 +362,7 @@ class TestArithmeticOperations(unittest.TestCase): # -128 + -1 = -129 (C = 1; V = 1) self.cpu.carry_flag = 0 self.cpu.accumulator = 0x80 - self.memory.write_byte(0x1000, 0xFF) + self.memory.write_byte(None, 0x1000, 0xFF) self.cpu.ADC(0x1000) self.assertEqual(self.cpu.accumulator, 0x7F) # @@@ self.assertEqual(self.cpu.carry_flag, 1) @@ -371,7 +371,7 @@ class TestArithmeticOperations(unittest.TestCase): # 63 + 64 + 1 = 128 (C = 0; V = 1) self.cpu.carry_flag = 1 self.cpu.accumulator = 0x3F - self.memory.write_byte(0x1000, 0x40) + self.memory.write_byte(None, 0x1000, 0x40) self.cpu.ADC(0x1000) self.assertEqual(self.cpu.accumulator, 0x80) self.assertEqual(self.cpu.carry_flag, 0) @@ -379,14 +379,14 @@ class TestArithmeticOperations(unittest.TestCase): def test_SBC_without_BCD(self): self.cpu.accumulator = 0x02 - self.memory.write_byte(0x1000, 0x01) + self.memory.write_byte(None, 0x1000, 0x01) self.cpu.SBC(0x1000) self.assertEqual(self.cpu.accumulator, 0x00) self.assertEqual(self.cpu.carry_flag, 1) self.assertEqual(self.cpu.overflow_flag, 0) self.cpu.accumulator = 0x01 - self.memory.write_byte(0x1000, 0x02) + self.memory.write_byte(None, 0x1000, 0x02) self.cpu.SBC(0x1000) self.assertEqual(self.cpu.accumulator, 0xFF) self.assertEqual(self.cpu.carry_flag, 0) @@ -397,7 +397,7 @@ class TestArithmeticOperations(unittest.TestCase): # 0 - 1 = -1 (V = 0) self.cpu.carry_flag = 1 self.cpu.accumulator = 0x00 - self.memory.write_byte(0x1000, 0x01) + self.memory.write_byte(None, 0x1000, 0x01) self.cpu.SBC(0x1000) self.assertEqual(self.cpu.accumulator, 0xFF) self.assertEqual(self.cpu.carry_flag, 0) @@ -406,7 +406,7 @@ class TestArithmeticOperations(unittest.TestCase): # -128 - 1 = -129 (V = 1) self.cpu.carry_flag = 1 self.cpu.accumulator = 0x80 - self.memory.write_byte(0x1000, 0x01) + self.memory.write_byte(None, 0x1000, 0x01) self.cpu.SBC(0x1000) self.assertEqual(self.cpu.accumulator, 0x7F) self.assertEqual(self.cpu.carry_flag, 1) @@ -415,7 +415,7 @@ class TestArithmeticOperations(unittest.TestCase): # 127 - -1 = 128 (V = 1) self.cpu.carry_flag = 1 self.cpu.accumulator = 0x7F - self.memory.write_byte(0x1000, 0xFF) + self.memory.write_byte(None, 0x1000, 0xFF) self.cpu.SBC(0x1000) self.assertEqual(self.cpu.accumulator, 0x80) self.assertEqual(self.cpu.carry_flag, 0) @@ -424,7 +424,7 @@ class TestArithmeticOperations(unittest.TestCase): # -64 -64 -1 = -129 (V = 1) self.cpu.carry_flag = 0 self.cpu.accumulator = 0xC0 - self.memory.write_byte(0x1000, 0x40) + self.memory.write_byte(None, 0x1000, 0x40) self.cpu.SBC(0x1000) self.assertEqual(self.cpu.accumulator, 0x7F) self.assertEqual(self.cpu.carry_flag, 1) @@ -434,35 +434,35 @@ class TestArithmeticOperations(unittest.TestCase): def test_CMP(self): self.cpu.accumulator = 0x0A - self.memory.write_byte(0x1000, 0x09) + self.memory.write_byte(None, 0x1000, 0x09) self.cpu.CMP(0x1000) self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 0) self.assertEqual(self.cpu.carry_flag, 1) self.cpu.accumulator = 0x0A - self.memory.write_byte(0x1000, 0x0B) + self.memory.write_byte(None, 0x1000, 0x0B) self.cpu.CMP(0x1000) self.assertEqual(self.cpu.sign_flag, 1) self.assertEqual(self.cpu.zero_flag, 0) self.assertEqual(self.cpu.carry_flag, 0) self.cpu.accumulator = 0x0A - self.memory.write_byte(0x1000, 0x0A) + self.memory.write_byte(None, 0x1000, 0x0A) self.cpu.CMP(0x1000) self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 1) self.assertEqual(self.cpu.carry_flag, 1) self.cpu.accumulator = 0xA0 - self.memory.write_byte(0x1000, 0x0A) + self.memory.write_byte(None, 0x1000, 0x0A) self.cpu.CMP(0x1000) self.assertEqual(self.cpu.sign_flag, 1) self.assertEqual(self.cpu.zero_flag, 0) self.assertEqual(self.cpu.carry_flag, 1) self.cpu.accumulator = 0x0A - self.memory.write_byte(0x1000, 0xA0) + self.memory.write_byte(None, 0x1000, 0xA0) self.cpu.CMP(0x1000) self.assertEqual(self.cpu.sign_flag, 0) # @@@ self.assertEqual(self.cpu.zero_flag, 0) @@ -470,35 +470,35 @@ class TestArithmeticOperations(unittest.TestCase): def test_CPX(self): self.cpu.x_index = 0x0A - self.memory.write_byte(0x1000, 0x09) + self.memory.write_byte(None, 0x1000, 0x09) self.cpu.CPX(0x1000) self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 0) self.assertEqual(self.cpu.carry_flag, 1) self.cpu.x_index = 0x0A - self.memory.write_byte(0x1000, 0x0B) + self.memory.write_byte(None, 0x1000, 0x0B) self.cpu.CPX(0x1000) self.assertEqual(self.cpu.sign_flag, 1) self.assertEqual(self.cpu.zero_flag, 0) self.assertEqual(self.cpu.carry_flag, 0) self.cpu.x_index = 0x0A - self.memory.write_byte(0x1000, 0x0A) + self.memory.write_byte(None, 0x1000, 0x0A) self.cpu.CPX(0x1000) self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 1) self.assertEqual(self.cpu.carry_flag, 1) self.cpu.x_index = 0xA0 - self.memory.write_byte(0x1000, 0x0A) + self.memory.write_byte(None, 0x1000, 0x0A) self.cpu.CPX(0x1000) self.assertEqual(self.cpu.sign_flag, 1) self.assertEqual(self.cpu.zero_flag, 0) self.assertEqual(self.cpu.carry_flag, 1) self.cpu.x_index = 0x0A - self.memory.write_byte(0x1000, 0xA0) + self.memory.write_byte(None, 0x1000, 0xA0) self.cpu.CPX(0x1000) self.assertEqual(self.cpu.sign_flag, 0) # @@@ self.assertEqual(self.cpu.zero_flag, 0) @@ -506,35 +506,35 @@ class TestArithmeticOperations(unittest.TestCase): def test_CPY(self): self.cpu.y_index = 0x0A - self.memory.write_byte(0x1000, 0x09) + self.memory.write_byte(None, 0x1000, 0x09) self.cpu.CPY(0x1000) self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 0) self.assertEqual(self.cpu.carry_flag, 1) self.cpu.y_index = 0x0A - self.memory.write_byte(0x1000, 0x0B) + self.memory.write_byte(None, 0x1000, 0x0B) self.cpu.CPY(0x1000) self.assertEqual(self.cpu.sign_flag, 1) self.assertEqual(self.cpu.zero_flag, 0) self.assertEqual(self.cpu.carry_flag, 0) self.cpu.y_index = 0x0A - self.memory.write_byte(0x1000, 0x0A) + self.memory.write_byte(None, 0x1000, 0x0A) self.cpu.CPY(0x1000) self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 1) self.assertEqual(self.cpu.carry_flag, 1) self.cpu.y_index = 0xA0 - self.memory.write_byte(0x1000, 0x0A) + self.memory.write_byte(None, 0x1000, 0x0A) self.cpu.CPY(0x1000) self.assertEqual(self.cpu.sign_flag, 1) self.assertEqual(self.cpu.zero_flag, 0) self.assertEqual(self.cpu.carry_flag, 1) self.cpu.y_index = 0x0A - self.memory.write_byte(0x1000, 0xA0) + self.memory.write_byte(None, 0x1000, 0xA0) self.cpu.CPY(0x1000) self.assertEqual(self.cpu.sign_flag, 0) # @@@ self.assertEqual(self.cpu.zero_flag, 0) @@ -544,21 +544,21 @@ class TestArithmeticOperations(unittest.TestCase): class TestIncrementDecrementOperations(unittest.TestCase): def setUp(self): - self.memory = Memory() + self.memory = Memory(use_stdio=False) self.cpu = CPU(self.memory) def test_INC(self): - self.memory.write_byte(0x1000, 0x00) + self.memory.write_byte(None, 0x1000, 0x00) self.cpu.INC(0x1000) self.assertEqual(self.memory.read_byte(None, 0x1000), 0x01) self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 0) - self.memory.write_byte(0x1000, 0x7F) + self.memory.write_byte(None, 0x1000, 0x7F) self.cpu.INC(0x1000) self.assertEqual(self.memory.read_byte(None, 0x1000), 0x80) self.assertEqual(self.cpu.sign_flag, 1) self.assertEqual(self.cpu.zero_flag, 0) - self.memory.write_byte(0x1000, 0xFF) + self.memory.write_byte(None, 0x1000, 0xFF) self.cpu.INC(0x1000) self.assertEqual(self.memory.read_byte(None, 0x1000), 0x00) self.assertEqual(self.cpu.sign_flag, 0) @@ -599,17 +599,17 @@ class TestIncrementDecrementOperations(unittest.TestCase): self.assertEqual(self.cpu.zero_flag, 1) def test_DEC(self): - self.memory.write_byte(0x1000, 0x01) + self.memory.write_byte(None, 0x1000, 0x01) self.cpu.DEC(0x1000) self.assertEqual(self.memory.read_byte(None, 0x1000), 0x00) self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 1) - self.memory.write_byte(0x1000, 0x80) + self.memory.write_byte(None, 0x1000, 0x80) self.cpu.DEC(0x1000) self.assertEqual(self.memory.read_byte(None, 0x1000), 0x7F) self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 0) - self.memory.write_byte(0x1000, 0x00) + self.memory.write_byte(None, 0x1000, 0x00) self.cpu.DEC(0x1000) self.assertEqual(self.memory.read_byte(None, 0x1000), 0xFF) self.assertEqual(self.cpu.sign_flag, 1) @@ -653,7 +653,7 @@ class TestIncrementDecrementOperations(unittest.TestCase): class TestShiftOperations(unittest.TestCase): def setUp(self): - self.memory = Memory() + self.memory = Memory(use_stdio=False) self.cpu = CPU(self.memory) def test_ASL(self): @@ -663,7 +663,7 @@ class TestShiftOperations(unittest.TestCase): self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 0) self.assertEqual(self.cpu.carry_flag, 0) - self.memory.write_byte(0x1000, 0x02) + self.memory.write_byte(None, 0x1000, 0x02) self.cpu.ASL(0x1000) self.assertEqual(self.memory.read_byte(None, 0x1000), 0x04) self.assertEqual(self.cpu.sign_flag, 0) @@ -683,7 +683,7 @@ class TestShiftOperations(unittest.TestCase): self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 1) self.assertEqual(self.cpu.carry_flag, 1) - self.memory.write_byte(0x1000, 0x01) + self.memory.write_byte(None, 0x1000, 0x01) self.cpu.LSR(0x1000) self.assertEqual(self.memory.read_byte(None, 0x1000), 0x00) self.assertEqual(self.cpu.sign_flag, 0) @@ -712,14 +712,14 @@ class TestShiftOperations(unittest.TestCase): self.assertEqual(self.cpu.zero_flag, 0) # @@@ self.assertEqual(self.cpu.carry_flag, 1) self.cpu.carry_flag = 0 - self.memory.write_byte(0x1000, 0x80) + self.memory.write_byte(None, 0x1000, 0x80) self.cpu.ROL(0x1000) self.assertEqual(self.memory.read_byte(None, 0x1000), 0x00) self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 1) # @@@ self.assertEqual(self.cpu.carry_flag, 1) self.cpu.carry_flag = 1 - self.memory.write_byte(0x1000, 0x80) + self.memory.write_byte(None, 0x1000, 0x80) self.cpu.ROL(0x1000) self.assertEqual(self.memory.read_byte(None, 0x1000), 0x01) self.assertEqual(self.cpu.sign_flag, 0) @@ -742,14 +742,14 @@ class TestShiftOperations(unittest.TestCase): self.assertEqual(self.cpu.zero_flag, 0) # @@@ self.assertEqual(self.cpu.carry_flag, 1) self.cpu.carry_flag = 0 - self.memory.write_byte(0x1000, 0x01) + self.memory.write_byte(None, 0x1000, 0x01) self.cpu.ROR(0x1000) self.assertEqual(self.memory.read_byte(None, 0x1000), 0x00) self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 1) # @@@ self.assertEqual(self.cpu.carry_flag, 1) self.cpu.carry_flag = 1 - self.memory.write_byte(0x1000, 0x01) + self.memory.write_byte(None, 0x1000, 0x01) self.cpu.ROR(0x1000) self.assertEqual(self.memory.read_byte(None, 0x1000), 0x80) self.assertEqual(self.cpu.sign_flag, 1) # @@@ @@ -760,7 +760,7 @@ class TestShiftOperations(unittest.TestCase): class TestJumpCallOperations(unittest.TestCase): def setUp(self): - self.memory = Memory() + self.memory = Memory(use_stdio=False) self.cpu = CPU(self.memory) def test_JMP(self): @@ -775,8 +775,8 @@ class TestJumpCallOperations(unittest.TestCase): self.assertEqual(self.memory.read_byte(None, self.cpu.STACK_PAGE + self.cpu.stack_pointer + 2), 0x0F) def test_RTS(self): - self.memory.write_byte(self.cpu.STACK_PAGE + 0xFF, 0x12) - self.memory.write_byte(self.cpu.STACK_PAGE + 0xFE, 0x33) + self.memory.write_byte(None, self.cpu.STACK_PAGE + 0xFF, 0x12) + self.memory.write_byte(None, self.cpu.STACK_PAGE + 0xFE, 0x33) self.cpu.stack_pointer = 0xFD self.cpu.RTS() self.assertEqual(self.cpu.program_counter, 0x1234) @@ -792,7 +792,7 @@ class TestJumpCallOperations(unittest.TestCase): class TestBranchOperations(unittest.TestCase): def setUp(self): - self.memory = Memory() + self.memory = Memory(use_stdio=False) self.cpu = CPU(self.memory) def test_BCC(self): @@ -879,7 +879,7 @@ class TestBranchOperations(unittest.TestCase): class TestStatusFlagOperations(unittest.TestCase): def setUp(self): - self.memory = Memory() + self.memory = Memory(use_stdio=False) self.cpu = CPU(self.memory) def test_CLC(self): @@ -921,7 +921,7 @@ class TestStatusFlagOperations(unittest.TestCase): class TestSystemFunctionOperations(unittest.TestCase): def setUp(self): - self.memory = Memory() + self.memory = Memory(use_stdio=False) self.cpu = CPU(self.memory) def test_BRK(self): @@ -936,9 +936,9 @@ class TestSystemFunctionOperations(unittest.TestCase): self.assertEqual(self.memory.read_byte(None, self.cpu.STACK_PAGE + self.cpu.stack_pointer + 3), 0x10) def test_RTI(self): - self.memory.write_byte(self.cpu.STACK_PAGE + 0xFF, 0x12) - self.memory.write_byte(self.cpu.STACK_PAGE + 0xFE, 0x33) - self.memory.write_byte(self.cpu.STACK_PAGE + 0xFD, 0x20) + self.memory.write_byte(None, self.cpu.STACK_PAGE + 0xFF, 0x12) + self.memory.write_byte(None, self.cpu.STACK_PAGE + 0xFE, 0x33) + self.memory.write_byte(None, self.cpu.STACK_PAGE + 0xFD, 0x20) self.cpu.stack_pointer = 0xFC self.cpu.RTI() self.assertEqual(self.cpu.program_counter, 0x1233) @@ -951,7 +951,7 @@ class TestSystemFunctionOperations(unittest.TestCase): class Test6502Bugs(unittest.TestCase): def setUp(self): - self.memory = Memory() + self.memory = Memory(use_stdio=False) self.cpu = CPU(self.memory) def test_zero_page_x(self):