diff --git a/applepy.py b/applepy.py index 4cab99c..446c268 100644 --- a/applepy.py +++ b/applepy.py @@ -3,6 +3,7 @@ # originally written 2001, updated 2011 +import numpy import pygame import colorsys @@ -238,6 +239,30 @@ class Display: del pixels +class Speaker: + + CPU_CYCLES_PER_SAMPLE = 70 + CHECK_INTERVAL = 1000 + + def __init__(self): + pygame.mixer.pre_init(44100, -16, 1) + pygame.init() + self.reset() + + def toggle(self, cycle): + if self.last_toggle is not None: + l = (cycle - self.last_toggle) / Speaker.CPU_CYCLES_PER_SAMPLE + self.buffer.extend([0, 0.8] if self.polarity else [0, -0.8]) + self.buffer.extend(l * [0.5] if self.polarity else [-0.5]) + self.polarity = not self.polarity + self.last_toggle = cycle + + def reset(self): + self.last_toggle = None + self.buffer = [] + self.polarity = False + + class ROM: def __init__(self, start, size): @@ -267,18 +292,20 @@ class RAM(ROM): class SoftSwitches: - def __init__(self, display): + def __init__(self, display, speaker): self.kbd = 0x00 self.display = display + self.speaker = speaker - def read_byte(self, address): + def read_byte(self, cycle, address): assert 0xC000 <= address <= 0xCFFF if address == 0xC000: return self.kbd elif address == 0xC010: self.kbd = self.kbd & 0x7F elif address == 0xC030: - pass # toggle speaker + if self.speaker: + self.speaker.toggle(cycle) elif address == 0xC050: self.display.txtclr() elif address == 0xC051: @@ -302,36 +329,37 @@ class SoftSwitches: class Memory: - def __init__(self, display=None): + def __init__(self, display=None, speaker=None): self.display = display + self.speaker = speaker self.rom = ROM(0xD000, 0x3000) # available from http://www.easy68k.com/paulrsm/6502/index.html self.rom.load_file(0xD000, "A2ROM.BIN") self.ram = RAM(0x0000, 0xC000) - self.softswitches = SoftSwitches(display) + self.softswitches = SoftSwitches(display, speaker) def load(self, address, data): if address < 0xC000: self.ram.load(address, data) - def read_byte(self, address): + def read_byte(self, cycle, address): if address < 0xC000: return self.ram.read_byte(address) elif address < 0xD000: - return self.softswitches.read_byte(address) + return self.softswitches.read_byte(cycle, address) else: return self.rom.read_byte(address) - def read_word(self, address): - return self.read_byte(address) + (self.read_byte(address + 1) << 8) + 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, address): + def read_word_bug(self, cycle, address): if address % 0x100 == 0xFF: - return self.read_byte(address) + (self.read_byte(address & 0xFF00) << 8) + return self.read_byte(cycle, address) + (self.read_byte(cycle + 1, address & 0xFF00) << 8) else: - return self.read_word(address) + return self.read_word(cycle, address) def write_byte(self, address, value): if address < 0xC000: @@ -340,6 +368,13 @@ class Memory: self.display.update(address, value) if 0x2000 <= address < 0x5FFF and self.display: self.display.update(address, value) + + def update(self, cycle): + if self.speaker.buffer and (cycle - self.speaker.last_toggle) > self.speaker.CHECK_INTERVAL: + sample_array = numpy.array(self.speaker.buffer) + sound = pygame.sndarray.make_sound(sample_array) + sound.play() + self.speaker.reset() class Disassemble: @@ -583,6 +618,8 @@ class CPU: self.stack_pointer = 0xFF + self.cycles = 0 + self.setup_ops() self.reset() @@ -604,7 +641,7 @@ class CPU: 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()) + 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()) @@ -623,7 +660,7 @@ class CPU: 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()) + 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()) @@ -641,7 +678,7 @@ class CPU: 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()) + 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()) @@ -659,7 +696,7 @@ class CPU: 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()) + 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()) @@ -670,14 +707,14 @@ class CPU: 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()) + 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()) + 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()) + 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()) @@ -719,7 +756,7 @@ class CPU: 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()) + 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()) @@ -738,15 +775,16 @@ class CPU: 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()) + self.ops[0xFE] = lambda: self.INC(self.absolute_x_mode(rmw=True)) def reset(self): - self.program_counter = self.memory.read_word(self.RESET_VECTOR) + 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: @@ -771,8 +809,25 @@ class CPU: update_cycle += 1 if update_cycle >= 1024: pygame.display.flip() + self.memory.update(self.cycles) 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): @@ -780,11 +835,20 @@ class CPU: 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.memory.read_byte(self.get_pc()) + return self.read_byte(self.get_pc()) def read_pc_word(self): - return self.memory.read_word(self.get_pc(2)) + return self.read_word(self.get_pc(2)) #### @@ -808,7 +872,7 @@ class CPU: def pull_byte(self): self.stack_pointer = (self.stack_pointer + 1) % 0x100 - return self.memory.read_byte(self.STACK_PAGE + self.stack_pointer) + return self.read_byte(self.STACK_PAGE + self.stack_pointer) def push_word(self, word): hi, lo = divmod(word, 0x100) @@ -818,7 +882,7 @@ class CPU: def pull_word(self): s = self.STACK_PAGE + self.stack_pointer + 1 self.stack_pointer += 2 - return self.memory.read_word(s) + return self.read_word(s) #### @@ -826,35 +890,49 @@ class CPU: return self.get_pc() def absolute_mode(self): + self.cycles += 2 return self.read_pc_word() - def absolute_x_mode(self): + def absolute_x_mode(self, rmw=False): + if rmw: + self.cycles += 1 return self.absolute_mode() + self.x_index - def absolute_y_mode(self): + 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): - return self.memory.read_word_bug(self.absolute_mode()) + self.cycles += 2 + return self.read_word_bug(self.absolute_mode()) def indirect_x_mode(self): - return self.memory.read_word_bug((self.read_pc_byte() + self.x_index) % 0x100) + self.cycles += 4 + return self.read_word_bug((self.read_pc_byte() + self.x_index) % 0x100) - def indirect_y_mode(self): - return self.memory.read_word_bug(self.read_pc_byte()) + self.y_index + 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.memory.read_byte(pc)) + return pc + 1 + signed(self.read_byte(pc)) #### @@ -873,13 +951,13 @@ class CPU: # LOAD / STORE def LDA(self, operand_address): - self.accumulator = self.update_nz(self.memory.read_byte(operand_address)) + self.accumulator = self.update_nz(self.read_byte(operand_address)) def LDX(self, operand_address): - self.x_index = self.update_nz(self.memory.read_byte(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.memory.read_byte(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) @@ -916,7 +994,8 @@ class CPU: if operand_address is None: self.accumulator = self.update_nzc(self.accumulator << 1) else: - self.memory.write_byte(operand_address, self.update_nzc(self.memory.read_byte(operand_address) << 1)) + 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: @@ -925,7 +1004,8 @@ class CPU: a = a | 0x01 self.accumulator = self.update_nzc(a) else: - m = self.memory.read_byte(operand_address) << 1 + 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)) @@ -937,7 +1017,8 @@ class CPU: self.carry_flag = self.accumulator % 2 self.accumulator = self.update_nz(self.accumulator >> 1) else: - m = self.memory.read_byte(operand_address) + self.cycles += 2 + m = self.read_byte(operand_address) if self.carry_flag: m = m | 0x100 self.carry_flag = m % 2 @@ -948,53 +1029,65 @@ class CPU: self.carry_flag = self.accumulator % 2 self.accumulator = self.update_nz(self.accumulator >> 1) else: - self.carry_flag = self.memory.read_byte(operand_address) % 2 - self.memory.write_byte(operand_address, self.update_nz(self.memory.read_byte(operand_address) >> 1)) + 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 @@ -1023,7 +1116,8 @@ class CPU: # INCREMENT / DECREMENT def DEC(self, operand_address): - self.memory.write_byte(operand_address, self.update_nz(self.memory.read_byte(operand_address) - 1)) + 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) @@ -1032,7 +1126,8 @@ class CPU: self.y_index = self.update_nz(self.y_index - 1) def INC(self, operand_address): - self.memory.write_byte(operand_address, self.update_nz(self.memory.read_byte(operand_address) + 1)) + 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) @@ -1043,27 +1138,31 @@ class CPU: # 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.memory.read_byte(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.memory.read_byte(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.memory.read_byte(operand_address)) + self.accumulator = self.update_nz(self.accumulator ^ self.read_byte(operand_address)) # ARITHMETIC @@ -1073,7 +1172,7 @@ class CPU: a2 = self.accumulator a1 = signed(a2) - m2 = self.memory.read_byte(operand_address) + m2 = self.read_byte(operand_address) m1 = signed(m2) # twos complement addition @@ -1093,7 +1192,7 @@ class CPU: a2 = self.accumulator a1 = signed(a2) - m2 = self.memory.read_byte(operand_address) + m2 = self.read_byte(operand_address) m1 = signed(m2) # twos complement subtraction @@ -1111,7 +1210,7 @@ class CPU: # BIT def BIT(self, operand_address): - value = self.memory.read_byte(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)] @@ -1119,17 +1218,17 @@ class CPU: # COMPARISON def CMP(self, operand_address): - result = self.accumulator - self.memory.read_byte(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.memory.read_byte(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.memory.read_byte(operand_address) + result = self.y_index - self.read_byte(operand_address) self.carry_flag = [0, 1][(result >= 0)] self.update_nz(result) @@ -1139,12 +1238,14 @@ class CPU: 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.memory.read_word(0xFFFE) + 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() @@ -1155,7 +1256,8 @@ class CPU: if __name__ == "__main__": display = Display() - mem = Memory(display) + speaker = Speaker() + mem = Memory(display, speaker) cpu = CPU(mem) cpu.run() diff --git a/cycle_notes.txt b/cycle_notes.txt new file mode 100644 index 0000000..05cf883 --- /dev/null +++ b/cycle_notes.txt @@ -0,0 +1,138 @@ +There are two ways we could represent cycle information: + +1. just have an array of cycles for each opcode + the adjustment for + page boundary crossing (which seems opcode-specific, oddly) + +2. add cycles in individual methods like those accessing memory and the + operations themselves, to model *why* something takes the cycles it does. + +I prefer 2 on the grounds of it being more instructive but it assumes that +the way we do things is closely aligned to the way the 6502 is doing them +internally. Even if we end up having to do 1, I'd love to understand and +document some of the "why". + +What follows is an attempt to "find the patterns" in the cycle times (as +given on http://www.6502.org/tutorials/6502opcodes.html ) + +NOTE: there appears to be an error in AND and ORA zero page timings on that +webpage given above. I've now corrected this below. + +There are 10 classes of instructions when it comes to cycle times: + + +Class I +(followed by ADC, AND, BIT, CMP, CPX, CPY, EOR, LDA, LDX, LDY, ORA, SBC, STA, +STX, STY) + +immediate 2 +zero page 3 +zero page, x 4 +zero page, y 4 +absolute 4 +absolute, x 4 (+1 if page crossed or writing) +absolute, y 4 (+1 if page crossed or writing) +indirect, x 6 +indirect, y 5 (+1 if page crossed or writing) + +Note 1: the zero page indexed and x-index indirect don't have the page cross +addition because they wrap. + +Note 2: writes to indexed non-zero-page memory (e.g. STA) have the +1 even +if not page crossing. + + +Class II +(followed by ASL, DEC, INC, LSR, ROL, ROR) + +implied 2 +zero page 5 +zero page, x 6 +absolute 6 +absolute, x 7 + +Note 3: these take 2 cycles longer than Class I because they involve a +read-modify-write. Because the absolute, x is a write to an indexed +non-zero-page memory location, there is an additional +1 even if not page +crossing (see Note 2) + + +Class IIIa +(followed by CLC, CLD, CLI, CLV, DEX, DEY, INX, INY, NOP, SEC, SED, SEI, TAX, +TAY, TSX, TXA, TXS, TYA) + +implied 2 + + +Class IIIb +(followed by PHA, PHP) + +implied 3 + + +Class IIIc +(followed by PLA, PLP) + +implied 4 + + +Class IIId +(followed by RTI, RTS) + +implied 6 + + +Class IIIe +(followed by BRK) + +implied 7 + + +Class IV +(followed by BCC, BCS, BEQ, BMI, BNE, BPL, BVC, BVS) + +branch not taken 2 +branch taken 3 (+1 if page crossed) + + +Class V +(followed by JMP) + +absolute 3 +indirect 5 + + +Class VI +(followed by JSR) + +absolute 6 + + + +This seems a possible implementation (not yet considering page boundaries): + +1. all instructions start with 2 +2. absolute (including absolute indexed) adds 2 +3. absolute indexed adds an additional 1 *if* instruction is of RMW type +4. zero page (including zero page indexed) adds 1 +5. zero page indexed adds an addition 1 +6. indirect (JMP) adds 4 +7. indirect x adds 4 +8. indirect y adds 3 plus an additional 1 *if* instruction is of RMW type +9. ASL, LSR, ROL, ROR add 2 cycles if not implied +10. JMP subtracts 1 cycle +11. JSR adds 2 +12. RTS adds 4 +13. branches add 1 if taken +14. DEC and INC add 2 cycles +15. PHA and PHP add 1 cycle +16. PLA and PLP add 2 cycles +17. BRK adds 5 cycles +18. RTI adds 4 cycles + +RMW instructions are the absolute,x of ASL, DEC, INC, LSR ROL, ROR and STA +as well as indirect,y and absolute,y of STA + + +It may be possible to simplify even further given the particular functions +some of these share in command (where the cycle change could be placed +instead) diff --git a/tests.py b/tests.py index 05b2645..11fa2f4 100644 --- a/tests.py +++ b/tests.py @@ -9,17 +9,17 @@ class TestMemory(unittest.TestCase): def test_load(self): self.memory.load(0x1000, [0x01, 0x02, 0x03]) - self.assertEqual(self.memory.read_byte(0x1000), 0x01) - self.assertEqual(self.memory.read_byte(0x1001), 0x02) - self.assertEqual(self.memory.read_byte(0x1002), 0x03) + self.assertEqual(self.memory.read_byte(None, 0x1000), 0x01) + self.assertEqual(self.memory.read_byte(None, 0x1001), 0x02) + 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.assertEqual(self.memory.read_byte(0x1000), 0x11) - self.assertEqual(self.memory.read_byte(0x1001), 0x12) - self.assertEqual(self.memory.read_byte(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) class TestLoadStoreOperations(unittest.TestCase): @@ -98,17 +98,17 @@ class TestLoadStoreOperations(unittest.TestCase): def test_STA(self): self.cpu.accumulator = 0x37 self.cpu.STA(0x2000) - self.assertEqual(self.memory.read_byte(0x2000), 0x37) + self.assertEqual(self.memory.read_byte(None, 0x2000), 0x37) def test_STX(self): self.cpu.x_index = 0x38 self.cpu.STX(0x2000) - self.assertEqual(self.memory.read_byte(0x2000), 0x38) + self.assertEqual(self.memory.read_byte(None, 0x2000), 0x38) def test_STY(self): self.cpu.y_index = 0x39 self.cpu.STY(0x2000) - self.assertEqual(self.memory.read_byte(0x2000), 0x39) + self.assertEqual(self.memory.read_byte(None, 0x2000), 0x39) class TestRegisterTransferOperations(unittest.TestCase): @@ -550,17 +550,17 @@ class TestIncrementDecrementOperations(unittest.TestCase): def test_INC(self): self.memory.write_byte(0x1000, 0x00) self.cpu.INC(0x1000) - self.assertEqual(self.memory.read_byte(0x1000), 0x01) + 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.cpu.INC(0x1000) - self.assertEqual(self.memory.read_byte(0x1000), 0x80) + 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.cpu.INC(0x1000) - self.assertEqual(self.memory.read_byte(0x1000), 0x00) + self.assertEqual(self.memory.read_byte(None, 0x1000), 0x00) self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 1) @@ -601,17 +601,17 @@ class TestIncrementDecrementOperations(unittest.TestCase): def test_DEC(self): self.memory.write_byte(0x1000, 0x01) self.cpu.DEC(0x1000) - self.assertEqual(self.memory.read_byte(0x1000), 0x00) + 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.cpu.DEC(0x1000) - self.assertEqual(self.memory.read_byte(0x1000), 0x7F) + 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.cpu.DEC(0x1000) - self.assertEqual(self.memory.read_byte(0x1000), 0xFF) + self.assertEqual(self.memory.read_byte(None, 0x1000), 0xFF) self.assertEqual(self.cpu.sign_flag, 1) self.assertEqual(self.cpu.zero_flag, 0) @@ -665,7 +665,7 @@ class TestShiftOperations(unittest.TestCase): self.assertEqual(self.cpu.carry_flag, 0) self.memory.write_byte(0x1000, 0x02) self.cpu.ASL(0x1000) - self.assertEqual(self.memory.read_byte(0x1000), 0x04) + self.assertEqual(self.memory.read_byte(None, 0x1000), 0x04) self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 0) self.assertEqual(self.cpu.carry_flag, 0) @@ -685,7 +685,7 @@ class TestShiftOperations(unittest.TestCase): self.assertEqual(self.cpu.carry_flag, 1) self.memory.write_byte(0x1000, 0x01) self.cpu.LSR(0x1000) - self.assertEqual(self.memory.read_byte(0x1000), 0x00) + 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) @@ -714,14 +714,14 @@ class TestShiftOperations(unittest.TestCase): self.cpu.carry_flag = 0 self.memory.write_byte(0x1000, 0x80) self.cpu.ROL(0x1000) - self.assertEqual(self.memory.read_byte(0x1000), 0x00) + 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.cpu.ROL(0x1000) - self.assertEqual(self.memory.read_byte(0x1000), 0x01) + self.assertEqual(self.memory.read_byte(None, 0x1000), 0x01) self.assertEqual(self.cpu.sign_flag, 0) self.assertEqual(self.cpu.zero_flag, 0) # @@@ self.assertEqual(self.cpu.carry_flag, 1) @@ -744,14 +744,14 @@ class TestShiftOperations(unittest.TestCase): self.cpu.carry_flag = 0 self.memory.write_byte(0x1000, 0x01) self.cpu.ROR(0x1000) - self.assertEqual(self.memory.read_byte(0x1000), 0x00) + 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.cpu.ROR(0x1000) - self.assertEqual(self.memory.read_byte(0x1000), 0x80) + self.assertEqual(self.memory.read_byte(None, 0x1000), 0x80) self.assertEqual(self.cpu.sign_flag, 1) # @@@ self.assertEqual(self.cpu.zero_flag, 0) # @@@ self.assertEqual(self.cpu.carry_flag, 1) @@ -771,8 +771,8 @@ class TestJumpCallOperations(unittest.TestCase): self.cpu.program_counter = 0x1000 self.cpu.JSR(0x2000) self.assertEqual(self.cpu.program_counter, 0x2000) - self.assertEqual(self.memory.read_byte(self.cpu.STACK_PAGE + self.cpu.stack_pointer + 1), 0xFF) - self.assertEqual(self.memory.read_byte(self.cpu.STACK_PAGE + self.cpu.stack_pointer + 2), 0x0F) + self.assertEqual(self.memory.read_byte(None, self.cpu.STACK_PAGE + self.cpu.stack_pointer + 1), 0xFF) + 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) @@ -931,9 +931,9 @@ class TestSystemFunctionOperations(unittest.TestCase): self.cpu.BRK() self.assertEqual(self.cpu.program_counter, 0x2000) self.assertEqual(self.cpu.break_flag, 1) - self.assertEqual(self.memory.read_byte(self.cpu.STACK_PAGE + self.cpu.stack_pointer + 1), status) - self.assertEqual(self.memory.read_byte(self.cpu.STACK_PAGE + self.cpu.stack_pointer + 2), 0x01) - self.assertEqual(self.memory.read_byte(self.cpu.STACK_PAGE + self.cpu.stack_pointer + 3), 0x10) + self.assertEqual(self.memory.read_byte(None, self.cpu.STACK_PAGE + self.cpu.stack_pointer + 1), status) + self.assertEqual(self.memory.read_byte(None, self.cpu.STACK_PAGE + self.cpu.stack_pointer + 2), 0x01) + 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)