From a4b38aa7a513d6a12ac2291fc4f8e34ca84f080b Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sat, 6 Jul 2019 20:16:48 -0400 Subject: [PATCH] MC6800: Initial commit --- .../BizHawk.Emulation.Cores.csproj | 8 + .../CPUs/MC6800/Disassembler.cs | 502 +++++++++++++ .../CPUs/MC6800/Execute.cs | 285 +++++++ .../CPUs/MC6800/Indexed_Modes.cs | 450 ++++++++++++ .../CPUs/MC6800/Interrupts.cs | 82 +++ BizHawk.Emulation.Cores/CPUs/MC6800/MC6800.cs | 695 ++++++++++++++++++ .../CPUs/MC6800/OP_Tables.cs | 528 +++++++++++++ .../CPUs/MC6800/Operations.cs | 666 +++++++++++++++++ .../CPUs/MC6800/ReadMe.txt | 1 + .../CPUs/MC6800/Registers.cs | 87 +++ 10 files changed, 3304 insertions(+) create mode 100644 BizHawk.Emulation.Cores/CPUs/MC6800/Disassembler.cs create mode 100644 BizHawk.Emulation.Cores/CPUs/MC6800/Execute.cs create mode 100644 BizHawk.Emulation.Cores/CPUs/MC6800/Indexed_Modes.cs create mode 100644 BizHawk.Emulation.Cores/CPUs/MC6800/Interrupts.cs create mode 100644 BizHawk.Emulation.Cores/CPUs/MC6800/MC6800.cs create mode 100644 BizHawk.Emulation.Cores/CPUs/MC6800/OP_Tables.cs create mode 100644 BizHawk.Emulation.Cores/CPUs/MC6800/Operations.cs create mode 100644 BizHawk.Emulation.Cores/CPUs/MC6800/ReadMe.txt create mode 100644 BizHawk.Emulation.Cores/CPUs/MC6800/Registers.cs diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index ef1d8c3a49..7ff964b5fb 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -1543,6 +1543,14 @@ + + + + + + + + diff --git a/BizHawk.Emulation.Cores/CPUs/MC6800/Disassembler.cs b/BizHawk.Emulation.Cores/CPUs/MC6800/Disassembler.cs new file mode 100644 index 0000000000..a276eb209e --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/MC6800/Disassembler.cs @@ -0,0 +1,502 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace BizHawk.Emulation.Common.Components.MC6800 +{ + public sealed partial class MC6800 + { + static string[] table = + { + "NEG DP+i8", // 00 + "???", // 01 + "???", // 02 + "COM DP+i8", // 03 + "LSR DP+i8", // 04 + "???", // 05 + "ROR DP+i8", // 06 + "ASR DP+i8", // 07 + "ASL DP+i8", // 08 + "ROL DP+i8", // 09 + "DEC DP+i8", // 0a + "???", // 0b + "INC DP+i8", // 0c + "TST DP+i8", // 0d + "JMP DP+i8", // 0e + "CLR DP+i8", // 0f + "PAGE 2", // 10 + "PAGE 3", // 11 + "NOP", // 12 + "SYNC", // 13 + "???", // 14 + "???", // 15 + "LBRA i16", // 16 + "LBSR i16", // 17 + "???", // 18 + "DAA", // 19 + "ORCC i8", // 1a + "???", // 1b + "ANDCC i8", // 1c + "SEX", // 1d + "EXG i8", // 1e + "TFR i8", // 1f + "BRA i8", // 20 + "BRN i8", // 21 + "BHI i8", // 22 + "BLS i8", // 23 + "BHS i8", // 24 + "BLO i8", // 25 + "BNE i8", // 26 + "BEQ i8", // 27 + "BVC i8", // 28 + "BVS i8", // 29 + "BPL i8", // 2a + "BMI i8", // 2b + "BGE i8", // 2c + "BLT i8", // 2d + "BGT i8", // 2e + "BLE i8", // 2f + "LEAX ix16", // 30 + "LEAY ix16", // 31 + "LEAS ix16", // 32 + "LEAU ix16", // 33 + "PSHS i8", // 34 + "PULS i8", // 35 + "PSHU i8", // 36 + "PULU i8", // 37 + "???", // 38 + "RTS", // 39 + "ABX", // 3a + "RTI", // 3b + "CWAI i8", // 3c + "MUL", // 3d + "???", // 3e + "SWI1", // 3f + "NEG A", // 40 + "???", // 41 + "???", // 42 + "COM A", // 43 + "LSR A", // 44 + "???", // 45 + "ROR A", // 46 + "ASR A", // 47 + "ASL A", // 48 + "ROL A", // 49 + "DEC A", // 4a + "???", // 4b + "INC A", // 4c + "TST A", // 4d + "???", // 4e + "CLR A", // 4f + "NEG B", // 50 + "???", // 51 + "???", // 52 + "COM B", // 53 + "LSR B", // 54 + "???", // 55 + "ROR B", // 56 + "ASR B", // 57 + "ASL B", // 58 + "ROL B", // 59 + "DEC B", // 5a + "???", // 5b + "INC B", // 5c + "TST B", // 5d + "???", // 5e + "CLR B", // 5f + "NEG ix16", // 60 + "???", // 61 + "???", // 62 + "COM ix16", // 63 + "LSR ix16", // 64 + "???", // 65 + "ROR ix16", // 66 + "ASR ix16", // 67 + "ASL ix16", // 68 + "ROL ix16", // 69 + "DEC ix16", // 6a + "???", // 6b + "INC ix16", // 6c + "TST ix16", // 6d + "JMP ix16", // 6e + "CLR ix16", // 6f + "NEG ex16", // 70 + "???", // 71 + "???", // 72 + "COM ex16", // 73 + "LSR ex16", // 74 + "???", // 75 + "ROR ex16", // 76 + "ASR ex16", // 77 + "ASL ex16", // 78 + "ROL ex16", // 79 + "DEC ex16", // 7a + "???", // 7b + "INC ex16", // 7c + "TST ex16", // 7d + "JMP ex16", // 7e + "CLR ex16", // 7f + "SUB A,i8", // 80 + "CMP A,i8", // 81 + "SBC A,i8", // 82 + "SUB D,i16", // 83 + "AND A,i8", // 84 + "BIT A,i8", // 85 + "LD A,i8", // 86 + "???", // 87 + "EOR A,i8", // 88 + "ADC A,i8", // 89 + "OR A,i8", // 8a + "ADD A,i8", // 8b + "CMP X,i16", // 8c + "BSR i8", // 8d + "LD X,i16", // 8e + "???", // 8f + "SUB A,DP+i8", // 90 + "CMP A,DP+i8", // 91 + "SBC A,DP+i8", // 92 + "SUB D,DP+i8", // 93 + "AND A,DP+i8", // 94 + "BIT A,DP+i8", // 95 + "LD A,DP+i8", // 96 + "ST A,DP+i8", // 97 + "EOR A,DP+i8", // 98 + "ADC A,DP+i8", // 99 + "OR A,DP+i8", // 9a + "ADD A,DP+i8", // 9b + "CMP X,DP+i8", // 9c + "JSR DP+i8", // 9d + "LD X,DP+i8", // 9e + "ST X,DP+i8", // 9f + "SUB A,ix16", // a0 + "CMP A,ix16", // a1 + "SBC A,ix16", // a2 + "SUB D,ix16", // a3 + "AND A,ix16", // a4 + "BIT A,ix16", // a5 + "LD A,ix16", // a6 + "ST A,ix16", // a7 + "EOR A,ix16", // a8 + "ADC A,ix16", // a9 + "OR A,ix16", // aa + "ADD A,ix16", // ab + "CMP X,ix16", // ac + "JSR ix16", // ad + "LD X,ix16", // ae + "ST X,ix16", // af + "SUB A,ex16", // b0 + "CMP A,ex16", // b1 + "SBC A,ex16", // b2 + "SUB D,ex16", // b3 + "AND A,ex16", // b4 + "BIT A,ex16", // b5 + "LD A,ex16", // b6 + "ST A,ex16", // b7 + "EOR A,ex16", // b8 + "ADC A,ex16", // b9 + "OR A,ex16", // ba + "ADD A,ex16", // bb + "CMP X,ex16", // bc + "JSR ex16", // bd + "LD X,ex16", // be + "ST X,ex16", // bf + "SUB B,i8", // c0 + "CMP B,i8", // c1 + "SBC B,i8", // c2 + "ADD D,i16", // c3 + "AND B,i8", // c4 + "BIT B,i8", // c5 + "LD B,i8", // c6 + "???", // c7 + "EOR B,i8", // c8 + "ADC B,i8", // c9 + "OR B,i8", // ca + "ADD B,i8", // cb + "LD D,i16", // cc + "???", // cd + "LD U,i16", // ce + "???", // cf + "SUB B,DP+i8", // d0 + "CMP B,DP+i8", // d1 + "SBC B,DP+i8", // d2 + "ADD D,DP+i8", // d3 + "AND B,DP+i8", // d4 + "BIT B,DP+i8", // d5 + "LD B,DP+i8", // d6 + "ST B,DP+i8", // d7 + "EOR B,DP+i8", // d8 + "ADC B,DP+i8", // d9 + "OR B,DP+i8", // da + "ADD B,DP+i8", // db + "LD D,DP+i8", // dc + "ST D,DP+i8", // dd + "LD U,DP+i8", // de + "ST U,DP+i8", // df + "SUB B,ix16", // e0 + "CMP B,ix16", // e1 + "SBC B,ix16", // e2 + "ADD D,ix16", // e3 + "AND B,ix16", // e4 + "BIT B,ix16", // e5 + "LD B,ix16", // e6 + "ST B,ix16", // e7 + "EOR B,ix16", // e8 + "ADC B,ix16", // e9 + "OR B,ix16", // ea + "ADD B,ix16", // eb + "LD D,ix16", // ec + "ST D,ix16", // ed + "LD U,ix16", // ee + "ST U,ix16", // ef + "SUB B,ex16", // f0 + "CMP B,ex16", // f1 + "SBC B,ex16", // f2 + "ADD D,ex16", // f3 + "AND B,ex16", // f4 + "BIT B,ex16", // f5 + "LD B,ex16", // f6 + "ST B,ex16", // f7 + "EOR B,ex16", // f8 + "ADC B,ex16", // f9 + "OR B,ex16", // fa + "ADD B,ex16", // fb + "LD D,ex16", // fc + "ST D,ex16", // fd + "LD U,ex16", // fe + "ST U,ex16", // ff + }; + + public static string Disassemble(ushort addr, Func reader, out ushort size) + { + ushort origaddr = addr; + List bytes = new List(); + bytes.Add(reader(addr++)); + + string result = table[bytes[0]]; + + if (result.Contains("i8")) + { + byte d = reader(addr++); + bytes.Add(d); + result = result.Replace("i8", string.Format("#{0:X2}h", d)); + } + else if (result.Contains("i16")) + { + byte dhi = reader(addr++); + byte dlo = reader(addr++); + bytes.Add(dhi); + bytes.Add(dlo); + result = result.Replace("i16", string.Format("#{0:X2}{1:X2}h", dhi, dlo)); + } + else if (result.Contains("ex16")) + { + byte dhi = reader(addr++); + byte dlo = reader(addr++); + bytes.Add(dhi); + bytes.Add(dlo); + result = result.Replace("ex16", "(" + string.Format("#{0:X2}{1:X2}h", dhi, dlo) + ")"); + } + else if (result.Contains("ix16")) + { + byte d = reader(addr++); + bytes.Add(d); + + string temp_reg = ""; + + switch ((d >> 5) & 3) + { + case 0: temp_reg = "X"; break; + case 1: temp_reg = "Y"; break; + case 2: temp_reg = "US"; break; + case 3: temp_reg = "SP"; break; + } + + if ((d & 0x80) == 0) + { + short tempdis = (short)(d & 0x1F); + if (tempdis >= 16) + tempdis -= 32; + + result = result.Replace("ix16", temp_reg + " + ea"); + result = result.Replace("ea", string.Format("{0:N}h", tempdis)); + } + else + { + if ((d & 0x10) == 0x10) + { + switch (d & 0xF) + { + case 0x0: + result = result.Replace("ix16", "???"); + break; + case 0x1: + result = result.Replace("ix16","(" + temp_reg + ")++"); + break; + case 0x2: + result = result.Replace("ix16", "???"); + break; + case 0x3: + result = result.Replace("ix16", "--(" + temp_reg + ")"); + break; + case 0x4: + result = result.Replace("ix16", "(" + temp_reg + ")"); + break; + case 0x5: + result = result.Replace("ix16", "(" + temp_reg + " + B)"); + break; + case 0x6: + result = result.Replace("ix16", "(" + temp_reg + " + A)"); + break; + case 0x7: + result = result.Replace("ix16", "???"); + break; + case 0x8: + byte e = reader(addr++); + bytes.Add(e); + result = result.Replace("ix16", "(" + temp_reg + " + ea)"); + result = result.Replace("ea", string.Format("{0:X2}h", e)); + break; + case 0x9: + byte f = reader(addr++); + bytes.Add(f); + byte g = reader(addr++); + bytes.Add(g); + result = result.Replace("ix16", "(" + temp_reg + " + ea)"); + result = result.Replace("ea", string.Format("{0:X2}{1:X2}h", f, g)); + break; + case 0xA: + result = result.Replace("ix16", "???"); + break; + case 0xB: + result = result.Replace("ix16", "(" + temp_reg + " + D)"); + break; + case 0xC: + temp_reg = "PC"; + byte h = reader(addr++); + bytes.Add(h); + result = result.Replace("ix16", "(" + temp_reg + " + ea)"); + result = result.Replace("ea", string.Format("{0:X2}h", h)); + break; + case 0xD: + temp_reg = "PC"; + byte i = reader(addr++); + bytes.Add(i); + byte j = reader(addr++); + bytes.Add(j); + result = result.Replace("ix16", "(" + temp_reg + " + ea)"); + result = result.Replace("ea", string.Format("{0:X2}{1:X2}h", i, j)); + break; + case 0xE: + result = result.Replace("ix16", "???"); + break; + case 0xF: + if (((d >> 5) & 3) == 0) + { + byte k = reader(addr++); + bytes.Add(k); + byte l = reader(addr++); + bytes.Add(l); + result = result.Replace("ix16", "(" + string.Format("{0:X2}{1:X2}h", k, l) + ")"); + } + else + { + result = result.Replace("ix16", "???"); + } + break; + } + } + else + { + switch (d & 0xF) + { + case 0x0: + result = result.Replace("ix16", temp_reg + "+"); + break; + case 0x1: + result = result.Replace("ix16", temp_reg + "++"); + break; + case 0x2: + result = result.Replace("ix16", "-" + temp_reg); + break; + case 0x3: + result = result.Replace("ix16", "--" + temp_reg); + break; + case 0x4: + result = result.Replace("ix16", temp_reg); + break; + case 0x5: + result = result.Replace("ix16", temp_reg + " + B"); + break; + case 0x6: + result = result.Replace("ix16", temp_reg + " + A"); + break; + case 0x7: + result = result.Replace("ix16", "???"); + break; + case 0x8: + byte e = reader(addr++); + bytes.Add(e); + result = result.Replace("ix16", temp_reg + " + ea"); + result = result.Replace("ea", string.Format("{0:X2}h", e)); + break; + case 0x9: + byte f = reader(addr++); + bytes.Add(f); + byte g = reader(addr++); + bytes.Add(g); + result = result.Replace("ix16", temp_reg + " + ea"); + result = result.Replace("ea", string.Format("{0:X2}{1:X2}h", f, g)); + break; + case 0xA: + result = result.Replace("ix16", "???"); + break; + case 0xB: + result = result.Replace("ix16", temp_reg + " + D"); + break; + case 0xC: + temp_reg = "PC"; + byte h = reader(addr++); + bytes.Add(h); + result = result.Replace("ix16", temp_reg + " + ea"); + result = result.Replace("ea", string.Format("{0:X2}h", h)); + break; + case 0xD: + temp_reg = "PC"; + byte i = reader(addr++); + bytes.Add(i); + byte j = reader(addr++); + bytes.Add(j); + result = result.Replace("ix16", temp_reg + " + ea"); + result = result.Replace("ea", string.Format("{0:X2}{1:X2}h", i, j)); + break; + case 0xE: + result = result.Replace("ix16", "???"); + break; + case 0xF: + result = result.Replace("ix16", "???"); + break; + } + } + } + } + else if (result.Contains("r8")) + { + byte d = reader(addr++); + bytes.Add(d); + int offs = d; + if (offs >= 128) + offs -= 256; + result = result.Replace("r8", string.Format("{0:X4}h", (ushort)(addr + offs))); + } + StringBuilder ret = new StringBuilder(); + ret.Append(string.Format("{0:X4}: ", origaddr)); + foreach (var b in bytes) + ret.Append(string.Format("{0:X2} ", b)); + while (ret.Length < 22) + ret.Append(' '); + ret.Append(result); + size = (ushort)(addr - origaddr); + return ret.ToString(); + } + } +} diff --git a/BizHawk.Emulation.Cores/CPUs/MC6800/Execute.cs b/BizHawk.Emulation.Cores/CPUs/MC6800/Execute.cs new file mode 100644 index 0000000000..31a5068102 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/MC6800/Execute.cs @@ -0,0 +1,285 @@ +using System; + +namespace BizHawk.Emulation.Common.Components.MC6800 +{ + public partial class MC6800 + { + public ulong TotalExecutedCycles; + + // variables for executing instructions + public int instr_pntr = 0; + public ushort[] cur_instr = new ushort[60]; + public int opcode_see; + + public int IRQS; + public int irq_pntr; + + ushort reg_d_ad; + ushort reg_h_ad; + ushort reg_l_ad; + + public void FetchInstruction(byte opcode) + { + opcode_see = opcode; + switch (opcode) + { + case 0x00: ILLEGAL(); break; // ILLEGAL + case 0x01: NOP_(); break; // NOP (Inherent) + case 0x02: ILLEGAL(); break; // ILLEGAL + case 0x03: ILLEGAL(); break; // ILLEGAL + case 0x04: ILLEGAL(); break; // ILLEGAL + case 0x05: ILLEGAL(); break; // ILLEGAL + case 0x06: REG_OP(TAP, A); break; // TAP (Inherent) + case 0x07: REG_OP(TPA, A); break; // TPA (Inherent) + case 0x08: REG_OP_16(INX, X); break; // INX (Inherent) + case 0x09: REG_OP_16(DEX, X); break; // DEX (Inherent) + case 0x0A: REG_OP(CLV, CC); break; // CLV (Inherent) + case 0x0B: REG_OP(SEV, CC); break; // SEV (Inherent) + case 0x0C: REG_OP(CLC, CC); break; // CLC (Inherent) + case 0x0D: REG_OP(SEC, CC); break; // SEC (Inherent) + case 0x0E: REG_OP(CLI, CC); break; // CLI (Inherent) + case 0x0F: REG_OP(SEI, CC); break; // SEI (Inherent) + case 0x10: NOP_(); break; // Page 2 + case 0x11: NOP_(); break; // Page 3 + case 0x12: ILLEGAL(); break; // NOP (Inherent) + case 0x13: ILLEGAL(); break; // SYNC (Inherent) + case 0x14: ILLEGAL(); break; // ILLEGAL + case 0x15: ILLEGAL(); break; // ILLEGAL + case 0x16: LBR_(true); break; // LBRA (Relative) + case 0x17: LBSR_(); break; // LBSR (Relative) + case 0x18: ILLEGAL(); break; // ILLEGAL + case 0x19: REG_OP(DA, A); break; // DAA (Inherent) + case 0x1A: ILLEGAL(); break; // ORCC (Immediate) + case 0x1B: ILLEGAL(); break; // ILLEGAL + case 0x1C: ILLEGAL(); break; // ANDCC (Immediate) + case 0x1D: ILLEGAL(); break; // SEX (Inherent) + case 0x1E: ILLEGAL(); break; // EXG (Immediate) + case 0x1F: ILLEGAL(); break; // TFR (Immediate) + case 0x20: BR_(true); break; // BRA (Relative) + case 0x21: BR_(false); break; // BRN (Relative) + case 0x22: BR_(!(FlagC | FlagZ)); break; // BHI (Relative) + case 0x23: BR_(FlagC | FlagZ); break; // BLS (Relative) + case 0x24: BR_(!FlagC); break; // BHS , BCC (Relative) + case 0x25: BR_(FlagC); break; // BLO , BCS (Relative) + case 0x26: BR_(!FlagZ); break; // BNE (Relative) + case 0x27: BR_(FlagZ); break; // BEQ (Relative) + case 0x28: BR_(!FlagV); break; // BVC (Relative) + case 0x29: BR_(FlagV); break; // BVS (Relative) + case 0x2A: BR_(!FlagN); break; // BPL (Relative) + case 0x2B: BR_(FlagN); break; // BMI (Relative) + case 0x2C: BR_(FlagN == FlagV); break; // BGE (Relative) + case 0x2D: BR_(FlagN ^ FlagV); break; // BLT (Relative) + case 0x2E: BR_((!FlagZ) & (FlagN == FlagV)); break; // BGT (Relative) + case 0x2F: BR_(FlagZ | (FlagN ^ FlagV)); break; // BLE (Relative) + case 0x30: INDEX_OP(LEAX); break; // LEAX (Indexed) + case 0x31: INDEX_OP(LEAY); break; // LEAY (Indexed) + case 0x32: INDEX_OP(LEAS); break; // LEAS (Indexed) + case 0x33: INDEX_OP(LEAU); break; // LEAU (Indexed) + case 0x34: PSH_(SP); break; // PSHS (Immediate) + case 0x35: PUL_(SP); break; // PULS (Immediate) + case 0x36: PSH_(A); break; // PSHA (Inherent) + case 0x37: PSH_(B); break; // PSHB (Inherent) + case 0x38: ILLEGAL(); break; // ILLEGAL + case 0x39: RTS(); break; // RTS (Inherent) + case 0x3A: ABX_(); break; // ABX (Inherent) + case 0x3B: RTI(); break; // RTI (Inherent) + case 0x3C: CWAI_(); break; // CWAI (Inherent) + case 0x3D: MUL_(); break; // MUL (Inherent) + case 0x3E: ILLEGAL(); break; // ILLEGAL + case 0x3F: SWI1(); break; // SWI (Inherent) + case 0x40: REG_OP(NEG, A); break; // NEGA (Inherent) + case 0x41: ILLEGAL(); break; // ILLEGAL + case 0x42: ILLEGAL(); break; // ILLEGAL + case 0x43: REG_OP(COM, A); break; // COMA (Inherent) + case 0x44: REG_OP(LSR, A); break; // LSRA (Inherent) + case 0x45: ILLEGAL(); break; // ILLEGAL + case 0x46: REG_OP(ROR, A); break; // RORA (Inherent) + case 0x47: REG_OP(ASR, A); break; // ASRA (Inherent) + case 0x48: REG_OP(ASL, A); break; // ASLA , LSLA (Inherent) + case 0x49: REG_OP(ROL, A); break; // ROLA (Inherent) + case 0x4A: REG_OP(DEC8, A); break; // DECA (Inherent) + case 0x4B: ILLEGAL(); break; // ILLEGAL + case 0x4C: REG_OP(INC8, A); break; // INCA (Inherent) + case 0x4D: REG_OP(TST, A); break; // TSTA (Inherent) + case 0x4E: ILLEGAL(); break; // ILLEGAL + case 0x4F: REG_OP(CLR, A); break; // CLRA (Inherent) + case 0x50: REG_OP(NEG, B); break; // NEGB (Inherent) + case 0x51: ILLEGAL(); break; // ILLEGAL + case 0x52: ILLEGAL(); break; // ILLEGAL + case 0x53: REG_OP(COM, B); break; // COMB (Inherent) + case 0x54: REG_OP(LSR, B); break; // LSRB (Inherent) + case 0x55: ILLEGAL(); break; // ILLEGAL + case 0x56: REG_OP(ROR, B); break; // RORB (Inherent) + case 0x57: REG_OP(ASR, B); break; // ASRB (Inherent) + case 0x58: REG_OP(ASL, B); break; // ASLB , LSLB (Inherent) + case 0x59: REG_OP(ROL, B); break; // ROLB (Inherent) + case 0x5A: REG_OP(DEC8, B); break; // DECB (Inherent) + case 0x5B: ILLEGAL(); break; // ILLEGAL + case 0x5C: REG_OP(INC8, B); break; // INCB (Inherent) + case 0x5D: REG_OP(TST, B); break; // TSTB (Inherent) + case 0x5E: ILLEGAL(); break; // ILLEGAL + case 0x5F: REG_OP(CLR, B); break; // CLRB (Inherent) + case 0x60: INDEX_OP(I_NEG); break; // NEG (Indexed) + case 0x61: ILLEGAL(); break; // ILLEGAL + case 0x62: ILLEGAL(); break; // ILLEGAL + case 0x63: INDEX_OP(I_COM); break; // COM (Indexed) + case 0x64: INDEX_OP(I_LSR); break; // LSR (Indexed) + case 0x65: ILLEGAL(); break; // ILLEGAL + case 0x66: INDEX_OP(I_ROR); break; // ROR (Indexed) + case 0x67: INDEX_OP(I_ASR); break; // ASR (Indexed) + case 0x68: INDEX_OP(I_ASL); break; // ASL , LSL (Indexed) + case 0x69: INDEX_OP(I_ROL); break; // ROL (Indexed) + case 0x6A: INDEX_OP(I_DEC); break; // DEC (Indexed) + case 0x6B: ILLEGAL(); break; // ILLEGAL + case 0x6C: INDEX_OP(I_INC); break; // INC (Indexed) + case 0x6D: INDEX_OP(I_TST); break; // TST (Indexed) + case 0x6E: INDEX_OP(I_JMP); break; // JMP (Indexed) + case 0x6F: INDEX_OP(I_CLR); break; // CLR (Indexed) + case 0x70: EXT_MEM(NEG); break; // NEG (Extended) + case 0x71: ILLEGAL(); break; // ILLEGAL + case 0x72: ILLEGAL(); break; // ILLEGAL + case 0x73: EXT_MEM(COM); break; // COM (Extended) + case 0x74: EXT_MEM(LSR); break; // LSR (Extended) + case 0x75: ILLEGAL(); break; // ILLEGAL + case 0x76: EXT_MEM(ROR); break; // ROR (Extended) + case 0x77: EXT_MEM(ASR); break; // ASR (Extended) + case 0x78: EXT_MEM(ASL); break; // ASL , LSL (Extended) + case 0x79: EXT_MEM(ROL); break; // ROL (Extended) + case 0x7A: EXT_MEM(DEC8); break; // DEC (Extended) + case 0x7B: ILLEGAL(); break; // ILLEGAL + case 0x7C: EXT_MEM(INC8); break; // INC (Extended) + case 0x7D: EXT_MEM(TST); break; // TST (Extended) + case 0x7E: JMP_EXT_(); break; // JMP (Extended) + case 0x7F: EXT_MEM(CLR); break; // CLR (Extended) + case 0x80: REG_OP_IMD(SUB8, A); break; // SUBA (Immediate) + case 0x81: REG_OP_IMD(CMP8, A); break; // CMPA (Immediate) + case 0x82: REG_OP_IMD(SBC8, A); break; // SBCA (Immediate) + case 0x83: IMD_OP_D(SUB16, D); break; // SUBD (Immediate) + case 0x84: REG_OP_IMD(AND8, A); break; // ANDA (Immediate) + case 0x85: REG_OP_IMD(BIT, A); break; // BITA (Immediate) + case 0x86: REG_OP_IMD(LD_8, A); break; // LDA (Immediate) + case 0x87: ILLEGAL(); break; // ILLEGAL + case 0x88: REG_OP_IMD(XOR8, A); break; // EORA (Immediate) + case 0x89: REG_OP_IMD(ADC8, A); break; // ADCA (Immediate) + case 0x8A: REG_OP_IMD(OR8, A); break; // ORA (Immediate) + case 0x8B: REG_OP_IMD(ADD8, A); break; // ADDA (Immediate) + case 0x8C: IMD_CMP_16(CMP16, X); break; // CMPX (Immediate) + case 0x8D: BSR_(); break; // BSR (Relative) + case 0x8E: REG_OP_LD_16(X); break; // LDX (Immediate) + case 0x8F: ILLEGAL(); break; // ILLEGAL + case 0x90: DIRECT_MEM_4(SUB8, A); break; // SUBA (Direct) + case 0x91: DIRECT_MEM_4(CMP8, A); break; // CMPA (Direct) + case 0x92: DIRECT_MEM_4(SBC8, A); break; // SBCA (Direct) + case 0x93: DIR_OP_D(SUB16, D); break; // SUBD (Direct) + case 0x94: DIRECT_MEM_4(AND8, A); break; // ANDA (Direct) + case 0x95: DIRECT_MEM_4(BIT, A); break; // BITA (Direct) + case 0x96: DIRECT_MEM_4(LD_8, A); break; // LDA (Direct) + case 0x97: DIRECT_ST_4(A); break; // STA (Direct) + case 0x98: DIRECT_MEM_4(XOR8, A); break; // EORA (Direct) + case 0x99: DIRECT_MEM_4(ADC8, A); break; // ADCA (Direct) + case 0x9A: DIRECT_MEM_4(OR8, A); break; // ORA (Direct) + case 0x9B: DIRECT_MEM_4(ADD8, A); break; // ADDA (Direct) + case 0x9C: DIR_CMP_16(CMP16, X); break; // CMPX (Direct) + case 0x9D: REG_OP(ADC8, A); break; // JSR (Direct) + case 0x9E: DIR_OP_LD_16(X); break; // LDX (Direct) + case 0x9F: DIR_OP_ST_16(X); break; // STX (Direct) + case 0xA0: INDEX_OP_REG(I_SUB, A); break; // SUBA (Indexed) + case 0xA1: INDEX_OP_REG(I_CMP, A); break; // CMPA (Indexed) + case 0xA2: INDEX_OP_REG(I_SBC, A); break; // SBCA (Indexed) + case 0xA3: INDEX_OP_REG(I_SUBD, D); break; // SUBD (Indexed) + case 0xA4: INDEX_OP_REG(I_AND, A); break; // ANDA (Indexed) + case 0xA5: INDEX_OP_REG(I_BIT, A); break; // BITA (Indexed) + case 0xA6: INDEX_OP_REG(I_LD, A); break; // LDA (Indexed) + case 0xA7: INDEX_OP_REG(I_ST, A); break; // STA (Indexed) + case 0xA8: INDEX_OP_REG(I_XOR, A); break; // EORA (Indexed) + case 0xA9: INDEX_OP_REG(I_ADC, A); break; // ADCA (Indexed) + case 0xAA: INDEX_OP_REG(I_OR, A); break; // ORA (Indexed) + case 0xAB: INDEX_OP_REG(I_ADD, A); break; // ADDA (Indexed) + case 0xAC: INDEX_OP_REG(I_CMP16, X); break; // CMPX (Indexed) + case 0xAD: INDEX_OP(I_JSR); break; // JSR (Indexed) + case 0xAE: INDEX_OP_REG(I_LD16, X); break; // LDX (Indexed) + case 0xAF: INDEX_OP_REG(I_ST16, X); break; // STX (Indexed) + case 0xB0: EXT_REG(SUB8, A); break; // SUBA (Extended) + case 0xB1: EXT_REG(CMP8, A); break; // CMPA (Extended) + case 0xB2: EXT_REG(SBC8, A); break; // SBCA (Extended) + case 0xB3: EXT_OP_D(SUB16, D); break; // SUBD (Extended) + case 0xB4: EXT_REG(AND8, A); break; // ANDA (Extended) + case 0xB5: EXT_REG(BIT, A); break; // BITA (Extended) + case 0xB6: EXT_REG(LD_8, A); break; // LDA (Extended) + case 0xB7: EXT_ST(A); break; // STA (Extended) + case 0xB8: EXT_REG(XOR8, A); break; // EORA (Extended) + case 0xB9: EXT_REG(ADC8, A); break; // ADCA (Extended) + case 0xBA: EXT_REG(OR8, A); break; // ORA (Extended) + case 0xBB: EXT_REG(ADD8, A); break; // ADDA (Extended) + case 0xBC: EXT_CMP_16(CMP16, X); break; // CMPX (Extended) + case 0xBD: JSR_EXT(); break; // JSR (Extended) + case 0xBE: EXT_OP_LD_16(X); break; // LDX (Extended) + case 0xBF: EXT_OP_ST_16(X); break; // STX (Extended) + case 0xC0: REG_OP_IMD(SUB8, B); break; // SUBB (Immediate) + case 0xC1: REG_OP_IMD(CMP8, B); break; // CMPB (Immediate) + case 0xC2: REG_OP_IMD(SBC8, B); break; // SBCB (Immediate) + case 0xC3: IMD_OP_D(ADD16, D); break; // ADDD (Immediate) + case 0xC4: REG_OP_IMD(AND8, B); break; // ANDB (Immediate) + case 0xC5: REG_OP_IMD(BIT, B); break; // BITB (Immediate) + case 0xC6: REG_OP_IMD(LD_8, B); break; // LDB (Immediate) + case 0xC7: ILLEGAL(); break; // ILLEGAL + case 0xC8: REG_OP_IMD(XOR8, B); break; // EORB (Immediate) + case 0xC9: REG_OP_IMD(ADC8, B); break; // ADCB (Immediate) + case 0xCA: REG_OP_IMD(OR8, B); break; // ORB (Immediate) + case 0xCB: REG_OP_IMD(ADD8, B); break; // ADDB (Immediate) + case 0xCC: REG_OP_LD_16D(); break; // LDD (Immediate) + case 0xCD: ILLEGAL(); break; // ILLEGAL + case 0xCE: REG_OP_LD_16(X); break; // LDX (Immediate) + case 0xCF: ILLEGAL(); break; // ILLEGAL + case 0xD0: DIRECT_MEM_4(SUB8, B); break; // SUBB (Direct) + case 0xD1: DIRECT_MEM_4(CMP8, B); break; // CMPB (Direct) + case 0xD2: DIRECT_MEM_4(SBC8, B); break; // SBCB (Direct) + case 0xD3: DIR_OP_D(ADD16, D); break; // ADDD (Direct) + case 0xD4: DIRECT_MEM_4(AND8, B); break; // ANDB (Direct) + case 0xD5: DIRECT_MEM_4(BIT, B); break; // BITB (Direct) + case 0xD6: DIRECT_MEM_4(LD_8, B); break; // LDB (Direct) + case 0xD7: DIRECT_ST_4(B); break; // STB (Direct) + case 0xD8: DIRECT_MEM_4(XOR8, B); break; // EORB (Direct) + case 0xD9: DIRECT_MEM_4(ADC8, B); break; // ADCB (Direct) + case 0xDA: DIRECT_MEM_4(OR8, B); break; // ORB (Direct) + case 0xDB: DIRECT_MEM_4(ADD8, B); break; // ADDB (Direct) + case 0xDC: DIR_OP_LD_16D(); break; // LDD (Direct) + case 0xDD: DIR_OP_ST_16D(); break; // STD (Direct) + case 0xDE: DIR_OP_LD_16(X); break; // LDX (Direct) + case 0xDF: DIR_OP_ST_16(X); break; // STX (Direct) + case 0xE0: INDEX_OP_REG(I_SUB, B); break; // SUBB (Indexed) + case 0xE1: INDEX_OP_REG(I_CMP, B); break; // CMPB (Indexed) + case 0xE2: INDEX_OP_REG(I_SBC, B); break; // SBCB (Indexed) + case 0xE3: INDEX_OP_REG(I_ADDD, D); break; // ADDD (Indexed) + case 0xE4: INDEX_OP_REG(I_AND, B); break; // ANDB (Indexed) + case 0xE5: INDEX_OP_REG(I_BIT, B); break; // BITB (Indexed) + case 0xE6: INDEX_OP_REG(I_LD, B); break; // LDB (Indexed) + case 0xE7: INDEX_OP_REG(I_ST, B); break; // STB (Indexed) + case 0xE8: INDEX_OP_REG(I_XOR, B); break; // EORB (Indexed) + case 0xE9: INDEX_OP_REG(I_ADC, B); break; // ADCB (Indexed) + case 0xEA: INDEX_OP_REG(I_OR, B); break; // ORB (Indexed) + case 0xEB: INDEX_OP_REG(I_ADD, B); break; // ADDB (Indexed) + case 0xEC: INDEX_OP_REG(I_LD16D, D); break; // LDD (Indexed) + case 0xED: INDEX_OP_REG(I_ST16D, D); break; // STD (Indexed) + case 0xEE: INDEX_OP_REG(I_LD16, X); break; // LDX (Indexed) + case 0xEF: INDEX_OP_REG(I_ST16, X); break; // STX (Indexed) + case 0xF0: EXT_REG(SUB8, B); break; // SUBB (Extended) + case 0xF1: EXT_REG(CMP8, B); break; // CMPB (Extended) + case 0xF2: EXT_REG(SBC8, B); break; // SBCB (Extended) + case 0xF3: EXT_OP_D(ADD16, D); break; // ADDD (Extended) + case 0xF4: EXT_REG(AND8, B); break; // ANDB (Extended) + case 0xF5: EXT_REG(BIT, B); break; // BITB (Extended) + case 0xF6: EXT_REG(LD_8, B); break; // LDB (Extended) + case 0xF7: EXT_ST(B); break; // STB (Extended) + case 0xF8: EXT_REG(XOR8, B); break; // EORB (Extended) + case 0xF9: EXT_REG(ADC8, B); break; // ADCB (Extended) + case 0xFA: EXT_REG(OR8, B); break; // ORB (Extended) + case 0xFB: EXT_REG(ADD8, B); break; // ADDB (Extended) + case 0xFC: EXT_OP_LD_16D(); break; // LDD (Extended) + case 0xFD: EXT_OP_ST_16D(); break; // STD (Extended) + case 0xFE: EXT_OP_LD_16(X); break; // LDX (Extended) + case 0xFF: EXT_OP_ST_16(X); break; // STX (Extended) + } + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/MC6800/Indexed_Modes.cs b/BizHawk.Emulation.Cores/CPUs/MC6800/Indexed_Modes.cs new file mode 100644 index 0000000000..b356506e5c --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/MC6800/Indexed_Modes.cs @@ -0,0 +1,450 @@ +using System; + +namespace BizHawk.Emulation.Common.Components.MC6800 +{ + public partial class MC6800 + { + public const ushort LEAX = 0; + public const ushort LEAY = 1; + public const ushort LEAS = 2; + public const ushort LEAU = 3; + public const ushort I_NEG = 4; + public const ushort I_COM = 5; + public const ushort I_LSR = 6; + public const ushort I_ROR = 7; + public const ushort I_ASR = 8; + public const ushort I_ASL = 9; + public const ushort I_ROL = 10; + public const ushort I_DEC = 11; + public const ushort I_INC = 12; + public const ushort I_TST = 13; + public const ushort I_JMP = 14; + public const ushort I_CLR = 15; + public const ushort I_SUB = 16; + public const ushort I_CMP = 17; + public const ushort I_SBC = 18; + public const ushort I_AND = 19; + public const ushort I_BIT = 20; + public const ushort I_LD = 21; + public const ushort I_ST = 22; + public const ushort I_XOR = 23; + public const ushort I_ADC = 24; + public const ushort I_OR = 25; + public const ushort I_ADD = 26; + public const ushort I_SUBD = 27; + public const ushort I_ADDD = 28; + public const ushort I_CMP16 = 29; + public const ushort I_JSR = 30; + public const ushort I_LD16 = 31; + public const ushort I_ST16 = 32; + public const ushort I_LD16D = 33; + public const ushort I_ST16D = 34; + public const ushort I_CMP16D = 35; + + public ushort indexed_op; + public ushort indexed_reg; + public ushort indexed_op_reg; + + public ushort temp; + + private void INDEX_OP(ushort oper) + { + indexed_op = oper; + + PopulateCURINSTR(RD_INC_OP, ALU, PC, IDX_DCDE); + + IRQS = -1; + } + + private void INDEX_OP_REG(ushort oper, ushort src) + { + indexed_op = oper; + indexed_op_reg = src; + + PopulateCURINSTR(RD_INC_OP, ALU, PC, IDX_DCDE); + + IRQS = -1; + } + + private void INDEX_OP_JMP() + { + PopulateCURINSTR(TR, PC, IDX_EA); + + IRQS = 1; + } + + private void INDEX_OP_JSR() + { + PopulateCURINSTR(TR, ADDR, PC, + DEC16, SP, + TR, PC, IDX_EA, + WR_DEC_LO, SP, ADDR, + WR_HI, SP, ADDR); + + IRQS = 5; + } + + private void INDEX_OP_LEA(ushort dest) + { + PopulateCURINSTR(LEA, dest, IDX_EA, + IDLE); + + IRQS = 2; + } + + private void INDEX_OP_LD() + { + PopulateCURINSTR(IDLE, + RD_INC, ALU, IDX_EA, + RD_INC_OP, ALU2, IDX_EA, LD_16, indexed_op_reg, ALU, ALU2); + + IRQS = 3; + } + + private void INDEX_OP_ST() + { + PopulateCURINSTR(IDLE, + WR_HI_INC, IDX_EA, indexed_op_reg, + WR_DEC_LO, IDX_EA, indexed_op_reg); + + IRQS = 3; + } + + private void INDEX_OP_LDD() + { + PopulateCURINSTR(IDLE, + RD_INC, A, IDX_EA, + RD_INC_OP, B, IDX_EA, LD_16, ADDR, A, B); + + IRQS = 3; + } + + private void INDEX_OP_STD() + { + PopulateCURINSTR(SET_ADDR, ADDR, A, A, + WR_HI_INC, IDX_EA, ADDR, + WR_DEC_LO, IDX_EA, B); + + IRQS = 3; + } + + private void INDEX_OP_EX4(ushort oper) + { + PopulateCURINSTR(IDLE, + RD_INC_OP, ALU, IDX_EA, oper, indexed_op_reg, ALU); + + IRQS = 2; + } + + private void INDEX_OP_EX4_ST() + { + PopulateCURINSTR(IDLE, + WR, IDX_EA, indexed_op_reg); + + IRQS = 2; + } + + private void INDEX_OP_EX6(ushort oper) + { + PopulateCURINSTR(IDLE, + RD, ALU, IDX_EA, + oper, ALU, + WR, IDX_EA, ALU); + + IRQS = 4; + } + + private void INDEX_OP_EX6D(ushort oper) + { + PopulateCURINSTR(IDLE, + RD_INC, ALU, IDX_EA, + RD_INC_OP, ALU2, IDX_EA, SET_ADDR, ADDR, ALU, ALU2, + oper, ADDR); + + IRQS = 4; + } + + private void INDEX_CMP_EX6(ushort oper) + { + PopulateCURINSTR(IDLE, + RD_INC, ALU, IDX_EA, + RD_INC_OP, ALU2, IDX_EA, SET_ADDR, ADDR, ALU, ALU2, + oper, indexed_op_reg, ADDR); + + IRQS = 4; + } + + // ALU holds the post byte + public void Index_decode() + { + switch ((Regs[ALU] >> 5) & 3) + { + case 0: indexed_reg = X; break; + case 1: indexed_reg = SP; break; + } + + if ((Regs[ALU] & 0x80) == 0) + { + temp = (ushort)(Regs[ALU] & 0x1F); + if ((Regs[ALU] & 0x10) == 0x10) + { + temp |= 0xFFE0; + } + + Regs[IDX_EA] = (ushort)(Regs[indexed_reg] + temp); + + PopulateCURINSTR(IDX_OP_BLD); + } + else + { + if ((Regs[ALU] & 0x10) == 0x10) + { + switch (Regs[ALU] & 0xF) + { + case 0x0: + // Illegal + break; + case 0x1: + Regs[ADDR] = Regs[indexed_reg]; + PopulateCURINSTR(INC16, indexed_reg, + INC16, indexed_reg, + RD_INC, ALU, ADDR, + RD_INC, ALU2, ADDR, + SET_ADDR, IDX_EA, ALU, ALU2, + IDX_OP_BLD); + break; + case 0x2: + // Illegal + break; + case 0x3: + Regs[ADDR] = (ushort)(Regs[indexed_reg] - 2); + PopulateCURINSTR(DEC16, indexed_reg, + DEC16, indexed_reg, + RD_INC, ALU, ADDR, + RD_INC, ALU2, ADDR, + SET_ADDR, IDX_EA, ALU, ALU2, + IDX_OP_BLD); + break; + case 0x4: + Regs[ADDR] = Regs[indexed_reg]; + PopulateCURINSTR(RD_INC, ALU, ADDR, + RD_INC_OP, ALU2, ADDR, SET_ADDR, IDX_EA, ALU, ALU2, + IDX_OP_BLD); + break; + case 0x5: + Regs[ADDR] = (ushort)(Regs[indexed_reg] + (((Regs[B] & 0x80) == 0x80) ? (Regs[B] | 0xFF00) : Regs[B])); + PopulateCURINSTR(RD_INC, ALU, ADDR, + RD_INC, ALU2, ADDR, + SET_ADDR, IDX_EA, ALU, ALU2, + IDX_OP_BLD); + break; + case 0x6: + Regs[ADDR] = (ushort)(Regs[indexed_reg] + (((Regs[A] & 0x80) == 0x80) ? (Regs[A] | 0xFF00) : Regs[A])); + PopulateCURINSTR(RD_INC, ALU, ADDR, + RD_INC, ALU2, ADDR, + SET_ADDR, IDX_EA, ALU, ALU2, + IDX_OP_BLD); + break; + case 0x7: + // Illegal + break; + case 0x8: + Regs[ADDR] = Regs[indexed_reg]; + PopulateCURINSTR(RD_INC_OP, ALU2, PC, ADD8BR, ADDR, ALU2, + RD_INC, ALU, ADDR, + RD_INC_OP, ALU2, ADDR, SET_ADDR, IDX_EA, ALU, ALU2, + IDX_OP_BLD); + break; + case 0x9: + Regs[ADDR] = Regs[indexed_reg]; + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC, ALU2, PC, + SET_ADDR, IDX_EA, ALU, ALU2, + ADD16BR, ADDR, IDX_EA, + RD_INC, ALU, ADDR, + RD_INC_OP, ALU2, ADDR, SET_ADDR, IDX_EA, ALU, ALU2, + IDX_OP_BLD); + break; + case 0xA: + // Illegal + break; + case 0xB: + Regs[ADDR] = Regs[indexed_reg]; + PopulateCURINSTR(IDLE, + IDLE, + SET_ADDR, IDX_EA, A, B, + ADD16BR, ADDR, IDX_EA, + RD_INC, ALU, ADDR, + RD_INC_OP, ALU2, ADDR, SET_ADDR, IDX_EA, ALU, ALU2, + IDX_OP_BLD); + break; + case 0xC: + indexed_reg = PC; + Regs[ADDR] = Regs[indexed_reg]; + PopulateCURINSTR(RD_INC_OP, ALU2, PC, ADD8BR, ADDR, ALU2, + RD_INC, ALU, ADDR, + RD_INC_OP, ALU2, ADDR, SET_ADDR, IDX_EA, ALU, ALU2, + IDX_OP_BLD); + break; + case 0xD: + indexed_reg = PC; + Regs[ADDR] = Regs[indexed_reg]; + PopulateCURINSTR(IDLE, + RD_INC, ALU, PC, + RD_INC, ALU2, PC, + SET_ADDR, IDX_EA, ALU, ALU2, + ADD16BR, ADDR, IDX_EA, + RD_INC, ALU, ADDR, + RD_INC_OP, ALU2, ADDR, SET_ADDR, IDX_EA, ALU, ALU2, + IDX_OP_BLD); + break; + case 0xE: + // Illegal + break; + case 0xF: + if (((Regs[ALU] >> 5) & 3) == 0) + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC_OP, ALU2, PC, SET_ADDR, ADDR, ALU, ALU2, + RD_INC, ALU, ADDR, + RD_INC_OP, ALU2, ADDR, SET_ADDR, IDX_EA, ALU, ALU2, + IDX_OP_BLD); + } + else + { + // illegal + } + break; + } + } + else + { + switch (Regs[ALU] & 0xF) + { + case 0x0: + Regs[IDX_EA] = Regs[indexed_reg]; + PopulateCURINSTR(INC16, indexed_reg, + IDX_OP_BLD); + break; + case 0x1: + Regs[IDX_EA] = Regs[indexed_reg]; + PopulateCURINSTR(INC16, indexed_reg, + INC16, indexed_reg, + IDX_OP_BLD); + break; + case 0x2: + Regs[IDX_EA] = (ushort)(Regs[indexed_reg] - 1); + PopulateCURINSTR(DEC16, indexed_reg, + IDX_OP_BLD); + break; + case 0x3: + Regs[IDX_EA] = (ushort)(Regs[indexed_reg] - 2); + PopulateCURINSTR(DEC16, indexed_reg, + DEC16, indexed_reg, + IDX_OP_BLD); + break; + case 0x4: + Regs[IDX_EA] = Regs[indexed_reg]; + Index_Op_Builder(); + return; // need to return here or else we run into the code below invalidating irq_pntr + break; + case 0x5: + Regs[IDX_EA] = (ushort)(Regs[indexed_reg] + (((Regs[B] & 0x80) == 0x80) ? (Regs[B] | 0xFF00) : Regs[B])); + PopulateCURINSTR(IDX_OP_BLD); + break; + case 0x6: + Regs[IDX_EA] = (ushort)(Regs[indexed_reg] + (((Regs[A] & 0x80) == 0x80) ? (Regs[A] | 0xFF00) : Regs[A])); + PopulateCURINSTR(IDX_OP_BLD); + break; + case 0x7: + // Illegal + break; + case 0x8: + PopulateCURINSTR(RD_INC_OP, ALU2, PC, EA_8); + break; + case 0x9: + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC, ALU2, PC, + SET_ADDR, ADDR, ALU, ALU2, + EA_16); + break; + case 0xA: + // Illegal + break; + case 0xB: + PopulateCURINSTR(IDLE, + IDLE, + SET_ADDR, ADDR, A, B, + EA_16); + break; + case 0xC: + indexed_reg = PC; + PopulateCURINSTR(RD_INC_OP, ALU2, PC, EA_8); + break; + case 0xD: + indexed_reg = PC; + PopulateCURINSTR(IDLE, + RD_INC, ALU, PC, + RD_INC, ALU2, PC, + SET_ADDR, ADDR, ALU, ALU2, + EA_16); + break; + case 0xE: + // Illegal + break; + case 0xF: + // Illegal + break; + } + } + } + + instr_pntr = 0; + irq_pntr = 100; + } + + public void Index_Op_Builder() + { + switch(indexed_op) + { + case LEAX: INDEX_OP_LEA(X); break; // LEAX + case LEAS: INDEX_OP_LEA(SP); break; // LEAS + case I_NEG: INDEX_OP_EX6(NEG); break; // NEG + case I_COM: INDEX_OP_EX6(COM); break; // COM + case I_LSR: INDEX_OP_EX6(LSR); break; // LSR + case I_ROR: INDEX_OP_EX6(ROR); break; // ROR + case I_ASR: INDEX_OP_EX6(ASR); break; // ASR + case I_ASL: INDEX_OP_EX6(ASL); break; // ASL + case I_ROL: INDEX_OP_EX6(ROL); break; // ROL + case I_DEC: INDEX_OP_EX6(DEC8); break; // DEC + case I_INC: INDEX_OP_EX6(INC8); break; // INC + case I_TST: INDEX_OP_EX6(TST); break; // TST + case I_JMP: INDEX_OP_JMP(); break; // JMP + case I_CLR: INDEX_OP_EX6(CLR); break; // CLR + case I_SUB: INDEX_OP_EX4(SUB8); break; // SUB A,B + case I_CMP: INDEX_OP_EX4(CMP8); break; // CMP A,B + case I_SBC: INDEX_OP_EX4(SBC8); break; // SBC A,B + case I_AND: INDEX_OP_EX4(AND8); break; // AND A,B + case I_BIT: INDEX_OP_EX4(BIT); break; // BIT A,B + case I_LD: INDEX_OP_EX4(LD_8); break; // LD A,B + case I_ST: INDEX_OP_EX4_ST(); break; // ST A,B + case I_XOR: INDEX_OP_EX4(XOR8); break; // XOR A,B + case I_ADC: INDEX_OP_EX4(ADC8); break; // ADC A,B + case I_OR: INDEX_OP_EX4(OR8); break; // OR A,B + case I_ADD: INDEX_OP_EX4(ADD8); break; // ADD A,B + case I_SUBD: INDEX_OP_EX6D(SUB16); break; // SUB D + case I_ADDD: INDEX_OP_EX6D(ADD16); break; // ADD D + case I_CMP16: INDEX_CMP_EX6(CMP16); break; // CMP X, Y, SP, US + case I_JSR: INDEX_OP_JSR(); break; // JSR + case I_LD16: INDEX_OP_LD(); break; // LD X, Y, SP, US + case I_ST16: INDEX_OP_ST(); break; // ST X, Y, SP, US + case I_LD16D: INDEX_OP_LDD(); break; // LD D + case I_ST16D: INDEX_OP_STD(); break; // ST D + case I_CMP16D: INDEX_OP_EX6D(CMP16D); break; // CMP D + } + + instr_pntr = 0; + irq_pntr = -1; + } + } +} diff --git a/BizHawk.Emulation.Cores/CPUs/MC6800/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/MC6800/Interrupts.cs new file mode 100644 index 0000000000..ee76dfff88 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/MC6800/Interrupts.cs @@ -0,0 +1,82 @@ +using System; + +namespace BizHawk.Emulation.Common.Components.MC6800 +{ + public partial class MC6800 + { + private void IRQ_() + { + Regs[ADDR] = 0xFFF8; + PopulateCURINSTR(IDLE, + SET_E, + DEC16, SP, + WR_DEC_LO, SP, PC, + WR_DEC_HI, SP, PC, + WR_DEC_LO, SP, X, + WR_DEC_HI, SP, X, + WR_DEC_LO, SP, DP, + WR_DEC_LO, SP, B, + WR_DEC_LO, SP, A, + WR, SP, CC, + SET_I, + RD_INC, ALU, ADDR, + RD_INC, ALU2, ADDR, + SET_ADDR, PC, ALU, ALU2); + + IRQS = 19; + } + + private void FIRQ_() + { + Regs[ADDR] = 0xFFF6; + PopulateCURINSTR(IDLE, + CLR_E, + DEC16, SP, + WR_DEC_LO, SP, PC, + WR_DEC_HI, SP, PC, + WR, SP, CC, + SET_F_I, + RD_INC, ALU, ADDR, + RD_INC, ALU2, ADDR, + SET_ADDR, PC, ALU, ALU2); + + IRQS = 10; + } + + private void NMI_() + { + Regs[ADDR] = 0xFFFC; + PopulateCURINSTR(IDLE, + SET_E, + DEC16, SP, + WR_DEC_LO, SP, PC, + WR_DEC_HI, SP, PC, + WR_DEC_LO, SP, X, + WR_DEC_HI, SP, X, + WR_DEC_LO, SP, DP, + WR_DEC_LO, SP, B, + WR_DEC_LO, SP, A, + WR, SP, CC, + SET_F_I, + RD_INC, ALU, ADDR, + RD_INC, ALU2, ADDR, + SET_ADDR, PC, ALU, ALU2); + + IRQS = 19; + } + + public bool NMIPending; + public bool FIRQPending; + public bool IRQPending; + public bool IN_SYNC; + + public Action IRQCallback = delegate () { }; + public Action FIRQCallback = delegate () { }; + public Action NMICallback = delegate () { }; + + private void ResetInterrupts() + { + IN_SYNC = false; + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/MC6800/MC6800.cs b/BizHawk.Emulation.Cores/CPUs/MC6800/MC6800.cs new file mode 100644 index 0000000000..f13070fc08 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/MC6800/MC6800.cs @@ -0,0 +1,695 @@ +using System; + +using BizHawk.Common; + +// Motorola Corp 6800 +namespace BizHawk.Emulation.Common.Components.MC6800 +{ + public sealed partial class MC6800 + { + // operations that can take place in an instruction + public const ushort IDLE = 0; + public const ushort OP = 1; + public const ushort RD = 2; + public const ushort WR = 3; + public const ushort TR = 4; + public const ushort ADD16BR = 5; + public const ushort ADD8 = 6; + public const ushort SUB8 = 7; + public const ushort ADC8 = 8; + public const ushort SBC8 = 9; + public const ushort INC16 = 10; + public const ushort INC8 = 11; + public const ushort DEC16 = 12; + public const ushort DEC8 = 13; + public const ushort ROL = 14; + public const ushort ROR = 15; + public const ushort COM = 16; + public const ushort DA = 17; + public const ushort AND8 = 18; + public const ushort XOR8 = 19; + public const ushort OR8 = 20; + public const ushort ASL = 21; + public const ushort ASR = 22; + public const ushort LSR = 23; + public const ushort BIT = 24; + public const ushort CWAI = 25; + public const ushort SYNC = 26; + public const ushort RD_INC = 27; + public const ushort RD_INC_OP = 28; + public const ushort WR_DEC_LO = 29; + public const ushort WR_DEC_HI = 30; + public const ushort WR_HI = 31; + public const ushort SET_ADDR = 32; + public const ushort NEG = 33; + public const ushort TST = 34; + public const ushort CLR = 35; + public const ushort SEX = 38; + public const ushort EXG = 39; + public const ushort TFR = 40; + public const ushort ADD8BR = 41; + public const ushort ABX = 42; + public const ushort MUL = 43; + public const ushort JPE = 44; + public const ushort IDX_DCDE = 45; + public const ushort IDX_OP_BLD = 46; + public const ushort EA_8 = 47; + public const ushort EA_16 = 48; + public const ushort WR_DEC_LO_OP = 51; + public const ushort WR_DEC_HI_OP = 52; + public const ushort WR_HI_INC = 53; + public const ushort SET_F_I = 55; + public const ushort SET_I = 56; + public const ushort SET_E = 57; + public const ushort ANDCC = 58; + public const ushort CMP8 = 59; + public const ushort SUB16 = 60; + public const ushort ADD16 = 61; + public const ushort CMP16 = 62; + public const ushort CMP16D = 63; + public const ushort LD_8 = 64; + public const ushort LD_16 = 65; + public const ushort LEA = 66; + public const ushort CLR_E = 67; + public const ushort TAP = 68; + public const ushort TPA = 69; + public const ushort INX = 70; + public const ushort DEX = 71; + public const ushort CLV = 72; + public const ushort SEV = 73; + public const ushort CLC = 74; + public const ushort SEC = 75; + public const ushort CLI = 76; + public const ushort SEI = 77; + + public MC6800() + { + Reset(); + } + + public void Reset() + { + ResetRegisters(); + ResetInterrupts(); + TotalExecutedCycles = 0; + Regs[PC] = 0xFFFE; + PopulateCURINSTR(IDLE, + IDLE, + IDLE, + RD_INC, ALU, PC, + RD_INC, ALU2, PC, + SET_ADDR, PC, ALU, ALU2); + + IRQS = 6; + instr_pntr = irq_pntr = 0; + } + + // Memory Access + + public Func ReadMemory; + public Action WriteMemory; + public Func PeekMemory; + public Func DummyReadMemory; + + // Special Function for Speed switching executed on a STOP + public Func SpeedFunc; + + //this only calls when the first byte of an instruction is fetched. + public Action OnExecFetch; + + public void UnregisterMemoryMapper() + { + ReadMemory = null; + ReadMemory = null; + PeekMemory = null; + DummyReadMemory = null; + } + + public void SetCallbacks + ( + Func ReadMemory, + Func DummyReadMemory, + Func PeekMemory, + Action WriteMemory + ) + { + this.ReadMemory = ReadMemory; + this.DummyReadMemory = DummyReadMemory; + this.PeekMemory = PeekMemory; + this.WriteMemory = WriteMemory; + } + + //a little CDL related stuff + public delegate void DoCDLCallbackType(ushort addr, MC6800.eCDLogMemFlags flags); + + public DoCDLCallbackType CDLCallback; + + public enum eCDLogMemFlags + { + FetchFirst = 1, + FetchOperand = 2, + Data = 4, + Write = 8 + }; + + // Execute instructions + public void ExecuteOne() + { + //Console.Write(opcode_see + " "); + //Console.WriteLine(Regs[PC] + " "); + switch (cur_instr[instr_pntr++]) + { + case IDLE: + // do nothing + break; + case OP: + // Read the opcode of the next instruction + if (OnExecFetch != null) OnExecFetch(PC); + if (TraceCallback != null) TraceCallback(State()); + if (CDLCallback != null) CDLCallback(PC, eCDLogMemFlags.FetchFirst); + FetchInstruction(ReadMemory(Regs[PC]++)); + instr_pntr = 0; + irq_pntr = -1; + break; + case RD: + Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case RD_INC: + Read_Inc_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case RD_INC_OP: + Read_Inc_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + switch (cur_instr[instr_pntr++]) + { + case AND8: + AND8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADD8: + ADD8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADC8: + ADC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case OR8: + OR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case XOR8: + XOR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case BIT: + BIT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case SUB8: + SUB8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case SBC8: + SBC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case CMP8: + CMP8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case DEC16: + DEC16_Func(cur_instr[instr_pntr++]); + break; + case ADD8BR: + ADD8BR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case TR: + TR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case SET_ADDR: + reg_d_ad = cur_instr[instr_pntr++]; + reg_h_ad = cur_instr[instr_pntr++]; + reg_l_ad = cur_instr[instr_pntr++]; + + Regs[reg_d_ad] = (ushort)((Regs[reg_h_ad] << 8) | Regs[reg_l_ad]); + break; + case JPE: + if (!FlagE) { instr_pntr = 44; irq_pntr = 10; }; + break; + case IDX_DCDE: + Index_decode(); + break; + case IDX_OP_BLD: + Index_Op_Builder(); + break; + case EA_8: + Regs[IDX_EA] = (ushort)(Regs[indexed_reg] + (((Regs[ALU2] & 0x80) == 0x80) ? (Regs[ALU2] | 0xFF00) : Regs[ALU2])); + Index_Op_Builder(); + break; + case LD_8: + LD_8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case LD_16: + LD_16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case LEA: + LEA_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ANDCC: + Regs[CC] &= Regs[instr_pntr++]; + break; + } + break; + case WR: + Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case WR_DEC_LO: + Write_Dec_Lo_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case WR_DEC_HI: + Write_Dec_HI_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case WR_DEC_LO_OP: + Write_Dec_Lo_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + instr_pntr++; + break; + case WR_DEC_HI_OP: + Write_Dec_HI_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + instr_pntr++; + break; + case WR_HI: + Write_Hi_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case WR_HI_INC: + Write_Hi_Inc_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case TR: + TR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case LD_8: + LD_8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case LD_16: + LD_16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case LEA: + LEA_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case EXG: + EXG_Func(cur_instr[instr_pntr++]); + break; + case IDX_OP_BLD: + Index_Op_Builder(); + break; + case EA_16: + Regs[IDX_EA] = (ushort)(Regs[indexed_reg] + Regs[ADDR]); + Index_Op_Builder(); + break; + case TFR: + TFR_Func(cur_instr[instr_pntr++]); + break; + case SET_ADDR: + reg_d_ad = cur_instr[instr_pntr++]; + reg_h_ad = cur_instr[instr_pntr++]; + reg_l_ad = cur_instr[instr_pntr++]; + + // Console.WriteLine(reg_d_ad + " " + reg_h_ad + " " + reg_l_ad); + // Console.WriteLine(Regs[reg_d_ad] + " " + Regs[reg_h_ad] + " " + Regs[reg_l_ad]); + + Regs[reg_d_ad] = (ushort)((Regs[reg_h_ad] << 8) | Regs[reg_l_ad]); + break; + case NEG: + NEG_8_Func(cur_instr[instr_pntr++]); + break; + case TST: + TST_Func(cur_instr[instr_pntr++]); + break; + case CLR: + CLR_Func(cur_instr[instr_pntr++]); + break; + case SEX: + SEX_Func(cur_instr[instr_pntr++]); + break; + case ABX: + Regs[X] += Regs[B]; + break; + case MUL: + Mul_Func(); + break; + case SET_F_I: + FlagI = true; FlagF = true; + break; + case SET_I: + FlagI = true; + break; + case SET_E: + FlagE = true; + break; + case CLR_E: + FlagE = false; + break; + case ANDCC: + Regs[CC] &= Regs[instr_pntr++]; + break; + case ADD16BR: + ADD16BR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADD8BR: + ADD8BR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADD8: + ADD8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case SUB8: + SUB8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADC8: + ADC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case SBC8: + SBC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case CMP8: + CMP8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case INC16: + INC16_Func(cur_instr[instr_pntr++]); + break; + case INC8: + INC8_Func(cur_instr[instr_pntr++]); + break; + case DEC16: + DEC16_Func(cur_instr[instr_pntr++]); + break; + case SUB16: + SUB16_Func(cur_instr[instr_pntr++]); + break; + case ADD16: + ADD16_Func(cur_instr[instr_pntr++]); + break; + case CMP16: + CMP16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case CMP16D: + CMP16D_Func(cur_instr[instr_pntr++]); + break; + case DEC8: + DEC8_Func(cur_instr[instr_pntr++]); + break; + case ROL: + ROL_Func(cur_instr[instr_pntr++]); + break; + case ROR: + ROR_Func(cur_instr[instr_pntr++]); + break; + case COM: + COM_Func(cur_instr[instr_pntr++]); + break; + case DA: + DA_Func(cur_instr[instr_pntr++]); + break; + case AND8: + AND8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case XOR8: + XOR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case OR8: + OR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ASL: + ASL_Func(cur_instr[instr_pntr++]); + break; + case ASR: + ASR_Func(cur_instr[instr_pntr++]); + break; + case LSR: + LSR_Func(cur_instr[instr_pntr++]); + break; + case TAP: + instr_pntr++; + Regs[CC] = (ushort)((Regs[A] & 0x3F) | 0xC0); // last 2 bits always 1 + break; + case TPA: + instr_pntr++; + Regs[A] = Regs[CC]; + break; + case INX: + instr_pntr++; + Regs[X] = (ushort)(Regs[X] + 1); + FlagZ = Regs[X] == 0; + break; + case DEX: + instr_pntr++; + Regs[X] = (ushort)(Regs[X] - 1); + FlagZ = Regs[X] == 0; + break; + case CLV: + instr_pntr++; + FlagV = false; + break; + case SEV: + instr_pntr++; + FlagV = true; + break; + case CLC: + instr_pntr++; + FlagC = false; + break; + case SEC: + instr_pntr++; + FlagC = true; + break; + case CLI: + instr_pntr++; + FlagI = false; + break; + case SEI: + instr_pntr++; + FlagI = true; + break; + case BIT: + BIT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case CWAI: + if (NMIPending) + { + NMIPending = false; + + Regs[ADDR] = 0xFFFC; + PopulateCURINSTR(RD_INC, ALU, ADDR, + RD_INC, ALU2, ADDR, + SET_ADDR, PC, ALU, ALU2); + irq_pntr = -1; + IRQS = 3; + + if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====CWAI NMI====", RegisterInfo = "" }); } + } + else if (FIRQPending && !FlagF) + { + FIRQPending = false; + + Regs[ADDR] = 0xFFF6; + PopulateCURINSTR(RD_INC, ALU, ADDR, + RD_INC, ALU2, ADDR, + SET_ADDR, PC, ALU, ALU2); + irq_pntr = -1; + IRQS = 3; + + if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====CWAI FIRQ====", RegisterInfo = "" }); } + } + else if (IRQPending && !FlagI) + { + IRQPending = false; + + Regs[ADDR] = 0xFFF8; + PopulateCURINSTR(RD_INC, ALU, ADDR, + RD_INC, ALU2, ADDR, + SET_ADDR, PC, ALU, ALU2); + irq_pntr = -1; + IRQS = 3; + + if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====CWAI IRQ====", RegisterInfo = "" }); } + } + else + { + PopulateCURINSTR(CWAI); + irq_pntr = 0; + IRQS = -1; + } + instr_pntr = 0; + break; + case SYNC: + IN_SYNC = true; + IRQS = 1; + instr_pntr = irq_pntr = 0; + PopulateCURINSTR(SYNC); + break; + } + + if (++irq_pntr == IRQS) + { + // NMI has priority + if (NMIPending) + { + NMIPending = false; + + if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====NMI====", RegisterInfo = "" }); } + + IN_SYNC = false; + NMI_(); + NMICallback(); + instr_pntr = irq_pntr = 0; + } + // fast IRQ has next priority + else if (FIRQPending) + { + if (!FlagF) + { + FIRQPending = false; + + if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====FIRQ====", RegisterInfo = "" }); } + + IN_SYNC = false; + FIRQ_(); + FIRQCallback(); + instr_pntr = irq_pntr = 0; + } + else if (IN_SYNC) + { + FIRQPending = false; + + if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====SYNC====", RegisterInfo = "" }); } + + IN_SYNC = false; + IRQS = 1; + instr_pntr = irq_pntr = 0; + PopulateCURINSTR(IDLE); + } + } + // then regular IRQ + else if (IRQPending && !FlagI) + { + if (!FlagI) + { + IRQPending = false; + + if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====IRQ====", RegisterInfo = "" }); } + + IN_SYNC = false; + IRQ_(); + IRQCallback(); + instr_pntr = irq_pntr = 0; + } + else if (IN_SYNC) + { + IRQPending = false; + + if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====SYNC====", RegisterInfo = "" }); } + + IN_SYNC = false; + IRQS = 1; + instr_pntr = irq_pntr = 0; + PopulateCURINSTR(IDLE); + } + } + // otherwise start the next instruction + else + { + PopulateCURINSTR(OP); + instr_pntr = irq_pntr = 0; + IRQS = -1; + } + } + + TotalExecutedCycles++; + } + + // tracer stuff + + public Action TraceCallback; + + public string TraceHeader + { + get { return "MC6809: PC, machine code, mnemonic, operands, registers (A, B, X, Y, US, SP, DP, CC), Cy, flags (EFHINZVC)"; } + } + + public TraceInfo State(bool disassemble = true) + { + ushort notused; + + return new TraceInfo + { + Disassembly = $"{(disassemble ? Disassemble(Regs[PC], ReadMemory, out notused) : "---")} ".PadRight(50), + RegisterInfo = string.Format( + "A:{0:X2} B:{1:X2} X:{2:X4} SP:{3:X4} DP:{4:X2} CC:{5:X2} Cy:{6} {7}{8}{9}{10}{11}{12}{13}{14}", + Regs[A], + Regs[B], + Regs[X], + Regs[SP], + Regs[DP], + Regs[CC], + TotalExecutedCycles, + FlagE ? "E" : "e", + FlagF ? "F" : "f", + FlagH ? "H" : "h", + FlagI ? "I" : "i", + FlagN ? "N" : "n", + FlagZ ? "Z" : "z", + FlagV ? "V" : "v", + FlagC ? "C" : "c" + ) + }; + } + + /// + /// Optimization method to set cur_instr + /// + private void PopulateCURINSTR(ushort d0 = 0, ushort d1 = 0, ushort d2 = 0, ushort d3 = 0, ushort d4 = 0, ushort d5 = 0, ushort d6 = 0, ushort d7 = 0, ushort d8 = 0, + ushort d9 = 0, ushort d10 = 0, ushort d11 = 0, ushort d12 = 0, ushort d13 = 0, ushort d14 = 0, ushort d15 = 0, ushort d16 = 0, ushort d17 = 0, ushort d18 = 0, + ushort d19 = 0, ushort d20 = 0, ushort d21 = 0, ushort d22 = 0, ushort d23 = 0, ushort d24 = 0, ushort d25 = 0, ushort d26 = 0, ushort d27 = 0, ushort d28 = 0, + ushort d29 = 0, ushort d30 = 0, ushort d31 = 0, ushort d32 = 0, ushort d33 = 0, ushort d34 = 0, ushort d35 = 0, ushort d36 = 0, ushort d37 = 0, ushort d38 = 0, + ushort d39 = 0, ushort d40 = 0, ushort d41 = 0, ushort d42 = 0, ushort d43 = 0, ushort d44 = 0, ushort d45 = 0, ushort d46 = 0, ushort d47 = 0, ushort d48 = 0, + ushort d49 = 0, ushort d50 = 0, ushort d51 = 0, ushort d52 = 0, ushort d53 = 0, ushort d54 = 0, ushort d55 = 0, ushort d56 = 0, ushort d57 = 0, ushort d58 = 0) + { + cur_instr[0] = d0; cur_instr[1] = d1; cur_instr[2] = d2; + cur_instr[3] = d3; cur_instr[4] = d4; cur_instr[5] = d5; + cur_instr[6] = d6; cur_instr[7] = d7; cur_instr[8] = d8; + cur_instr[9] = d9; cur_instr[10] = d10; cur_instr[11] = d11; + cur_instr[12] = d12; cur_instr[13] = d13; cur_instr[14] = d14; + cur_instr[15] = d15; cur_instr[16] = d16; cur_instr[17] = d17; + cur_instr[18] = d18; cur_instr[19] = d19; cur_instr[20] = d20; + cur_instr[21] = d21; cur_instr[22] = d22; cur_instr[23] = d23; + cur_instr[24] = d24; cur_instr[25] = d25; cur_instr[26] = d26; + cur_instr[27] = d27; cur_instr[28] = d28; cur_instr[29] = d29; + cur_instr[30] = d30; cur_instr[31] = d31; cur_instr[32] = d32; + cur_instr[33] = d33; cur_instr[34] = d34; cur_instr[35] = d35; + cur_instr[36] = d36; cur_instr[37] = d37; cur_instr[38] = d38; + cur_instr[39] = d39; cur_instr[40] = d40; cur_instr[41] = d41; + cur_instr[42] = d42; cur_instr[43] = d43; cur_instr[44] = d44; + cur_instr[45] = d45; cur_instr[46] = d46; cur_instr[47] = d47; + cur_instr[48] = d48; cur_instr[49] = d49; cur_instr[50] = d50; + cur_instr[51] = d51; cur_instr[52] = d52; cur_instr[53] = d53; + cur_instr[54] = d54; cur_instr[55] = d55; cur_instr[56] = d56; + cur_instr[57] = d57; cur_instr[58] = d58; + } + + // State Save/Load + public void SyncState(Serializer ser) + { + ser.BeginSection("MC6809"); + + ser.Sync(nameof(IN_SYNC), ref IN_SYNC); + ser.Sync(nameof(NMIPending), ref NMIPending); + ser.Sync(nameof(FIRQPending), ref FIRQPending); + ser.Sync(nameof(IRQPending), ref IRQPending); + + ser.Sync(nameof(indexed_op), ref indexed_op); + ser.Sync(nameof(indexed_reg), ref indexed_reg); + ser.Sync(nameof(indexed_op_reg), ref indexed_op_reg); + ser.Sync(nameof(temp), ref temp); + + ser.Sync(nameof(instr_pntr), ref instr_pntr); + ser.Sync(nameof(cur_instr), ref cur_instr, false); + ser.Sync(nameof(opcode_see), ref opcode_see); + ser.Sync(nameof(IRQS), ref IRQS); + ser.Sync(nameof(irq_pntr), ref irq_pntr); + + ser.Sync(nameof(Regs), ref Regs, false); + ser.Sync(nameof(TotalExecutedCycles), ref TotalExecutedCycles); + + ser.EndSection(); + } + } +} diff --git a/BizHawk.Emulation.Cores/CPUs/MC6800/OP_Tables.cs b/BizHawk.Emulation.Cores/CPUs/MC6800/OP_Tables.cs new file mode 100644 index 0000000000..cdcb3a829b --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/MC6800/OP_Tables.cs @@ -0,0 +1,528 @@ +using System; +using BizHawk.Common.NumberExtensions; + +namespace BizHawk.Emulation.Common.Components.MC6800 +{ + public partial class MC6800 + { + // this contains the vectors of instrcution operations + // NOTE: This list is NOT confirmed accurate for each individual cycle + + private void NOP_() + { + PopulateCURINSTR(IDLE); + + IRQS = 1; + } + + private void ILLEGAL() + { + //throw new Exception("Encountered illegal instruction"); + PopulateCURINSTR(IDLE); + + IRQS = 1; + } + + private void SYNC_() + { + PopulateCURINSTR(IDLE, + SYNC); + + IRQS = -1; + } + + private void REG_OP(ushort oper, ushort src) + { + PopulateCURINSTR(oper, src); + + IRQS = 1; + } + + private void REG_OP_16(ushort oper, ushort src) + { + PopulateCURINSTR(IDLE, + IDLE, + oper, src); + + IRQS = 3; + } + + private void DIRECT_MEM(ushort oper) + { + PopulateCURINSTR(RD_INC, ALU, PC, + SET_ADDR, ADDR, DP, ALU, + RD, ALU, ADDR, + oper, ALU, + WR, ADDR, ALU); + + IRQS = 5; + } + + private void DIRECT_ST_4(ushort dest) + { + PopulateCURINSTR(RD_INC_OP, ALU, PC, SET_ADDR, ADDR, DP, ALU, + IDLE, + WR, ADDR, dest); + + IRQS = 3; + } + + private void DIRECT_MEM_4(ushort oper, ushort dest) + { + PopulateCURINSTR(RD_INC_OP, ALU, PC, SET_ADDR, ADDR, DP, ALU, + IDLE, + RD_INC_OP, ALU, ADDR, oper, dest, ALU); + + IRQS = 3; + } + + private void EXT_MEM(ushort oper) + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC, ALU2, PC, + SET_ADDR, ADDR, ALU, ALU2, + RD, ALU, ADDR, + oper, ALU, + WR, ADDR, ALU); + + IRQS = 6; + } + + private void EXT_REG(ushort oper, ushort dest) + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC_OP, ALU2, PC, SET_ADDR, ADDR, ALU, ALU2, + RD, ALU, ADDR, + oper, dest, ALU); + + IRQS = 4; + } + + private void EXT_ST(ushort dest) + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC_OP, ALU2, PC, SET_ADDR, ADDR, ALU, ALU2, + IDLE, + WR, ADDR, dest); + + IRQS = 4; + } + + private void REG_OP_IMD_CC(ushort oper) + { + Regs[ALU2] = Regs[CC]; + PopulateCURINSTR(RD_INC_OP, ALU, PC, oper, ALU2, ALU, + TR, CC, ALU2); + + IRQS = 2; + } + + private void REG_OP_IMD(ushort oper, ushort dest) + { + PopulateCURINSTR(RD_INC_OP, ALU, PC, oper, dest, ALU); + + IRQS = 1; + } + + private void IMD_OP_D(ushort oper, ushort dest) + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC_OP, ALU2, PC, SET_ADDR, ADDR, ALU, ALU2, + oper, ADDR); + + IRQS = 3; + } + + private void DIR_OP_D(ushort oper, ushort dest) + { + PopulateCURINSTR(RD_INC_OP, ALU, PC, SET_ADDR, ADDR, DP, ALU, + RD_INC, ALU, ADDR, + RD, ALU2, ADDR, + SET_ADDR, ADDR, ALU, ALU2, + oper, ADDR); + + IRQS = 5; + } + + private void EXT_OP_D(ushort oper, ushort dest) + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC_OP, ALU2, PC, SET_ADDR, ADDR, ALU, ALU2, + RD_INC, ALU, ADDR, + RD, ALU2, ADDR, + SET_ADDR, ADDR, ALU, ALU2, + oper, ADDR); + + IRQS = 6; + } + + private void REG_OP_LD_16D() + { + PopulateCURINSTR(RD_INC, A, PC, + RD_INC_OP, B, PC, LD_16, ADDR, A, B); + + IRQS = 2; + } + + private void DIR_OP_LD_16D() + { + PopulateCURINSTR(RD_INC_OP, ALU, PC, SET_ADDR, ADDR, DP, ALU, + IDLE, + RD_INC, A, ADDR, + RD_INC_OP, B, ADDR, LD_16, ADDR, A, B); + + IRQS = 4; + } + + private void DIR_OP_ST_16D() + { + PopulateCURINSTR(RD_INC_OP, ALU, PC, SET_ADDR, ADDR, DP, ALU, + SET_ADDR, ALU, A, A, + WR_HI_INC, ADDR, ALU, + WR, ADDR, B); + + IRQS = 4; + } + + private void DIR_CMP_16(ushort oper, ushort dest) + { + PopulateCURINSTR(RD_INC_OP, ALU, PC, SET_ADDR, ADDR, DP, ALU, + RD_INC, ALU, ADDR, + RD, ALU2, ADDR, + SET_ADDR, ADDR, ALU, ALU2, + oper, dest, ADDR); + + IRQS = 5; + } + + private void IMD_CMP_16(ushort oper, ushort dest) + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC_OP, ALU2, PC, SET_ADDR, ADDR, ALU, ALU2, + oper, dest, ADDR); + + IRQS = 3; + } + + private void REG_OP_LD_16(ushort dest) + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC_OP, ALU2, PC, LD_16, dest, ALU, ALU2); + + IRQS = 2; + } + + private void DIR_OP_LD_16(ushort dest) + { + PopulateCURINSTR(RD_INC_OP, ALU, PC, SET_ADDR, ADDR, DP, ALU, + IDLE, + RD_INC, ALU, ADDR, + RD_INC_OP, ALU2, ADDR, LD_16, dest, ALU, ALU2); + + IRQS = 4; + } + + private void DIR_OP_ST_16(ushort src) + { + PopulateCURINSTR(RD_INC_OP, ALU, PC, SET_ADDR, ADDR, DP, ALU, + IDLE, + WR_HI_INC, ADDR, src, + WR_DEC_LO, ADDR, src); + + IRQS = 4; + } + + private void EXT_OP_LD_16(ushort dest) + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC_OP, ALU2, PC, SET_ADDR, ADDR, ALU, ALU2, + IDLE, + RD_INC, ALU, ADDR, + RD_INC_OP, ALU2, ADDR, LD_16, dest, ALU, ALU2); + + IRQS = 5; + } + + private void EXT_OP_ST_16(ushort src) + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC_OP, ALU2, PC, SET_ADDR, ADDR, ALU, ALU2, + IDLE, + WR_HI_INC, ADDR, src, + WR_DEC_LO, ADDR, src); + + IRQS = 5; + } + + private void EXT_OP_LD_16D() + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC_OP, ALU2, PC, SET_ADDR, ADDR, ALU, ALU2, + IDLE, + RD_INC, A, ADDR, + RD_INC_OP, B, ADDR, LD_16, ADDR, A, B); + + IRQS = 5; + } + + private void EXT_OP_ST_16D() + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC_OP, ALU2, PC, SET_ADDR, ADDR, ALU, ALU2, + SET_ADDR, ALU, A, A, + WR_HI_INC, ADDR, ALU, + WR, ADDR, B); + + IRQS = 5; + } + + private void EXT_CMP_16(ushort oper, ushort dest) + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC_OP, ALU2, PC, SET_ADDR, ADDR, ALU, ALU2, + RD_INC, ALU, ADDR, + RD, ALU2, ADDR, + SET_ADDR, ADDR, ALU, ALU2, + oper, dest, ADDR); + + IRQS = 6; + } + + private void EXG_() + { + PopulateCURINSTR(RD_INC, ALU, PC, + EXG, ALU, + IDLE, + IDLE, + IDLE, + IDLE, + IDLE); + + IRQS = 7; + } + + private void TFR_() + { + PopulateCURINSTR(RD_INC, ALU, PC, + TFR, ALU, + IDLE, + IDLE, + IDLE); + + IRQS = 5; + } + + private void JMP_DIR_() + { + PopulateCURINSTR(RD_INC, ALU, PC, + SET_ADDR, PC, DP, ALU); + + IRQS = 2; + } + + private void JMP_EXT_() + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC, ALU2, PC, + SET_ADDR, PC, ALU, ALU2); + + IRQS = 3; + } + + private void JSR_() + { + PopulateCURINSTR(RD_INC, ALU, PC, + SET_ADDR, ADDR, DP, ALU, + DEC16, SP, + TR, PC, ADDR, + WR_DEC_LO, SP, ADDR, + WR_HI, SP, ADDR); + + IRQS = 6; + } + + private void JSR_EXT() + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC_OP, ALU2, PC, SET_ADDR, ADDR, ALU, ALU2, + TR, ALU, PC, + DEC16, SP, + TR, PC, ADDR, + WR_DEC_LO, SP, ALU, + WR_HI, SP, ALU); + + IRQS = 7; + } + + private void LBR_(bool cond) + { + if (cond) + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC, ALU2, PC, + SET_ADDR, ADDR, ALU, ALU2, + ADD16BR, PC, ADDR); + + IRQS = 4; + } + else + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC, ALU2, PC, + SET_ADDR, ADDR, ALU, ALU2); + + IRQS = 3; + } + } + + private void BR_(bool cond) + { + if (cond) + { + PopulateCURINSTR(RD_INC, ALU, PC, + ADD8BR, PC, ALU); + + IRQS = 2; + } + else + { + PopulateCURINSTR(RD_INC, ALU, PC, + IDLE); + + IRQS = 2; + } + } + + private void BSR_() + { + PopulateCURINSTR(RD_INC, ALU, PC, + TR, ADDR, PC, + ADD8BR, PC, ALU, + DEC16, SP, + WR_DEC_LO, SP, ADDR, + WR_HI, SP, ADDR); + + IRQS = 6; + } + + private void LBSR_() + { + PopulateCURINSTR(RD_INC, ALU, PC, + RD_INC, ALU2, PC, + SET_ADDR, ADDR, ALU, ALU2, + TR, ALU, PC, + ADD16BR, PC, ADDR, + DEC16, SP, + WR_DEC_LO, SP, ALU, + WR_HI, SP, ALU); + + IRQS = 8; + } + + private void ABX_() + { + PopulateCURINSTR(ABX, + IDLE); + + IRQS = 2; + } + + private void MUL_() + { + PopulateCURINSTR(MUL, + IDLE, + IDLE, + IDLE, + IDLE, + IDLE, + IDLE, + IDLE, + IDLE, + IDLE); + + IRQS = 10; + } + + private void RTS() + { + PopulateCURINSTR(IDLE, + RD_INC, ALU, SP, + RD_INC, ALU2, SP, + SET_ADDR, PC, ALU, ALU2); + + IRQS = 4; + } + + private void RTI() + { + PopulateCURINSTR(IDLE, + RD_INC_OP, CC, SP, JPE, + RD_INC, A, SP, + RD_INC, B, SP, + RD_INC, DP, SP, + RD_INC, ALU, SP, + RD_INC_OP, ALU2, SP, SET_ADDR, X, ALU, ALU2, + RD_INC, ALU, SP, + RD_INC_OP, ALU2, SP, SET_ADDR, PC, ALU, ALU2); + + IRQS = 14; + } + + private void PSH_(ushort src) + { + PopulateCURINSTR(WR, SP, src, + IDLE, + DEC16, SP); + + IRQS = 3; + } + + private void PUL_(ushort src) + { + PopulateCURINSTR(INC16, SP, + IDLE, + RD, src, SP); + + IRQS = 3; + } + + private void SWI1() + { + Regs[ADDR] = 0xFFFA; + PopulateCURINSTR(SET_E, + DEC16, SP, + WR_DEC_LO, SP, PC, + WR_DEC_HI, SP, PC, + WR_DEC_LO, SP, X, + WR_DEC_HI, SP, X, + WR_DEC_LO, SP, DP, + WR_DEC_LO, SP, B, + WR_DEC_LO, SP, A, + WR, SP, CC, + SET_F_I, + RD_INC, ALU, ADDR, + RD_INC, ALU2, ADDR, + SET_ADDR, PC, ALU, ALU2); + + IRQS = 18; + } + + private void CWAI_() + { + PopulateCURINSTR(RD_INC_OP, ALU, PC, ANDCC, ALU, + SET_E, + DEC16, SP, + WR_DEC_LO, SP, PC, + WR_DEC_HI, SP, PC, + WR_DEC_LO, SP, X, + WR_DEC_HI, SP, X, + WR_DEC_LO, SP, DP, + WR_DEC_LO, SP, B, + WR_DEC_LO, SP, A, + WR, SP, CC, + CWAI); + + IRQS = 16; + } + } +} diff --git a/BizHawk.Emulation.Cores/CPUs/MC6800/Operations.cs b/BizHawk.Emulation.Cores/CPUs/MC6800/Operations.cs new file mode 100644 index 0000000000..f5e6ba2080 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/MC6800/Operations.cs @@ -0,0 +1,666 @@ +using System; +using BizHawk.Common.NumberExtensions; + +namespace BizHawk.Emulation.Common.Components.MC6800 +{ + public partial class MC6800 + { + public void Read_Func(ushort dest, ushort src) + { + if (CDLCallback != null) + { + if (src == PC) CDLCallback(Regs[src], eCDLogMemFlags.FetchOperand); + else CDLCallback(Regs[src], eCDLogMemFlags.Data); + } + Regs[dest] = ReadMemory(Regs[src]); + } + + public void Read_Inc_Func(ushort dest, ushort src) + { + if (CDLCallback != null) + { + if (src == PC) CDLCallback(Regs[src], eCDLogMemFlags.FetchOperand); + else CDLCallback(Regs[src], eCDLogMemFlags.Data); + } + //Console.WriteLine(dest + " " + src + " " + opcode_see); + + Regs[dest] = ReadMemory(Regs[src]); + + Regs[src]++; + } + + public void Write_Func(ushort dest, ushort src) + { + if (CDLCallback != null) CDLCallback(Regs[dest], eCDLogMemFlags.Write | eCDLogMemFlags.Data); + WriteMemory(Regs[dest], (byte)Regs[src]); + } + + public void Write_Dec_Lo_Func(ushort dest, ushort src) + { + if (CDLCallback != null) CDLCallback(Regs[dest], eCDLogMemFlags.Write | eCDLogMemFlags.Data); + WriteMemory(Regs[dest], (byte)Regs[src]); + Regs[dest] -= 1; + } + + public void Write_Dec_HI_Func(ushort dest, ushort src) + { + if (CDLCallback != null) CDLCallback(Regs[dest], eCDLogMemFlags.Write | eCDLogMemFlags.Data); + WriteMemory(Regs[dest], (byte)(Regs[src] >> 8)); + Regs[dest] -= 1; + } + + public void Write_Hi_Func(ushort dest, ushort src) + { + if (CDLCallback != null) CDLCallback(Regs[dest], eCDLogMemFlags.Write | eCDLogMemFlags.Data); + WriteMemory(Regs[dest], (byte)(Regs[src] >> 8)); + } + + public void Write_Hi_Inc_Func(ushort dest, ushort src) + { + if (CDLCallback != null) CDLCallback(Regs[dest], eCDLogMemFlags.Write | eCDLogMemFlags.Data); + WriteMemory(Regs[dest], (byte)(Regs[src] >> 8)); + Regs[dest]++; + } + + public void NEG_8_Func(ushort src) + { + int Reg16_d = 0; + Reg16_d -= Regs[src]; + + FlagC = Regs[src] != 0x0; + FlagZ = (Reg16_d & 0xFF) == 0; + FlagV = Regs[src] == 0x80; + FlagN = (Reg16_d & 0xFF) > 127; + + ushort ans = (ushort)(Reg16_d & 0xFF); + // redo for half carry flag + Reg16_d = 0; + Reg16_d -= (Regs[src] & 0xF); + FlagH = Reg16_d.Bit(4); + Regs[src] = ans; + } + + public void TR_Func(ushort dest, ushort src) + { + Regs[dest] = Regs[src]; + } + + public void LD_8_Func(ushort dest, ushort src) + { + Regs[dest] = Regs[src]; + + FlagZ = (Regs[dest] & 0xFF) == 0; + FlagV = false; + FlagN = (Regs[dest] & 0xFF) > 127; + } + + public void LD_16_Func(ushort dest, ushort src_h, ushort src_l) + { + Regs[dest] = (ushort)(Regs[src_h] << 8 | Regs[src_l]); + + FlagZ = Regs[dest] == 0; + FlagV = false; + FlagN = Regs[dest] > 0x7FFF; + } + + // for LEAX/Y, zero flag can be effected, but not for U/S + public void LEA_Func(ushort dest, ushort src) + { + Regs[dest] = Regs[src]; + + if (dest == X) + { + FlagZ = Regs[dest] == 0; + } + } + + public void TST_Func(ushort src) + { + FlagZ = Regs[src] == 0; + FlagV = false; + FlagN = (Regs[src] & 0xFF) > 127; + } + + public void CLR_Func(ushort src) + { + Regs[src] = 0; + + FlagZ = true; + FlagV = false; + FlagC = false; + FlagN = false; + } + + // source is considered a 16 bit signed value, used for long relative branch + // no flags used + public void ADD16BR_Func(ushort dest, ushort src) + { + Regs[dest] = (ushort)(Regs[dest] + (short)Regs[src]); + } + + public void ADD8BR_Func(ushort dest, ushort src) + { + if (Regs[src] > 127) { Regs[src] |= 0xFF00; } + Regs[dest] = (ushort)(Regs[dest] + (short)Regs[src]); + } + + public void Mul_Func() + { + Regs[ALU] = (ushort)(Regs[A] * Regs[B]); + D = Regs[ALU]; + FlagC = Regs[A] > 127; + FlagZ = D == 0; + } + + public void ADD8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + Reg16_d += Regs[src]; + + FlagC = Reg16_d.Bit(8); + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d += (Regs[src] & 0xF); + + FlagH = Reg16_d.Bit(4); + FlagV = (Regs[dest].Bit(7) == Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7)); + FlagN = ans > 127; + + Regs[dest] = ans; + } + + public void SUB8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + Reg16_d -= Regs[src]; + + FlagC = Reg16_d.Bit(8); + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d -= (Regs[src] & 0xF); + + FlagH = Reg16_d.Bit(4); + FlagN = ans > 127; + FlagV = (Regs[dest].Bit(7) != Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7)); + + Regs[dest] = ans; + } + + // same as SUB8 but result not stored + public void CMP8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + Reg16_d -= Regs[src]; + + FlagC = Reg16_d.Bit(8); + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d -= (Regs[src] & 0xF); + + FlagH = Reg16_d.Bit(4); + FlagN = ans > 127; + FlagV = (Regs[dest].Bit(7) != Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7)); + } + + public void BIT_Func(ushort dest, ushort src) + { + ushort ans = (ushort)(Regs[dest] & Regs[src]); + + FlagZ = ans == 0; + FlagV = false; + FlagN = ans > 127; + } + + public void ASL_Func(ushort src) + { + FlagC = Regs[src].Bit(7); + FlagV = Regs[src].Bit(7) ^ Regs[src].Bit(6); + + Regs[src] = (ushort)((Regs[src] << 1) & 0xFF); + + FlagZ = Regs[src] == 0; + FlagH = false; + FlagN = (Regs[src] & 0xFF) > 127; + + } + + public void ASR_Func(ushort src) + { + FlagC = Regs[src].Bit(0); + + ushort temp = (ushort)(Regs[src] & 0x80); // MSB doesn't change in this operation + + Regs[src] = (ushort)((Regs[src] >> 1) | temp); + + FlagZ = Regs[src] == 0; + FlagH = false; + FlagN = (Regs[src] & 0xFF) > 127; + } + + public void LSR_Func(ushort src) + { + FlagC = Regs[src].Bit(0); + + Regs[src] = (ushort)(Regs[src] >> 1); + + FlagZ = Regs[src] == 0; + FlagN = false; + } + + public void COM_Func(ushort src) + { + Regs[src] = (ushort)((~Regs[src]) & 0xFF); + + FlagC = true; + FlagZ = Regs[src] == 0; + FlagV = false; + FlagN = (Regs[src] & 0xFF) > 127; + } + + public void SEX_Func(ushort src) + { + if (Regs[B] > 127) + { + Regs[A] = 0xFF; + } + else + { + Regs[A] = 0; + } + + FlagZ = D == 0; + FlagN = Regs[A] > 127; + } + + public void AND8_Func(ushort dest, ushort src) + { + Regs[dest] = (ushort)(Regs[dest] & Regs[src]); + + FlagZ = Regs[dest] == 0; + FlagV = false; + FlagN = Regs[dest] > 127; + } + + public void OR8_Func(ushort dest, ushort src) + { + Regs[dest] = (ushort)(Regs[dest] | Regs[src]); + + FlagZ = Regs[dest] == 0; + FlagV = false; + FlagN = Regs[dest] > 127; + } + + public void XOR8_Func(ushort dest, ushort src) + { + Regs[dest] = (ushort)(Regs[dest] ^ Regs[src]); + + FlagZ = Regs[dest] == 0; + FlagV = false; + FlagN = Regs[dest] > 127; + } + + public void ROR_Func(ushort src) + { + ushort c = (ushort)(FlagC ? 0x80 : 0); + + FlagC = Regs[src].Bit(0); + + Regs[src] = (ushort)(c | (Regs[src] >> 1)); + + FlagZ = Regs[src] == 0; + FlagN = (Regs[src] & 0xFF) > 127; + } + + public void ROL_Func(ushort src) + { + ushort c = (ushort)(FlagC ? 1 : 0); + FlagC = Regs[src].Bit(7); + FlagV = Regs[src].Bit(7) ^ Regs[src].Bit(6); + + + Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | c); + + FlagZ = Regs[src] == 0; + FlagN = (Regs[src] & 0xFF) > 127; + } + + public void INC8_Func(ushort src) + { + FlagV = Regs[src] == 0x7F; + + Regs[src] = (ushort)((Regs[src] + 1) & 0xFF); + + FlagZ = Regs[src] == 0; + FlagN = (Regs[src] & 0xFF) > 127; + } + + public void DEC8_Func(ushort src) + { + FlagV = Regs[src] == 0x80; + + Regs[src] = (ushort)((Regs[src] - 1) & 0xFF); + + FlagZ = Regs[src] == 0; + FlagN = (Regs[src] & 0xFF) > 127; + } + + public void INC16_Func(ushort src) + { + Regs[src] += 1; + } + + public void DEC16_Func(ushort src) + { + Regs[src] -= 1; + } + + public void ADC8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + int c = FlagC ? 1 : 0; + + Reg16_d += (Regs[src] + c); + + FlagC = Reg16_d.Bit(8); + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d += ((Regs[src] & 0xF) + c); + + FlagH = Reg16_d.Bit(4); + FlagV = (Regs[dest].Bit(7) == Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7)); + FlagN = false; + + Regs[dest] = ans; + } + + public void SBC8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + int c = FlagC ? 1 : 0; + + Reg16_d -= (Regs[src] + c); + + FlagC = Reg16_d.Bit(8); + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d -= ((Regs[src] & 0xF) + c); + + FlagH = Reg16_d.Bit(4); + FlagN = ans > 127; + FlagV = (Regs[dest].Bit(7) != Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7)); + + Regs[dest] = ans; + } + + // DA code courtesy of AWJ: http://forums.nesdev.com/viewtopic.php?f=20&t=15944 + public void DA_Func(ushort src) + { + byte a = (byte)Regs[src]; + + if (!FlagN) + { // after an addition, adjust if (half-)carry occurred or if result is out of bounds + if (FlagC || a > 0x99) { a += 0x60; FlagC = true; } + if (FlagH || (a & 0x0f) > 0x09) { a += 0x6; } + } + else + { // after a subtraction, only adjust if (half-)carry occurred + if (FlagC) { a -= 0x60; } + if (FlagH) { a -= 0x6; } + } + + a &= 0xFF; + + Regs[src] = a; + + FlagZ = a == 0; + FlagH = false; + } + + // D register implied + public void SUB16_Func(ushort src) + { + int Reg16_d = D; + int Reg16_s = Regs[src]; + + Reg16_d -= Reg16_s; + + FlagC = Reg16_d.Bit(16); + FlagZ = (Reg16_d & 0xFFFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFFFF); + + FlagN = ans > 0x7FFF; + FlagV = (D.Bit(15) != Regs[src].Bit(15)) && (D.Bit(15) != ans.Bit(15)); + + D = ans; + } + + // D register implied + public void ADD16_Func(ushort src) + { + int Reg16_d = D; + int Reg16_s = Regs[src]; + + Reg16_d += Reg16_s; + + FlagC = Reg16_d.Bit(16); + FlagZ = (Reg16_d & 0xFFFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFFFF); + + FlagN = ans > 0x7FFF; + FlagV = (D.Bit(15) == Regs[src].Bit(15)) && (D.Bit(15) != ans.Bit(15)); + + D = ans; + } + + // D register implied + public void CMP16D_Func(ushort src) + { + int Reg16_d = D; + int Reg16_s = Regs[src]; + + Reg16_d -= Reg16_s; + + FlagC = Reg16_d.Bit(16); + FlagZ = (Reg16_d & 0xFFFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFFFF); + + FlagN = ans > 0x7FFF; + FlagV = (D.Bit(15) != Regs[src].Bit(15)) && (D.Bit(15) != ans.Bit(15)); + } + + public void CMP16_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + int Reg16_s = Regs[src]; + + Reg16_d -= Reg16_s; + + FlagC = Reg16_d.Bit(16); + FlagZ = (Reg16_d & 0xFFFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFFFF); + + FlagN = ans > 0x7FFF; + FlagV = (Regs[dest].Bit(15) != Regs[src].Bit(15)) && (Regs[dest].Bit(15) != ans.Bit(15)); + } + + public void EXG_Func(ushort sel) + { + ushort src = 0; + ushort dest = 0; + ushort temp = 0; + if ((Regs[sel] & 0x8) == 0) + { + switch (Regs[sel] & 0xF) + { + case 0: src = Dr; break; + case 1: src = X; break; + + case 4: src = SP; break; + case 5: src = PC; break; + case 6: src = 0xFF; break; + case 7: src = 0xFF; break; + } + + switch ((Regs[sel] >> 4) & 0xF) + { + case 0: dest = Dr; break; + case 1: dest = X; break; + + case 4: dest = SP; break; + case 5: dest = PC; break; + case 6: dest = 0xFF; break; + case 7: dest = 0xFF; break; + default: dest = 0xFF; break; + } + } + else + { + switch (Regs[sel] & 0xF) + { + case 8: src = A; break; + case 9: src = B; break; + case 10: src = CC; break; + case 11: src = DP; break; + case 12: src = 0xFF; break; + case 13: src = 0xFF; break; + case 14: src = 0xFF; break; + case 15: src = 0xFF; break; + } + + switch ((Regs[sel] >> 4) & 0xF) + { + case 8: dest = A; break; + case 9: dest = B; break; + case 10: dest = CC; break; + case 11: dest = DP; break; + case 12: dest = 0xFF; break; + case 13: dest = 0xFF; break; + case 14: dest = 0xFF; break; + case 15: dest = 0xFF; break; + default: dest = 0xFF; break; + } + } + + if ((src != 0xFF) && (dest != 0xFF)) + { + if (src == Dr) + { + temp = D; + D = Regs[dest]; + Regs[dest] = temp; + } + else if (dest == Dr) + { + temp = D; + D = Regs[src]; + Regs[src] = temp; + } + else + { + temp = Regs[src]; + Regs[src] = Regs[dest]; + Regs[dest] = temp; + } + } + } + + public void TFR_Func(ushort sel) + { + ushort src = 0; + ushort dest = 0; + + if ((Regs[sel] & 0x8) == 0) + { + switch (Regs[sel] & 0xF) + { + case 0: dest = Dr; break; + case 1: dest = X; break; + + case 4: dest = SP; break; + case 5: dest = PC; break; + case 6: dest = 0xFF; break; + case 7: dest = 0xFF; break; + } + + switch ((Regs[sel] >> 4) & 0xF) + { + case 0: src = Dr; break; + case 1: src = X; break; + + case 4: src = SP; break; + case 5: src = PC; break; + case 6: src = 0xFF; break; + case 7: src = 0xFF; break; + default: src = 0xFF; break; + } + } + else + { + switch (Regs[sel] & 0xF) + { + case 8: dest = A; break; + case 9: dest = B; break; + case 10: dest = CC; break; + case 11: dest = DP; break; + case 12: dest = 0xFF; break; + case 13: dest = 0xFF; break; + case 14: dest = 0xFF; break; + case 15: dest = 0xFF; break; + } + + switch ((Regs[sel] >> 4) & 0xF) + { + case 8: src = A; break; + case 9: src = B; break; + case 10: src = CC; break; + case 11: src = DP; break; + case 12: src = 0xFF; break; + case 13: src = 0xFF; break; + case 14: src = 0xFF; break; + case 15: src = 0xFF; break; + default: src = 0xFF; break; + } + } + + if ((src != 0xFF) && (dest != 0xFF)) + { + if (src == Dr) + { + Regs[dest] = D; + } + else if (dest == Dr) + { + D = Regs[src]; + } + else + { + Regs[dest] = Regs[src]; + } + } + } + } +} diff --git a/BizHawk.Emulation.Cores/CPUs/MC6800/ReadMe.txt b/BizHawk.Emulation.Cores/CPUs/MC6800/ReadMe.txt new file mode 100644 index 0000000000..115b568cb8 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/MC6800/ReadMe.txt @@ -0,0 +1 @@ +TODO: STOP for second byte nonzero diff --git a/BizHawk.Emulation.Cores/CPUs/MC6800/Registers.cs b/BizHawk.Emulation.Cores/CPUs/MC6800/Registers.cs new file mode 100644 index 0000000000..9fd091d230 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/MC6800/Registers.cs @@ -0,0 +1,87 @@ +using System; + +namespace BizHawk.Emulation.Common.Components.MC6800 +{ + public partial class MC6800 + { + // registers + public ushort[] Regs = new ushort[14]; + + public const ushort PC = 0; + public const ushort SP = 1; + public const ushort X = 2; + public const ushort A = 3; + public const ushort B = 4; + public const ushort ADDR = 5; // internal + public const ushort ALU = 6; // internal + public const ushort ALU2 = 7; // internal + public const ushort DP = 8; + public const ushort CC = 9; + public const ushort Dr = 10; + public const ushort IDX_EA = 11; + + public ushort D + { + get { return (ushort)(Regs[B] | (Regs[A] << 8)); } + set { Regs[B] = (ushort)(value & 0xFF); Regs[A] = (ushort)((value >> 8) & 0xFF); } + } + + public bool FlagC + { + get { return (Regs[CC] & 0x01) != 0; } + set { Regs[CC] = (byte)((Regs[CC] & ~0x01) | (value ? 0x01 : 0x00)); } + } + + public bool FlagV + { + get { return (Regs[CC] & 0x02) != 0; } + set { Regs[CC] = (byte)((Regs[CC] & ~0x02) | (value ? 0x02 : 0x00)); } + } + + public bool FlagZ + { + get { return (Regs[CC] & 0x04) != 0; } + set { Regs[CC] = (byte)((Regs[CC] & ~0x04) | (value ? 0x04 : 0x00)); } + } + + public bool FlagN + { + get { return (Regs[CC] & 0x08) != 0; } + set { Regs[CC] = (byte)((Regs[CC] & ~0x08) | (value ? 0x08 : 0x00)); } + } + + public bool FlagI + { + get { return (Regs[CC] & 0x10) != 0; } + set { Regs[CC] = (byte)((Regs[CC] & ~0x10) | (value ? 0x10 : 0x00)); } + } + + public bool FlagH + { + get { return (Regs[CC] & 0x20) != 0; } + set { Regs[CC] = (byte)((Regs[CC] & ~0x20) | (value ? 0x20 : 0x00)); } + } + + public bool FlagF + { + get { return (Regs[CC] & 0x40) != 0; } + set { Regs[CC] = (byte)((Regs[CC] & ~0x40) | (value ? 0x40 : 0x00)); } + } + + public bool FlagE + { + get { return (Regs[CC] & 0x80) != 0; } + set { Regs[CC] = (byte)((Regs[CC] & ~0x80) | (value ? 0x80 : 0x00)); } + } + + private void ResetRegisters() + { + for (int i = 0; i < 14; i++) + { + Regs[i] = 0; + } + + FlagI = true; + } + } +} \ No newline at end of file