This commit is contained in:
Jens Diemer 2013-08-29 09:47:00 -07:00
commit 8a45d0f0a0
18 changed files with 1963 additions and 1312 deletions

0
Dragon32/__init__.py Normal file
View File

405
Dragon32/cpu6809.py Normal file
View File

@ -0,0 +1,405 @@
"""
TODO: Just a copy of cpi6502.py yet :(
"""
import BaseHTTPServer
import json
import re
import select
import socket
import sys
from dragon32memory import Memory, RAM, ROM
from generic.cpu import BaseCPU
from generic.disassembler import BaseDisassemble
from Dragon32.dragon32config import Dragon32Config
class Disassemble6809(BaseDisassemble):
def setup_ops(self):
self.ops = [(1, "???")] * 0x100
self.ops[0x00] = (1, "BRK",)
self.ops[0x01] = (2, "ORA", self.indirect_x_mode)
self.ops[0x05] = (2, "ORA", self.zero_page_mode)
self.ops[0x06] = (2, "ASL", self.zero_page_mode)
self.ops[0x08] = (1, "PHP",)
self.ops[0x09] = (2, "ORA", self.immediate_mode)
self.ops[0x0A] = (1, "ASL",)
self.ops[0x0D] = (3, "ORA", self.absolute_mode)
self.ops[0x0E] = (3, "ASL", self.absolute_mode)
self.ops[0x10] = (2, "BPL", self.relative_mode)
self.ops[0x11] = (2, "ORA", self.indirect_y_mode)
self.ops[0x15] = (2, "ORA", self.zero_page_x_mode)
self.ops[0x16] = (2, "ASL", self.zero_page_x_mode)
self.ops[0x18] = (1, "CLC",)
self.ops[0x19] = (3, "ORA", self.absolute_y_mode)
self.ops[0x1D] = (3, "ORA", self.absolute_x_mode)
self.ops[0x1E] = (3, "ASL", self.absolute_x_mode)
self.ops[0x20] = (3, "JSR", self.absolute_mode)
self.ops[0x21] = (2, "AND", self.indirect_x_mode)
self.ops[0x24] = (2, "BIT", self.zero_page_mode)
self.ops[0x25] = (2, "AND", self.zero_page_mode)
self.ops[0x26] = (2, "ROL", self.zero_page_mode)
self.ops[0x28] = (1, "PLP",)
self.ops[0x29] = (2, "AND", self.immediate_mode)
self.ops[0x2A] = (1, "ROL",)
self.ops[0x2C] = (3, "BIT", self.absolute_mode)
self.ops[0x2D] = (3, "AND", self.absolute_mode)
self.ops[0x2E] = (3, "ROL", self.absolute_mode)
self.ops[0x30] = (2, "BMI", self.relative_mode)
self.ops[0x31] = (2, "AND", self.indirect_y_mode)
self.ops[0x35] = (2, "AND", self.zero_page_x_mode)
self.ops[0x36] = (2, "ROL", self.zero_page_x_mode)
self.ops[0x38] = (1, "SEC",)
self.ops[0x39] = (3, "AND", self.absolute_y_mode)
self.ops[0x3D] = (3, "AND", self.absolute_x_mode)
self.ops[0x3E] = (3, "ROL", self.absolute_x_mode)
self.ops[0x40] = (1, "RTI",)
self.ops[0x41] = (2, "EOR", self.indirect_x_mode)
self.ops[0x45] = (2, "EOR", self.zero_page_mode)
self.ops[0x46] = (2, "LSR", self.zero_page_mode)
self.ops[0x48] = (1, "PHA",)
self.ops[0x49] = (2, "EOR", self.immediate_mode)
self.ops[0x4A] = (1, "LSR",)
self.ops[0x4C] = (3, "JMP", self.absolute_mode)
self.ops[0x4D] = (3, "EOR", self.absolute_mode)
self.ops[0x4E] = (3, "LSR", self.absolute_mode)
self.ops[0x50] = (2, "BVC", self.relative_mode)
self.ops[0x51] = (2, "EOR", self.indirect_y_mode)
self.ops[0x55] = (2, "EOR", self.zero_page_x_mode)
self.ops[0x56] = (2, "LSR", self.zero_page_x_mode)
self.ops[0x58] = (1, "CLI",)
self.ops[0x59] = (3, "EOR", self.absolute_y_mode)
self.ops[0x5D] = (3, "EOR", self.absolute_x_mode)
self.ops[0x5E] = (3, "LSR", self.absolute_x_mode)
self.ops[0x60] = (1, "RTS",)
self.ops[0x61] = (2, "ADC", self.indirect_x_mode)
self.ops[0x65] = (2, "ADC", self.zero_page_mode)
self.ops[0x66] = (2, "ROR", self.zero_page_mode)
self.ops[0x68] = (1, "PLA",)
self.ops[0x69] = (2, "ADC", self.immediate_mode)
self.ops[0x6A] = (1, "ROR",)
self.ops[0x6C] = (3, "JMP", self.indirect_mode)
self.ops[0x6D] = (3, "ADC", self.absolute_mode)
self.ops[0x6E] = (3, "ROR", self.absolute_mode)
self.ops[0x70] = (2, "BVS", self.relative_mode)
self.ops[0x71] = (2, "ADC", self.indirect_y_mode)
self.ops[0x75] = (2, "ADC", self.zero_page_x_mode)
self.ops[0x76] = (2, "ROR", self.zero_page_x_mode)
self.ops[0x78] = (1, "SEI",)
self.ops[0x79] = (3, "ADC", self.absolute_y_mode)
self.ops[0x7D] = (3, "ADC", self.absolute_x_mode)
self.ops[0x7E] = (3, "ROR", self.absolute_x_mode)
self.ops[0x81] = (2, "STA", self.indirect_x_mode)
self.ops[0x84] = (2, "STY", self.zero_page_mode)
self.ops[0x85] = (2, "STA", self.zero_page_mode)
self.ops[0x86] = (2, "STX", self.zero_page_mode)
self.ops[0x88] = (1, "DEY",)
self.ops[0x8A] = (1, "TXA",)
self.ops[0x8C] = (3, "STY", self.absolute_mode)
self.ops[0x8D] = (3, "STA", self.absolute_mode)
self.ops[0x8E] = (3, "STX", self.absolute_mode)
self.ops[0x90] = (2, "BCC", self.relative_mode)
self.ops[0x91] = (2, "STA", self.indirect_y_mode)
self.ops[0x94] = (2, "STY", self.zero_page_x_mode)
self.ops[0x95] = (2, "STA", self.zero_page_x_mode)
self.ops[0x96] = (2, "STX", self.zero_page_y_mode)
self.ops[0x98] = (1, "TYA",)
self.ops[0x99] = (3, "STA", self.absolute_y_mode)
self.ops[0x9A] = (1, "TXS",)
self.ops[0x9D] = (3, "STA", self.absolute_x_mode)
self.ops[0xA0] = (2, "LDY", self.immediate_mode)
self.ops[0xA1] = (2, "LDA", self.indirect_x_mode)
self.ops[0xA2] = (2, "LDX", self.immediate_mode)
self.ops[0xA4] = (2, "LDY", self.zero_page_mode)
self.ops[0xA5] = (2, "LDA", self.zero_page_mode)
self.ops[0xA6] = (2, "LDX", self.zero_page_mode)
self.ops[0xA8] = (1, "TAY",)
self.ops[0xA9] = (2, "LDA", self.immediate_mode)
self.ops[0xAA] = (1, "TAX",)
self.ops[0xAC] = (3, "LDY", self.absolute_mode)
self.ops[0xAD] = (3, "LDA", self.absolute_mode)
self.ops[0xAE] = (3, "LDX", self.absolute_mode)
self.ops[0xB0] = (2, "BCS", self.relative_mode)
self.ops[0xB1] = (2, "LDA", self.indirect_y_mode)
self.ops[0xB4] = (2, "LDY", self.zero_page_x_mode)
self.ops[0xB5] = (2, "LDA", self.zero_page_x_mode)
self.ops[0xB6] = (2, "LDX", self.zero_page_y_mode)
self.ops[0xB8] = (1, "CLV",)
self.ops[0xB9] = (3, "LDA", self.absolute_y_mode)
self.ops[0xBA] = (1, "TSX",)
self.ops[0xBC] = (3, "LDY", self.absolute_x_mode)
self.ops[0xBD] = (3, "LDA", self.absolute_x_mode)
self.ops[0xBE] = (3, "LDX", self.absolute_y_mode)
self.ops[0xC0] = (2, "CPY", self.immediate_mode)
self.ops[0xC1] = (2, "CMP", self.indirect_x_mode)
self.ops[0xC4] = (2, "CPY", self.zero_page_mode)
self.ops[0xC5] = (2, "CMP", self.zero_page_mode)
self.ops[0xC6] = (2, "DEC", self.zero_page_mode)
self.ops[0xC8] = (1, "INY",)
self.ops[0xC9] = (2, "CMP", self.immediate_mode)
self.ops[0xCA] = (1, "DEX",)
self.ops[0xCC] = (3, "CPY", self.absolute_mode)
self.ops[0xCD] = (3, "CMP", self.absolute_mode)
self.ops[0xCE] = (3, "DEC", self.absolute_mode)
self.ops[0xD0] = (2, "BNE", self.relative_mode)
self.ops[0xD1] = (2, "CMP", self.indirect_y_mode)
self.ops[0xD5] = (2, "CMP", self.zero_page_x_mode)
self.ops[0xD6] = (2, "DEC", self.zero_page_x_mode)
self.ops[0xD8] = (1, "CLD",)
self.ops[0xD9] = (3, "CMP", self.absolute_y_mode)
self.ops[0xDD] = (3, "CMP", self.absolute_x_mode)
self.ops[0xDE] = (3, "DEC", self.absolute_x_mode)
self.ops[0xE0] = (2, "CPX", self.immediate_mode)
self.ops[0xE1] = (2, "SBC", self.indirect_x_mode)
self.ops[0xE4] = (2, "CPX", self.zero_page_mode)
self.ops[0xE5] = (2, "SBC", self.zero_page_mode)
self.ops[0xE6] = (2, "INC", self.zero_page_mode)
self.ops[0xE8] = (1, "INX",)
self.ops[0xE9] = (2, "SBC", self.immediate_mode)
self.ops[0xEA] = (1, "NOP",)
self.ops[0xEC] = (3, "CPX", self.absolute_mode)
self.ops[0xED] = (3, "SBC", self.absolute_mode)
self.ops[0xEE] = (3, "INC", self.absolute_mode)
self.ops[0xF0] = (2, "BEQ", self.relative_mode)
self.ops[0xF1] = (2, "SBC", self.indirect_y_mode)
self.ops[0xF5] = (2, "SBC", self.zero_page_x_mode)
self.ops[0xF6] = (2, "INC", self.zero_page_x_mode)
self.ops[0xF8] = (1, "SED",)
self.ops[0xF9] = (3, "SBC", self.absolute_y_mode)
self.ops[0xFD] = (3, "SBC", self.absolute_x_mode)
self.ops[0xFE] = (3, "INC", self.absolute_x_mode)
class CPU6502(BaseCPU):
def __init__(self, *args, **kwargs):
super(CPU6502, self).__init__(*args, **kwargs)
self.stack_pointer = 0xFF
def setup_ops(self):
self.ops = [None] * 0x100
self.ops[0x00] = lambda: self.BRK()
self.ops[0x01] = lambda: self.ORA(self.indirect_x_mode())
self.ops[0x05] = lambda: self.ORA(self.zero_page_mode())
self.ops[0x06] = lambda: self.ASL(self.zero_page_mode())
self.ops[0x08] = lambda: self.PHP()
self.ops[0x09] = lambda: self.ORA(self.immediate_mode())
self.ops[0x0A] = lambda: self.ASL()
self.ops[0x0D] = lambda: self.ORA(self.absolute_mode())
self.ops[0x0E] = lambda: self.ASL(self.absolute_mode())
self.ops[0x10] = lambda: self.BPL(self.relative_mode())
self.ops[0x11] = lambda: self.ORA(self.indirect_y_mode())
self.ops[0x15] = lambda: self.ORA(self.zero_page_x_mode())
self.ops[0x16] = lambda: self.ASL(self.zero_page_x_mode())
self.ops[0x18] = lambda: self.CLC()
self.ops[0x19] = lambda: self.ORA(self.absolute_y_mode())
self.ops[0x1D] = lambda: self.ORA(self.absolute_x_mode())
self.ops[0x1E] = lambda: self.ASL(self.absolute_x_mode(rmw=True))
self.ops[0x20] = lambda: self.JSR(self.absolute_mode())
self.ops[0x21] = lambda: self.AND(self.indirect_x_mode())
self.ops[0x24] = lambda: self.BIT(self.zero_page_mode())
self.ops[0x25] = lambda: self.AND(self.zero_page_mode())
self.ops[0x26] = lambda: self.ROL(self.zero_page_mode())
self.ops[0x28] = lambda: self.PLP()
self.ops[0x29] = lambda: self.AND(self.immediate_mode())
self.ops[0x2A] = lambda: self.ROL()
self.ops[0x2C] = lambda: self.BIT(self.absolute_mode())
self.ops[0x2D] = lambda: self.AND(self.absolute_mode())
self.ops[0x2E] = lambda: self.ROL(self.absolute_mode())
self.ops[0x30] = lambda: self.BMI(self.relative_mode())
self.ops[0x31] = lambda: self.AND(self.indirect_y_mode())
self.ops[0x35] = lambda: self.AND(self.zero_page_x_mode())
self.ops[0x36] = lambda: self.ROL(self.zero_page_x_mode())
self.ops[0x38] = lambda: self.SEC()
self.ops[0x39] = lambda: self.AND(self.absolute_y_mode())
self.ops[0x3D] = lambda: self.AND(self.absolute_x_mode())
self.ops[0x3E] = lambda: self.ROL(self.absolute_x_mode(rmw=True))
self.ops[0x40] = lambda: self.RTI()
self.ops[0x41] = lambda: self.EOR(self.indirect_x_mode())
self.ops[0x45] = lambda: self.EOR(self.zero_page_mode())
self.ops[0x46] = lambda: self.LSR(self.zero_page_mode())
self.ops[0x48] = lambda: self.PHA()
self.ops[0x49] = lambda: self.EOR(self.immediate_mode())
self.ops[0x4A] = lambda: self.LSR()
self.ops[0x4C] = lambda: self.JMP(self.absolute_mode())
self.ops[0x4D] = lambda: self.EOR(self.absolute_mode())
self.ops[0x4E] = lambda: self.LSR(self.absolute_mode())
self.ops[0x50] = lambda: self.BVC(self.relative_mode())
self.ops[0x51] = lambda: self.EOR(self.indirect_y_mode())
self.ops[0x55] = lambda: self.EOR(self.zero_page_x_mode())
self.ops[0x56] = lambda: self.LSR(self.zero_page_x_mode())
self.ops[0x58] = lambda: self.CLI()
self.ops[0x59] = lambda: self.EOR(self.absolute_y_mode())
self.ops[0x5D] = lambda: self.EOR(self.absolute_x_mode())
self.ops[0x5E] = lambda: self.LSR(self.absolute_x_mode(rmw=True))
self.ops[0x60] = lambda: self.RTS()
self.ops[0x61] = lambda: self.ADC(self.indirect_x_mode())
self.ops[0x65] = lambda: self.ADC(self.zero_page_mode())
self.ops[0x66] = lambda: self.ROR(self.zero_page_mode())
self.ops[0x68] = lambda: self.PLA()
self.ops[0x69] = lambda: self.ADC(self.immediate_mode())
self.ops[0x6A] = lambda: self.ROR()
self.ops[0x6C] = lambda: self.JMP(self.indirect_mode())
self.ops[0x6D] = lambda: self.ADC(self.absolute_mode())
self.ops[0x6E] = lambda: self.ROR(self.absolute_mode())
self.ops[0x70] = lambda: self.BVS(self.relative_mode())
self.ops[0x71] = lambda: self.ADC(self.indirect_y_mode())
self.ops[0x75] = lambda: self.ADC(self.zero_page_x_mode())
self.ops[0x76] = lambda: self.ROR(self.zero_page_x_mode())
self.ops[0x78] = lambda: self.SEI()
self.ops[0x79] = lambda: self.ADC(self.absolute_y_mode())
self.ops[0x7D] = lambda: self.ADC(self.absolute_x_mode())
self.ops[0x7E] = lambda: self.ROR(self.absolute_x_mode(rmw=True))
self.ops[0x81] = lambda: self.STA(self.indirect_x_mode())
self.ops[0x84] = lambda: self.STY(self.zero_page_mode())
self.ops[0x85] = lambda: self.STA(self.zero_page_mode())
self.ops[0x86] = lambda: self.STX(self.zero_page_mode())
self.ops[0x88] = lambda: self.DEY()
self.ops[0x8A] = lambda: self.TXA()
self.ops[0x8C] = lambda: self.STY(self.absolute_mode())
self.ops[0x8D] = lambda: self.STA(self.absolute_mode())
self.ops[0x8E] = lambda: self.STX(self.absolute_mode())
self.ops[0x90] = lambda: self.BCC(self.relative_mode())
self.ops[0x91] = lambda: self.STA(self.indirect_y_mode(rmw=True))
self.ops[0x94] = lambda: self.STY(self.zero_page_x_mode())
self.ops[0x95] = lambda: self.STA(self.zero_page_x_mode())
self.ops[0x96] = lambda: self.STX(self.zero_page_y_mode())
self.ops[0x98] = lambda: self.TYA()
self.ops[0x99] = lambda: self.STA(self.absolute_y_mode(rmw=True))
self.ops[0x9A] = lambda: self.TXS()
self.ops[0x9D] = lambda: self.STA(self.absolute_x_mode(rmw=True))
self.ops[0xA0] = lambda: self.LDY(self.immediate_mode())
self.ops[0xA1] = lambda: self.LDA(self.indirect_x_mode())
self.ops[0xA2] = lambda: self.LDX(self.immediate_mode())
self.ops[0xA4] = lambda: self.LDY(self.zero_page_mode())
self.ops[0xA5] = lambda: self.LDA(self.zero_page_mode())
self.ops[0xA6] = lambda: self.LDX(self.zero_page_mode())
self.ops[0xA8] = lambda: self.TAY()
self.ops[0xA9] = lambda: self.LDA(self.immediate_mode())
self.ops[0xAA] = lambda: self.TAX()
self.ops[0xAC] = lambda: self.LDY(self.absolute_mode())
self.ops[0xAD] = lambda: self.LDA(self.absolute_mode())
self.ops[0xAE] = lambda: self.LDX(self.absolute_mode())
self.ops[0xB0] = lambda: self.BCS(self.relative_mode())
self.ops[0xB1] = lambda: self.LDA(self.indirect_y_mode())
self.ops[0xB4] = lambda: self.LDY(self.zero_page_x_mode())
self.ops[0xB5] = lambda: self.LDA(self.zero_page_x_mode())
self.ops[0xB6] = lambda: self.LDX(self.zero_page_y_mode())
self.ops[0xB8] = lambda: self.CLV()
self.ops[0xB9] = lambda: self.LDA(self.absolute_y_mode())
self.ops[0xBA] = lambda: self.TSX()
self.ops[0xBC] = lambda: self.LDY(self.absolute_x_mode())
self.ops[0xBD] = lambda: self.LDA(self.absolute_x_mode())
self.ops[0xBE] = lambda: self.LDX(self.absolute_y_mode())
self.ops[0xC0] = lambda: self.CPY(self.immediate_mode())
self.ops[0xC1] = lambda: self.CMP(self.indirect_x_mode())
self.ops[0xC4] = lambda: self.CPY(self.zero_page_mode())
self.ops[0xC5] = lambda: self.CMP(self.zero_page_mode())
self.ops[0xC6] = lambda: self.DEC(self.zero_page_mode())
self.ops[0xC8] = lambda: self.INY()
self.ops[0xC9] = lambda: self.CMP(self.immediate_mode())
self.ops[0xCA] = lambda: self.DEX()
self.ops[0xCC] = lambda: self.CPY(self.absolute_mode())
self.ops[0xCD] = lambda: self.CMP(self.absolute_mode())
self.ops[0xCE] = lambda: self.DEC(self.absolute_mode())
self.ops[0xD0] = lambda: self.BNE(self.relative_mode())
self.ops[0xD1] = lambda: self.CMP(self.indirect_y_mode())
self.ops[0xD5] = lambda: self.CMP(self.zero_page_x_mode())
self.ops[0xD6] = lambda: self.DEC(self.zero_page_x_mode())
self.ops[0xD8] = lambda: self.CLD()
self.ops[0xD9] = lambda: self.CMP(self.absolute_y_mode())
self.ops[0xDD] = lambda: self.CMP(self.absolute_x_mode())
self.ops[0xDE] = lambda: self.DEC(self.absolute_x_mode(rmw=True))
self.ops[0xE0] = lambda: self.CPX(self.immediate_mode())
self.ops[0xE1] = lambda: self.SBC(self.indirect_x_mode())
self.ops[0xE4] = lambda: self.CPX(self.zero_page_mode())
self.ops[0xE5] = lambda: self.SBC(self.zero_page_mode())
self.ops[0xE6] = lambda: self.INC(self.zero_page_mode())
self.ops[0xE8] = lambda: self.INX()
self.ops[0xE9] = lambda: self.SBC(self.immediate_mode())
self.ops[0xEA] = lambda: self.NOP()
self.ops[0xEC] = lambda: self.CPX(self.absolute_mode())
self.ops[0xED] = lambda: self.SBC(self.absolute_mode())
self.ops[0xEE] = lambda: self.INC(self.absolute_mode())
self.ops[0xF0] = lambda: self.BEQ(self.relative_mode())
self.ops[0xF1] = lambda: self.SBC(self.indirect_y_mode())
self.ops[0xF5] = lambda: self.SBC(self.zero_page_x_mode())
self.ops[0xF6] = lambda: self.INC(self.zero_page_x_mode())
self.ops[0xF8] = lambda: self.SED()
self.ops[0xF9] = lambda: self.SBC(self.absolute_y_mode())
self.ops[0xFD] = lambda: self.SBC(self.absolute_x_mode())
self.ops[0xFE] = lambda: self.INC(self.absolute_x_mode(rmw=True))
def usage():
print >> sys.stderr, "ApplePy - an Apple ][ emulator in Python"
print >> sys.stderr, "James Tauber / http://jtauber.com/"
print >> sys.stderr
print >> sys.stderr, "Usage: cpu6502.py [options]"
print >> sys.stderr
print >> sys.stderr, " -b, --bus Bus port number"
print >> sys.stderr, " -p, --pc Initial PC value"
print >> sys.stderr, " -R, --rom ROM file to use (default A2ROM.BIN)"
print >> sys.stderr, " -r, --ram RAM file to load (default none)"
sys.exit(1)
def get_options():
class Options:
def __init__(self):
self.rom = "d32.rom"
self.ram = None
self.bus = None
self.pc = None
options = Options()
a = 1
while a < len(sys.argv):
if sys.argv[a].startswith("-"):
if sys.argv[a] in ("-b", "--bus"):
a += 1
options.bus_port = 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
options.rom = sys.argv[a]
elif sys.argv[a] in ("-r", "--ram"):
a += 1
options.ram = sys.argv[a]
else:
usage()
else:
usage()
a += 1
return options
if __name__ == "__main__":
options = get_options()
if options.bus_port is None:
print "Dragon 32 cpu core"
print "Run dragonpy.py instead"
sys.exit(0)
cfg = Dragon32Config()
bus = socket.socket()
bus_address = (cfg.LOCAL_HOST_IP, options.bus_port)
print "bus I/O connect to %s" % repr(bus_address)
bus.connect(bus_address)
mem = Memory(cfg, bus, RAM, ROM, options)
cpu = CPU6502(cfg, bus, options, mem, Disassemble6809)
cpu.run()

View File

@ -0,0 +1,40 @@
from generic.generic_config import BaseConfig
class Dragon32Config(BaseConfig):
"""
FIXME: Wrong values here?
max Memory is 64KB ($FFFF Bytes)
32 kB RAM ($0000-$7FFF)
16 kB ROM ($8000-$BFFF)
~16 kB free/reseved ($C000-$FEFF)
$FF00-$FFFF 6883-SAM / PIA
"""
# Memory
RAM_START = 0x0000
RAM_SIZE = 0x7FFF
RAM_END = RAM_START + RAM_SIZE
ROM_START = 0x8000
ROM_SIZE = 0x4000
ROM_END = ROM_START + ROM_SIZE
# CPU
STACK_PAGE = 0x100
# RESET_VECTOR = 0xb44f
RESET_VECTOR = 0xB3B4
# RESET_VECTOR = 0xfffe
HTTPSERVER_PORT = 6809
CPU_MODULE = "Dragon32.cpu6809"
KEY_LEFT = 0x08 # ???
KEY_RIGHT = 0x15 # ???
if __name__ == "__main__":
cfg = Dragon32Config()
cfg.print_debug_info()

View File

@ -0,0 +1,26 @@
"""
TODO: Just a copy of apple2memory.py yet :(
"""
from generic.base_memory import MemoryBase, ROMBase, RAMBase
class ROM(ROMBase):
pass
class RAM(RAMBase):
pass
class Memory(MemoryBase):
def read_word_bug(self, cycle, address):
if address % 0x100 == 0xFF:
return self.read_byte(cycle, address) + (self.read_byte(cycle + 1, address & 0xFF00) << 8)
else:
return self.read_word(cycle, address)
def write_byte(self, cycle, address, value):
if address < self.cfg.RAM_SIZE:
self.ram.write_byte(address, value)
if 0x400 <= address < 0x800 or 0x2000 <= address < 0x5FFF:
self.bus_write(cycle, address, value)

0
apple2/__init__.py Normal file
View File

30
apple2/apple2config.py Normal file
View File

@ -0,0 +1,30 @@
from generic.generic_config import BaseConfig
class Apple2Config(BaseConfig):
# Memory
ROM_START = 0xD000
ROM_SIZE = 0x3000
ROM_END = ROM_START + ROM_SIZE # 0x10000
RAM_START = 0x0000
RAM_SIZE = 0xC000
RAM_END = RAM_START + RAM_SIZE # 0xc000
# CPU
STACK_PAGE = 0x100
RESET_VECTOR = 0xFFFC
HTTPSERVER_PORT = 6502
CPU_MODULE = "apple2.cpu6502"
KEY_LEFT = 0x08
KEY_RIGHT = 0x15
if __name__ == "__main__":
cfg = Apple2Config()
cfg.print_debug_info()
print "CPU script:", cfg.get_cpu_script()

21
apple2/apple2memory.py Normal file
View File

@ -0,0 +1,21 @@
from generic.base_memory import MemoryBase, ROMBase, RAMBase
class ROM(ROMBase):
pass
class RAM(RAMBase):
pass
class Memory(MemoryBase):
def read_word_bug(self, cycle, address):
if address % 0x100 == 0xFF:
return self.read_byte(cycle, address) + (self.read_byte(cycle + 1, address & 0xFF00) << 8)
else:
return self.read_word(cycle, address)
def write_byte(self, cycle, address, value):
if address < self.cfg.RAM_SIZE:
self.ram.write_byte(address, value)
if 0x400 <= address < 0x800 or 0x2000 <= address < 0x5FFF:
self.bus_write(cycle, address, value)

404
apple2/cpu6502.py Normal file
View File

@ -0,0 +1,404 @@
# ApplePy - an Apple ][ emulator in Python
# James Tauber / http://jtauber.com/
# originally written 2001, updated 2011
import BaseHTTPServer
import json
import re
import select
import socket
import sys
from apple2memory import Memory, RAM, ROM
from apple2config import Apple2Config
from generic.cpu import BaseCPU
from generic.disassembler import BaseDisassemble
class Disassemble6809(BaseDisassemble):
def setup_ops(self):
self.ops = [(1, "???")] * 0x100
self.ops[0x00] = (1, "BRK", )
self.ops[0x01] = (2, "ORA", self.indirect_x_mode)
self.ops[0x05] = (2, "ORA", self.zero_page_mode)
self.ops[0x06] = (2, "ASL", self.zero_page_mode)
self.ops[0x08] = (1, "PHP", )
self.ops[0x09] = (2, "ORA", self.immediate_mode)
self.ops[0x0A] = (1, "ASL", )
self.ops[0x0D] = (3, "ORA", self.absolute_mode)
self.ops[0x0E] = (3, "ASL", self.absolute_mode)
self.ops[0x10] = (2, "BPL", self.relative_mode)
self.ops[0x11] = (2, "ORA", self.indirect_y_mode)
self.ops[0x15] = (2, "ORA", self.zero_page_x_mode)
self.ops[0x16] = (2, "ASL", self.zero_page_x_mode)
self.ops[0x18] = (1, "CLC", )
self.ops[0x19] = (3, "ORA", self.absolute_y_mode)
self.ops[0x1D] = (3, "ORA", self.absolute_x_mode)
self.ops[0x1E] = (3, "ASL", self.absolute_x_mode)
self.ops[0x20] = (3, "JSR", self.absolute_mode)
self.ops[0x21] = (2, "AND", self.indirect_x_mode)
self.ops[0x24] = (2, "BIT", self.zero_page_mode)
self.ops[0x25] = (2, "AND", self.zero_page_mode)
self.ops[0x26] = (2, "ROL", self.zero_page_mode)
self.ops[0x28] = (1, "PLP", )
self.ops[0x29] = (2, "AND", self.immediate_mode)
self.ops[0x2A] = (1, "ROL", )
self.ops[0x2C] = (3, "BIT", self.absolute_mode)
self.ops[0x2D] = (3, "AND", self.absolute_mode)
self.ops[0x2E] = (3, "ROL", self.absolute_mode)
self.ops[0x30] = (2, "BMI", self.relative_mode)
self.ops[0x31] = (2, "AND", self.indirect_y_mode)
self.ops[0x35] = (2, "AND", self.zero_page_x_mode)
self.ops[0x36] = (2, "ROL", self.zero_page_x_mode)
self.ops[0x38] = (1, "SEC", )
self.ops[0x39] = (3, "AND", self.absolute_y_mode)
self.ops[0x3D] = (3, "AND", self.absolute_x_mode)
self.ops[0x3E] = (3, "ROL", self.absolute_x_mode)
self.ops[0x40] = (1, "RTI", )
self.ops[0x41] = (2, "EOR", self.indirect_x_mode)
self.ops[0x45] = (2, "EOR", self.zero_page_mode)
self.ops[0x46] = (2, "LSR", self.zero_page_mode)
self.ops[0x48] = (1, "PHA", )
self.ops[0x49] = (2, "EOR", self.immediate_mode)
self.ops[0x4A] = (1, "LSR", )
self.ops[0x4C] = (3, "JMP", self.absolute_mode)
self.ops[0x4D] = (3, "EOR", self.absolute_mode)
self.ops[0x4E] = (3, "LSR", self.absolute_mode)
self.ops[0x50] = (2, "BVC", self.relative_mode)
self.ops[0x51] = (2, "EOR", self.indirect_y_mode)
self.ops[0x55] = (2, "EOR", self.zero_page_x_mode)
self.ops[0x56] = (2, "LSR", self.zero_page_x_mode)
self.ops[0x58] = (1, "CLI", )
self.ops[0x59] = (3, "EOR", self.absolute_y_mode)
self.ops[0x5D] = (3, "EOR", self.absolute_x_mode)
self.ops[0x5E] = (3, "LSR", self.absolute_x_mode)
self.ops[0x60] = (1, "RTS", )
self.ops[0x61] = (2, "ADC", self.indirect_x_mode)
self.ops[0x65] = (2, "ADC", self.zero_page_mode)
self.ops[0x66] = (2, "ROR", self.zero_page_mode)
self.ops[0x68] = (1, "PLA", )
self.ops[0x69] = (2, "ADC", self.immediate_mode)
self.ops[0x6A] = (1, "ROR", )
self.ops[0x6C] = (3, "JMP", self.indirect_mode)
self.ops[0x6D] = (3, "ADC", self.absolute_mode)
self.ops[0x6E] = (3, "ROR", self.absolute_mode)
self.ops[0x70] = (2, "BVS", self.relative_mode)
self.ops[0x71] = (2, "ADC", self.indirect_y_mode)
self.ops[0x75] = (2, "ADC", self.zero_page_x_mode)
self.ops[0x76] = (2, "ROR", self.zero_page_x_mode)
self.ops[0x78] = (1, "SEI", )
self.ops[0x79] = (3, "ADC", self.absolute_y_mode)
self.ops[0x7D] = (3, "ADC", self.absolute_x_mode)
self.ops[0x7E] = (3, "ROR", self.absolute_x_mode)
self.ops[0x81] = (2, "STA", self.indirect_x_mode)
self.ops[0x84] = (2, "STY", self.zero_page_mode)
self.ops[0x85] = (2, "STA", self.zero_page_mode)
self.ops[0x86] = (2, "STX", self.zero_page_mode)
self.ops[0x88] = (1, "DEY", )
self.ops[0x8A] = (1, "TXA", )
self.ops[0x8C] = (3, "STY", self.absolute_mode)
self.ops[0x8D] = (3, "STA", self.absolute_mode)
self.ops[0x8E] = (3, "STX", self.absolute_mode)
self.ops[0x90] = (2, "BCC", self.relative_mode)
self.ops[0x91] = (2, "STA", self.indirect_y_mode)
self.ops[0x94] = (2, "STY", self.zero_page_x_mode)
self.ops[0x95] = (2, "STA", self.zero_page_x_mode)
self.ops[0x96] = (2, "STX", self.zero_page_y_mode)
self.ops[0x98] = (1, "TYA", )
self.ops[0x99] = (3, "STA", self.absolute_y_mode)
self.ops[0x9A] = (1, "TXS", )
self.ops[0x9D] = (3, "STA", self.absolute_x_mode)
self.ops[0xA0] = (2, "LDY", self.immediate_mode)
self.ops[0xA1] = (2, "LDA", self.indirect_x_mode)
self.ops[0xA2] = (2, "LDX", self.immediate_mode)
self.ops[0xA4] = (2, "LDY", self.zero_page_mode)
self.ops[0xA5] = (2, "LDA", self.zero_page_mode)
self.ops[0xA6] = (2, "LDX", self.zero_page_mode)
self.ops[0xA8] = (1, "TAY", )
self.ops[0xA9] = (2, "LDA", self.immediate_mode)
self.ops[0xAA] = (1, "TAX", )
self.ops[0xAC] = (3, "LDY", self.absolute_mode)
self.ops[0xAD] = (3, "LDA", self.absolute_mode)
self.ops[0xAE] = (3, "LDX", self.absolute_mode)
self.ops[0xB0] = (2, "BCS", self.relative_mode)
self.ops[0xB1] = (2, "LDA", self.indirect_y_mode)
self.ops[0xB4] = (2, "LDY", self.zero_page_x_mode)
self.ops[0xB5] = (2, "LDA", self.zero_page_x_mode)
self.ops[0xB6] = (2, "LDX", self.zero_page_y_mode)
self.ops[0xB8] = (1, "CLV", )
self.ops[0xB9] = (3, "LDA", self.absolute_y_mode)
self.ops[0xBA] = (1, "TSX", )
self.ops[0xBC] = (3, "LDY", self.absolute_x_mode)
self.ops[0xBD] = (3, "LDA", self.absolute_x_mode)
self.ops[0xBE] = (3, "LDX", self.absolute_y_mode)
self.ops[0xC0] = (2, "CPY", self.immediate_mode)
self.ops[0xC1] = (2, "CMP", self.indirect_x_mode)
self.ops[0xC4] = (2, "CPY", self.zero_page_mode)
self.ops[0xC5] = (2, "CMP", self.zero_page_mode)
self.ops[0xC6] = (2, "DEC", self.zero_page_mode)
self.ops[0xC8] = (1, "INY", )
self.ops[0xC9] = (2, "CMP", self.immediate_mode)
self.ops[0xCA] = (1, "DEX", )
self.ops[0xCC] = (3, "CPY", self.absolute_mode)
self.ops[0xCD] = (3, "CMP", self.absolute_mode)
self.ops[0xCE] = (3, "DEC", self.absolute_mode)
self.ops[0xD0] = (2, "BNE", self.relative_mode)
self.ops[0xD1] = (2, "CMP", self.indirect_y_mode)
self.ops[0xD5] = (2, "CMP", self.zero_page_x_mode)
self.ops[0xD6] = (2, "DEC", self.zero_page_x_mode)
self.ops[0xD8] = (1, "CLD", )
self.ops[0xD9] = (3, "CMP", self.absolute_y_mode)
self.ops[0xDD] = (3, "CMP", self.absolute_x_mode)
self.ops[0xDE] = (3, "DEC", self.absolute_x_mode)
self.ops[0xE0] = (2, "CPX", self.immediate_mode)
self.ops[0xE1] = (2, "SBC", self.indirect_x_mode)
self.ops[0xE4] = (2, "CPX", self.zero_page_mode)
self.ops[0xE5] = (2, "SBC", self.zero_page_mode)
self.ops[0xE6] = (2, "INC", self.zero_page_mode)
self.ops[0xE8] = (1, "INX", )
self.ops[0xE9] = (2, "SBC", self.immediate_mode)
self.ops[0xEA] = (1, "NOP", )
self.ops[0xEC] = (3, "CPX", self.absolute_mode)
self.ops[0xED] = (3, "SBC", self.absolute_mode)
self.ops[0xEE] = (3, "INC", self.absolute_mode)
self.ops[0xF0] = (2, "BEQ", self.relative_mode)
self.ops[0xF1] = (2, "SBC", self.indirect_y_mode)
self.ops[0xF5] = (2, "SBC", self.zero_page_x_mode)
self.ops[0xF6] = (2, "INC", self.zero_page_x_mode)
self.ops[0xF8] = (1, "SED", )
self.ops[0xF9] = (3, "SBC", self.absolute_y_mode)
self.ops[0xFD] = (3, "SBC", self.absolute_x_mode)
self.ops[0xFE] = (3, "INC", self.absolute_x_mode)
class CPU6502(BaseCPU):
def __init__(self, *args, **kwargs):
super(CPU6502, self).__init__(*args, **kwargs)
self.stack_pointer = 0xFF
def setup_ops(self):
self.ops = [None] * 0x100
self.ops[0x00] = lambda: self.BRK()
self.ops[0x01] = lambda: self.ORA(self.indirect_x_mode())
self.ops[0x05] = lambda: self.ORA(self.zero_page_mode())
self.ops[0x06] = lambda: self.ASL(self.zero_page_mode())
self.ops[0x08] = lambda: self.PHP()
self.ops[0x09] = lambda: self.ORA(self.immediate_mode())
self.ops[0x0A] = lambda: self.ASL()
self.ops[0x0D] = lambda: self.ORA(self.absolute_mode())
self.ops[0x0E] = lambda: self.ASL(self.absolute_mode())
self.ops[0x10] = lambda: self.BPL(self.relative_mode())
self.ops[0x11] = lambda: self.ORA(self.indirect_y_mode())
self.ops[0x15] = lambda: self.ORA(self.zero_page_x_mode())
self.ops[0x16] = lambda: self.ASL(self.zero_page_x_mode())
self.ops[0x18] = lambda: self.CLC()
self.ops[0x19] = lambda: self.ORA(self.absolute_y_mode())
self.ops[0x1D] = lambda: self.ORA(self.absolute_x_mode())
self.ops[0x1E] = lambda: self.ASL(self.absolute_x_mode(rmw=True))
self.ops[0x20] = lambda: self.JSR(self.absolute_mode())
self.ops[0x21] = lambda: self.AND(self.indirect_x_mode())
self.ops[0x24] = lambda: self.BIT(self.zero_page_mode())
self.ops[0x25] = lambda: self.AND(self.zero_page_mode())
self.ops[0x26] = lambda: self.ROL(self.zero_page_mode())
self.ops[0x28] = lambda: self.PLP()
self.ops[0x29] = lambda: self.AND(self.immediate_mode())
self.ops[0x2A] = lambda: self.ROL()
self.ops[0x2C] = lambda: self.BIT(self.absolute_mode())
self.ops[0x2D] = lambda: self.AND(self.absolute_mode())
self.ops[0x2E] = lambda: self.ROL(self.absolute_mode())
self.ops[0x30] = lambda: self.BMI(self.relative_mode())
self.ops[0x31] = lambda: self.AND(self.indirect_y_mode())
self.ops[0x35] = lambda: self.AND(self.zero_page_x_mode())
self.ops[0x36] = lambda: self.ROL(self.zero_page_x_mode())
self.ops[0x38] = lambda: self.SEC()
self.ops[0x39] = lambda: self.AND(self.absolute_y_mode())
self.ops[0x3D] = lambda: self.AND(self.absolute_x_mode())
self.ops[0x3E] = lambda: self.ROL(self.absolute_x_mode(rmw=True))
self.ops[0x40] = lambda: self.RTI()
self.ops[0x41] = lambda: self.EOR(self.indirect_x_mode())
self.ops[0x45] = lambda: self.EOR(self.zero_page_mode())
self.ops[0x46] = lambda: self.LSR(self.zero_page_mode())
self.ops[0x48] = lambda: self.PHA()
self.ops[0x49] = lambda: self.EOR(self.immediate_mode())
self.ops[0x4A] = lambda: self.LSR()
self.ops[0x4C] = lambda: self.JMP(self.absolute_mode())
self.ops[0x4D] = lambda: self.EOR(self.absolute_mode())
self.ops[0x4E] = lambda: self.LSR(self.absolute_mode())
self.ops[0x50] = lambda: self.BVC(self.relative_mode())
self.ops[0x51] = lambda: self.EOR(self.indirect_y_mode())
self.ops[0x55] = lambda: self.EOR(self.zero_page_x_mode())
self.ops[0x56] = lambda: self.LSR(self.zero_page_x_mode())
self.ops[0x58] = lambda: self.CLI()
self.ops[0x59] = lambda: self.EOR(self.absolute_y_mode())
self.ops[0x5D] = lambda: self.EOR(self.absolute_x_mode())
self.ops[0x5E] = lambda: self.LSR(self.absolute_x_mode(rmw=True))
self.ops[0x60] = lambda: self.RTS()
self.ops[0x61] = lambda: self.ADC(self.indirect_x_mode())
self.ops[0x65] = lambda: self.ADC(self.zero_page_mode())
self.ops[0x66] = lambda: self.ROR(self.zero_page_mode())
self.ops[0x68] = lambda: self.PLA()
self.ops[0x69] = lambda: self.ADC(self.immediate_mode())
self.ops[0x6A] = lambda: self.ROR()
self.ops[0x6C] = lambda: self.JMP(self.indirect_mode())
self.ops[0x6D] = lambda: self.ADC(self.absolute_mode())
self.ops[0x6E] = lambda: self.ROR(self.absolute_mode())
self.ops[0x70] = lambda: self.BVS(self.relative_mode())
self.ops[0x71] = lambda: self.ADC(self.indirect_y_mode())
self.ops[0x75] = lambda: self.ADC(self.zero_page_x_mode())
self.ops[0x76] = lambda: self.ROR(self.zero_page_x_mode())
self.ops[0x78] = lambda: self.SEI()
self.ops[0x79] = lambda: self.ADC(self.absolute_y_mode())
self.ops[0x7D] = lambda: self.ADC(self.absolute_x_mode())
self.ops[0x7E] = lambda: self.ROR(self.absolute_x_mode(rmw=True))
self.ops[0x81] = lambda: self.STA(self.indirect_x_mode())
self.ops[0x84] = lambda: self.STY(self.zero_page_mode())
self.ops[0x85] = lambda: self.STA(self.zero_page_mode())
self.ops[0x86] = lambda: self.STX(self.zero_page_mode())
self.ops[0x88] = lambda: self.DEY()
self.ops[0x8A] = lambda: self.TXA()
self.ops[0x8C] = lambda: self.STY(self.absolute_mode())
self.ops[0x8D] = lambda: self.STA(self.absolute_mode())
self.ops[0x8E] = lambda: self.STX(self.absolute_mode())
self.ops[0x90] = lambda: self.BCC(self.relative_mode())
self.ops[0x91] = lambda: self.STA(self.indirect_y_mode(rmw=True))
self.ops[0x94] = lambda: self.STY(self.zero_page_x_mode())
self.ops[0x95] = lambda: self.STA(self.zero_page_x_mode())
self.ops[0x96] = lambda: self.STX(self.zero_page_y_mode())
self.ops[0x98] = lambda: self.TYA()
self.ops[0x99] = lambda: self.STA(self.absolute_y_mode(rmw=True))
self.ops[0x9A] = lambda: self.TXS()
self.ops[0x9D] = lambda: self.STA(self.absolute_x_mode(rmw=True))
self.ops[0xA0] = lambda: self.LDY(self.immediate_mode())
self.ops[0xA1] = lambda: self.LDA(self.indirect_x_mode())
self.ops[0xA2] = lambda: self.LDX(self.immediate_mode())
self.ops[0xA4] = lambda: self.LDY(self.zero_page_mode())
self.ops[0xA5] = lambda: self.LDA(self.zero_page_mode())
self.ops[0xA6] = lambda: self.LDX(self.zero_page_mode())
self.ops[0xA8] = lambda: self.TAY()
self.ops[0xA9] = lambda: self.LDA(self.immediate_mode())
self.ops[0xAA] = lambda: self.TAX()
self.ops[0xAC] = lambda: self.LDY(self.absolute_mode())
self.ops[0xAD] = lambda: self.LDA(self.absolute_mode())
self.ops[0xAE] = lambda: self.LDX(self.absolute_mode())
self.ops[0xB0] = lambda: self.BCS(self.relative_mode())
self.ops[0xB1] = lambda: self.LDA(self.indirect_y_mode())
self.ops[0xB4] = lambda: self.LDY(self.zero_page_x_mode())
self.ops[0xB5] = lambda: self.LDA(self.zero_page_x_mode())
self.ops[0xB6] = lambda: self.LDX(self.zero_page_y_mode())
self.ops[0xB8] = lambda: self.CLV()
self.ops[0xB9] = lambda: self.LDA(self.absolute_y_mode())
self.ops[0xBA] = lambda: self.TSX()
self.ops[0xBC] = lambda: self.LDY(self.absolute_x_mode())
self.ops[0xBD] = lambda: self.LDA(self.absolute_x_mode())
self.ops[0xBE] = lambda: self.LDX(self.absolute_y_mode())
self.ops[0xC0] = lambda: self.CPY(self.immediate_mode())
self.ops[0xC1] = lambda: self.CMP(self.indirect_x_mode())
self.ops[0xC4] = lambda: self.CPY(self.zero_page_mode())
self.ops[0xC5] = lambda: self.CMP(self.zero_page_mode())
self.ops[0xC6] = lambda: self.DEC(self.zero_page_mode())
self.ops[0xC8] = lambda: self.INY()
self.ops[0xC9] = lambda: self.CMP(self.immediate_mode())
self.ops[0xCA] = lambda: self.DEX()
self.ops[0xCC] = lambda: self.CPY(self.absolute_mode())
self.ops[0xCD] = lambda: self.CMP(self.absolute_mode())
self.ops[0xCE] = lambda: self.DEC(self.absolute_mode())
self.ops[0xD0] = lambda: self.BNE(self.relative_mode())
self.ops[0xD1] = lambda: self.CMP(self.indirect_y_mode())
self.ops[0xD5] = lambda: self.CMP(self.zero_page_x_mode())
self.ops[0xD6] = lambda: self.DEC(self.zero_page_x_mode())
self.ops[0xD8] = lambda: self.CLD()
self.ops[0xD9] = lambda: self.CMP(self.absolute_y_mode())
self.ops[0xDD] = lambda: self.CMP(self.absolute_x_mode())
self.ops[0xDE] = lambda: self.DEC(self.absolute_x_mode(rmw=True))
self.ops[0xE0] = lambda: self.CPX(self.immediate_mode())
self.ops[0xE1] = lambda: self.SBC(self.indirect_x_mode())
self.ops[0xE4] = lambda: self.CPX(self.zero_page_mode())
self.ops[0xE5] = lambda: self.SBC(self.zero_page_mode())
self.ops[0xE6] = lambda: self.INC(self.zero_page_mode())
self.ops[0xE8] = lambda: self.INX()
self.ops[0xE9] = lambda: self.SBC(self.immediate_mode())
self.ops[0xEA] = lambda: self.NOP()
self.ops[0xEC] = lambda: self.CPX(self.absolute_mode())
self.ops[0xED] = lambda: self.SBC(self.absolute_mode())
self.ops[0xEE] = lambda: self.INC(self.absolute_mode())
self.ops[0xF0] = lambda: self.BEQ(self.relative_mode())
self.ops[0xF1] = lambda: self.SBC(self.indirect_y_mode())
self.ops[0xF5] = lambda: self.SBC(self.zero_page_x_mode())
self.ops[0xF6] = lambda: self.INC(self.zero_page_x_mode())
self.ops[0xF8] = lambda: self.SED()
self.ops[0xF9] = lambda: self.SBC(self.absolute_y_mode())
self.ops[0xFD] = lambda: self.SBC(self.absolute_x_mode())
self.ops[0xFE] = lambda: self.INC(self.absolute_x_mode(rmw=True))
def usage():
print >>sys.stderr, "ApplePy - an Apple ][ emulator in Python"
print >>sys.stderr, "James Tauber / http://jtauber.com/"
print >>sys.stderr
print >>sys.stderr, "Usage: cpu6502.py [options]"
print >>sys.stderr
print >>sys.stderr, " -b, --bus Bus port number"
print >>sys.stderr, " -p, --pc Initial PC value"
print >>sys.stderr, " -R, --rom ROM file to use (default A2ROM.BIN)"
print >>sys.stderr, " -r, --ram RAM file to load (default none)"
sys.exit(1)
def get_options():
class Options:
def __init__(self):
self.rom = "A2ROM.BIN"
self.ram = None
self.bus = None
self.pc = None
options = Options()
a = 1
while a < len(sys.argv):
if sys.argv[a].startswith("-"):
if sys.argv[a] in ("-b", "--bus"):
a += 1
options.bus_port = 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
options.rom = sys.argv[a]
elif sys.argv[a] in ("-r", "--ram"):
a += 1
options.ram = sys.argv[a]
else:
usage()
else:
usage()
a += 1
return options
if __name__ == "__main__":
options = get_options()
if options.bus_port is None:
print "ApplePy cpu core"
print "Run applepy.py instead"
sys.exit(0)
cfg = Apple2Config()
bus = socket.socket()
bus_address = (cfg.LOCAL_HOST_IP, options.bus_port)
print "bus I/O connect to %s" % repr(bus_address)
bus.connect(bus_address)
mem = Memory(cfg, bus, RAM, ROM, options)
cpu = CPU6502(cfg, bus, options, mem, Disassemble6809)
cpu.run()

View File

@ -14,6 +14,10 @@ import subprocess
import sys
import time
import wave
import os
from apple2.apple2config import Apple2Config
from generic.base_machine import BaseMachine
class Display:
@ -362,76 +366,10 @@ class SoftSwitches:
return 0x00
class Apple2:
class Apple2(BaseMachine):
pass
def __init__(self, options, display, speaker, cassette):
self.display = display
self.speaker = speaker
self.softswitches = SoftSwitches(display, speaker, cassette)
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,
]
if options.ram:
args.extend([
"--ram", options.ram,
])
if options.pc is not None:
args.extend([
"--pc", str(options.pc),
])
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):
update_cycle = 0
quit = False
while not quit:
op = self.cpu.recv(8)
if len(op) == 0:
break
cycle, rw, addr, val = struct.unpack("<IBHB", op)
if rw == 0:
self.cpu.send(chr(self.softswitches.read_byte(cycle, addr)))
elif rw == 1:
self.display.update(addr, val)
else:
break
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit = True
if event.type == pygame.KEYDOWN:
key = ord(event.unicode) if event.unicode else 0
if event.key == pygame.K_LEFT:
key = 0x08
if event.key == pygame.K_RIGHT:
key = 0x15
if key:
if key == 0x7F:
key = 0x08
self.softswitches.kbd = 0x80 + (key & 0x7F)
update_cycle += 1
if update_cycle >= 1024:
self.display.flash()
pygame.display.flip()
if self.speaker:
self.speaker.update(cycle)
update_cycle = 0
def usage():
@ -485,10 +423,14 @@ def get_options():
if __name__ == "__main__":
cfg = Apple2Config()
options = get_options()
display = Display()
speaker = None if options.quiet else Speaker()
cassette = Cassette(options.cassette) if options.cassette else None
apple = Apple2(options, display, speaker, cassette)
softswitches = SoftSwitches(display, speaker, cassette)
apple = Apple2(cfg, options, display, speaker, softswitches)
apple.run()

1230
cpu6502.py

File diff suppressed because it is too large Load Diff

40
dragonpy.py Normal file
View File

@ -0,0 +1,40 @@
"""
=== Dragon 32 emulator in Python
Some links:
* http://www.burgins.com/m6809.html
* http://dragondata.worldofdragon.org/Publications/inside-dragon.htm
* http://mamedev.org/source/src/mess/drivers/dragon.c.html
* http://mamedev.org/source/src/mess/machine/dragon.c.html
* http://koti.mbnet.fi/~atjs/mc6809/
* http://www.colorcomputerarchive.com/coco/Documents/Manuals/Programming/6502-6809Translator%20%28Computer%20Systems%20Consultants%29.pdf
Dragon 32 resources:
* Forum: http://archive.worldofdragon.org/phpBB3/index.php
* Wiki: http://archive.worldofdragon.org/index.php?title=Main_Page
Dragon 32 Emulator that works:
* http://archive.worldofdragon.org/index.php?title=Emulation
"""
from applepy import get_options, Display
from Dragon32.dragon32config import Dragon32Config
from generic.base_machine import BaseMachine
class Dragon32(BaseMachine):
pass
if __name__ == "__main__":
cfg = Dragon32Config()
options = get_options()
display = Display()
speaker = None
cassette = None
apple = Dragon32(cfg, options, display, speaker, cassette)
apple.run()

0
generic/__init__.py Normal file
View File

85
generic/base_machine.py Normal file
View File

@ -0,0 +1,85 @@
import socket
import sys
import subprocess
import select
import struct
import pygame
class BaseMachine(object):
def __init__(self, cfg, options, display, speaker, softswitches):
self.cfg = cfg
self.display = display
self.speaker = speaker
self.softswitches = softswitches
listener = socket.socket()
listener.bind((self.cfg.LOCAL_HOST_IP, 0))
listener.listen(0)
bus_port = listener.getsockname()[1]
print "bus I/O listen on %s:%s" % (self.cfg.LOCAL_HOST_IP, bus_port)
cpu_script = cfg.get_cpu_script()
args = [
sys.executable,
cpu_script,
"--bus", str(bus_port),
"--rom", options.rom,
]
if options.ram:
args.extend([
"--ram", options.ram,
])
if options.pc is not None:
args.extend([
"--pc", str(options.pc),
])
self.core = subprocess.Popen(args)
rs, _, _ = select.select([listener], [], [], 2)
if not rs:
print >> sys.stderr, "CPU module did not start '%s'" % " ".join(args)
sys.exit(1)
self.cpu, _ = listener.accept()
def run(self):
sys.stdout.flush()
update_cycle = 0
quit = False
while not quit:
op = self.cpu.recv(8)
if len(op) == 0:
break
cycle, rw, addr, val = struct.unpack("<IBHB", op)
if rw == 0:
self.cpu.send(chr(self.softswitches.read_byte(cycle, addr)))
elif rw == 1:
self.display.update(addr, val)
else:
break
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit = True
if event.type == pygame.KEYDOWN:
key = ord(event.unicode) if event.unicode else 0
if event.key == pygame.K_LEFT:
key = self.cfg.KEY_LEFT
if event.key == pygame.K_RIGHT:
key = self.cfg.KEY_RIGHT
if key:
if key == 0x7F:
key = self.cfg.KEY_LEFT
self.softswitches.kbd = 0x80 + (key & 0x7F)
update_cycle += 1
if update_cycle >= 1024:
self.display.flash()
pygame.display.flip()
if self.speaker:
self.speaker.update(cycle)
update_cycle = 0

89
generic/base_memory.py Normal file
View File

@ -0,0 +1,89 @@
import sys
import socket
import struct
class ROMBase(object):
def __init__(self, start, size):
self.start = start
self.end = start + size - 1
self._mem = [0x00] * size
def load(self, address, data):
for offset, datum in enumerate(data):
self._mem[address - self.start + offset] = datum
def load_file(self, address, filename):
with open(filename, "rb") as f:
for offset, datum in enumerate(f.read()):
index = address - self.start + offset
try:
self._mem[index] = ord(datum)
except IndexError:
raise IndexError("ROM file %s bigger than: %s" % (filename, hex(index)))
def read_byte(self, address):
assert self.start <= address <= self.end, "Read %s from %s is not in range %s-%s" % (hex(address), self.__class__.__name__, hex(self.start), hex(self.end))
return self._mem[address - self.start]
class RAMBase(ROMBase):
def write_byte(self, address, value):
self._mem[address] = value
class MemoryBase(object):
def __init__(self, cfg, bus, ram_class, rom_class, options=None, use_bus=True):
self.cfg = cfg
if use_bus:
self.bus = bus
self.use_bus = use_bus
self.rom = rom_class(self.cfg.ROM_START, self.cfg.ROM_SIZE)
if options:
self.rom.load_file(self.cfg.ROM_START, options.rom)
self.ram = ram_class(self.cfg.RAM_START, self.cfg.RAM_SIZE)
if options and options.ram:
self.ram.load_file(self.cfg.RAM_START, options.ram)
def load(self, address, data):
if address < self.cfg.RAM_SIZE:
self.ram.load(address, data)
def read_byte(self, cycle, address):
if address < self.cfg.RAM_SIZE:
return self.ram.read_byte(address)
elif address < self.cfg.ROM_START:
return self.bus_read(cycle, address)
else:
return self.rom.read_byte(address)
def read_word(self, cycle, address):
return self.read_byte(cycle, address) + (self.read_byte(cycle + 1, address + 1) << 8)
def bus_read(self, cycle, address):
if not self.use_bus:
return 0
op = struct.pack("<IBHB", cycle, 0, address, 0)
try:
self.bus.send(op)
b = self.bus.recv(1)
if len(b) == 0:
sys.exit(0)
return ord(b)
except socket.error:
sys.exit(0)
def bus_write(self, cycle, address, value):
if not self.use_bus:
return
op = struct.pack("<IBHB", cycle, 1, address, value)
try:
self.bus.send(op)
except IOError:
sys.exit(0)

666
generic/cpu.py Normal file
View File

@ -0,0 +1,666 @@
import BaseHTTPServer
import re
import json
import select
import sys
def signed(x):
if x > 0x7F:
x = x - 0x100
return x
class ControlHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def __init__(self, request, client_address, server, cpu, disassemble):
self.cpu = cpu
self.disassemble = disassemble
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, disassemble):
self.cpu = cpu
self.disassemble = disassemble
def __call__(self, request, client_address, server):
return ControlHandler(
request, client_address, server, self.cpu, self.disassemble
)
class BaseCPU(object):
def __init__(self, cfg, bus, options, memory, DisassembleClass):
self.cfg = cfg
self.bus = bus
self.memory = memory
disassemble = DisassembleClass(self, memory)
self.control_server = BaseHTTPServer.HTTPServer(
(self.cfg.LOCAL_HOST_IP, self.cfg.HTTPSERVER_PORT),
ControlHandlerFactory(self, disassemble)
)
self.accumulator = 0x00
self.x_index = 0x00
self.y_index = 0x00
self.carry_flag = 0
self.zero_flag = 0
self.interrupt_disable_flag = 0
self.decimal_mode_flag = 0
self.break_flag = 1
self.overflow_flag = 0
self.sign_flag = 0
self.cycles = 0
self.setup_ops()
self.reset()
if options.pc is not None:
self.program_counter = options.pc
self.running = True
self.quit = False
def reset(self):
self.program_counter = self.read_word(self.cfg.RESET_VECTOR)
def run(self):
sys.stdout.flush()
while not self.quit:
timeout = 0
if not self.running:
timeout = 1
# Currently this handler blocks from the moment
# 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):
self.program_counter = start
while True:
self.cycles += 2 # all instructions take this as a minimum
if self.program_counter == end:
break
op = self.read_pc_byte()
func = self.ops[op]
if func is None:
print "UNKNOWN OP"
print hex(self.program_counter - 1)
print hex(op)
break
else:
self.ops[op]()
####
def get_pc(self, inc=1):
pc = self.program_counter
self.program_counter += inc
return pc
def read_byte(self, address):
return self.memory.read_byte(self.cycles, address)
def read_word(self, address):
return self.memory.read_word(self.cycles, address)
def read_word_bug(self, address):
return self.memory.read_word_bug(self.cycles, address)
def read_pc_byte(self):
return self.read_byte(self.get_pc())
def read_pc_word(self):
return self.read_word(self.get_pc(2))
def write_byte(self, address, value):
self.memory.write_byte(self.cycles, address, value)
####
def status_from_byte(self, status):
self.carry_flag = [0, 1][0 != status & 1]
self.zero_flag = [0, 1][0 != status & 2]
self.interrupt_disable_flag = [0, 1][0 != status & 4]
self.decimal_mode_flag = [0, 1][0 != status & 8]
self.break_flag = [0, 1][0 != status & 16]
self.overflow_flag = [0, 1][0 != status & 64]
self.sign_flag = [0, 1][0 != status & 128]
def status_as_byte(self):
return self.carry_flag | self.zero_flag << 1 | self.interrupt_disable_flag << 2 | self.decimal_mode_flag << 3 | self.break_flag << 4 | 1 << 5 | self.overflow_flag << 6 | self.sign_flag << 7
####
def push_byte(self, byte):
self.write_byte(self.cfg.STACK_PAGE + self.stack_pointer, byte)
self.stack_pointer = (self.stack_pointer - 1) % 0x100
def pull_byte(self):
self.stack_pointer = (self.stack_pointer + 1) % 0x100
return self.read_byte(self.cfg.STACK_PAGE + self.stack_pointer)
def push_word(self, word):
hi, lo = divmod(word, 0x100)
self.push_byte(hi)
self.push_byte(lo)
def pull_word(self):
s = self.cfg.STACK_PAGE + self.stack_pointer + 1
self.stack_pointer += 2
return self.read_word(s)
####
def immediate_mode(self):
return self.get_pc()
def absolute_mode(self):
self.cycles += 2
return self.read_pc_word()
def absolute_x_mode(self, rmw=False):
if rmw:
self.cycles += 1
return self.absolute_mode() + self.x_index
def absolute_y_mode(self, rmw=False):
if rmw:
self.cycles += 1
return self.absolute_mode() + self.y_index
def zero_page_mode(self):
self.cycles += 1
return self.read_pc_byte()
def zero_page_x_mode(self):
self.cycles += 1
return (self.zero_page_mode() + self.x_index) % 0x100
def zero_page_y_mode(self):
self.cycles += 1
return (self.zero_page_mode() + self.y_index) % 0x100
def indirect_mode(self):
self.cycles += 2
return self.read_word_bug(self.absolute_mode())
def indirect_x_mode(self):
self.cycles += 4
return self.read_word_bug((self.read_pc_byte() + self.x_index) % 0x100)
def indirect_y_mode(self, rmw=False):
if rmw:
self.cycles += 4
else:
self.cycles += 3
return self.read_word_bug(self.read_pc_byte()) + self.y_index
def relative_mode(self):
pc = self.get_pc()
return pc + 1 + signed(self.read_byte(pc))
####
def update_nz(self, value):
value = value % 0x100
self.zero_flag = [0, 1][(value == 0)]
self.sign_flag = [0, 1][((value & 0x80) != 0)]
return value
def update_nzc(self, value):
self.carry_flag = [0, 1][(value > 0xFF)]
return self.update_nz(value)
####
# LOAD / STORE
def LDA(self, operand_address):
self.accumulator = self.update_nz(self.read_byte(operand_address))
def LDX(self, operand_address):
self.x_index = self.update_nz(self.read_byte(operand_address))
def LDY(self, operand_address):
self.y_index = self.update_nz(self.read_byte(operand_address))
def STA(self, operand_address):
self.write_byte(operand_address, self.accumulator)
def STX(self, operand_address):
self.write_byte(operand_address, self.x_index)
def STY(self, operand_address):
self.write_byte(operand_address, self.y_index)
# TRANSFER
def TAX(self):
self.x_index = self.update_nz(self.accumulator)
def TXA(self):
self.accumulator = self.update_nz(self.x_index)
def TAY(self):
self.y_index = self.update_nz(self.accumulator)
def TYA(self):
self.accumulator = self.update_nz(self.y_index)
def TSX(self):
self.x_index = self.update_nz(self.stack_pointer)
def TXS(self):
self.stack_pointer = self.x_index
# SHIFTS / ROTATES
def ASL(self, operand_address=None):
if operand_address is None:
self.accumulator = self.update_nzc(self.accumulator << 1)
else:
self.cycles += 2
self.write_byte(operand_address, self.update_nzc(self.read_byte(operand_address) << 1))
def ROL(self, operand_address=None):
if operand_address is None:
a = self.accumulator << 1
if self.carry_flag:
a = a | 0x01
self.accumulator = self.update_nzc(a)
else:
self.cycles += 2
m = self.read_byte(operand_address) << 1
if self.carry_flag:
m = m | 0x01
self.write_byte(operand_address, self.update_nzc(m))
def ROR(self, operand_address=None):
if operand_address is None:
if self.carry_flag:
self.accumulator = self.accumulator | 0x100
self.carry_flag = self.accumulator % 2
self.accumulator = self.update_nz(self.accumulator >> 1)
else:
self.cycles += 2
m = self.read_byte(operand_address)
if self.carry_flag:
m = m | 0x100
self.carry_flag = m % 2
self.write_byte(operand_address, self.update_nz(m >> 1))
def LSR(self, operand_address=None):
if operand_address is None:
self.carry_flag = self.accumulator % 2
self.accumulator = self.update_nz(self.accumulator >> 1)
else:
self.cycles += 2
self.carry_flag = self.read_byte(operand_address) % 2
self.write_byte(operand_address, self.update_nz(self.read_byte(operand_address) >> 1))
# JUMPS / RETURNS
def JMP(self, operand_address):
self.cycles -= 1
self.program_counter = operand_address
def JSR(self, operand_address):
self.cycles += 2
self.push_word(self.program_counter - 1)
self.program_counter = operand_address
def RTS(self):
self.cycles += 4
self.program_counter = self.pull_word() + 1
# BRANCHES
def BCC(self, operand_address):
if not self.carry_flag:
self.cycles += 1
self.program_counter = operand_address
def BCS(self, operand_address):
if self.carry_flag:
self.cycles += 1
self.program_counter = operand_address
def BEQ(self, operand_address):
if self.zero_flag:
self.cycles += 1
self.program_counter = operand_address
def BNE(self, operand_address):
if not self.zero_flag:
self.cycles += 1
self.program_counter = operand_address
def BMI(self, operand_address):
if self.sign_flag:
self.cycles += 1
self.program_counter = operand_address
def BPL(self, operand_address):
if not self.sign_flag:
self.cycles += 1
self.program_counter = operand_address
def BVC(self, operand_address):
if not self.overflow_flag:
self.cycles += 1
self.program_counter = operand_address
def BVS(self, operand_address):
if self.overflow_flag:
self.cycles += 1
self.program_counter = operand_address
# SET / CLEAR FLAGS
def CLC(self):
self.carry_flag = 0
def CLD(self):
self.decimal_mode_flag = 0
def CLI(self):
self.interrupt_disable_flag = 0
def CLV(self):
self.overflow_flag = 0
def SEC(self):
self.carry_flag = 1
def SED(self):
self.decimal_mode_flag = 1
def SEI(self):
self.interrupt_disable_flag = 1
# INCREMENT / DECREMENT
def DEC(self, operand_address):
self.cycles += 2
self.write_byte(operand_address, self.update_nz(self.read_byte(operand_address) - 1))
def DEX(self):
self.x_index = self.update_nz(self.x_index - 1)
def DEY(self):
self.y_index = self.update_nz(self.y_index - 1)
def INC(self, operand_address):
self.cycles += 2
self.write_byte(operand_address, self.update_nz(self.read_byte(operand_address) + 1))
def INX(self):
self.x_index = self.update_nz(self.x_index + 1)
def INY(self):
self.y_index = self.update_nz(self.y_index + 1)
# PUSH / PULL
def PHA(self):
self.cycles += 1
self.push_byte(self.accumulator)
def PHP(self):
self.cycles += 1
self.push_byte(self.status_as_byte())
def PLA(self):
self.cycles += 2
self.accumulator = self.update_nz(self.pull_byte())
def PLP(self):
self.cycles += 2
self.status_from_byte(self.pull_byte())
# LOGIC
def AND(self, operand_address):
self.accumulator = self.update_nz(self.accumulator & self.read_byte(operand_address))
def ORA(self, operand_address):
self.accumulator = self.update_nz(self.accumulator | self.read_byte(operand_address))
def EOR(self, operand_address):
self.accumulator = self.update_nz(self.accumulator ^ self.read_byte(operand_address))
# ARITHMETIC
def ADC(self, operand_address):
# @@@ doesn't handle BCD yet
assert not self.decimal_mode_flag
a2 = self.accumulator
a1 = signed(a2)
m2 = self.read_byte(operand_address)
m1 = signed(m2)
# twos complement addition
result1 = a1 + m1 + self.carry_flag
# unsigned addition
result2 = a2 + m2 + self.carry_flag
self.accumulator = self.update_nzc(result2)
# perhaps this could be calculated from result2 but result1 is more intuitive
self.overflow_flag = [0, 1][(result1 > 127) | (result1 < -128)]
def SBC(self, operand_address):
# @@@ doesn't handle BCD yet
assert not self.decimal_mode_flag
a2 = self.accumulator
a1 = signed(a2)
m2 = self.read_byte(operand_address)
m1 = signed(m2)
# twos complement subtraction
result1 = a1 - m1 - [1, 0][self.carry_flag]
# unsigned subtraction
result2 = a2 - m2 - [1, 0][self.carry_flag]
self.accumulator = self.update_nz(result2)
self.carry_flag = [0, 1][(result2 >= 0)]
# perhaps this could be calculated from result2 but result1 is more intuitive
self.overflow_flag = [0, 1][(result1 > 127) | (result1 < -128)]
# BIT
def BIT(self, operand_address):
value = self.read_byte(operand_address)
self.sign_flag = ((value >> 7) % 2) # bit 7
self.overflow_flag = ((value >> 6) % 2) # bit 6
self.zero_flag = [0, 1][((self.accumulator & value) == 0)]
# COMPARISON
def CMP(self, operand_address):
result = self.accumulator - self.read_byte(operand_address)
self.carry_flag = [0, 1][(result >= 0)]
self.update_nz(result)
def CPX(self, operand_address):
result = self.x_index - self.read_byte(operand_address)
self.carry_flag = [0, 1][(result >= 0)]
self.update_nz(result)
def CPY(self, operand_address):
result = self.y_index - self.read_byte(operand_address)
self.carry_flag = [0, 1][(result >= 0)]
self.update_nz(result)
# SYSTEM
def NOP(self):
pass
def BRK(self):
self.cycles += 5
self.push_word(self.program_counter + 1)
self.push_byte(self.status_as_byte())
self.program_counter = self.read_word(0xFFFE)
self.break_flag = 1
def RTI(self):
self.cycles += 4
self.status_from_byte(self.pull_byte())
self.program_counter = self.pull_word()
# @@@ IRQ
# @@@ NMI

101
generic/disassembler.py Normal file
View File

@ -0,0 +1,101 @@
from generic.cpu import signed
class BaseDisassemble(object):
def __init__(self, cpu, memory):
self.cpu = cpu
self.memory = memory
self.setup_ops()
def absolute_mode(self, pc):
a = self.cpu.read_word(pc + 1)
return {
"operand": "$%04X" % a,
"memory": [a, 2, self.cpu.read_word(a)],
}
def absolute_x_mode(self, pc):
a = self.cpu.read_word(pc + 1)
e = a + self.cpu.x_index
return {
"operand": "$%04X,X" % a,
"memory": [e, 1, self.cpu.read_byte(e)],
}
def absolute_y_mode(self, pc):
a = self.cpu.read_word(pc + 1)
e = a + self.cpu.y_index
return {
"operand": "$%04X,Y" % a,
"memory": [e, 1, self.cpu.read_byte(e)],
}
def immediate_mode(self, pc):
return {
"operand": "#$%02X" % (self.cpu.read_byte(pc + 1)),
}
def indirect_mode(self, pc):
a = self.cpu.read_word(pc + 1)
return {
"operand": "($%04X)" % a,
"memory": [a, 2, self.cpu.read_word(a)],
}
def indirect_x_mode(self, pc):
z = self.cpu.read_byte(pc + 1)
a = self.cpu.read_word((z + self.cpu.x_index) % 0x100)
return {
"operand": "($%02X,X)" % z,
"memory": [a, 1, self.cpu.read_byte(a)],
}
def indirect_y_mode(self, pc):
z = self.cpu.read_byte(pc + 1)
a = self.cpu.read_word(z) + self.cpu.y_index
return {
"operand": "($%02X),Y" % z,
"memory": [a, 1, self.cpu.read_byte(a)],
}
def relative_mode(self, pc):
return {
"operand": "$%04X" % (pc + signed(self.cpu.read_byte(pc + 1) + 2)),
}
def zero_page_mode(self, pc):
a = self.cpu.read_byte(pc + 1)
return {
"operand": "$%02X" % a,
"memory": [a, 1, self.cpu.read_byte(a)],
}
def zero_page_x_mode(self, pc):
z = self.cpu.read_byte(pc + 1)
a = (z + self.cpu.x_index) % 0x100
return {
"operand": "$%02X,X" % z,
"memory": [a, 1, self.cpu.read_byte(a)],
}
def zero_page_y_mode(self, pc):
z = self.cpu.read_byte(pc + 1)
a = (z + self.cpu.y_index) % 0x100
return {
"operand": "$%02X,Y" % z,
"memory": [a, 1, self.cpu.read_byte(a)],
}
def disasm(self, pc):
op = self.cpu.read_byte(pc)
info = self.ops[op]
r = {
"address": pc,
"bytes": [self.cpu.read_byte(pc + i) for i in range(info[0])],
"mnemonic": info[1],
}
if len(info) > 2:
r.update(info[2](pc))
return r, info[0]

32
generic/generic_config.py Normal file
View File

@ -0,0 +1,32 @@
import inspect
import importlib
import os
class BaseConfig(object):
LOCAL_HOST_IP = "127.0.0.1"
def get_cpu_script(self):
cpu_module = importlib.import_module(self.CPU_MODULE)
cpu_module_path = cpu_module.__file__
# FIXME: Use .py instead of .pyc (if exist)
cpu_module_path = os.path.splitext(cpu_module_path)[0] + ".py"
return cpu_module_path
def print_debug_info(self):
print "Config: '%s'" % self.__class__.__name__
for name, value in inspect.getmembers(self): # , inspect.isdatadescriptor):
if name.startswith("_"):
continue
# print name, type(value)
if not isinstance(value, (int, basestring, list, tuple, dict)):
continue
if isinstance(value, (int,)):
print "%20s = %-4s (in hex: %7s)" % (
name, value, repr(hex(value))
)
else:
print "%20s = %s" % (name, value)

View File

@ -1,5 +1,5 @@
import unittest
from cpu6502 import Memory, CPU
from cpu6502 import Memory, CPU6502
class TestMemory(unittest.TestCase):
@ -26,7 +26,7 @@ class TestLoadStoreOperations(unittest.TestCase):
def setUp(self):
self.memory = Memory(use_bus=False)
self.cpu = CPU(self.memory)
self.cpu = CPU6502(self.memory)
self.memory.load(0x1000, [0x00, 0x01, 0x7F, 0x80, 0xFF])
def test_LDA(self):
@ -115,7 +115,7 @@ class TestRegisterTransferOperations(unittest.TestCase):
def setUp(self):
self.memory = Memory(use_bus=False)
self.cpu = CPU(self.memory)
self.cpu = CPU6502(self.memory)
def test_TAX(self):
self.cpu.accumulator = 0x00
@ -190,7 +190,7 @@ class TestStackOperations(unittest.TestCase):
def setUp(self):
self.memory = Memory(use_bus=False)
self.cpu = CPU(self.memory)
self.cpu = CPU6502(self.memory)
def test_TSX(self):
s = self.cpu.stack_pointer
@ -238,7 +238,7 @@ class TestLogicalOperations(unittest.TestCase):
def setUp(self):
self.memory = Memory(use_bus=False)
self.cpu = CPU(self.memory)
self.cpu = CPU6502(self.memory)
def test_AND(self):
self.memory.write_byte(None, 0x1000, 0x37)
@ -326,7 +326,7 @@ class TestArithmeticOperations(unittest.TestCase):
def setUp(self):
self.memory = Memory(use_bus=False)
self.cpu = CPU(self.memory)
self.cpu = CPU6502(self.memory)
def test_ADC_without_BCD(self):
@ -545,7 +545,7 @@ class TestIncrementDecrementOperations(unittest.TestCase):
def setUp(self):
self.memory = Memory(use_bus=False)
self.cpu = CPU(self.memory)
self.cpu = CPU6502(self.memory)
def test_INC(self):
self.memory.write_byte(None, 0x1000, 0x00)
@ -654,7 +654,7 @@ class TestShiftOperations(unittest.TestCase):
def setUp(self):
self.memory = Memory(use_bus=False)
self.cpu = CPU(self.memory)
self.cpu = CPU6502(self.memory)
def test_ASL(self):
self.cpu.accumulator = 0x01
@ -761,7 +761,7 @@ class TestJumpCallOperations(unittest.TestCase):
def setUp(self):
self.memory = Memory(use_bus=False)
self.cpu = CPU(self.memory)
self.cpu = CPU6502(self.memory)
def test_JMP(self):
self.cpu.JMP(0x1000)
@ -793,7 +793,7 @@ class TestBranchOperations(unittest.TestCase):
def setUp(self):
self.memory = Memory(use_bus=False)
self.cpu = CPU(self.memory)
self.cpu = CPU6502(self.memory)
def test_BCC(self):
self.cpu.program_counter = 0x1000
@ -880,7 +880,7 @@ class TestStatusFlagOperations(unittest.TestCase):
def setUp(self):
self.memory = Memory(use_bus=False)
self.cpu = CPU(self.memory)
self.cpu = CPU6502(self.memory)
def test_CLC(self):
self.cpu.carry_flag = 1
@ -922,7 +922,7 @@ class TestSystemFunctionOperations(unittest.TestCase):
def setUp(self):
self.memory = Memory(use_bus=False)
self.cpu = CPU(self.memory)
self.cpu = CPU6502(self.memory)
def test_BRK(self):
self.cpu.program_counter = 0x1000
@ -952,7 +952,7 @@ class Test6502Bugs(unittest.TestCase):
def setUp(self):
self.memory = Memory(use_bus=False)
self.cpu = CPU(self.memory)
self.cpu = CPU6502(self.memory)
def test_zero_page_x(self):
self.cpu.x_index = 0x01