From 22031e8d1deee04981df9a75306e458c172aff7f Mon Sep 17 00:00:00 2001 From: Philippe Chataignon Date: Wed, 24 Nov 2021 13:08:07 +0100 Subject: [PATCH 1/5] Fix BRK bug. Ensure break_flag is set. --- cpu6502.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu6502.py b/cpu6502.py index f17c09c..e89d28a 100644 --- a/cpu6502.py +++ b/cpu6502.py @@ -1156,10 +1156,10 @@ class CPU: def BRK(self): self.cycles += 5 + self.break_flag = 1 # set break_flag before status pushed 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 From 8934c979387176fc1277923c6e4ee89a0970766a Mon Sep 17 00:00:00 2001 From: Brian Pollock Date: Sun, 1 Dec 2019 11:14:08 +0000 Subject: [PATCH 2/5] unittest fix/workaround - remove CPU options and disable control_server - CPU options were only used to pass 'pc'. Rather than adding another get_options/Options to tests,py, replacing options with a pc argument removes CPU's dependency on command-line options. - As a workaround for 'Address already in use', control_server is now enabled/disabled by memory.use_bus (which is False in unit tests). --- cpu6502.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/cpu6502.py b/cpu6502.py index e89d28a..8198217 100644 --- a/cpu6502.py +++ b/cpu6502.py @@ -505,10 +505,10 @@ class CPU: STACK_PAGE = 0x100 RESET_VECTOR = 0xFFFC - def __init__(self, options, memory): + def __init__(self, memory, pc=None): self.memory = memory - self.control_server = BaseHTTPServer.HTTPServer(("127.0.0.1", 6502), ControlHandlerFactory(self)) + self.control_server = memory.use_bus and BaseHTTPServer.HTTPServer(("127.0.0.1", 6502), ControlHandlerFactory(self)) self.accumulator = 0x00 self.x_index = 0x00 @@ -528,8 +528,8 @@ class CPU: self.setup_ops() self.reset() - if options.pc is not None: - self.program_counter = options.pc + if pc is not None: + self.program_counter = pc self.running = True self.quit = False @@ -704,13 +704,14 @@ class CPU: # a connection is accepted until the response # is sent. TODO: use an async HTTP server that # handles input data asynchronously. - sockets = [self.control_server] - rs, _, _ = select.select(sockets, [], [], timeout) - for s in rs: - if s is self.control_server: - self.control_server._handle_request_noblock() - else: - pass + if self.control_server: + sockets = [self.control_server] + rs, _, _ = select.select(sockets, [], [], timeout) + for s in rs: + if s is self.control_server: + self.control_server._handle_request_noblock() + else: + pass count = 1000 while count > 0 and self.running: @@ -1225,5 +1226,5 @@ if __name__ == "__main__": mem = Memory(options) - cpu = CPU(options, mem) + cpu = CPU(mem, options.pc) cpu.run(options.bus) From b717984056bcd7f3d3fb8bbcfc3b681b14b1daed Mon Sep 17 00:00:00 2001 From: Philippe Chataignon Date: Wed, 24 Nov 2021 22:07:20 +0100 Subject: [PATCH 3/5] Convert to python3 --- applepy.py | 26 +++++++++++++------------- applepy_curses.py | 12 ++++++------ control.py | 32 ++++++++++++++++---------------- cpu6502.py | 46 +++++++++++++++++++++++----------------------- 4 files changed, 58 insertions(+), 58 deletions(-) diff --git a/applepy.py b/applepy.py index e54962d..95dec7c 100755 --- a/applepy.py +++ b/applepy.py @@ -391,7 +391,7 @@ class Apple2: rs, _, _ = select.select([listener], [], [], 2) if not rs: - print >>sys.stderr, "CPU module did not start" + print("CPU module did not start", file=sys.stderr) sys.exit(1) self.cpu, _ = listener.accept() @@ -404,7 +404,7 @@ class Apple2: break cycle, rw, addr, val = struct.unpack(">sys.stderr, "ApplePy - an Apple ][ emulator in Python" - print >>sys.stderr, "James Tauber / http://jtauber.com/" - print >>sys.stderr - print >>sys.stderr, "Usage: applepy.py [options]" - print >>sys.stderr - print >>sys.stderr, " -c, --cassette Cassette wav file to load" - print >>sys.stderr, " -R, --rom ROM file to use (default A2ROM.BIN)" - print >>sys.stderr, " -r, --ram RAM file to load (default none)" - print >>sys.stderr, " -p, --pc Initial PC value" - print >>sys.stderr, " -q, --quiet Quiet mode, no sounds (default sounds)" + print("ApplePy - an Apple ][ emulator in Python", file=sys.stderr) + print("James Tauber / http://jtauber.com/", file=sys.stderr) + print(file=sys.stderr) + print("Usage: applepy.py [options]", file=sys.stderr) + print(file=sys.stderr) + print(" -c, --cassette Cassette wav file to load", file=sys.stderr) + print(" -R, --rom ROM file to use (default A2ROM.BIN)", file=sys.stderr) + print(" -r, --ram RAM file to load (default none)", file=sys.stderr) + print(" -p, --pc Initial PC value", file=sys.stderr) + print(" -q, --quiet Quiet mode, no sounds (default sounds)", file=sys.stderr) sys.exit(1) diff --git a/applepy_curses.py b/applepy_curses.py index f0fbd0a..38c0341 100644 --- a/applepy_curses.py +++ b/applepy_curses.py @@ -98,12 +98,12 @@ def run(win): 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: applepy_curses.py [options]" - print >>sys.stderr - print >>sys.stderr, " -R, --rom ROM file to use (default A2ROM.BIN)" + print("ApplePy - an Apple ][ emulator in Python", file=sys.stderr) + print("James Tauber / http://jtauber.com/", file=sys.stderr) + print(file=sys.stderr) + print("Usage: applepy_curses.py [options]", file=sys.stderr) + print(file=sys.stderr) + print(" -R, --rom ROM file to use (default A2ROM.BIN)", file=sys.stderr) sys.exit(1) diff --git a/control.py b/control.py index 053c394..516d941 100644 --- a/control.py +++ b/control.py @@ -1,16 +1,16 @@ import json import sys -import urllib +import urllib.request, urllib.parse, urllib.error URL_PREFIX = "http://localhost:6502" def get(url): - return json.loads(urllib.urlopen(URL_PREFIX + url).read()) + return json.loads(urllib.request.urlopen(URL_PREFIX + url).read()) def post(url, data=None): - return urllib.urlopen(URL_PREFIX + url, json.dumps(data) if data is not None else "") + return urllib.request.urlopen(URL_PREFIX + url, json.dumps(data) if data is not None else "") def value(s): @@ -45,7 +45,7 @@ def cmd_disassemble(a): addr = status["program_counter"] disasm = get("/disassemble/%d" % addr) for d in disasm: - print format_disassemble(d) + print(format_disassemble(d)) def cmd_dump(a): @@ -80,7 +80,7 @@ def cmd_dump(a): s += "." else: s += " " - print s + print(s) addr += 16 @@ -89,20 +89,20 @@ def cmd_help(a): if len(a) > 1: f = Commands.get(a[1]) if f is not None: - print f.__doc__ + print(f.__doc__) else: - print "Unknown command:", a[1] + print("Unknown command:", a[1]) else: - print "Commands:" + print("Commands:") for c in sorted(Commands): - print " ", c + print(" ", c) def cmd_peek(a): """Peek memory location""" addr = value(a[1]) dump = get("/memory/%d" % addr) - print "%04X: %02X" % (addr, dump[0]) + print("%04X: %02X" % (addr, dump[0])) def cmd_poke(a): @@ -115,7 +115,7 @@ def cmd_poke(a): def cmd_status(a): """CPU status""" status = get("/status") - print "A=%02X X=%02X Y=%02X S=%02X PC=%04X F=%c%c0%c%c%c%c%c" % ( + print("A=%02X X=%02X Y=%02X S=%02X PC=%04X F=%c%c0%c%c%c%c%c" % ( status["accumulator"], status["x_index"], status["y_index"], @@ -128,9 +128,9 @@ def cmd_status(a): "I" if status["interrupt_disable_flag"] else "i", "Z" if status["zero_flag"] else "z", "C" if status["carry_flag"] else "c", - ) + )) disasm = get("/disassemble/%d" % status["program_counter"]) - print format_disassemble(disasm[0]) + print(format_disassemble(disasm[0])) def cmd_quit(a): @@ -155,15 +155,15 @@ Commands = { def main(): - print "ApplePy control console" + print("ApplePy control console") while True: - s = raw_input("6502> ") + s = input("6502> ") a = s.strip().split() f = Commands.get(a[0]) if f is not None: f(a) else: - print "Unknown command:", s + print("Unknown command:", s) if __name__ == "__main__": main() diff --git a/cpu6502.py b/cpu6502.py index 8198217..fad89e1 100644 --- a/cpu6502.py +++ b/cpu6502.py @@ -3,7 +3,7 @@ # originally written 2001, updated 2011 -import BaseHTTPServer +import http.server import json import re import select @@ -35,7 +35,7 @@ class ROM: def load_file(self, address, filename): with open(filename, "rb") as f: for offset, datum in enumerate(f.read()): - self._mem[address - self.start + offset] = ord(datum) + self._mem[address - self.start + offset] = datum def read_byte(self, address): assert self.start <= address <= self.end @@ -365,7 +365,7 @@ class Disassemble: return r, info[0] -class ControlHandler(BaseHTTPServer.BaseHTTPRequestHandler): +class ControlHandler(http.server.BaseHTTPRequestHandler): def __init__(self, request, client_address, server, cpu): self.cpu = cpu @@ -385,13 +385,13 @@ class ControlHandler(BaseHTTPServer.BaseHTTPRequestHandler): r"/reset$": self.post_reset, } - BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, request, client_address, server) + http.server.BaseHTTPRequestHandler.__init__(self, request, client_address, server) def log_request(self, code, size=0): pass def dispatch(self, urls): - for r, f in urls.items(): + for r, f in list(urls.items()): m = re.match(r, self.path) if m is not None: f(m) @@ -439,7 +439,7 @@ class ControlHandler(BaseHTTPServer.BaseHTTPRequestHandler): end = int(e) else: end = addr - self.response(json.dumps(list(map(self.cpu.read_byte, range(addr, end + 1))))) + self.response(json.dumps(list(map(self.cpu.read_byte, list(range(addr, end + 1)))))) def get_status(self, m): self.response(json.dumps(dict((x, getattr(self.cpu, x)) for x in ( @@ -719,9 +719,9 @@ class CPU: 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) + print("UNKNOWN OP") + print(hex(self.program_counter - 1)) + print(hex(op)) break else: self.ops[op]() @@ -736,9 +736,9 @@ class CPU: 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) + print("UNKNOWN OP") + print(hex(self.program_counter - 1)) + print(hex(op)) break else: self.ops[op]() @@ -1172,15 +1172,15 @@ class CPU: 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, " -b, --bus Bus port number" - print >>sys.stderr, " -p, --pc Initial PC value" - print >>sys.stderr, " -R, --rom ROM file to use (default A2ROM.BIN)" - print >>sys.stderr, " -r, --ram RAM file to load (default none)" + print("ApplePy - an Apple ][ emulator in Python", file=sys.stderr) + print("James Tauber / http://jtauber.com/", file=sys.stderr) + print(file=sys.stderr) + print("Usage: cpu6502.py [options]", file=sys.stderr) + print(file=sys.stderr) + print(" -b, --bus Bus port number", file=sys.stderr) + print(" -p, --pc Initial PC value", file=sys.stderr) + print(" -R, --rom ROM file to use (default A2ROM.BIN)", file=sys.stderr) + print(" -r, --ram RAM file to load (default none)", file=sys.stderr) sys.exit(1) @@ -1220,8 +1220,8 @@ def get_options(): if __name__ == "__main__": options = get_options() if options.bus is None: - print "ApplePy cpu core" - print "Run applepy.py instead" + print("ApplePy cpu core") + print("Run applepy.py instead") sys.exit(0) mem = Memory(options) From 2d6e6f5de60ddb6019105983d4c56a35f42b5347 Mon Sep 17 00:00:00 2001 From: Philippe Chataignon Date: Wed, 24 Nov 2021 23:39:47 +0100 Subject: [PATCH 4/5] Fix speaker Float division in python3 -> force integer division with // --- applepy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applepy.py b/applepy.py index 95dec7c..c6a6a97 100755 --- a/applepy.py +++ b/applepy.py @@ -279,7 +279,7 @@ class Speaker: def toggle(self, cycle): if self.last_toggle is not None: - l = (cycle - self.last_toggle) / Speaker.CPU_CYCLES_PER_SAMPLE + l = (cycle - self.last_toggle) // Speaker.CPU_CYCLES_PER_SAMPLE self.buffer.extend([0, 26000] if self.polarity else [0, -2600]) self.buffer.extend((l - 2) * [16384] if self.polarity else [-16384]) self.polarity = not self.polarity From 23e7f442425f1076cba75ab5b1d3d7970bf58ec4 Mon Sep 17 00:00:00 2001 From: Philippe Chataignon Date: Thu, 25 Nov 2021 00:10:18 +0100 Subject: [PATCH 5/5] Fix error Remaining BaseHTTPServer instead of http.server --- applepy.py | 2 +- cpu6502.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/applepy.py b/applepy.py index c6a6a97..ce9f890 100755 --- a/applepy.py +++ b/applepy.py @@ -404,7 +404,7 @@ class Apple2: break cycle, rw, addr, val = struct.unpack("