diff --git a/Dragon32/__init__.py b/Dragon32/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Dragon32/cpu6809.py b/Dragon32/cpu6809.py new file mode 100644 index 0000000..2040d05 --- /dev/null +++ b/Dragon32/cpu6809.py @@ -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() diff --git a/Dragon32/dragon32config.py b/Dragon32/dragon32config.py new file mode 100644 index 0000000..ba5dfea --- /dev/null +++ b/Dragon32/dragon32config.py @@ -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() diff --git a/Dragon32/dragon32memory.py b/Dragon32/dragon32memory.py new file mode 100644 index 0000000..fa43a34 --- /dev/null +++ b/Dragon32/dragon32memory.py @@ -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) diff --git a/apple2/apple2config.py b/apple2/apple2config.py index 5cc83e0..c5c3736 100644 --- a/apple2/apple2config.py +++ b/apple2/apple2config.py @@ -1,3 +1,4 @@ + from generic.generic_config import BaseConfig @@ -17,7 +18,13 @@ class Apple2Config(BaseConfig): 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() diff --git a/apple2/cpu6502.py b/apple2/cpu6502.py index ee4af55..04dd2b2 100644 --- a/apple2/cpu6502.py +++ b/apple2/cpu6502.py @@ -16,7 +16,7 @@ from generic.cpu import BaseCPU from generic.disassembler import BaseDisassemble -class Disassemble6502(BaseDisassemble): +class Disassemble6809(BaseDisassemble): def setup_ops(self): self.ops = [(1, "???")] * 0x100 self.ops[0x00] = (1, "BRK", ) @@ -400,5 +400,5 @@ if __name__ == "__main__": mem = Memory(cfg, bus, RAM, ROM, options) - cpu = CPU6502(cfg, bus, options, mem, Disassemble6502) + cpu = CPU6502(cfg, bus, options, mem, Disassemble6809) cpu.run() diff --git a/applepy.py b/applepy.py index 48d0d00..0ee6645 100755 --- a/applepy.py +++ b/applepy.py @@ -17,6 +17,7 @@ import wave import os from apple2.apple2config import Apple2Config +from generic.base_machine import BaseMachine class Display: @@ -365,81 +366,10 @@ class SoftSwitches: return 0x00 -class Apple2: +class Apple2(BaseMachine): + pass - def __init__(self, cfg, options, display, speaker, cassette): - self.cfg = cfg - self.display = display - self.speaker = speaker - self.softswitches = SoftSwitches(display, speaker, cassette) - 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) - - args = [ - sys.executable, - os.path.join("apple2", "cpu6502.py"), - "--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("= 1024: - self.display.flash() - pygame.display.flip() - if self.speaker: - self.speaker.update(cycle) - update_cycle = 0 def usage(): @@ -500,5 +430,7 @@ if __name__ == "__main__": speaker = None if options.quiet else Speaker() cassette = Cassette(options.cassette) if options.cassette else None - apple = Apple2(cfg, options, display, speaker, cassette) + softswitches = SoftSwitches(display, speaker, cassette) + + apple = Apple2(cfg, options, display, speaker, softswitches) apple.run() diff --git a/dragonpy.py b/dragonpy.py new file mode 100644 index 0000000..869fdbe --- /dev/null +++ b/dragonpy.py @@ -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() diff --git a/generic/base_machine.py b/generic/base_machine.py new file mode 100644 index 0000000..8eb9b99 --- /dev/null +++ b/generic/base_machine.py @@ -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("= 1024: + self.display.flash() + pygame.display.flip() + if self.speaker: + self.speaker.update(cycle) + update_cycle = 0 diff --git a/generic/disassembler.py b/generic/disassembler.py new file mode 100644 index 0000000..0be47dd --- /dev/null +++ b/generic/disassembler.py @@ -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] + diff --git a/generic/generic_config.py b/generic/generic_config.py index 3ffcba9..a259b3b 100644 --- a/generic/generic_config.py +++ b/generic/generic_config.py @@ -1,9 +1,19 @@ 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__