def _install_mpu_observers(self,getc_addr,putc_addr,fsio_addr): def putc(address, value): try: self.stdout.write(chr(value)) except UnicodeEncodeError: # Python 3 self.stdout.write("?") self.stdout.flush() def getc(address): char = console.getch_noblock(self.stdin) if char: byte = ord(char) else: byte = 0 return byte m = ObservableMemory(addrWidth=self.addrWidth) m.subscribe_to_write([self.putc_addr], putc) m.subscribe_to_read([self.getc_addr], getc) fs = FileSystem() fsio_range = range(fsio_addr, fsio_addr+fs.registers) m.subscribe_to_write(fsio_range, fs.write_mem) m.subscribe_to_read(fsio_range, fs.read_mem) self._mpu.memory = m
def __init__(self, filename): self.nsf = NSFParser(bytearray(file(filename).read())) # Set up Memory with Hooks self.mem = ObservableMemory() self.mem.write(self.nsf.load_addr, self.nsf.data) self.cpu = MPU(self.mem) self.deltaCallTime = 0 self.totalCycles = 0
def test_write_directly_writes_values_to_subject(self): subject = self._make_subject() mem = ObservableMemory(subject=subject) def write_subscriber(address, value): return 0xFF mem.subscribe_to_write([0xC000,0xC001], write_subscriber) mem.write(0xC000, [0x01, 002]) self.assertEqual(0x01, subject[0xC000]) self.assertEqual(0x02, subject[0xC001])
def test_write_directly_writes_values_to_subject(self): subject = self._make_subject() mem = ObservableMemory(subject=subject) def write_subscriber(address, value): return 0xFF mem.subscribe_to_write([0xC000, 0xC001], write_subscriber) mem.write(0xC000, [0x01, 002]) self.assertEqual(0x01, subject[0xC000]) self.assertEqual(0x02, subject[0xC001])
class NSFSoftCPU: NES_CLK_period = 46 * 12 def __init__(self, filename): self.nsf = NSFParser(bytearray(file(filename).read())) # Set up Memory with Hooks self.mem = ObservableMemory() self.mem.write(self.nsf.load_addr, self.nsf.data) self.cpu = MPU(self.mem) self.deltaCallTime = 0 self.totalCycles = 0 def subscribe_to_write(self, range, callback): self.mem.subscribe_to_write(range, callback) # Call NSF Init code def setup(self, start_song = -1): if start_song == -1: start_song = self.nsf.start_song - 1 # Push a special address -1 to the stack to implement function calls self.cpu.stPushWord(0x1337 - 1) # NSF Style init call self.cpu.a = start_song self.cpu.x = 0 self.cpu.pc = self.nsf.init_addr while self.cpu.pc != 0x1337: self.cpu.step() # Execute 1 CPU Step, or wait to until enough cycles have passed def play_cycle(self): self.deltaCallTime = self.deltaCallTime + self.NES_CLK_period self.check_frame() if self.cpu.pc != 0x1337: self.totalCycles = self.totalCycles + 1 if self.totalCycles == self.cpu.processorCycles: self.cpu.step() # Internal: Check if frame is completed and restart it periodically def check_frame(self): if self.cpu.pc == 0x1337: frame_time = self.nsf.ntsc_ticks * 1000 if self.deltaCallTime >= frame_time: self.deltaCallTime = self.deltaCallTime - frame_time self.cpu.stPushWord(0x1337 - 1) self.cpu.pc = self.nsf.play_addr print "Frame Completed"
def test__subscribe_to_read_does_not_register_same_listener_twice(self): subject = self._make_subject() mem = ObservableMemory(subject=subject) calls = [] def read_subscriber(address): calls.append('read_subscriber') mem.subscribe_to_read([0xC000], read_subscriber) mem.subscribe_to_read([0xC000], read_subscriber) value = mem[0xC000] self.assertEqual(['read_subscriber'], calls)
def test_subscribe_to_read_covers_all_addresses_in_range(self): subject = self._make_subject() mem = ObservableMemory(subject=subject) def read_subscriber(address, value): return 0xAB mem.subscribe_to_read(xrange(0xC000, 0xC001+1), read_subscriber) mem[0xC000] = 0xAB mem[0xC001] = 0xAB self.assertEqual(0xAB, subject[0xC001]) self.assertEqual(0xAB, subject[0xC001])
def test_subscribe_to_read_covers_all_addresses_in_range(self): subject = self._make_subject() mem = ObservableMemory(subject=subject) def read_subscriber(address, value): return 0xAB mem.subscribe_to_read(range(0xC000, 0xC001 + 1), read_subscriber) mem[0xC000] = 0xAB mem[0xC001] = 0xAB self.assertEqual(0xAB, subject[0xC001]) self.assertEqual(0xAB, subject[0xC001])
class NSFSoftCPU: NES_CLK_period = 46 * 12 def __init__(self, filename): self.nsf = NSFParser(bytearray(file(filename).read())) # Set up Memory with Hooks self.mem = ObservableMemory() self.mem.write(self.nsf.load_addr, self.nsf.data) self.cpu = MPU(self.mem) self.deltaCallTime = 0 self.totalCycles = 0 def subscribe_to_write(self, range, callback): self.mem.subscribe_to_write(range, callback) # Call NSF Init code def setup(self, start_song=-1): if start_song == -1: start_song = self.nsf.start_song - 1 # Push a special address -1 to the stack to implement function calls self.cpu.stPushWord(0x1337 - 1) # NSF Style init call self.cpu.a = start_song self.cpu.x = 0 self.cpu.pc = self.nsf.init_addr while self.cpu.pc != 0x1337: self.cpu.step() # Execute 1 CPU Step, or wait to until enough cycles have passed def play_cycle(self): self.deltaCallTime = self.deltaCallTime + self.NES_CLK_period self.check_frame() if self.cpu.pc != 0x1337: self.totalCycles = self.totalCycles + 1 if self.totalCycles == self.cpu.processorCycles: self.cpu.step() # Internal: Check if frame is completed and restart it periodically def check_frame(self): if self.cpu.pc == 0x1337: frame_time = self.nsf.ntsc_ticks * 1000 if self.deltaCallTime >= frame_time: self.deltaCallTime = self.deltaCallTime - frame_time self.cpu.stPushWord(0x1337 - 1) self.cpu.pc = self.nsf.play_addr print "Frame Completed"
def test___setitem__uses_result_of_last_subscriber(self): subject = self._make_subject() mem = ObservableMemory(subject=subject) def write_subscriber_1(address, value): return 0x01 def write_subscriber_2(address, value): return 0x02 mem.subscribe_to_write([0xC000], write_subscriber_1) mem.subscribe_to_write([0xC000], write_subscriber_2) mem[0xC000] = 0xAB self.assertEqual(0x02, subject[0xC000])
def test___getitem__ignores_read_subscribers_returning_none(self): subject = self._make_subject() mem = ObservableMemory(subject=subject) def read_subscriber_1(address): return None def read_subscriber_2(address): return None mem.subscribe_to_read([0xC000], read_subscriber_1) mem.subscribe_to_read([0xC000], read_subscriber_2) mem[0xC000] = 0xAB self.assertEqual(0xAB, subject[0xC000])
def __init__(self, console_fo, disk_fo): self.mpu = NMOS6502(memory=ObservableMemory()) self.hw = {} self.hw['console'] = Console(self, console_fo) self.hw['info'] = Info(self) self.hw['pmc'] = Power(self) self.hw['disk'] = Disk(self, disk_fo) self._status = 'halted'
def get_cpu(self, filename): start, data = self.get_data(filename) self.memory = ObservableMemory() self.memory[0xf000:0xffff] = data cpu = TestMPU(self.memory, start) cpu.reset() return cpu
def _install_mpu_observers(self): def putc(address, value): self.stdout.write(chr(value)) self.stdout.flush() def getc(address): char = console.getch_noblock(self.stdin) if char: byte = ord(char) else: byte = 0 return byte m = ObservableMemory(addrWidth=self.addrWidth) m.subscribe_to_write([0xF001], putc) m.subscribe_to_read([0xF004], getc) self._mpu.memory = m
def test___getitem__calls_all_read_subscribers_uses_last_result(self): subject = self._make_subject() mem = ObservableMemory(subject=subject) calls = [] def read_subscriber_1(address): calls.append('read_subscriber_1') return 0x01 def read_subscriber_2(address): calls.append('read_subscriber_2') return 0x02 mem.subscribe_to_read([0xC000], read_subscriber_1) mem.subscribe_to_read([0xC000], read_subscriber_2) subject[0xC000] = 0xAB self.assertEqual(0x02, mem[0xC000]) expected_calls = ['read_subscriber_1', 'read_subscriber_2'] self.assertEqual(expected_calls, calls)
def _install_mpu_observers(self,getc_addr,putc_addr): def putc(address, value): try: self.stdout.write(chr(value)) except UnicodeEncodeError: # Python 3 self.stdout.write("?") self.stdout.flush() def getc(address): char = console.getch_noblock(self.stdin) if char: byte = ord(char) else: byte = 0 return byte m = ObservableMemory(addrWidth=self.addrWidth) m.subscribe_to_write([self.putc_addr], putc) m.subscribe_to_read([self.getc_addr], getc) self._mpu.memory = m
def _install_mpu_observers(self): def putc(address, value): self.stdout.write(chr(value)) self.stdout.flush() def getc(address): char = console.getch_noblock(self.stdin) if char: byte = ord(char) else: byte = 0 return byte m = ObservableMemory() #m.subscribe_to_write([0xF001], putc) #m.subscribe_to_read([0xF004], getc) self._mpu.memory = m
def _install_mpu_observers(self, getc_addr, putc_addr): def putc(address, value): try: self.stdout.write(chr(value)) except UnicodeEncodeError: # Python 3 self.stdout.write("?") self.stdout.flush() def getc(address): char = console.getch_noblock(self.stdin) if char: byte = ord(char) else: byte = 0 return byte m = ObservableMemory(subject=self.memory, addrWidth=self.addrWidth) m.subscribe_to_write([self.putc_addr], putc) m.subscribe_to_read([self.getc_addr], getc) self._mpu.memory = m
def _install_io(self): def getc_from_test(_): """Parameter (originally "address") required by py65mon but unused here as "_" """ global test_string, test_index test_index = test_index + 1 if test_index < len(test_string): result = ord(test_string[test_index]) else: result = 0 return result def putc_results(_, value): """First parameter (originally "address") required by py65mon but unused here as "_" """ global fout # Save results to file. if value != 0: if not args.suppress_tester or \ test_index > end_of_tester: fout.write(chr(value).encode()) # Print to the screen if we are not muted. if not args.mute: if not args.suppress_tester or \ test_index > end_of_tester: sys.stdout.write(chr(value)) sys.stdout.flush() # Install the above handlers for I/O mem = ObservableMemory(subject=self.memory) mem.subscribe_to_write([0xF001], putc_results) mem.subscribe_to_read([0xF004], getc_from_test) self._mpu.memory = mem
def reset(self): self.mpu = NMOS6502(memory=ObservableMemory()) for name, module in self.hw.items(): module.reset() self.status = 'halted'
def test___setitem__with_no_listeners_changes_memory(self): subject = self._make_subject() mem = ObservableMemory(subject=subject) mem[0xC000] = 0xAB self.assertEqual(0xAB, subject[0xC000])
def _install_io(self): def getc_from_test(_): """Parameter (originally "address") required by py65mon but unused here as "_" """ global test_string, test_index test_index = test_index + 1 if test_index < len(test_string): result = ord(test_string[test_index]) else: result = 0 return result def putc_results(_, value): """First parameter (originally "address") required by py65mon but unused here as "_" """ global fout # Save results to file. if value != 0: fout.write(chr(value).encode()) # Print to the screen if we are not muted. if not args.mute: sys.stdout.write(chr(value)) sys.stdout.flush() def update_cycle_start(_): """Parameter (originally "address") required by py65mon but unused here as "_" """ # When this address is read from, note the cycle time. self.cycle_start = self._mpu.processorCycles return 0 def update_cycle_end(_): """Parameter (originally "address") required by py65mon but unused here as "_" """ # When this address is read from, note the cycle time. self.cycle_end = self._mpu.processorCycles # # Compute the elapsed time (in CPU cycles). # # With a 1MHz clock, this will also be in microseconds. # fout.write((" CYCLES: "+str(self.cycle_end-self.cycle_start)+" ").encode()) # # # Print to the screen if we are not muted. # if not args.mute: # sys.stdout.write((" CYCLES: "+str(self.cycle_end-self.cycle_start)+" ")) # sys.stdout.flush() return 0 def read_cycle_count(address): """Break up the 32-bit result into bytes for Tali to read out of virtual memory. Note that the hex value 12345678 is stored in memory as bytes 34 12 78 56. The value will be read (as a double) starting at memory address 0xFF00 """ if address == 0xFF00: return ((self.cycle_end-self.cycle_start)&0x00FF0000)>>16 elif address == 0xFF01: return ((self.cycle_end-self.cycle_start)&0xFF000000)>>24 elif address == 0xFF02: return ((self.cycle_end-self.cycle_start)&0x000000FF) elif address == 0xFF03: return ((self.cycle_end-self.cycle_start)&0x0000FF00)>>8 else: return 0 # Install the above handlers for I/O mem = ObservableMemory(subject=self.memory) mem.subscribe_to_write([0xF001], putc_results) mem.subscribe_to_read([0xF004], getc_from_test) # Install the handlers for timing cycles. mem.subscribe_to_read([0xF002], update_cycle_start) mem.subscribe_to_read([0xF003], update_cycle_end) mem.subscribe_to_read([0xFF00, 0xFF01, 0xFF02, 0xFF03], read_cycle_count) self._mpu.memory = mem
def test__getattr__proxies_subject(self): subject = self._make_subject() mem = ObservableMemory(subject=subject) self.assertEqual(subject.count, mem.count)
def test___getitem__with_no_write_subscribers_changes_memory(self): subject = self._make_subject() mem = ObservableMemory(subject=subject) subject[0xC000] = 0xAB self.assertEqual(0xAB, mem[0xC000])