mirror of
https://github.com/jtauber/applepy.git
synced 2024-11-29 05:49:24 +00:00
Merge branch 'master' into timer
This commit is contained in:
commit
0c29d5a27d
3
README
3
README
@ -31,4 +31,5 @@ runs all the programs I've tried so far.
|
|||||||
The only I/O supported is the keyboard and screen but 40-column text, LORES
|
The only I/O supported is the keyboard and screen but 40-column text, LORES
|
||||||
and HIRES graphics are all supported.
|
and HIRES graphics are all supported.
|
||||||
|
|
||||||
ApplePy currently requires Pygame.
|
ApplePy currently requires Pygame (although there is a minimal applepy_curses.py
|
||||||
|
that uses curses to display text mode only).
|
80
applepy.py
80
applepy.py
@ -5,10 +5,13 @@
|
|||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
import pygame
|
import pygame
|
||||||
|
import select
|
||||||
|
import socket
|
||||||
import struct
|
import struct
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
import wave
|
||||||
|
|
||||||
|
|
||||||
class Display:
|
class Display:
|
||||||
@ -106,6 +109,10 @@ class Display:
|
|||||||
self.flash_time = time.time()
|
self.flash_time = time.time()
|
||||||
self.flash_on = False
|
self.flash_on = False
|
||||||
self.flash_chars = [[0] * 0x400] * 2
|
self.flash_chars = [[0] * 0x400] * 2
|
||||||
|
|
||||||
|
self.page = 1
|
||||||
|
self.text = True
|
||||||
|
self.colour = False
|
||||||
|
|
||||||
self.chargen = []
|
self.chargen = []
|
||||||
for c in self.characters:
|
for c in self.characters:
|
||||||
@ -288,12 +295,33 @@ class Speaker:
|
|||||||
self.play()
|
self.play()
|
||||||
|
|
||||||
|
|
||||||
|
class Cassette:
|
||||||
|
|
||||||
|
def __init__(self, fn):
|
||||||
|
wav = wave.open(fn, "r")
|
||||||
|
self.raw = wav.readframes(wav.getnframes())
|
||||||
|
self.start_cycle = 0
|
||||||
|
self.start_offset = 0
|
||||||
|
|
||||||
|
for i, b in enumerate(self.raw):
|
||||||
|
if ord(b) > 0xA0:
|
||||||
|
self.start_offset = i
|
||||||
|
break
|
||||||
|
|
||||||
|
def read_byte(self, cycle):
|
||||||
|
if self.start_cycle == 0:
|
||||||
|
self.start_cycle = cycle
|
||||||
|
offset = self.start_offset + (cycle - self.start_cycle) * 22000 / 1000000
|
||||||
|
return ord(self.raw[offset]) if offset < len(self.raw) else 0x80
|
||||||
|
|
||||||
|
|
||||||
class SoftSwitches:
|
class SoftSwitches:
|
||||||
|
|
||||||
def __init__(self, display, speaker):
|
def __init__(self, display, speaker, cassette):
|
||||||
self.kbd = 0x00
|
self.kbd = 0x00
|
||||||
self.display = display
|
self.display = display
|
||||||
self.speaker = speaker
|
self.speaker = speaker
|
||||||
|
self.cassette = cassette
|
||||||
|
|
||||||
def read_byte(self, cycle, address):
|
def read_byte(self, cycle, address):
|
||||||
assert 0xC000 <= address <= 0xCFFF
|
assert 0xC000 <= address <= 0xCFFF
|
||||||
@ -320,6 +348,9 @@ class SoftSwitches:
|
|||||||
self.display.lores()
|
self.display.lores()
|
||||||
elif address == 0xC057:
|
elif address == 0xC057:
|
||||||
self.display.hires()
|
self.display.hires()
|
||||||
|
elif address == 0xC060:
|
||||||
|
if self.cassette:
|
||||||
|
return self.cassette.read_byte(cycle)
|
||||||
else:
|
else:
|
||||||
pass # print "%04X" % address
|
pass # print "%04X" % address
|
||||||
return 0x00
|
return 0x00
|
||||||
@ -327,25 +358,36 @@ class SoftSwitches:
|
|||||||
|
|
||||||
class Apple2:
|
class Apple2:
|
||||||
|
|
||||||
def __init__(self, options, display, speaker):
|
def __init__(self, options, display, speaker, cassette):
|
||||||
self.display = display
|
self.display = display
|
||||||
self.speaker = speaker
|
self.speaker = speaker
|
||||||
self.softswitches = SoftSwitches(display, speaker)
|
self.softswitches = SoftSwitches(display, speaker, cassette)
|
||||||
|
|
||||||
|
listener = socket.socket()
|
||||||
|
listener.bind(("127.0.0.1", 0))
|
||||||
|
listener.listen(0)
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
sys.executable,
|
sys.executable,
|
||||||
"cpu6502.py",
|
"cpu6502.py",
|
||||||
|
"--bus", str(listener.getsockname()[1]),
|
||||||
"--rom", options.rom,
|
"--rom", options.rom,
|
||||||
]
|
]
|
||||||
if options.ram:
|
if options.ram:
|
||||||
args.extend([
|
args.extend([
|
||||||
"--ram", options.ram,
|
"--ram", options.ram,
|
||||||
])
|
])
|
||||||
self.core = subprocess.Popen(
|
if options.pc is not None:
|
||||||
args=args,
|
args.extend([
|
||||||
stdin=subprocess.PIPE,
|
"--pc", str(options.pc),
|
||||||
stdout=subprocess.PIPE,
|
])
|
||||||
)
|
self.core = subprocess.Popen(args)
|
||||||
|
|
||||||
|
rs, _, _ = select.select([listener], [], [], 2)
|
||||||
|
if not rs:
|
||||||
|
print >>sys.stderr, "CPU module did not start"
|
||||||
|
sys.exit(1)
|
||||||
|
self.cpu, _ = listener.accept()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
update_cycle = 0
|
update_cycle = 0
|
||||||
@ -354,11 +396,12 @@ class Apple2:
|
|||||||
|
|
||||||
quit = False
|
quit = False
|
||||||
while not quit:
|
while not quit:
|
||||||
op = self.core.stdout.read(8)
|
op = self.cpu.recv(8)
|
||||||
|
if len(op) == 0:
|
||||||
|
break
|
||||||
cycle, rw, addr, val = struct.unpack("<IBHB", op)
|
cycle, rw, addr, val = struct.unpack("<IBHB", op)
|
||||||
if rw == 0:
|
if rw == 0:
|
||||||
self.core.stdin.write(chr(self.softswitches.read_byte(cycle, addr)))
|
self.cpu.send(chr(self.softswitches.read_byte(cycle, addr)))
|
||||||
self.core.stdin.flush()
|
|
||||||
elif rw == 1:
|
elif rw == 1:
|
||||||
self.display.update(addr, val)
|
self.display.update(addr, val)
|
||||||
else:
|
else:
|
||||||
@ -397,8 +440,10 @@ def usage():
|
|||||||
print >>sys.stderr
|
print >>sys.stderr
|
||||||
print >>sys.stderr, "Usage: applepy.py [options]"
|
print >>sys.stderr, "Usage: applepy.py [options]"
|
||||||
print >>sys.stderr
|
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, --rom ROM file to use (default A2ROM.BIN)"
|
||||||
print >>sys.stderr, " -r, --ram RAM file to load (default none)"
|
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 >>sys.stderr, " -q, --quiet Quiet mode, no sounds (default sounds)"
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
@ -406,20 +451,28 @@ def usage():
|
|||||||
def get_options():
|
def get_options():
|
||||||
class Options:
|
class Options:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
self.cassette = None
|
||||||
self.rom = "A2ROM.BIN"
|
self.rom = "A2ROM.BIN"
|
||||||
self.ram = None
|
self.ram = None
|
||||||
|
self.pc = None
|
||||||
self.quiet = False
|
self.quiet = False
|
||||||
|
|
||||||
options = Options()
|
options = Options()
|
||||||
a = 1
|
a = 1
|
||||||
while a < len(sys.argv):
|
while a < len(sys.argv):
|
||||||
if sys.argv[a].startswith("-"):
|
if sys.argv[a].startswith("-"):
|
||||||
if sys.argv[a] in ("-R", "--rom"):
|
if sys.argv[a] in ("-c", "--cassette"):
|
||||||
|
a += 1
|
||||||
|
options.cassette = sys.argv[a]
|
||||||
|
elif sys.argv[a] in ("-R", "--rom"):
|
||||||
a += 1
|
a += 1
|
||||||
options.rom = sys.argv[a]
|
options.rom = sys.argv[a]
|
||||||
elif sys.argv[a] in ("-r", "--ram"):
|
elif sys.argv[a] in ("-r", "--ram"):
|
||||||
a += 1
|
a += 1
|
||||||
options.ram = sys.argv[a]
|
options.ram = sys.argv[a]
|
||||||
|
elif sys.argv[a] in ("-p", "--pc"):
|
||||||
|
a += 1
|
||||||
|
options.pc = int(sys.argv[a])
|
||||||
elif sys.argv[a] in ("-q", "--quiet"):
|
elif sys.argv[a] in ("-q", "--quiet"):
|
||||||
options.quiet = True
|
options.quiet = True
|
||||||
else:
|
else:
|
||||||
@ -435,6 +488,7 @@ if __name__ == "__main__":
|
|||||||
options = get_options()
|
options = get_options()
|
||||||
display = Display()
|
display = Display()
|
||||||
speaker = None if options.quiet else Speaker()
|
speaker = None if options.quiet else Speaker()
|
||||||
|
cassette = Cassette(options.cassette) if options.cassette else None
|
||||||
|
|
||||||
apple = Apple2(options, display, speaker)
|
apple = Apple2(options, display, speaker, cassette)
|
||||||
apple.run()
|
apple.run()
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import curses
|
import curses
|
||||||
|
import socket
|
||||||
import struct
|
import struct
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
@ -55,20 +56,29 @@ def write(win, addr, val):
|
|||||||
|
|
||||||
def run(win):
|
def run(win):
|
||||||
global kbd
|
global kbd
|
||||||
p = subprocess.Popen(
|
|
||||||
args=[sys.executable, "cpu6502.py"],
|
listener = socket.socket()
|
||||||
stdin=subprocess.PIPE,
|
listener.bind(("127.0.0.1", 0))
|
||||||
stdout=subprocess.PIPE,
|
listener.listen(0)
|
||||||
)
|
|
||||||
|
args = [
|
||||||
|
sys.executable,
|
||||||
|
"cpu6502.py",
|
||||||
|
"--bus", str(listener.getsockname()[1]),
|
||||||
|
"--rom", options.rom,
|
||||||
|
]
|
||||||
|
|
||||||
|
p = subprocess.Popen(args)
|
||||||
|
cpu, _ = listener.accept()
|
||||||
|
|
||||||
win.clear()
|
win.clear()
|
||||||
curses.noecho()
|
curses.noecho()
|
||||||
win.nodelay(True)
|
win.nodelay(True)
|
||||||
while True:
|
while True:
|
||||||
op = p.stdout.read(8)
|
op = cpu.recv(8)
|
||||||
cycle, rw, addr, val = struct.unpack("<IBHB", op)
|
cycle, rw, addr, val = struct.unpack("<IBHB", op)
|
||||||
if rw == 0:
|
if rw == 0:
|
||||||
p.stdin.write(chr(read(addr, val)))
|
cpu.send(chr(read(addr, val)))
|
||||||
p.stdin.flush()
|
|
||||||
elif rw == 1:
|
elif rw == 1:
|
||||||
write(win, addr, val)
|
write(win, addr, val)
|
||||||
else:
|
else:
|
||||||
@ -85,7 +95,39 @@ def run(win):
|
|||||||
pass
|
pass
|
||||||
except TypeError:
|
except TypeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
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)"
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def get_options():
|
||||||
|
class Options:
|
||||||
|
def __init__(self):
|
||||||
|
self.rom = "A2ROM.BIN"
|
||||||
|
|
||||||
|
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]
|
||||||
|
else:
|
||||||
|
usage()
|
||||||
|
else:
|
||||||
|
usage()
|
||||||
|
a += 1
|
||||||
|
|
||||||
|
return options
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
options = get_options()
|
||||||
curses.wrapper(run)
|
curses.wrapper(run)
|
||||||
|
157
control.py
Normal file
157
control.py
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
import json
|
||||||
|
import readline
|
||||||
|
import sys
|
||||||
|
import urllib
|
||||||
|
|
||||||
|
URL_PREFIX = "http://localhost:6502"
|
||||||
|
|
||||||
|
def get(url):
|
||||||
|
return json.loads(urllib.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 "")
|
||||||
|
|
||||||
|
def value(s):
|
||||||
|
if s.startswith("$"):
|
||||||
|
return int(s[1:], 16)
|
||||||
|
if s.startswith("0x"):
|
||||||
|
return int(s[2:], 16)
|
||||||
|
return int(s)
|
||||||
|
|
||||||
|
def format_disassemble(dis):
|
||||||
|
r = "%04X- " % dis["address"]
|
||||||
|
for i in range(3):
|
||||||
|
if i < len(dis["bytes"]):
|
||||||
|
r += "%02X " % dis["bytes"][i]
|
||||||
|
else:
|
||||||
|
r += " "
|
||||||
|
r += " %s" % dis["mnemonic"]
|
||||||
|
if "operand" in dis:
|
||||||
|
r += " %-10s" % dis["operand"]
|
||||||
|
if "memory" in dis:
|
||||||
|
r += "[%04X] = %0*X" % tuple(dis["memory"])
|
||||||
|
return r
|
||||||
|
|
||||||
|
def cmd_disassemble(a):
|
||||||
|
"""Disassemble"""
|
||||||
|
if len(a) > 1:
|
||||||
|
addr = value(a[1])
|
||||||
|
else:
|
||||||
|
status = get("/status")
|
||||||
|
addr = status["program_counter"]
|
||||||
|
disasm = get("/disassemble/%d" % addr)
|
||||||
|
for d in disasm:
|
||||||
|
print format_disassemble(d)
|
||||||
|
|
||||||
|
def cmd_dump(a):
|
||||||
|
"""Dump memory"""
|
||||||
|
start = value(a[1])
|
||||||
|
if len(a) > 2:
|
||||||
|
end = value(a[2])
|
||||||
|
else:
|
||||||
|
end = start + 15
|
||||||
|
data = get("/memory/%d-%d" % (start, end))
|
||||||
|
addr = start & ~0xF
|
||||||
|
while addr <= end:
|
||||||
|
s = "%04X-" % addr
|
||||||
|
for i in range(16):
|
||||||
|
if start <= addr + i <= end:
|
||||||
|
s += " %02X" % data[addr + i - start]
|
||||||
|
else:
|
||||||
|
s += " "
|
||||||
|
s += " "
|
||||||
|
for i in range(16):
|
||||||
|
if start <= addr + i <= end:
|
||||||
|
c = data[addr + i - start]
|
||||||
|
|
||||||
|
# adjust for apple character set
|
||||||
|
c &= 0x3f
|
||||||
|
if c < 0x20:
|
||||||
|
c += 0x40
|
||||||
|
|
||||||
|
if 0x20 <= c < 0x7f:
|
||||||
|
s += chr(c)
|
||||||
|
else:
|
||||||
|
s += "."
|
||||||
|
else:
|
||||||
|
s += " "
|
||||||
|
print s
|
||||||
|
addr += 16
|
||||||
|
|
||||||
|
def cmd_help(a):
|
||||||
|
"""Help commands"""
|
||||||
|
if len(a) > 1:
|
||||||
|
f = Commands.get(a[1])
|
||||||
|
if f is not None:
|
||||||
|
print f.__doc__
|
||||||
|
else:
|
||||||
|
print "Unknown command:", a[1]
|
||||||
|
else:
|
||||||
|
print "Commands:"
|
||||||
|
for c in sorted(Commands):
|
||||||
|
print " ", c
|
||||||
|
|
||||||
|
def cmd_peek(a):
|
||||||
|
"""Peek memory location"""
|
||||||
|
addr = value(a[1])
|
||||||
|
dump = get("/memory/%d" % addr)
|
||||||
|
print "%04X: %02X" % (addr, dump[0])
|
||||||
|
|
||||||
|
def cmd_poke(a):
|
||||||
|
"""Poke memory location"""
|
||||||
|
addr = value(a[1])
|
||||||
|
val = value(a[2])
|
||||||
|
post("/memory/%d" % addr, [val])
|
||||||
|
|
||||||
|
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" % (
|
||||||
|
status["accumulator"],
|
||||||
|
status["x_index"],
|
||||||
|
status["y_index"],
|
||||||
|
status["stack_pointer"],
|
||||||
|
status["program_counter"],
|
||||||
|
"N" if status["sign_flag"] else "n",
|
||||||
|
"V" if status["overflow_flag"] else "v",
|
||||||
|
"B" if status["break_flag"] else "b",
|
||||||
|
"D" if status["decimal_mode_flag"] else "d",
|
||||||
|
"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])
|
||||||
|
|
||||||
|
def cmd_quit(a):
|
||||||
|
"""Quit"""
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
def cmd_reset(a):
|
||||||
|
"""Reset"""
|
||||||
|
post("/reset")
|
||||||
|
|
||||||
|
Commands = {
|
||||||
|
"disassemble": cmd_disassemble,
|
||||||
|
"dump": cmd_dump,
|
||||||
|
"help": cmd_help,
|
||||||
|
"peek": cmd_peek,
|
||||||
|
"poke": cmd_poke,
|
||||||
|
"status": cmd_status,
|
||||||
|
"quit": cmd_quit,
|
||||||
|
"reset": cmd_reset,
|
||||||
|
}
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print "ApplePy control console"
|
||||||
|
while True:
|
||||||
|
s = raw_input("6502> ")
|
||||||
|
a = s.strip().split()
|
||||||
|
f = Commands.get(a[0])
|
||||||
|
if f is not None:
|
||||||
|
f(a)
|
||||||
|
else:
|
||||||
|
print "Unknown command:", s
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
638
cpu6502.py
638
cpu6502.py
@ -3,10 +3,18 @@
|
|||||||
# originally written 2001, updated 2011
|
# originally written 2001, updated 2011
|
||||||
|
|
||||||
|
|
||||||
|
import BaseHTTPServer
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import select
|
||||||
|
import socket
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
bus = None # socket for bus I/O
|
||||||
|
|
||||||
|
|
||||||
def signed(x):
|
def signed(x):
|
||||||
if x > 0x7F:
|
if x > 0x7F:
|
||||||
x = x - 0x100
|
x = x - 0x100
|
||||||
@ -25,7 +33,7 @@ class ROM:
|
|||||||
self._mem[address - self.start + offset] = datum
|
self._mem[address - self.start + offset] = datum
|
||||||
|
|
||||||
def load_file(self, address, filename):
|
def load_file(self, address, filename):
|
||||||
with open(filename) as f:
|
with open(filename, "rb") as f:
|
||||||
for offset, datum in enumerate(f.read()):
|
for offset, datum in enumerate(f.read()):
|
||||||
self._mem[address - self.start + offset] = ord(datum)
|
self._mem[address - self.start + offset] = ord(datum)
|
||||||
|
|
||||||
@ -42,8 +50,8 @@ class RAM(ROM):
|
|||||||
|
|
||||||
class Memory:
|
class Memory:
|
||||||
|
|
||||||
def __init__(self, options=None, use_stdio=True):
|
def __init__(self, options=None, use_bus=True):
|
||||||
self.use_stdio = use_stdio
|
self.use_bus = use_bus
|
||||||
self.rom = ROM(0xD000, 0x3000)
|
self.rom = ROM(0xD000, 0x3000)
|
||||||
|
|
||||||
if options:
|
if options:
|
||||||
@ -82,26 +90,24 @@ class Memory:
|
|||||||
self.bus_write(cycle, address, value)
|
self.bus_write(cycle, address, value)
|
||||||
|
|
||||||
def bus_read(self, cycle, address):
|
def bus_read(self, cycle, address):
|
||||||
if not self.use_stdio:
|
if not self.use_bus:
|
||||||
return 0
|
return 0
|
||||||
op = struct.pack("<IBHB", cycle, 0, address, 0)
|
op = struct.pack("<IBHB", cycle, 0, address, 0)
|
||||||
try:
|
try:
|
||||||
sys.stdout.write(op)
|
bus.send(op)
|
||||||
sys.stdout.flush()
|
b = bus.recv(1)
|
||||||
except IOError:
|
if len(b) == 0:
|
||||||
|
sys.exit(0)
|
||||||
|
return ord(b)
|
||||||
|
except socket.error:
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
b = sys.stdin.read(1)
|
|
||||||
if len(b) == 0:
|
|
||||||
sys.exit(0)
|
|
||||||
return ord(b)
|
|
||||||
|
|
||||||
def bus_write(self, cycle, address, value):
|
def bus_write(self, cycle, address, value):
|
||||||
if not self.use_stdio:
|
if not self.use_bus:
|
||||||
return
|
return
|
||||||
op = struct.pack("<IBHB", cycle, 1, address, value)
|
op = struct.pack("<IBHB", cycle, 1, address, value)
|
||||||
try:
|
try:
|
||||||
sys.stdout.write(op)
|
bus.send(op)
|
||||||
sys.stdout.flush()
|
|
||||||
except IOError:
|
except IOError:
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
@ -114,214 +120,384 @@ class Disassemble:
|
|||||||
self.setup_ops()
|
self.setup_ops()
|
||||||
|
|
||||||
def setup_ops(self):
|
def setup_ops(self):
|
||||||
self.ops = [None] * 0x100
|
self.ops = [(1, "???")] * 0x100
|
||||||
self.ops[0x00] = ("BRK", )
|
self.ops[0x00] = (1, "BRK", )
|
||||||
self.ops[0x01] = ("ORA", self.indirect_x_mode)
|
self.ops[0x01] = (2, "ORA", self.indirect_x_mode)
|
||||||
self.ops[0x05] = ("ORA", self.zero_page_mode)
|
self.ops[0x05] = (2, "ORA", self.zero_page_mode)
|
||||||
self.ops[0x06] = ("ASL", self.zero_page_mode)
|
self.ops[0x06] = (2, "ASL", self.zero_page_mode)
|
||||||
self.ops[0x08] = ("PHP", )
|
self.ops[0x08] = (1, "PHP", )
|
||||||
self.ops[0x09] = ("ORA", self.immediate_mode)
|
self.ops[0x09] = (2, "ORA", self.immediate_mode)
|
||||||
self.ops[0x0A] = ("ASL", )
|
self.ops[0x0A] = (1, "ASL", )
|
||||||
self.ops[0x0D] = ("ORA", self.absolute_mode)
|
self.ops[0x0D] = (3, "ORA", self.absolute_mode)
|
||||||
self.ops[0x0E] = ("ASL", self.absolute_mode)
|
self.ops[0x0E] = (3, "ASL", self.absolute_mode)
|
||||||
self.ops[0x10] = ("BPL", self.relative_mode)
|
self.ops[0x10] = (2, "BPL", self.relative_mode)
|
||||||
self.ops[0x11] = ("ORA", self.indirect_y_mode)
|
self.ops[0x11] = (2, "ORA", self.indirect_y_mode)
|
||||||
self.ops[0x15] = ("ORA", self.zero_page_x_mode)
|
self.ops[0x15] = (2, "ORA", self.zero_page_x_mode)
|
||||||
self.ops[0x16] = ("ASL", self.zero_page_x_mode)
|
self.ops[0x16] = (2, "ASL", self.zero_page_x_mode)
|
||||||
self.ops[0x18] = ("CLC", )
|
self.ops[0x18] = (1, "CLC", )
|
||||||
self.ops[0x19] = ("ORA", self.absolute_y_mode)
|
self.ops[0x19] = (3, "ORA", self.absolute_y_mode)
|
||||||
self.ops[0x1D] = ("ORA", self.absolute_x_mode)
|
self.ops[0x1D] = (3, "ORA", self.absolute_x_mode)
|
||||||
self.ops[0x1E] = ("ASL", self.absolute_x_mode)
|
self.ops[0x1E] = (3, "ASL", self.absolute_x_mode)
|
||||||
self.ops[0x20] = ("JSR", self.absolute_mode)
|
self.ops[0x20] = (3, "JSR", self.absolute_mode)
|
||||||
self.ops[0x21] = ("AND", self.indirect_x_mode)
|
self.ops[0x21] = (2, "AND", self.indirect_x_mode)
|
||||||
self.ops[0x24] = ("BIT", self.zero_page_mode)
|
self.ops[0x24] = (2, "BIT", self.zero_page_mode)
|
||||||
self.ops[0x25] = ("AND", self.zero_page_mode)
|
self.ops[0x25] = (2, "AND", self.zero_page_mode)
|
||||||
self.ops[0x26] = ("ROL", self.zero_page_mode)
|
self.ops[0x26] = (2, "ROL", self.zero_page_mode)
|
||||||
self.ops[0x28] = ("PLP", )
|
self.ops[0x28] = (1, "PLP", )
|
||||||
self.ops[0x29] = ("AND", self.immediate_mode)
|
self.ops[0x29] = (2, "AND", self.immediate_mode)
|
||||||
self.ops[0x2A] = ("ROL", )
|
self.ops[0x2A] = (1, "ROL", )
|
||||||
self.ops[0x2C] = ("BIT", self.absolute_mode)
|
self.ops[0x2C] = (3, "BIT", self.absolute_mode)
|
||||||
self.ops[0x2D] = ("AND", self.absolute_mode)
|
self.ops[0x2D] = (3, "AND", self.absolute_mode)
|
||||||
self.ops[0x2E] = ("ROL", self.absolute_mode)
|
self.ops[0x2E] = (3, "ROL", self.absolute_mode)
|
||||||
self.ops[0x30] = ("BMI", self.relative_mode)
|
self.ops[0x30] = (2, "BMI", self.relative_mode)
|
||||||
self.ops[0x31] = ("AND", self.indirect_y_mode)
|
self.ops[0x31] = (2, "AND", self.indirect_y_mode)
|
||||||
self.ops[0x35] = ("AND", self.zero_page_x_mode)
|
self.ops[0x35] = (2, "AND", self.zero_page_x_mode)
|
||||||
self.ops[0x36] = ("ROL", self.zero_page_x_mode)
|
self.ops[0x36] = (2, "ROL", self.zero_page_x_mode)
|
||||||
self.ops[0x38] = ("SEC", )
|
self.ops[0x38] = (1, "SEC", )
|
||||||
self.ops[0x39] = ("AND", self.absolute_y_mode)
|
self.ops[0x39] = (3, "AND", self.absolute_y_mode)
|
||||||
self.ops[0x3D] = ("AND", self.absolute_x_mode)
|
self.ops[0x3D] = (3, "AND", self.absolute_x_mode)
|
||||||
self.ops[0x3E] = ("ROL", self.absolute_x_mode)
|
self.ops[0x3E] = (3, "ROL", self.absolute_x_mode)
|
||||||
self.ops[0x40] = ("RTI", )
|
self.ops[0x40] = (1, "RTI", )
|
||||||
self.ops[0x41] = ("EOR", self.indirect_x_mode)
|
self.ops[0x41] = (2, "EOR", self.indirect_x_mode)
|
||||||
self.ops[0x45] = ("EOR", self.zero_page_mode)
|
self.ops[0x45] = (2, "EOR", self.zero_page_mode)
|
||||||
self.ops[0x46] = ("LSR", self.zero_page_mode)
|
self.ops[0x46] = (2, "LSR", self.zero_page_mode)
|
||||||
self.ops[0x48] = ("PHA", )
|
self.ops[0x48] = (1, "PHA", )
|
||||||
self.ops[0x49] = ("EOR", self.immediate_mode)
|
self.ops[0x49] = (2, "EOR", self.immediate_mode)
|
||||||
self.ops[0x4A] = ("LSR", )
|
self.ops[0x4A] = (1, "LSR", )
|
||||||
self.ops[0x4C] = ("JMP", self.absolute_mode)
|
self.ops[0x4C] = (3, "JMP", self.absolute_mode)
|
||||||
self.ops[0x4D] = ("EOR", self.absolute_mode)
|
self.ops[0x4D] = (3, "EOR", self.absolute_mode)
|
||||||
self.ops[0x4E] = ("LSR", self.absolute_mode)
|
self.ops[0x4E] = (3, "LSR", self.absolute_mode)
|
||||||
self.ops[0x50] = ("BVC", self.relative_mode)
|
self.ops[0x50] = (2, "BVC", self.relative_mode)
|
||||||
self.ops[0x51] = ("EOR", self.indirect_y_mode)
|
self.ops[0x51] = (2, "EOR", self.indirect_y_mode)
|
||||||
self.ops[0x55] = ("EOR", self.zero_page_x_mode)
|
self.ops[0x55] = (2, "EOR", self.zero_page_x_mode)
|
||||||
self.ops[0x56] = ("LSR", self.zero_page_x_mode)
|
self.ops[0x56] = (2, "LSR", self.zero_page_x_mode)
|
||||||
self.ops[0x58] = ("CLI", )
|
self.ops[0x58] = (1, "CLI", )
|
||||||
self.ops[0x59] = ("EOR", self.absolute_y_mode)
|
self.ops[0x59] = (3, "EOR", self.absolute_y_mode)
|
||||||
self.ops[0x5D] = ("EOR", self.absolute_x_mode)
|
self.ops[0x5D] = (3, "EOR", self.absolute_x_mode)
|
||||||
self.ops[0x5E] = ("LSR", self.absolute_x_mode)
|
self.ops[0x5E] = (3, "LSR", self.absolute_x_mode)
|
||||||
self.ops[0x60] = ("RTS", )
|
self.ops[0x60] = (1, "RTS", )
|
||||||
self.ops[0x61] = ("ADC", self.indirect_x_mode)
|
self.ops[0x61] = (2, "ADC", self.indirect_x_mode)
|
||||||
self.ops[0x65] = ("ADC", self.zero_page_mode)
|
self.ops[0x65] = (2, "ADC", self.zero_page_mode)
|
||||||
self.ops[0x66] = ("ROR", self.zero_page_mode)
|
self.ops[0x66] = (2, "ROR", self.zero_page_mode)
|
||||||
self.ops[0x68] = ("PLA", )
|
self.ops[0x68] = (1, "PLA", )
|
||||||
self.ops[0x69] = ("ADC", self.immediate_mode)
|
self.ops[0x69] = (2, "ADC", self.immediate_mode)
|
||||||
self.ops[0x6A] = ("ROR", )
|
self.ops[0x6A] = (1, "ROR", )
|
||||||
self.ops[0x6C] = ("JMP", self.indirect_mode)
|
self.ops[0x6C] = (3, "JMP", self.indirect_mode)
|
||||||
self.ops[0x6D] = ("ADC", self.absolute_mode)
|
self.ops[0x6D] = (3, "ADC", self.absolute_mode)
|
||||||
self.ops[0x6E] = ("ROR", self.absolute_mode)
|
self.ops[0x6E] = (3, "ROR", self.absolute_mode)
|
||||||
self.ops[0x70] = ("BVS", self.relative_mode)
|
self.ops[0x70] = (2, "BVS", self.relative_mode)
|
||||||
self.ops[0x71] = ("ADC", self.indirect_y_mode)
|
self.ops[0x71] = (2, "ADC", self.indirect_y_mode)
|
||||||
self.ops[0x75] = ("ADC", self.zero_page_x_mode)
|
self.ops[0x75] = (2, "ADC", self.zero_page_x_mode)
|
||||||
self.ops[0x76] = ("ROR", self.zero_page_x_mode)
|
self.ops[0x76] = (2, "ROR", self.zero_page_x_mode)
|
||||||
self.ops[0x78] = ("SEI", )
|
self.ops[0x78] = (1, "SEI", )
|
||||||
self.ops[0x79] = ("ADC", self.absolute_y_mode)
|
self.ops[0x79] = (3, "ADC", self.absolute_y_mode)
|
||||||
self.ops[0x7D] = ("ADC", self.absolute_x_mode)
|
self.ops[0x7D] = (3, "ADC", self.absolute_x_mode)
|
||||||
self.ops[0x7E] = ("ROR", self.absolute_x_mode)
|
self.ops[0x7E] = (3, "ROR", self.absolute_x_mode)
|
||||||
self.ops[0x81] = ("STA", self.indirect_x_mode)
|
self.ops[0x81] = (2, "STA", self.indirect_x_mode)
|
||||||
self.ops[0x84] = ("STY", self.zero_page_mode)
|
self.ops[0x84] = (2, "STY", self.zero_page_mode)
|
||||||
self.ops[0x85] = ("STA", self.zero_page_mode)
|
self.ops[0x85] = (2, "STA", self.zero_page_mode)
|
||||||
self.ops[0x86] = ("STX", self.zero_page_mode)
|
self.ops[0x86] = (2, "STX", self.zero_page_mode)
|
||||||
self.ops[0x88] = ("DEY", )
|
self.ops[0x88] = (1, "DEY", )
|
||||||
self.ops[0x8A] = ("TXA", )
|
self.ops[0x8A] = (1, "TXA", )
|
||||||
self.ops[0x8C] = ("STY", self.absolute_mode)
|
self.ops[0x8C] = (3, "STY", self.absolute_mode)
|
||||||
self.ops[0x8D] = ("STA", self.absolute_mode)
|
self.ops[0x8D] = (3, "STA", self.absolute_mode)
|
||||||
self.ops[0x8E] = ("STX", self.absolute_mode)
|
self.ops[0x8E] = (3, "STX", self.absolute_mode)
|
||||||
self.ops[0x90] = ("BCC", self.relative_mode)
|
self.ops[0x90] = (2, "BCC", self.relative_mode)
|
||||||
self.ops[0x91] = ("STA", self.indirect_y_mode)
|
self.ops[0x91] = (2, "STA", self.indirect_y_mode)
|
||||||
self.ops[0x94] = ("STY", self.zero_page_x_mode)
|
self.ops[0x94] = (2, "STY", self.zero_page_x_mode)
|
||||||
self.ops[0x95] = ("STA", self.zero_page_x_mode)
|
self.ops[0x95] = (2, "STA", self.zero_page_x_mode)
|
||||||
self.ops[0x96] = ("STX", self.zero_page_y_mode)
|
self.ops[0x96] = (2, "STX", self.zero_page_y_mode)
|
||||||
self.ops[0x98] = ("TYA", )
|
self.ops[0x98] = (1, "TYA", )
|
||||||
self.ops[0x99] = ("STA", self.absolute_y_mode)
|
self.ops[0x99] = (3, "STA", self.absolute_y_mode)
|
||||||
self.ops[0x9A] = ("TXS", )
|
self.ops[0x9A] = (1, "TXS", )
|
||||||
self.ops[0x9D] = ("STA", self.absolute_x_mode)
|
self.ops[0x9D] = (3, "STA", self.absolute_x_mode)
|
||||||
self.ops[0xA0] = ("LDY", self.immediate_mode)
|
self.ops[0xA0] = (2, "LDY", self.immediate_mode)
|
||||||
self.ops[0xA1] = ("LDA", self.indirect_x_mode)
|
self.ops[0xA1] = (2, "LDA", self.indirect_x_mode)
|
||||||
self.ops[0xA2] = ("LDX", self.immediate_mode)
|
self.ops[0xA2] = (2, "LDX", self.immediate_mode)
|
||||||
self.ops[0xA4] = ("LDY", self.zero_page_mode)
|
self.ops[0xA4] = (2, "LDY", self.zero_page_mode)
|
||||||
self.ops[0xA5] = ("LDA", self.zero_page_mode)
|
self.ops[0xA5] = (2, "LDA", self.zero_page_mode)
|
||||||
self.ops[0xA6] = ("LDX", self.zero_page_mode)
|
self.ops[0xA6] = (2, "LDX", self.zero_page_mode)
|
||||||
self.ops[0xA8] = ("TAY", )
|
self.ops[0xA8] = (1, "TAY", )
|
||||||
self.ops[0xA9] = ("LDA", self.immediate_mode)
|
self.ops[0xA9] = (2, "LDA", self.immediate_mode)
|
||||||
self.ops[0xAA] = ("TAX", )
|
self.ops[0xAA] = (1, "TAX", )
|
||||||
self.ops[0xAC] = ("LDY", self.absolute_mode)
|
self.ops[0xAC] = (3, "LDY", self.absolute_mode)
|
||||||
self.ops[0xAD] = ("LDA", self.absolute_mode)
|
self.ops[0xAD] = (3, "LDA", self.absolute_mode)
|
||||||
self.ops[0xAE] = ("LDX", self.absolute_mode)
|
self.ops[0xAE] = (3, "LDX", self.absolute_mode)
|
||||||
self.ops[0xB0] = ("BCS", self.relative_mode)
|
self.ops[0xB0] = (2, "BCS", self.relative_mode)
|
||||||
self.ops[0xB1] = ("LDA", self.indirect_y_mode)
|
self.ops[0xB1] = (2, "LDA", self.indirect_y_mode)
|
||||||
self.ops[0xB4] = ("LDY", self.zero_page_x_mode)
|
self.ops[0xB4] = (2, "LDY", self.zero_page_x_mode)
|
||||||
self.ops[0xB5] = ("LDA", self.zero_page_x_mode)
|
self.ops[0xB5] = (2, "LDA", self.zero_page_x_mode)
|
||||||
self.ops[0xB6] = ("LDX", self.zero_page_y_mode)
|
self.ops[0xB6] = (2, "LDX", self.zero_page_y_mode)
|
||||||
self.ops[0xB8] = ("CLV", )
|
self.ops[0xB8] = (1, "CLV", )
|
||||||
self.ops[0xB9] = ("LDA", self.absolute_y_mode)
|
self.ops[0xB9] = (3, "LDA", self.absolute_y_mode)
|
||||||
self.ops[0xBA] = ("TSX", )
|
self.ops[0xBA] = (1, "TSX", )
|
||||||
self.ops[0xBC] = ("LDY", self.absolute_x_mode)
|
self.ops[0xBC] = (3, "LDY", self.absolute_x_mode)
|
||||||
self.ops[0xBD] = ("LDA", self.absolute_x_mode)
|
self.ops[0xBD] = (3, "LDA", self.absolute_x_mode)
|
||||||
self.ops[0xBE] = ("LDX", self.absolute_y_mode)
|
self.ops[0xBE] = (3, "LDX", self.absolute_y_mode)
|
||||||
self.ops[0xC0] = ("CPY", self.immediate_mode)
|
self.ops[0xC0] = (2, "CPY", self.immediate_mode)
|
||||||
self.ops[0xC1] = ("CMP", self.indirect_x_mode)
|
self.ops[0xC1] = (2, "CMP", self.indirect_x_mode)
|
||||||
self.ops[0xC4] = ("CPY", self.zero_page_mode)
|
self.ops[0xC4] = (2, "CPY", self.zero_page_mode)
|
||||||
self.ops[0xC5] = ("CMP", self.zero_page_mode)
|
self.ops[0xC5] = (2, "CMP", self.zero_page_mode)
|
||||||
self.ops[0xC6] = ("DEC", self.zero_page_mode)
|
self.ops[0xC6] = (2, "DEC", self.zero_page_mode)
|
||||||
self.ops[0xC8] = ("INY", )
|
self.ops[0xC8] = (1, "INY", )
|
||||||
self.ops[0xC9] = ("CMP", self.immediate_mode)
|
self.ops[0xC9] = (2, "CMP", self.immediate_mode)
|
||||||
self.ops[0xCA] = ("DEX", )
|
self.ops[0xCA] = (1, "DEX", )
|
||||||
self.ops[0xCC] = ("CPY", self.absolute_mode)
|
self.ops[0xCC] = (3, "CPY", self.absolute_mode)
|
||||||
self.ops[0xCD] = ("CMP", self.absolute_mode)
|
self.ops[0xCD] = (3, "CMP", self.absolute_mode)
|
||||||
self.ops[0xCE] = ("DEC", self.absolute_mode)
|
self.ops[0xCE] = (3, "DEC", self.absolute_mode)
|
||||||
self.ops[0xD0] = ("BNE", self.relative_mode)
|
self.ops[0xD0] = (2, "BNE", self.relative_mode)
|
||||||
self.ops[0xD1] = ("CMP", self.indirect_y_mode)
|
self.ops[0xD1] = (2, "CMP", self.indirect_y_mode)
|
||||||
self.ops[0xD5] = ("CMP", self.zero_page_x_mode)
|
self.ops[0xD5] = (2, "CMP", self.zero_page_x_mode)
|
||||||
self.ops[0xD6] = ("DEC", self.zero_page_x_mode)
|
self.ops[0xD6] = (2, "DEC", self.zero_page_x_mode)
|
||||||
self.ops[0xD8] = ("CLD", )
|
self.ops[0xD8] = (1, "CLD", )
|
||||||
self.ops[0xD9] = ("CMP", self.absolute_y_mode)
|
self.ops[0xD9] = (3, "CMP", self.absolute_y_mode)
|
||||||
self.ops[0xDD] = ("CMP", self.absolute_x_mode)
|
self.ops[0xDD] = (3, "CMP", self.absolute_x_mode)
|
||||||
self.ops[0xDE] = ("DEC", self.absolute_x_mode)
|
self.ops[0xDE] = (3, "DEC", self.absolute_x_mode)
|
||||||
self.ops[0xE0] = ("CPX", self.immediate_mode)
|
self.ops[0xE0] = (2, "CPX", self.immediate_mode)
|
||||||
self.ops[0xE1] = ("SBC", self.indirect_x_mode)
|
self.ops[0xE1] = (2, "SBC", self.indirect_x_mode)
|
||||||
self.ops[0xE4] = ("CPX", self.zero_page_mode)
|
self.ops[0xE4] = (2, "CPX", self.zero_page_mode)
|
||||||
self.ops[0xE5] = ("SBC", self.zero_page_mode)
|
self.ops[0xE5] = (2, "SBC", self.zero_page_mode)
|
||||||
self.ops[0xE6] = ("INC", self.zero_page_mode)
|
self.ops[0xE6] = (2, "INC", self.zero_page_mode)
|
||||||
self.ops[0xE8] = ("INX", )
|
self.ops[0xE8] = (1, "INX", )
|
||||||
self.ops[0xE9] = ("SBC", self.immediate_mode)
|
self.ops[0xE9] = (2, "SBC", self.immediate_mode)
|
||||||
self.ops[0xEA] = ("NOP", )
|
self.ops[0xEA] = (1, "NOP", )
|
||||||
self.ops[0xEC] = ("CPX", self.absolute_mode)
|
self.ops[0xEC] = (3, "CPX", self.absolute_mode)
|
||||||
self.ops[0xED] = ("SBC", self.absolute_mode)
|
self.ops[0xED] = (3, "SBC", self.absolute_mode)
|
||||||
self.ops[0xEE] = ("INC", self.absolute_mode)
|
self.ops[0xEE] = (3, "INC", self.absolute_mode)
|
||||||
self.ops[0xF0] = ("BEQ", self.relative_mode)
|
self.ops[0xF0] = (2, "BEQ", self.relative_mode)
|
||||||
self.ops[0xF1] = ("SBC", self.indirect_y_mode)
|
self.ops[0xF1] = (2, "SBC", self.indirect_y_mode)
|
||||||
self.ops[0xF5] = ("SBC", self.zero_page_x_mode)
|
self.ops[0xF5] = (2, "SBC", self.zero_page_x_mode)
|
||||||
self.ops[0xF6] = ("INC", self.zero_page_x_mode)
|
self.ops[0xF6] = (2, "INC", self.zero_page_x_mode)
|
||||||
self.ops[0xF8] = ("SED", )
|
self.ops[0xF8] = (1, "SED", )
|
||||||
self.ops[0xF9] = ("SBC", self.absolute_y_mode)
|
self.ops[0xF9] = (3, "SBC", self.absolute_y_mode)
|
||||||
self.ops[0xFD] = ("SBC", self.absolute_x_mode)
|
self.ops[0xFD] = (3, "SBC", self.absolute_x_mode)
|
||||||
self.ops[0xFE] = ("INC", self.absolute_x_mode)
|
self.ops[0xFE] = (3, "INC", self.absolute_x_mode)
|
||||||
|
|
||||||
def absolute_mode(self, pc):
|
def absolute_mode(self, pc):
|
||||||
a = self.memory.read_word(pc + 1)
|
a = self.cpu.read_word(pc + 1)
|
||||||
return "$%04X [%04X] = %02X" % (a, a, self.memory.read_word(a))
|
return {
|
||||||
|
"operand": "$%04X" % a,
|
||||||
|
"memory": [a, 2, self.cpu.read_word(a)],
|
||||||
|
}
|
||||||
|
|
||||||
def absolute_x_mode(self, pc):
|
def absolute_x_mode(self, pc):
|
||||||
a = self.memory.read_word(pc + 1)
|
a = self.cpu.read_word(pc + 1)
|
||||||
e = a + self.cpu.x_index
|
e = a + self.cpu.x_index
|
||||||
return "$%04X,X [%04X] = %02X" % (a, e, self.memory.read_byte(e))
|
return {
|
||||||
|
"operand": "$%04X,X" % a,
|
||||||
|
"memory": [e, 1, self.cpu.read_byte(e)],
|
||||||
|
}
|
||||||
|
|
||||||
def absolute_y_mode(self, pc):
|
def absolute_y_mode(self, pc):
|
||||||
a = self.memory.read_word(pc + 1)
|
a = self.cpu.read_word(pc + 1)
|
||||||
e = a + self.cpu.y_index
|
e = a + self.cpu.y_index
|
||||||
return "$%04X,Y [%04X] = %02X" % (a, e, self.memory.read_byte(e))
|
return {
|
||||||
|
"operand": "$%04X,Y" % a,
|
||||||
|
"memory": [e, 1, self.cpu.read_byte(e)],
|
||||||
|
}
|
||||||
|
|
||||||
def immediate_mode(self, pc):
|
def immediate_mode(self, pc):
|
||||||
return "#$%02X" % (self.memory.read_byte(pc + 1))
|
return {
|
||||||
|
"operand": "#$%02X" % (self.cpu.read_byte(pc + 1)),
|
||||||
|
}
|
||||||
|
|
||||||
def indirect_mode(self, pc):
|
def indirect_mode(self, pc):
|
||||||
a = self.memory.read_word(pc + 1)
|
a = self.cpu.read_word(pc + 1)
|
||||||
return "($%04X) [%04X] = %02X" % (a, a, self.memory.read_word(a))
|
return {
|
||||||
|
"operand": "($%04X)" % a,
|
||||||
|
"memory": [a, 2, self.cpu.read_word(a)],
|
||||||
|
}
|
||||||
|
|
||||||
def indirect_x_mode(self, pc):
|
def indirect_x_mode(self, pc):
|
||||||
z = self.memory.read_byte(pc + 1)
|
z = self.cpu.read_byte(pc + 1)
|
||||||
a = self.memory.read_word((z + self.cpu.x_index) % 0x100)
|
a = self.cpu.read_word((z + self.cpu.x_index) % 0x100)
|
||||||
return "($%02X,X) [%04X] = %02X" % (z, a, self.memory.read_byte(a))
|
return {
|
||||||
|
"operand": "($%02X,X)" % z,
|
||||||
|
"memory": [a, 1, self.cpu.read_byte(a)],
|
||||||
|
}
|
||||||
|
|
||||||
def indirect_y_mode(self, pc):
|
def indirect_y_mode(self, pc):
|
||||||
z = self.memory.read_byte(pc + 1)
|
z = self.cpu.read_byte(pc + 1)
|
||||||
a = self.memory.read_word(z) + self.cpu.y_index
|
a = self.cpu.read_word(z) + self.cpu.y_index
|
||||||
return "($%02X),Y [%04X] = %02X" % (z, a, self.memory.read_byte(a))
|
return {
|
||||||
|
"operand": "($%02X),Y" % z,
|
||||||
|
"memory": [a, 1, self.cpu.read_byte(a)],
|
||||||
|
}
|
||||||
|
|
||||||
def relative_mode(self, pc):
|
def relative_mode(self, pc):
|
||||||
return "$%04X" % (pc + signed(self.memory.read_byte(pc + 1) + 2))
|
return {
|
||||||
|
"operand": "$%04X" % (pc + signed(self.cpu.read_byte(pc + 1) + 2)),
|
||||||
|
}
|
||||||
|
|
||||||
def zero_page_mode(self, pc):
|
def zero_page_mode(self, pc):
|
||||||
a = self.memory.read_byte(pc + 1)
|
a = self.cpu.read_byte(pc + 1)
|
||||||
return "$%02X [%04X] = %02X" % (a, a, self.memory.read_byte(a))
|
return {
|
||||||
|
"operand": "$%02X" % a,
|
||||||
|
"memory": [a, 1, self.cpu.read_byte(a)],
|
||||||
|
}
|
||||||
|
|
||||||
def zero_page_x_mode(self, pc):
|
def zero_page_x_mode(self, pc):
|
||||||
z = self.memory.read_byte(pc + 1)
|
z = self.cpu.read_byte(pc + 1)
|
||||||
a = (z + self.cpu.x_index) % 0x100
|
a = (z + self.cpu.x_index) % 0x100
|
||||||
return "$%02X,X [%04X] = %02X" % (z, a, self.memory.read_byte(a))
|
return {
|
||||||
|
"operand": "$%02X,X" % z,
|
||||||
|
"memory": [a, 1, self.cpu.read_byte(a)],
|
||||||
|
}
|
||||||
|
|
||||||
def zero_page_y_mode(self, pc):
|
def zero_page_y_mode(self, pc):
|
||||||
z = self.memory.read_byte(pc + 1)
|
z = self.cpu.read_byte(pc + 1)
|
||||||
a = (z + self.cpu.y_index) % 0x100
|
a = (z + self.cpu.y_index) % 0x100
|
||||||
return "$%02X,Y [%04X] = %02X" % (z, a, self.memory.read_byte(a))
|
return {
|
||||||
|
"operand": "$%02X,Y" % z,
|
||||||
|
"memory": [a, 1, self.cpu.read_byte(a)],
|
||||||
|
}
|
||||||
|
|
||||||
def disasm(self, pc):
|
def disasm(self, pc):
|
||||||
op = self.memory.read_byte(pc)
|
op = self.cpu.read_byte(pc)
|
||||||
info = self.ops[op]
|
info = self.ops[op]
|
||||||
s = "%02X %s" % (pc, info[0])
|
r = {
|
||||||
if len(info) > 1:
|
"address": pc,
|
||||||
s += " " + info[1](pc)
|
"bytes": [self.cpu.read_byte(pc + i) for i in range(info[0])],
|
||||||
return s
|
"mnemonic": info[1],
|
||||||
|
}
|
||||||
|
if len(info) > 2:
|
||||||
|
r.update(info[2](pc))
|
||||||
|
return r, info[0]
|
||||||
|
|
||||||
|
|
||||||
|
class ControlHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||||
|
|
||||||
|
def __init__(self, request, client_address, server, cpu):
|
||||||
|
self.cpu = cpu
|
||||||
|
self.disassemble = Disassemble(self.cpu, self.cpu.memory)
|
||||||
|
|
||||||
|
self.get_urls = {
|
||||||
|
r"/disassemble/(\d+)$": self.get_disassemble,
|
||||||
|
r"/memory/(\d+)(-(\d+))?$": self.get_memory,
|
||||||
|
r"/memory/(\d+)(-(\d+))?/raw$": self.get_memory_raw,
|
||||||
|
r"/status$": self.get_status,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.post_urls = {
|
||||||
|
r"/memory/(\d+)(-(\d+))?$": self.post_memory,
|
||||||
|
r"/memory/(\d+)(-(\d+))?/raw$": self.post_memory_raw,
|
||||||
|
r"/quit$": self.post_quit,
|
||||||
|
r"/reset$": self.post_reset,
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseHTTPServer.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():
|
||||||
|
m = re.match(r, self.path)
|
||||||
|
if m is not None:
|
||||||
|
f(m)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.send_response(404)
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
|
def response(self, s):
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Length", str(len(s)))
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(s)
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
self.dispatch(self.get_urls)
|
||||||
|
|
||||||
|
def do_POST(self):
|
||||||
|
self.dispatch(self.post_urls)
|
||||||
|
|
||||||
|
def get_disassemble(self, m):
|
||||||
|
addr = int(m.group(1))
|
||||||
|
r = []
|
||||||
|
n = 20
|
||||||
|
while n > 0:
|
||||||
|
dis, length = self.disassemble.disasm(addr)
|
||||||
|
r.append(dis)
|
||||||
|
addr += length
|
||||||
|
n -= 1
|
||||||
|
self.response(json.dumps(r))
|
||||||
|
|
||||||
|
def get_memory_raw(self, m):
|
||||||
|
addr = int(m.group(1))
|
||||||
|
e = m.group(3)
|
||||||
|
if e is not None:
|
||||||
|
end = int(e)
|
||||||
|
else:
|
||||||
|
end = addr
|
||||||
|
self.response("".join([chr(self.cpu.read_byte(x)) for x in range(addr, end + 1)]))
|
||||||
|
|
||||||
|
def get_memory(self, m):
|
||||||
|
addr = int(m.group(1))
|
||||||
|
e = m.group(3)
|
||||||
|
if e is not None:
|
||||||
|
end = int(e)
|
||||||
|
else:
|
||||||
|
end = addr
|
||||||
|
self.response(json.dumps(list(map(self.cpu.read_byte, range(addr, end + 1)))))
|
||||||
|
|
||||||
|
def get_status(self, m):
|
||||||
|
self.response(json.dumps(dict((x, getattr(self.cpu, x)) for x in (
|
||||||
|
"accumulator",
|
||||||
|
"x_index",
|
||||||
|
"y_index",
|
||||||
|
"stack_pointer",
|
||||||
|
"program_counter",
|
||||||
|
"sign_flag",
|
||||||
|
"overflow_flag",
|
||||||
|
"break_flag",
|
||||||
|
"decimal_mode_flag",
|
||||||
|
"interrupt_disable_flag",
|
||||||
|
"zero_flag",
|
||||||
|
"carry_flag",
|
||||||
|
))))
|
||||||
|
|
||||||
|
def post_memory(self, m):
|
||||||
|
addr = int(m.group(1))
|
||||||
|
e = m.group(3)
|
||||||
|
if e is not None:
|
||||||
|
end = int(e)
|
||||||
|
else:
|
||||||
|
end = addr
|
||||||
|
data = json.loads(self.rfile.read(int(self.headers["Content-Length"])))
|
||||||
|
for i, a in enumerate(range(addr, end + 1)):
|
||||||
|
self.cpu.write_byte(a, data[i])
|
||||||
|
self.response("")
|
||||||
|
|
||||||
|
def post_memory_raw(self, m):
|
||||||
|
addr = int(m.group(1))
|
||||||
|
e = m.group(3)
|
||||||
|
if e is not None:
|
||||||
|
end = int(e)
|
||||||
|
else:
|
||||||
|
end = addr
|
||||||
|
data = self.rfile.read(int(self.headers["Content-Length"]))
|
||||||
|
for i, a in enumerate(range(addr, end + 1)):
|
||||||
|
self.cpu.write_byte(a, data[i])
|
||||||
|
self.response("")
|
||||||
|
|
||||||
|
def post_quit(self, m):
|
||||||
|
self.cpu.quit = True
|
||||||
|
self.response("")
|
||||||
|
|
||||||
|
def post_reset(self, m):
|
||||||
|
self.cpu.reset()
|
||||||
|
self.cpu.running = True
|
||||||
|
self.response("")
|
||||||
|
|
||||||
|
|
||||||
|
class ControlHandlerFactory:
|
||||||
|
|
||||||
|
def __init__(self, cpu):
|
||||||
|
self.cpu = cpu
|
||||||
|
|
||||||
|
def __call__(self, request, client_address, server):
|
||||||
|
return ControlHandler(request, client_address, server, self.cpu)
|
||||||
|
|
||||||
|
|
||||||
class CPU:
|
class CPU:
|
||||||
@ -329,9 +505,10 @@ class CPU:
|
|||||||
STACK_PAGE = 0x100
|
STACK_PAGE = 0x100
|
||||||
RESET_VECTOR = 0xFFFC
|
RESET_VECTOR = 0xFFFC
|
||||||
|
|
||||||
def __init__(self, memory):
|
def __init__(self, options, memory):
|
||||||
self.memory = memory
|
self.memory = memory
|
||||||
self.disassemble = Disassemble(self, memory)
|
|
||||||
|
self.control_server = BaseHTTPServer.HTTPServer(("127.0.0.1", 6502), ControlHandlerFactory(self))
|
||||||
|
|
||||||
self.accumulator = 0x00
|
self.accumulator = 0x00
|
||||||
self.x_index = 0x00
|
self.x_index = 0x00
|
||||||
@ -351,6 +528,10 @@ class CPU:
|
|||||||
|
|
||||||
self.setup_ops()
|
self.setup_ops()
|
||||||
self.reset()
|
self.reset()
|
||||||
|
if options.pc is not None:
|
||||||
|
self.program_counter = options.pc
|
||||||
|
self.running = True
|
||||||
|
self.quit = False
|
||||||
|
|
||||||
def setup_ops(self):
|
def setup_ops(self):
|
||||||
self.ops = [None] * 0x100
|
self.ops = [None] * 0x100
|
||||||
@ -509,18 +690,41 @@ class CPU:
|
|||||||
def reset(self):
|
def reset(self):
|
||||||
self.program_counter = self.read_word(self.RESET_VECTOR)
|
self.program_counter = self.read_word(self.RESET_VECTOR)
|
||||||
|
|
||||||
def run(self):
|
def run(self, bus_port):
|
||||||
while True:
|
global bus
|
||||||
self.cycles += 2 # all instructions take this as a minimum
|
bus = socket.socket()
|
||||||
op = self.read_pc_byte()
|
bus.connect(("127.0.0.1", bus_port))
|
||||||
func = self.ops[op]
|
|
||||||
if func is None:
|
while not self.quit:
|
||||||
print "UNKNOWN OP"
|
|
||||||
print hex(self.program_counter - 1)
|
timeout = 0
|
||||||
print hex(op)
|
if not self.running:
|
||||||
break
|
timeout = 1
|
||||||
else:
|
# Currently this handler blocks from the moment
|
||||||
self.ops[op]()
|
# 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
|
||||||
|
|
||||||
|
count = 1000
|
||||||
|
while count > 0 and self.running:
|
||||||
|
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]()
|
||||||
|
count -= 1
|
||||||
|
|
||||||
def test_run(self, start, end):
|
def test_run(self, start, end):
|
||||||
self.program_counter = start
|
self.program_counter = start
|
||||||
@ -973,6 +1177,8 @@ def usage():
|
|||||||
print >>sys.stderr
|
print >>sys.stderr
|
||||||
print >>sys.stderr, "Usage: cpu6502.py [options]"
|
print >>sys.stderr, "Usage: cpu6502.py [options]"
|
||||||
print >>sys.stderr
|
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, --rom ROM file to use (default A2ROM.BIN)"
|
||||||
print >>sys.stderr, " -r, --ram RAM file to load (default none)"
|
print >>sys.stderr, " -r, --ram RAM file to load (default none)"
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@ -983,12 +1189,20 @@ def get_options():
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.rom = "A2ROM.BIN"
|
self.rom = "A2ROM.BIN"
|
||||||
self.ram = None
|
self.ram = None
|
||||||
|
self.bus = None
|
||||||
|
self.pc = None
|
||||||
|
|
||||||
options = Options()
|
options = Options()
|
||||||
a = 1
|
a = 1
|
||||||
while a < len(sys.argv):
|
while a < len(sys.argv):
|
||||||
if sys.argv[a].startswith("-"):
|
if sys.argv[a].startswith("-"):
|
||||||
if sys.argv[a] in ("-R", "--rom"):
|
if sys.argv[a] in ("-b", "--bus"):
|
||||||
|
a += 1
|
||||||
|
options.bus = int(sys.argv[a])
|
||||||
|
elif sys.argv[a] in ("-p", "--pc"):
|
||||||
|
a += 1
|
||||||
|
options.pc = int(sys.argv[a])
|
||||||
|
elif sys.argv[a] in ("-R", "--rom"):
|
||||||
a += 1
|
a += 1
|
||||||
options.rom = sys.argv[a]
|
options.rom = sys.argv[a]
|
||||||
elif sys.argv[a] in ("-r", "--ram"):
|
elif sys.argv[a] in ("-r", "--ram"):
|
||||||
@ -1004,13 +1218,13 @@ def get_options():
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
if sys.stdout.isatty():
|
options = get_options()
|
||||||
|
if options.bus is None:
|
||||||
print "ApplePy cpu core"
|
print "ApplePy cpu core"
|
||||||
print "Run applepy.py instead"
|
print "Run applepy.py instead"
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
options = get_options()
|
|
||||||
mem = Memory(options)
|
mem = Memory(options)
|
||||||
|
|
||||||
cpu = CPU(mem)
|
cpu = CPU(options, mem)
|
||||||
cpu.run()
|
cpu.run(options.bus)
|
||||||
|
26
tests.py
26
tests.py
@ -5,7 +5,7 @@ from cpu6502 import Memory, CPU
|
|||||||
class TestMemory(unittest.TestCase):
|
class TestMemory(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.memory = Memory(use_stdio=False)
|
self.memory = Memory(use_bus=False)
|
||||||
|
|
||||||
def test_load(self):
|
def test_load(self):
|
||||||
self.memory.load(0x1000, [0x01, 0x02, 0x03])
|
self.memory.load(0x1000, [0x01, 0x02, 0x03])
|
||||||
@ -25,7 +25,7 @@ class TestMemory(unittest.TestCase):
|
|||||||
class TestLoadStoreOperations(unittest.TestCase):
|
class TestLoadStoreOperations(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.memory = Memory(use_stdio=False)
|
self.memory = Memory(use_bus=False)
|
||||||
self.cpu = CPU(self.memory)
|
self.cpu = CPU(self.memory)
|
||||||
self.memory.load(0x1000, [0x00, 0x01, 0x7F, 0x80, 0xFF])
|
self.memory.load(0x1000, [0x00, 0x01, 0x7F, 0x80, 0xFF])
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ class TestLoadStoreOperations(unittest.TestCase):
|
|||||||
class TestRegisterTransferOperations(unittest.TestCase):
|
class TestRegisterTransferOperations(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.memory = Memory(use_stdio=False)
|
self.memory = Memory(use_bus=False)
|
||||||
self.cpu = CPU(self.memory)
|
self.cpu = CPU(self.memory)
|
||||||
|
|
||||||
def test_TAX(self):
|
def test_TAX(self):
|
||||||
@ -189,7 +189,7 @@ class TestRegisterTransferOperations(unittest.TestCase):
|
|||||||
class TestStackOperations(unittest.TestCase):
|
class TestStackOperations(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.memory = Memory(use_stdio=False)
|
self.memory = Memory(use_bus=False)
|
||||||
self.cpu = CPU(self.memory)
|
self.cpu = CPU(self.memory)
|
||||||
|
|
||||||
def test_TSX(self):
|
def test_TSX(self):
|
||||||
@ -237,7 +237,7 @@ class TestStackOperations(unittest.TestCase):
|
|||||||
class TestLogicalOperations(unittest.TestCase):
|
class TestLogicalOperations(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.memory = Memory(use_stdio=False)
|
self.memory = Memory(use_bus=False)
|
||||||
self.cpu = CPU(self.memory)
|
self.cpu = CPU(self.memory)
|
||||||
|
|
||||||
def test_AND(self):
|
def test_AND(self):
|
||||||
@ -325,7 +325,7 @@ class TestLogicalOperations(unittest.TestCase):
|
|||||||
class TestArithmeticOperations(unittest.TestCase):
|
class TestArithmeticOperations(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.memory = Memory(use_stdio=False)
|
self.memory = Memory(use_bus=False)
|
||||||
self.cpu = CPU(self.memory)
|
self.cpu = CPU(self.memory)
|
||||||
|
|
||||||
def test_ADC_without_BCD(self):
|
def test_ADC_without_BCD(self):
|
||||||
@ -544,7 +544,7 @@ class TestArithmeticOperations(unittest.TestCase):
|
|||||||
class TestIncrementDecrementOperations(unittest.TestCase):
|
class TestIncrementDecrementOperations(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.memory = Memory(use_stdio=False)
|
self.memory = Memory(use_bus=False)
|
||||||
self.cpu = CPU(self.memory)
|
self.cpu = CPU(self.memory)
|
||||||
|
|
||||||
def test_INC(self):
|
def test_INC(self):
|
||||||
@ -653,7 +653,7 @@ class TestIncrementDecrementOperations(unittest.TestCase):
|
|||||||
class TestShiftOperations(unittest.TestCase):
|
class TestShiftOperations(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.memory = Memory(use_stdio=False)
|
self.memory = Memory(use_bus=False)
|
||||||
self.cpu = CPU(self.memory)
|
self.cpu = CPU(self.memory)
|
||||||
|
|
||||||
def test_ASL(self):
|
def test_ASL(self):
|
||||||
@ -760,7 +760,7 @@ class TestShiftOperations(unittest.TestCase):
|
|||||||
class TestJumpCallOperations(unittest.TestCase):
|
class TestJumpCallOperations(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.memory = Memory(use_stdio=False)
|
self.memory = Memory(use_bus=False)
|
||||||
self.cpu = CPU(self.memory)
|
self.cpu = CPU(self.memory)
|
||||||
|
|
||||||
def test_JMP(self):
|
def test_JMP(self):
|
||||||
@ -792,7 +792,7 @@ class TestJumpCallOperations(unittest.TestCase):
|
|||||||
class TestBranchOperations(unittest.TestCase):
|
class TestBranchOperations(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.memory = Memory(use_stdio=False)
|
self.memory = Memory(use_bus=False)
|
||||||
self.cpu = CPU(self.memory)
|
self.cpu = CPU(self.memory)
|
||||||
|
|
||||||
def test_BCC(self):
|
def test_BCC(self):
|
||||||
@ -879,7 +879,7 @@ class TestBranchOperations(unittest.TestCase):
|
|||||||
class TestStatusFlagOperations(unittest.TestCase):
|
class TestStatusFlagOperations(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.memory = Memory(use_stdio=False)
|
self.memory = Memory(use_bus=False)
|
||||||
self.cpu = CPU(self.memory)
|
self.cpu = CPU(self.memory)
|
||||||
|
|
||||||
def test_CLC(self):
|
def test_CLC(self):
|
||||||
@ -921,7 +921,7 @@ class TestStatusFlagOperations(unittest.TestCase):
|
|||||||
class TestSystemFunctionOperations(unittest.TestCase):
|
class TestSystemFunctionOperations(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.memory = Memory(use_stdio=False)
|
self.memory = Memory(use_bus=False)
|
||||||
self.cpu = CPU(self.memory)
|
self.cpu = CPU(self.memory)
|
||||||
|
|
||||||
def test_BRK(self):
|
def test_BRK(self):
|
||||||
@ -951,7 +951,7 @@ class TestSystemFunctionOperations(unittest.TestCase):
|
|||||||
class Test6502Bugs(unittest.TestCase):
|
class Test6502Bugs(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.memory = Memory(use_stdio=False)
|
self.memory = Memory(use_bus=False)
|
||||||
self.cpu = CPU(self.memory)
|
self.cpu = CPU(self.memory)
|
||||||
|
|
||||||
def test_zero_page_x(self):
|
def test_zero_page_x(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user