Compare commits
39 Commits
Author | SHA1 | Date |
---|---|---|
James Tauber | 934bf1a495 | |
James Tauber | d340d9cb5f | |
James Tauber | fe80bc897d | |
James Tauber | 0d41f951b9 | |
James Tauber | e9c9581857 | |
James Tauber | 6a818ae8ac | |
James Tauber | 1de396334e | |
James Tauber | 82de64b000 | |
James Tauber | 2492947e1d | |
James Tauber | bdbc60e6e5 | |
Greg Hewgill | 9ff2dbb70e | |
Greg Hewgill | 4ee9b846f9 | |
James Tauber | c9ecb5f31e | |
Greg Hewgill | 60acf37150 | |
Greg Hewgill | 6782a1d268 | |
Greg Hewgill | 80e95d114b | |
James Tauber | fad0de8cc9 | |
James Tauber | aac75ef1cb | |
Greg Hewgill | 0604bd1515 | |
Greg Hewgill | 0b86a8693f | |
Greg Hewgill | 29b1342a47 | |
Greg Hewgill | aee0bba7aa | |
Greg Hewgill | 8b62860152 | |
Greg Hewgill | 19693bc905 | |
Greg Hewgill | a673f8a4d4 | |
Greg Hewgill | 9f09818aa0 | |
Greg Hewgill | 15e174c02a | |
Greg Hewgill | 9ffbf63716 | |
Greg Hewgill | dcc8e9d8ce | |
Greg Hewgill | cd692af6f3 | |
James Tauber | c36ad8b662 | |
Greg Hewgill | a73ab29be2 | |
Greg Hewgill | 338f8962fd | |
James Tauber | 6f1005693c | |
Greg Hewgill | b8c7949d8e | |
Greg Hewgill | 6951db69ad | |
Greg Hewgill | 4963eeca9d | |
James Tauber | 360f415fc9 | |
Greg Hewgill | c9c609be1d |
|
@ -0,0 +1 @@
|
|||
*.pyc
|
|
@ -0,0 +1,19 @@
|
|||
# Copyright (c) 2001-2013 James Tauber and contributors
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
|
@ -31,4 +31,18 @@ runs all the programs I've tried so far.
|
|||
The only I/O supported is the keyboard and screen but 40-column text, LORES
|
||||
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) and numpy (just for an array for
|
||||
speaker sounds)
|
||||
|
||||
Here's how I set up the dependencies (on Mac OS X 10.8):
|
||||
|
||||
pip install numpy
|
||||
brew install sdl sdl_image sdl_mixer sdl_ttf portmidi hg
|
||||
pip install hg+http://bitbucket.org/pygame/pygame
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
This code is made available under an MIT License. See LICENSE.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,133 @@
|
|||
# ApplePy - an Apple ][ emulator in Python
|
||||
# James Tauber / http://jtauber.com/
|
||||
# originally written 2001, updated 2011
|
||||
|
||||
|
||||
import curses
|
||||
import socket
|
||||
import struct
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
kbd = 0
|
||||
|
||||
|
||||
def write_screen(win, address, value):
|
||||
base = address - 0x400
|
||||
hi, lo = divmod(base, 0x80)
|
||||
row_group, column = divmod(lo, 0x28)
|
||||
row = hi + 8 * row_group
|
||||
|
||||
# skip if writing to row group 3
|
||||
if row_group == 3:
|
||||
return
|
||||
|
||||
c = chr(0x20 + ((value + 0x20) % 0x40))
|
||||
|
||||
if value < 0x40:
|
||||
attr = curses.A_DIM
|
||||
elif value < 0x80:
|
||||
attr = curses.A_REVERSE
|
||||
elif value < 0xA0:
|
||||
attr = curses.A_UNDERLINE
|
||||
else:
|
||||
attr = curses.A_DIM
|
||||
|
||||
try:
|
||||
win.addch(row, column, c, attr)
|
||||
except curses.error:
|
||||
pass
|
||||
|
||||
|
||||
def read(addr, val):
|
||||
global kbd
|
||||
if addr == 0xC000:
|
||||
return kbd
|
||||
elif addr == 0xC010:
|
||||
kbd = kbd & 0x7F
|
||||
return 0x00
|
||||
|
||||
|
||||
def write(win, addr, val):
|
||||
if 0x400 <= addr <= 0x800:
|
||||
write_screen(win, addr, val)
|
||||
|
||||
|
||||
def run(win):
|
||||
global kbd
|
||||
|
||||
listener = socket.socket()
|
||||
listener.bind(("127.0.0.1", 0))
|
||||
listener.listen(0)
|
||||
|
||||
args = [
|
||||
sys.executable,
|
||||
"cpu6502.py",
|
||||
"--bus", str(listener.getsockname()[1]),
|
||||
"--rom", options.rom,
|
||||
]
|
||||
|
||||
subprocess.Popen(args)
|
||||
cpu, _ = listener.accept()
|
||||
|
||||
win.clear()
|
||||
curses.noecho()
|
||||
win.nodelay(True)
|
||||
while True:
|
||||
op = cpu.recv(8)
|
||||
cycle, rw, addr, val = struct.unpack("<IBHB", op)
|
||||
if rw == 0:
|
||||
cpu.send(chr(read(addr, val)))
|
||||
elif rw == 1:
|
||||
write(win, addr, val)
|
||||
else:
|
||||
break
|
||||
try:
|
||||
key = ord(win.getkey())
|
||||
if key == 0xA:
|
||||
key = 0xD
|
||||
elif key == 0x7F:
|
||||
key = 0x8
|
||||
# win.addstr(15, 50, hex(key))
|
||||
kbd = 0x80 | key
|
||||
except curses.error:
|
||||
pass
|
||||
except TypeError:
|
||||
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__":
|
||||
options = get_options()
|
||||
curses.wrapper(run)
|
|
@ -0,0 +1,169 @@
|
|||
import json
|
||||
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()
|
File diff suppressed because it is too large
Load Diff
380
tests.py
380
tests.py
|
@ -1,34 +1,34 @@
|
|||
import unittest
|
||||
from applepy import Memory, CPU
|
||||
from cpu6502 import Memory, CPU
|
||||
|
||||
|
||||
class TestMemory(unittest.TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.memory = Memory()
|
||||
|
||||
self.memory = Memory(use_bus=False)
|
||||
|
||||
def test_load(self):
|
||||
self.memory.load(0x1000, [0x01, 0x02, 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.memory.write_byte(None, 0x1000, 0x11)
|
||||
self.memory.write_byte(None, 0x1001, 0x12)
|
||||
self.memory.write_byte(None, 0x1002, 0x13)
|
||||
self.assertEqual(self.memory.read_byte(None, 0x1000), 0x11)
|
||||
self.assertEqual(self.memory.read_byte(None, 0x1001), 0x12)
|
||||
self.assertEqual(self.memory.read_byte(None, 0x1002), 0x13)
|
||||
|
||||
|
||||
class TestLoadStoreOperations(unittest.TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.memory = Memory()
|
||||
self.memory = Memory(use_bus=False)
|
||||
self.cpu = CPU(self.memory)
|
||||
self.memory.load(0x1000, [0x00, 0x01, 0x7F, 0x80, 0xFF])
|
||||
|
||||
|
||||
def test_LDA(self):
|
||||
self.cpu.LDA(0x1000)
|
||||
self.assertEqual(self.cpu.accumulator, 0x00)
|
||||
|
@ -50,7 +50,7 @@ class TestLoadStoreOperations(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.accumulator, 0xFF)
|
||||
self.assertEqual(self.cpu.sign_flag, 1)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
|
||||
|
||||
def test_LDX(self):
|
||||
self.cpu.LDX(0x1000)
|
||||
self.assertEqual(self.cpu.x_index, 0x00)
|
||||
|
@ -72,7 +72,7 @@ class TestLoadStoreOperations(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.x_index, 0xFF)
|
||||
self.assertEqual(self.cpu.sign_flag, 1)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
|
||||
|
||||
def test_LDY(self):
|
||||
self.cpu.LDY(0x1000)
|
||||
self.assertEqual(self.cpu.y_index, 0x00)
|
||||
|
@ -94,17 +94,17 @@ class TestLoadStoreOperations(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.y_index, 0xFF)
|
||||
self.assertEqual(self.cpu.sign_flag, 1)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
|
||||
|
||||
def test_STA(self):
|
||||
self.cpu.accumulator = 0x37
|
||||
self.cpu.STA(0x2000)
|
||||
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(None, 0x2000), 0x38)
|
||||
|
||||
|
||||
def test_STY(self):
|
||||
self.cpu.y_index = 0x39
|
||||
self.cpu.STY(0x2000)
|
||||
|
@ -112,11 +112,11 @@ class TestLoadStoreOperations(unittest.TestCase):
|
|||
|
||||
|
||||
class TestRegisterTransferOperations(unittest.TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.memory = Memory()
|
||||
self.memory = Memory(use_bus=False)
|
||||
self.cpu = CPU(self.memory)
|
||||
|
||||
|
||||
def test_TAX(self):
|
||||
self.cpu.accumulator = 0x00
|
||||
self.cpu.TAX()
|
||||
|
@ -133,7 +133,7 @@ class TestRegisterTransferOperations(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.x_index, 0xFF)
|
||||
self.assertEqual(self.cpu.sign_flag, 1)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
|
||||
|
||||
def test_TAY(self):
|
||||
self.cpu.accumulator = 0x00
|
||||
self.cpu.TAY()
|
||||
|
@ -150,7 +150,7 @@ class TestRegisterTransferOperations(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.y_index, 0xFF)
|
||||
self.assertEqual(self.cpu.sign_flag, 1)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
|
||||
|
||||
def test_TXA(self):
|
||||
self.cpu.x_index = 0x00
|
||||
self.cpu.TXA()
|
||||
|
@ -167,7 +167,7 @@ class TestRegisterTransferOperations(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.accumulator, 0xFF)
|
||||
self.assertEqual(self.cpu.sign_flag, 1)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
|
||||
|
||||
def test_TYA(self):
|
||||
self.cpu.y_index = 0x00
|
||||
self.cpu.TYA()
|
||||
|
@ -187,22 +187,22 @@ class TestRegisterTransferOperations(unittest.TestCase):
|
|||
|
||||
|
||||
class TestStackOperations(unittest.TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.memory = Memory()
|
||||
self.memory = Memory(use_bus=False)
|
||||
self.cpu = CPU(self.memory)
|
||||
|
||||
|
||||
def test_TSX(self):
|
||||
s = self.cpu.stack_pointer
|
||||
self.cpu.TSX()
|
||||
self.assertEqual(self.cpu.x_index, s)
|
||||
# @@@ check NZ?
|
||||
|
||||
|
||||
def test_TXS(self):
|
||||
x = self.cpu.x_index
|
||||
self.cpu.TXS()
|
||||
self.assertEqual(self.cpu.stack_pointer, x)
|
||||
|
||||
|
||||
def test_PHA_and_PLA(self):
|
||||
self.cpu.accumulator = 0x00
|
||||
self.cpu.PHA()
|
||||
|
@ -225,7 +225,7 @@ class TestStackOperations(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.accumulator, 0x00)
|
||||
self.assertEqual(self.cpu.zero_flag, 1)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
|
||||
|
||||
def test_PHP_and_PLP(self):
|
||||
p = self.cpu.status_as_byte()
|
||||
self.cpu.PHP()
|
||||
|
@ -235,13 +235,13 @@ class TestStackOperations(unittest.TestCase):
|
|||
|
||||
|
||||
class TestLogicalOperations(unittest.TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.memory = Memory()
|
||||
self.memory = Memory(use_bus=False)
|
||||
self.cpu = CPU(self.memory)
|
||||
|
||||
|
||||
def test_AND(self):
|
||||
self.memory.write_byte(0x1000, 0x37)
|
||||
self.memory.write_byte(None, 0x1000, 0x37)
|
||||
self.cpu.accumulator = 0x34
|
||||
self.cpu.AND(0x1000)
|
||||
self.assertEqual(self.cpu.accumulator, 0x34)
|
||||
|
@ -252,9 +252,9 @@ class TestLogicalOperations(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.accumulator, 0x00)
|
||||
self.assertEqual(self.cpu.zero_flag, 1)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
|
||||
|
||||
def test_EOR(self):
|
||||
self.memory.write_byte(0x1000, 0x37)
|
||||
self.memory.write_byte(None, 0x1000, 0x37)
|
||||
self.cpu.accumulator = 0x34
|
||||
self.cpu.EOR(0x1000)
|
||||
self.assertEqual(self.cpu.accumulator, 0x03)
|
||||
|
@ -270,9 +270,9 @@ class TestLogicalOperations(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.accumulator, 0x00)
|
||||
self.assertEqual(self.cpu.zero_flag, 1)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
|
||||
|
||||
def test_ORA(self):
|
||||
self.memory.write_byte(0x1000, 0x37)
|
||||
self.memory.write_byte(None, 0x1000, 0x37)
|
||||
self.cpu.accumulator = 0x34
|
||||
self.cpu.ORA(0x1000)
|
||||
self.assertEqual(self.cpu.accumulator, 0x37)
|
||||
|
@ -288,33 +288,33 @@ class TestLogicalOperations(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.accumulator, 0x00)
|
||||
self.assertEqual(self.cpu.zero_flag, 1)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
|
||||
|
||||
def test_BIT(self):
|
||||
self.memory.write_byte(0x1000, 0x00)
|
||||
self.memory.write_byte(None, 0x1000, 0x00)
|
||||
self.cpu.accumulator = 0x00
|
||||
self.cpu.BIT(0x1000)
|
||||
self.assertEqual(self.cpu.overflow_flag, 0)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 1)
|
||||
self.memory.write_byte(0x1000, 0x40)
|
||||
self.memory.write_byte(None, 0x1000, 0x40)
|
||||
self.cpu.accumulator = 0x00
|
||||
self.cpu.BIT(0x1000)
|
||||
self.assertEqual(self.cpu.overflow_flag, 1)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 1)
|
||||
self.memory.write_byte(0x1000, 0x80)
|
||||
self.memory.write_byte(None, 0x1000, 0x80)
|
||||
self.cpu.accumulator = 0x00
|
||||
self.cpu.BIT(0x1000)
|
||||
self.assertEqual(self.cpu.overflow_flag, 0)
|
||||
self.assertEqual(self.cpu.sign_flag, 1)
|
||||
self.assertEqual(self.cpu.zero_flag, 1)
|
||||
self.memory.write_byte(0x1000, 0xC0)
|
||||
self.memory.write_byte(None, 0x1000, 0xC0)
|
||||
self.cpu.accumulator = 0x00
|
||||
self.cpu.BIT(0x1000)
|
||||
self.assertEqual(self.cpu.overflow_flag, 1)
|
||||
self.assertEqual(self.cpu.sign_flag, 1)
|
||||
self.assertEqual(self.cpu.zero_flag, 1)
|
||||
self.memory.write_byte(0x1000, 0xC0)
|
||||
self.memory.write_byte(None, 0x1000, 0xC0)
|
||||
self.cpu.accumulator = 0xC0
|
||||
self.cpu.BIT(0x1000)
|
||||
self.assertEqual(self.cpu.overflow_flag, 1)
|
||||
|
@ -323,247 +323,247 @@ class TestLogicalOperations(unittest.TestCase):
|
|||
|
||||
|
||||
class TestArithmeticOperations(unittest.TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.memory = Memory()
|
||||
self.memory = Memory(use_bus=False)
|
||||
self.cpu = CPU(self.memory)
|
||||
|
||||
|
||||
def test_ADC_without_BCD(self):
|
||||
|
||||
|
||||
## test cases from http://www.6502.org/tutorials/vflag.html
|
||||
|
||||
|
||||
# 1 + 1 = 2 (C = 0; V = 0)
|
||||
self.cpu.carry_flag = 0
|
||||
self.cpu.accumulator = 0x01
|
||||
self.memory.write_byte(0x1000, 0x01)
|
||||
self.memory.write_byte(None, 0x1000, 0x01)
|
||||
self.cpu.ADC(0x1000)
|
||||
self.assertEqual(self.cpu.accumulator, 0x02)
|
||||
self.assertEqual(self.cpu.carry_flag, 0)
|
||||
self.assertEqual(self.cpu.overflow_flag, 0)
|
||||
|
||||
|
||||
# 1 + -1 = 0 (C = 1; V = 0)
|
||||
self.cpu.carry_flag = 0
|
||||
self.cpu.accumulator = 0x01
|
||||
self.memory.write_byte(0x1000, 0xFF)
|
||||
self.memory.write_byte(None, 0x1000, 0xFF)
|
||||
self.cpu.ADC(0x1000)
|
||||
self.assertEqual(self.cpu.accumulator, 0x00)
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
self.assertEqual(self.cpu.overflow_flag, 0)
|
||||
|
||||
|
||||
# 127 + 1 = 128 (C = 0; V = 1)
|
||||
self.cpu.carry_flag = 0
|
||||
self.cpu.accumulator = 0x7F
|
||||
self.memory.write_byte(0x1000, 0x01)
|
||||
self.memory.write_byte(None, 0x1000, 0x01)
|
||||
self.cpu.ADC(0x1000)
|
||||
self.assertEqual(self.cpu.accumulator, 0x80) # @@@
|
||||
self.assertEqual(self.cpu.accumulator, 0x80) # @@@
|
||||
self.assertEqual(self.cpu.carry_flag, 0)
|
||||
self.assertEqual(self.cpu.overflow_flag, 1)
|
||||
|
||||
|
||||
# -128 + -1 = -129 (C = 1; V = 1)
|
||||
self.cpu.carry_flag = 0
|
||||
self.cpu.accumulator = 0x80
|
||||
self.memory.write_byte(0x1000, 0xFF)
|
||||
self.memory.write_byte(None, 0x1000, 0xFF)
|
||||
self.cpu.ADC(0x1000)
|
||||
self.assertEqual(self.cpu.accumulator, 0x7F) # @@@
|
||||
self.assertEqual(self.cpu.accumulator, 0x7F) # @@@
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
self.assertEqual(self.cpu.overflow_flag, 1)
|
||||
|
||||
|
||||
# 63 + 64 + 1 = 128 (C = 0; V = 1)
|
||||
self.cpu.carry_flag = 1
|
||||
self.cpu.accumulator = 0x3F
|
||||
self.memory.write_byte(0x1000, 0x40)
|
||||
self.memory.write_byte(None, 0x1000, 0x40)
|
||||
self.cpu.ADC(0x1000)
|
||||
self.assertEqual(self.cpu.accumulator, 0x80)
|
||||
self.assertEqual(self.cpu.carry_flag, 0)
|
||||
self.assertEqual(self.cpu.overflow_flag, 1)
|
||||
|
||||
|
||||
def test_SBC_without_BCD(self):
|
||||
self.cpu.accumulator = 0x02
|
||||
self.memory.write_byte(0x1000, 0x01)
|
||||
self.memory.write_byte(None, 0x1000, 0x01)
|
||||
self.cpu.SBC(0x1000)
|
||||
self.assertEqual(self.cpu.accumulator, 0x00)
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
self.assertEqual(self.cpu.overflow_flag, 0)
|
||||
|
||||
|
||||
self.cpu.accumulator = 0x01
|
||||
self.memory.write_byte(0x1000, 0x02)
|
||||
self.memory.write_byte(None, 0x1000, 0x02)
|
||||
self.cpu.SBC(0x1000)
|
||||
self.assertEqual(self.cpu.accumulator, 0xFF)
|
||||
self.assertEqual(self.cpu.carry_flag, 0)
|
||||
self.assertEqual(self.cpu.overflow_flag, 0) # @@@
|
||||
|
||||
self.assertEqual(self.cpu.overflow_flag, 0) # @@@
|
||||
|
||||
## test cases from http://www.6502.org/tutorials/vflag.html
|
||||
|
||||
|
||||
# 0 - 1 = -1 (V = 0)
|
||||
self.cpu.carry_flag = 1
|
||||
self.cpu.accumulator = 0x00
|
||||
self.memory.write_byte(0x1000, 0x01)
|
||||
self.memory.write_byte(None, 0x1000, 0x01)
|
||||
self.cpu.SBC(0x1000)
|
||||
self.assertEqual(self.cpu.accumulator, 0xFF)
|
||||
self.assertEqual(self.cpu.carry_flag, 0)
|
||||
self.assertEqual(self.cpu.overflow_flag, 0) # @@@
|
||||
|
||||
self.assertEqual(self.cpu.overflow_flag, 0) # @@@
|
||||
|
||||
# -128 - 1 = -129 (V = 1)
|
||||
self.cpu.carry_flag = 1
|
||||
self.cpu.accumulator = 0x80
|
||||
self.memory.write_byte(0x1000, 0x01)
|
||||
self.memory.write_byte(None, 0x1000, 0x01)
|
||||
self.cpu.SBC(0x1000)
|
||||
self.assertEqual(self.cpu.accumulator, 0x7F)
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
self.assertEqual(self.cpu.overflow_flag, 1)
|
||||
|
||||
|
||||
# 127 - -1 = 128 (V = 1)
|
||||
self.cpu.carry_flag = 1
|
||||
self.cpu.accumulator = 0x7F
|
||||
self.memory.write_byte(0x1000, 0xFF)
|
||||
self.memory.write_byte(None, 0x1000, 0xFF)
|
||||
self.cpu.SBC(0x1000)
|
||||
self.assertEqual(self.cpu.accumulator, 0x80)
|
||||
self.assertEqual(self.cpu.carry_flag, 0)
|
||||
self.assertEqual(self.cpu.overflow_flag, 1)
|
||||
|
||||
|
||||
# -64 -64 -1 = -129 (V = 1)
|
||||
self.cpu.carry_flag = 0
|
||||
self.cpu.accumulator = 0xC0
|
||||
self.memory.write_byte(0x1000, 0x40)
|
||||
self.memory.write_byte(None, 0x1000, 0x40)
|
||||
self.cpu.SBC(0x1000)
|
||||
self.assertEqual(self.cpu.accumulator, 0x7F)
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
self.assertEqual(self.cpu.overflow_flag, 1) # @@@
|
||||
|
||||
self.assertEqual(self.cpu.overflow_flag, 1) # @@@
|
||||
|
||||
## @@@ BCD versions still to do
|
||||
|
||||
|
||||
def test_CMP(self):
|
||||
self.cpu.accumulator = 0x0A
|
||||
self.memory.write_byte(0x1000, 0x09)
|
||||
self.memory.write_byte(None, 0x1000, 0x09)
|
||||
self.cpu.CMP(0x1000)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
|
||||
|
||||
self.cpu.accumulator = 0x0A
|
||||
self.memory.write_byte(0x1000, 0x0B)
|
||||
self.memory.write_byte(None, 0x1000, 0x0B)
|
||||
self.cpu.CMP(0x1000)
|
||||
self.assertEqual(self.cpu.sign_flag, 1)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
self.assertEqual(self.cpu.carry_flag, 0)
|
||||
|
||||
|
||||
self.cpu.accumulator = 0x0A
|
||||
self.memory.write_byte(0x1000, 0x0A)
|
||||
self.memory.write_byte(None, 0x1000, 0x0A)
|
||||
self.cpu.CMP(0x1000)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 1)
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
|
||||
|
||||
self.cpu.accumulator = 0xA0
|
||||
self.memory.write_byte(0x1000, 0x0A)
|
||||
self.memory.write_byte(None, 0x1000, 0x0A)
|
||||
self.cpu.CMP(0x1000)
|
||||
self.assertEqual(self.cpu.sign_flag, 1)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
|
||||
|
||||
self.cpu.accumulator = 0x0A
|
||||
self.memory.write_byte(0x1000, 0xA0)
|
||||
self.memory.write_byte(None, 0x1000, 0xA0)
|
||||
self.cpu.CMP(0x1000)
|
||||
self.assertEqual(self.cpu.sign_flag, 0) # @@@
|
||||
self.assertEqual(self.cpu.sign_flag, 0) # @@@
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
self.assertEqual(self.cpu.carry_flag, 0)
|
||||
|
||||
|
||||
def test_CPX(self):
|
||||
self.cpu.x_index = 0x0A
|
||||
self.memory.write_byte(0x1000, 0x09)
|
||||
self.memory.write_byte(None, 0x1000, 0x09)
|
||||
self.cpu.CPX(0x1000)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
|
||||
|
||||
self.cpu.x_index = 0x0A
|
||||
self.memory.write_byte(0x1000, 0x0B)
|
||||
self.memory.write_byte(None, 0x1000, 0x0B)
|
||||
self.cpu.CPX(0x1000)
|
||||
self.assertEqual(self.cpu.sign_flag, 1)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
self.assertEqual(self.cpu.carry_flag, 0)
|
||||
|
||||
|
||||
self.cpu.x_index = 0x0A
|
||||
self.memory.write_byte(0x1000, 0x0A)
|
||||
self.memory.write_byte(None, 0x1000, 0x0A)
|
||||
self.cpu.CPX(0x1000)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 1)
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
|
||||
|
||||
self.cpu.x_index = 0xA0
|
||||
self.memory.write_byte(0x1000, 0x0A)
|
||||
self.memory.write_byte(None, 0x1000, 0x0A)
|
||||
self.cpu.CPX(0x1000)
|
||||
self.assertEqual(self.cpu.sign_flag, 1)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
|
||||
|
||||
self.cpu.x_index = 0x0A
|
||||
self.memory.write_byte(0x1000, 0xA0)
|
||||
self.memory.write_byte(None, 0x1000, 0xA0)
|
||||
self.cpu.CPX(0x1000)
|
||||
self.assertEqual(self.cpu.sign_flag, 0) # @@@
|
||||
self.assertEqual(self.cpu.sign_flag, 0) # @@@
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
self.assertEqual(self.cpu.carry_flag, 0)
|
||||
|
||||
|
||||
def test_CPY(self):
|
||||
self.cpu.y_index = 0x0A
|
||||
self.memory.write_byte(0x1000, 0x09)
|
||||
self.memory.write_byte(None, 0x1000, 0x09)
|
||||
self.cpu.CPY(0x1000)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
|
||||
|
||||
self.cpu.y_index = 0x0A
|
||||
self.memory.write_byte(0x1000, 0x0B)
|
||||
self.memory.write_byte(None, 0x1000, 0x0B)
|
||||
self.cpu.CPY(0x1000)
|
||||
self.assertEqual(self.cpu.sign_flag, 1)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
self.assertEqual(self.cpu.carry_flag, 0)
|
||||
|
||||
|
||||
self.cpu.y_index = 0x0A
|
||||
self.memory.write_byte(0x1000, 0x0A)
|
||||
self.memory.write_byte(None, 0x1000, 0x0A)
|
||||
self.cpu.CPY(0x1000)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 1)
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
|
||||
|
||||
self.cpu.y_index = 0xA0
|
||||
self.memory.write_byte(0x1000, 0x0A)
|
||||
self.memory.write_byte(None, 0x1000, 0x0A)
|
||||
self.cpu.CPY(0x1000)
|
||||
self.assertEqual(self.cpu.sign_flag, 1)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
|
||||
|
||||
self.cpu.y_index = 0x0A
|
||||
self.memory.write_byte(0x1000, 0xA0)
|
||||
self.memory.write_byte(None, 0x1000, 0xA0)
|
||||
self.cpu.CPY(0x1000)
|
||||
self.assertEqual(self.cpu.sign_flag, 0) # @@@
|
||||
self.assertEqual(self.cpu.sign_flag, 0) # @@@
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
self.assertEqual(self.cpu.carry_flag, 0)
|
||||
|
||||
|
||||
class TestIncrementDecrementOperations(unittest.TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.memory = Memory()
|
||||
self.memory = Memory(use_bus=False)
|
||||
self.cpu = CPU(self.memory)
|
||||
|
||||
|
||||
def test_INC(self):
|
||||
self.memory.write_byte(0x1000, 0x00)
|
||||
self.memory.write_byte(None, 0x1000, 0x00)
|
||||
self.cpu.INC(0x1000)
|
||||
self.assertEqual(self.memory.read_byte(None, 0x1000), 0x01)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
self.memory.write_byte(0x1000, 0x7F)
|
||||
self.memory.write_byte(None, 0x1000, 0x7F)
|
||||
self.cpu.INC(0x1000)
|
||||
self.assertEqual(self.memory.read_byte(None, 0x1000), 0x80)
|
||||
self.assertEqual(self.cpu.sign_flag, 1)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
self.memory.write_byte(0x1000, 0xFF)
|
||||
self.memory.write_byte(None, 0x1000, 0xFF)
|
||||
self.cpu.INC(0x1000)
|
||||
self.assertEqual(self.memory.read_byte(None, 0x1000), 0x00)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 1)
|
||||
|
||||
|
||||
def test_INX(self):
|
||||
self.cpu.x_index = 0x00
|
||||
self.cpu.INX()
|
||||
|
@ -580,7 +580,7 @@ class TestIncrementDecrementOperations(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.x_index, 0x00)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 1)
|
||||
|
||||
|
||||
def test_INY(self):
|
||||
self.cpu.y_index = 0x00
|
||||
self.cpu.INY()
|
||||
|
@ -597,24 +597,24 @@ class TestIncrementDecrementOperations(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.y_index, 0x00)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 1)
|
||||
|
||||
|
||||
def test_DEC(self):
|
||||
self.memory.write_byte(0x1000, 0x01)
|
||||
self.memory.write_byte(None, 0x1000, 0x01)
|
||||
self.cpu.DEC(0x1000)
|
||||
self.assertEqual(self.memory.read_byte(None, 0x1000), 0x00)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 1)
|
||||
self.memory.write_byte(0x1000, 0x80)
|
||||
self.memory.write_byte(None, 0x1000, 0x80)
|
||||
self.cpu.DEC(0x1000)
|
||||
self.assertEqual(self.memory.read_byte(None, 0x1000), 0x7F)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
self.memory.write_byte(0x1000, 0x00)
|
||||
self.memory.write_byte(None, 0x1000, 0x00)
|
||||
self.cpu.DEC(0x1000)
|
||||
self.assertEqual(self.memory.read_byte(None, 0x1000), 0xFF)
|
||||
self.assertEqual(self.cpu.sign_flag, 1)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
|
||||
|
||||
def test_DEX(self):
|
||||
self.cpu.x_index = 0x01
|
||||
self.cpu.DEX()
|
||||
|
@ -631,7 +631,7 @@ class TestIncrementDecrementOperations(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.x_index, 0xFF)
|
||||
self.assertEqual(self.cpu.sign_flag, 1)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
|
||||
|
||||
def test_DEY(self):
|
||||
self.cpu.y_index = 0x01
|
||||
self.cpu.DEY()
|
||||
|
@ -651,11 +651,11 @@ class TestIncrementDecrementOperations(unittest.TestCase):
|
|||
|
||||
|
||||
class TestShiftOperations(unittest.TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.memory = Memory()
|
||||
self.memory = Memory(use_bus=False)
|
||||
self.cpu = CPU(self.memory)
|
||||
|
||||
|
||||
def test_ASL(self):
|
||||
self.cpu.accumulator = 0x01
|
||||
self.cpu.ASL()
|
||||
|
@ -663,7 +663,7 @@ class TestShiftOperations(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
self.assertEqual(self.cpu.carry_flag, 0)
|
||||
self.memory.write_byte(0x1000, 0x02)
|
||||
self.memory.write_byte(None, 0x1000, 0x02)
|
||||
self.cpu.ASL(0x1000)
|
||||
self.assertEqual(self.memory.read_byte(None, 0x1000), 0x04)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
|
@ -675,7 +675,7 @@ class TestShiftOperations(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 1)
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
|
||||
|
||||
def test_LSR(self):
|
||||
self.cpu.accumulator = 0x01
|
||||
self.cpu.LSR()
|
||||
|
@ -683,7 +683,7 @@ class TestShiftOperations(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 1)
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
self.memory.write_byte(0x1000, 0x01)
|
||||
self.memory.write_byte(None, 0x1000, 0x01)
|
||||
self.cpu.LSR(0x1000)
|
||||
self.assertEqual(self.memory.read_byte(None, 0x1000), 0x00)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
|
@ -695,7 +695,7 @@ class TestShiftOperations(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 0)
|
||||
self.assertEqual(self.cpu.carry_flag, 0)
|
||||
|
||||
|
||||
def test_ROL(self):
|
||||
self.cpu.carry_flag = 0
|
||||
self.cpu.accumulator = 0x80
|
||||
|
@ -709,92 +709,92 @@ class TestShiftOperations(unittest.TestCase):
|
|||
self.cpu.ROL()
|
||||
self.assertEqual(self.cpu.accumulator, 0x01)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 0) # @@@
|
||||
self.assertEqual(self.cpu.zero_flag, 0) # @@@
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
self.cpu.carry_flag = 0
|
||||
self.memory.write_byte(0x1000, 0x80)
|
||||
self.memory.write_byte(None, 0x1000, 0x80)
|
||||
self.cpu.ROL(0x1000)
|
||||
self.assertEqual(self.memory.read_byte(None, 0x1000), 0x00)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 1) # @@@
|
||||
self.assertEqual(self.cpu.zero_flag, 1) # @@@
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
self.cpu.carry_flag = 1
|
||||
self.memory.write_byte(0x1000, 0x80)
|
||||
self.memory.write_byte(None, 0x1000, 0x80)
|
||||
self.cpu.ROL(0x1000)
|
||||
self.assertEqual(self.memory.read_byte(None, 0x1000), 0x01)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 0) # @@@
|
||||
self.assertEqual(self.cpu.zero_flag, 0) # @@@
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
|
||||
|
||||
def test_ROR(self):
|
||||
self.cpu.carry_flag = 0
|
||||
self.cpu.accumulator = 0x01
|
||||
self.cpu.ROR()
|
||||
self.assertEqual(self.cpu.accumulator, 0x00)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 1) # @@@
|
||||
self.assertEqual(self.cpu.zero_flag, 1) # @@@
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
self.cpu.carry_flag = 1
|
||||
self.cpu.accumulator = 0x01
|
||||
self.cpu.ROR()
|
||||
self.assertEqual(self.cpu.accumulator, 0x80)
|
||||
self.assertEqual(self.cpu.sign_flag, 1) # @@@
|
||||
self.assertEqual(self.cpu.zero_flag, 0) # @@@
|
||||
self.assertEqual(self.cpu.sign_flag, 1) # @@@
|
||||
self.assertEqual(self.cpu.zero_flag, 0) # @@@
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
self.cpu.carry_flag = 0
|
||||
self.memory.write_byte(0x1000, 0x01)
|
||||
self.memory.write_byte(None, 0x1000, 0x01)
|
||||
self.cpu.ROR(0x1000)
|
||||
self.assertEqual(self.memory.read_byte(None, 0x1000), 0x00)
|
||||
self.assertEqual(self.cpu.sign_flag, 0)
|
||||
self.assertEqual(self.cpu.zero_flag, 1) # @@@
|
||||
self.assertEqual(self.cpu.zero_flag, 1) # @@@
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
self.cpu.carry_flag = 1
|
||||
self.memory.write_byte(0x1000, 0x01)
|
||||
self.memory.write_byte(None, 0x1000, 0x01)
|
||||
self.cpu.ROR(0x1000)
|
||||
self.assertEqual(self.memory.read_byte(None, 0x1000), 0x80)
|
||||
self.assertEqual(self.cpu.sign_flag, 1) # @@@
|
||||
self.assertEqual(self.cpu.zero_flag, 0) # @@@
|
||||
self.assertEqual(self.cpu.sign_flag, 1) # @@@
|
||||
self.assertEqual(self.cpu.zero_flag, 0) # @@@
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
|
||||
|
||||
class TestJumpCallOperations(unittest.TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.memory = Memory()
|
||||
self.memory = Memory(use_bus=False)
|
||||
self.cpu = CPU(self.memory)
|
||||
|
||||
|
||||
def test_JMP(self):
|
||||
self.cpu.JMP(0x1000)
|
||||
self.assertEqual(self.cpu.program_counter, 0x1000)
|
||||
|
||||
|
||||
def test_JSR(self):
|
||||
self.cpu.program_counter = 0x1000
|
||||
self.cpu.JSR(0x2000)
|
||||
self.assertEqual(self.cpu.program_counter, 0x2000)
|
||||
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)
|
||||
self.memory.write_byte(self.cpu.STACK_PAGE + 0xFE, 0x33)
|
||||
self.memory.write_byte(None, self.cpu.STACK_PAGE + 0xFF, 0x12)
|
||||
self.memory.write_byte(None, self.cpu.STACK_PAGE + 0xFE, 0x33)
|
||||
self.cpu.stack_pointer = 0xFD
|
||||
self.cpu.RTS()
|
||||
self.assertEqual(self.cpu.program_counter, 0x1234)
|
||||
|
||||
|
||||
def test_JSR_and_RTS(self):
|
||||
self.cpu.program_counter = 0x1000
|
||||
self.cpu.JSR(0x2000)
|
||||
self.assertEqual(self.cpu.program_counter, 0x2000)
|
||||
self.cpu.RTS()
|
||||
self.assertEqual(self.cpu.program_counter, 0x1000) # @@@
|
||||
self.assertEqual(self.cpu.program_counter, 0x1000) # @@@
|
||||
|
||||
|
||||
class TestBranchOperations(unittest.TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.memory = Memory()
|
||||
self.memory = Memory(use_bus=False)
|
||||
self.cpu = CPU(self.memory)
|
||||
|
||||
|
||||
def test_BCC(self):
|
||||
self.cpu.program_counter = 0x1000
|
||||
self.cpu.carry_flag = 1
|
||||
|
@ -804,7 +804,7 @@ class TestBranchOperations(unittest.TestCase):
|
|||
self.cpu.carry_flag = 0
|
||||
self.cpu.BCC(0x2000)
|
||||
self.assertEqual(self.cpu.program_counter, 0x2000)
|
||||
|
||||
|
||||
def test_BCS(self):
|
||||
self.cpu.program_counter = 0x1000
|
||||
self.cpu.carry_flag = 0
|
||||
|
@ -814,7 +814,7 @@ class TestBranchOperations(unittest.TestCase):
|
|||
self.cpu.carry_flag = 1
|
||||
self.cpu.BCS(0x2000)
|
||||
self.assertEqual(self.cpu.program_counter, 0x2000)
|
||||
|
||||
|
||||
def test_BEQ(self):
|
||||
self.cpu.program_counter = 0x1000
|
||||
self.cpu.zero_flag = 0
|
||||
|
@ -824,7 +824,7 @@ class TestBranchOperations(unittest.TestCase):
|
|||
self.cpu.zero_flag = 1
|
||||
self.cpu.BEQ(0x2000)
|
||||
self.assertEqual(self.cpu.program_counter, 0x2000)
|
||||
|
||||
|
||||
def test_BMI(self):
|
||||
self.cpu.program_counter = 0x1000
|
||||
self.cpu.sign_flag = 0
|
||||
|
@ -834,7 +834,7 @@ class TestBranchOperations(unittest.TestCase):
|
|||
self.cpu.sign_flag = 1
|
||||
self.cpu.BMI(0x2000)
|
||||
self.assertEqual(self.cpu.program_counter, 0x2000)
|
||||
|
||||
|
||||
def test_BNE(self):
|
||||
self.cpu.program_counter = 0x1000
|
||||
self.cpu.zero_flag = 1
|
||||
|
@ -844,7 +844,7 @@ class TestBranchOperations(unittest.TestCase):
|
|||
self.cpu.zero_flag = 0
|
||||
self.cpu.BNE(0x2000)
|
||||
self.assertEqual(self.cpu.program_counter, 0x2000)
|
||||
|
||||
|
||||
def test_BPL(self):
|
||||
self.cpu.program_counter = 0x1000
|
||||
self.cpu.sign_flag = 1
|
||||
|
@ -854,7 +854,7 @@ class TestBranchOperations(unittest.TestCase):
|
|||
self.cpu.sign_flag = 0
|
||||
self.cpu.BPL(0x2000)
|
||||
self.assertEqual(self.cpu.program_counter, 0x2000)
|
||||
|
||||
|
||||
def test_BVC(self):
|
||||
self.cpu.program_counter = 0x1000
|
||||
self.cpu.overflow_flag = 1
|
||||
|
@ -864,7 +864,7 @@ class TestBranchOperations(unittest.TestCase):
|
|||
self.cpu.overflow_flag = 0
|
||||
self.cpu.BVC(0x2000)
|
||||
self.assertEqual(self.cpu.program_counter, 0x2000)
|
||||
|
||||
|
||||
def test_BVS(self):
|
||||
self.cpu.program_counter = 0x1000
|
||||
self.cpu.overflow_flag = 0
|
||||
|
@ -877,41 +877,41 @@ class TestBranchOperations(unittest.TestCase):
|
|||
|
||||
|
||||
class TestStatusFlagOperations(unittest.TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.memory = Memory()
|
||||
self.memory = Memory(use_bus=False)
|
||||
self.cpu = CPU(self.memory)
|
||||
|
||||
|
||||
def test_CLC(self):
|
||||
self.cpu.carry_flag = 1
|
||||
self.cpu.CLC()
|
||||
self.assertEqual(self.cpu.carry_flag, 0)
|
||||
|
||||
|
||||
def test_CLD(self):
|
||||
self.cpu.decimal_mode_flag = 1
|
||||
self.cpu.CLD()
|
||||
self.assertEqual(self.cpu.decimal_mode_flag, 0)
|
||||
|
||||
|
||||
def test_CLI(self):
|
||||
self.cpu.interrupt_disable_flag = 1
|
||||
self.cpu.CLI()
|
||||
self.assertEqual(self.cpu.interrupt_disable_flag, 0)
|
||||
|
||||
|
||||
def test_CLV(self):
|
||||
self.cpu.overflow_flag = 1
|
||||
self.cpu.CLV()
|
||||
self.assertEqual(self.cpu.overflow_flag, 0)
|
||||
|
||||
|
||||
def test_SEC(self):
|
||||
self.cpu.carry_flag = 0
|
||||
self.cpu.SEC()
|
||||
self.assertEqual(self.cpu.carry_flag, 1)
|
||||
|
||||
|
||||
def test_SED(self):
|
||||
self.cpu.decimal_mode_flag = 0
|
||||
self.cpu.SED()
|
||||
self.assertEqual(self.cpu.decimal_mode_flag, 1)
|
||||
|
||||
|
||||
def test_SEI(self):
|
||||
self.cpu.interrupt_disable_flag = 0
|
||||
self.cpu.SEI()
|
||||
|
@ -919,11 +919,11 @@ class TestStatusFlagOperations(unittest.TestCase):
|
|||
|
||||
|
||||
class TestSystemFunctionOperations(unittest.TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.memory = Memory()
|
||||
self.memory = Memory(use_bus=False)
|
||||
self.cpu = CPU(self.memory)
|
||||
|
||||
|
||||
def test_BRK(self):
|
||||
self.cpu.program_counter = 0x1000
|
||||
self.memory.rom.load(0xFFFE, [0x00, 0x20])
|
||||
|
@ -934,26 +934,26 @@ class TestSystemFunctionOperations(unittest.TestCase):
|
|||
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)
|
||||
self.memory.write_byte(self.cpu.STACK_PAGE + 0xFE, 0x33)
|
||||
self.memory.write_byte(self.cpu.STACK_PAGE + 0xFD, 0x20)
|
||||
self.memory.write_byte(None, self.cpu.STACK_PAGE + 0xFF, 0x12)
|
||||
self.memory.write_byte(None, self.cpu.STACK_PAGE + 0xFE, 0x33)
|
||||
self.memory.write_byte(None, self.cpu.STACK_PAGE + 0xFD, 0x20)
|
||||
self.cpu.stack_pointer = 0xFC
|
||||
self.cpu.RTI()
|
||||
self.assertEqual(self.cpu.program_counter, 0x1233)
|
||||
self.assertEqual(self.cpu.status_as_byte(), 0x20)
|
||||
|
||||
|
||||
def test_NOP(self):
|
||||
self.cpu.NOP()
|
||||
|
||||
|
||||
class Test6502Bugs(unittest.TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.memory = Memory()
|
||||
self.memory = Memory(use_bus=False)
|
||||
self.cpu = CPU(self.memory)
|
||||
|
||||
|
||||
def test_zero_page_x(self):
|
||||
self.cpu.x_index = 0x01
|
||||
self.memory.load(0x1000, [0x00, 0x7F, 0xFF])
|
||||
|
@ -961,7 +961,7 @@ class Test6502Bugs(unittest.TestCase):
|
|||
self.assertEqual(self.cpu.zero_page_x_mode(), 0x01)
|
||||
self.assertEqual(self.cpu.zero_page_x_mode(), 0x80)
|
||||
self.assertEqual(self.cpu.zero_page_x_mode(), 0x00)
|
||||
|
||||
|
||||
def test_indirect(self):
|
||||
self.memory.load(0x20, [0x00, 0x20])
|
||||
self.memory.load(0x00, [0x12])
|
||||
|
@ -971,29 +971,29 @@ class Test6502Bugs(unittest.TestCase):
|
|||
self.memory.load(0x2000, [0x05])
|
||||
self.memory.load(0x1234, [0x05])
|
||||
self.memory.load(0x2345, [0x00, 0xF0])
|
||||
|
||||
|
||||
self.cpu.program_counter = 0x1000
|
||||
|
||||
|
||||
self.cpu.x_index = 0x00
|
||||
self.cpu.LDA(self.cpu.indirect_x_mode())
|
||||
self.assertEqual(self.cpu.accumulator, 0x05)
|
||||
|
||||
|
||||
self.cpu.y_index = 0x00
|
||||
self.cpu.LDA(self.cpu.indirect_y_mode())
|
||||
self.assertEqual(self.cpu.accumulator, 0x05)
|
||||
|
||||
|
||||
self.cpu.y_index = 0x00
|
||||
self.cpu.LDA(self.cpu.indirect_y_mode())
|
||||
self.assertEqual(self.cpu.accumulator, 0x05)
|
||||
|
||||
|
||||
self.cpu.x_index = 0x00
|
||||
self.cpu.LDA(self.cpu.indirect_x_mode())
|
||||
self.assertEqual(self.cpu.accumulator, 0x05)
|
||||
|
||||
|
||||
self.cpu.x_index = 0xFF
|
||||
self.cpu.LDA(self.cpu.indirect_x_mode())
|
||||
self.assertEqual(self.cpu.accumulator, 0x05)
|
||||
|
||||
|
||||
self.assertEqual(self.cpu.indirect_mode(), 0xF000)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue