C64 emulation on STM32F429 Discovery board with builtin LCD and USB keyboard support (OTG). More info at davevw.com and/or github.com/davervw

Dependencies:   LCD_DISCO_F429ZI BSP_DISCO_F429ZI USBHOST

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers emu6502.cpp Source File

emu6502.cpp

00001 // emu6502.cpp - Emu6502 - MOS6502 Emulator
00002 //
00003 ////////////////////////////////////////////////////////////////////////////////
00004 //
00005 // C64-stm429_discovery
00006 // C64/6502 Emulator targeting STM32F429 LCD/USBHOST
00007 // [ported from c-simple-emu-cbm (C Portable Version - for console)]
00008 //
00009 // MIT License
00010 //
00011 // Copyright(c) 2020 by David R.Van Wagner
00012 // davevw.com
00013 //
00014 // Permission is hereby granted, free of charge, to any person obtaining a copy
00015 // of this software and associated documentation files (the "Software"), to deal
00016 // in the Software without restriction, including without limitation the rights
00017 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00018 // copies of the Software, and to permit persons to whom the Software is
00019 // furnished to do so, subject to the following conditions:
00020 //
00021 // The above copyright notice and this permission notice shall be included in all
00022 // copies or substantial portions of the Software.
00023 //
00024 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00025 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00026 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
00027 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00028 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00029 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00030 // SOFTWARE.
00031 //
00032 ////////////////////////////////////////////////////////////////////////////////
00033 
00034 //#define snprintf sprintf_s
00035 
00036 #include <mbed.h>
00037 #include "emu6502.h"
00038 
00039 // globals
00040 byte A = 0;
00041 byte X = 0;
00042 byte Y = 0;
00043 byte S = 0xFF;
00044 bool N = false;
00045 bool V = false;
00046 bool B = false;
00047 bool D = false;
00048 bool I = false;
00049 bool Z = false;
00050 bool C = false;
00051 ushort PC = 0;
00052 bool trace = false;
00053 bool step = false;
00054 
00055 extern void ResetRun(bool (*ExecutePatch)(void))
00056 {
00057     ushort addr = (ushort)((GetMemory(0xFFFC) | (GetMemory(0xFFFD) << 8))); // RESET vector
00058     Execute(addr, ExecutePatch);
00059 }
00060 
00061 #ifndef WIN32
00062 static void strcpy_s(char* dest, size_t size, const char* src)
00063 {
00064     strncpy(dest, src, size);
00065 }
00066 
00067 static void strcat_s(char* dest, size_t size, const char* src)
00068 {
00069     strncat(dest, src, size);
00070 }
00071 #endif
00072 
00073 extern void PHP()
00074 {
00075     int flags = (N ? 0x80 : 0)
00076         | (V ? 0x40 : 0)
00077         | (B ? 0x10 : 0)
00078         | (D ? 0x08 : 0)
00079         | (I ? 0x04 : 0)
00080         | (Z ? 0x02 : 0)
00081         | (C ? 0x01 : 0);
00082     Push(flags);
00083 }
00084 
00085 extern byte LO(ushort value)
00086 {
00087     return (byte)value;
00088 }
00089 
00090 extern byte HI(ushort value)
00091 {
00092     return (byte)(value >> 8);
00093 }
00094 
00095 static void BRK(byte *p_bytes)
00096 {
00097     ++PC;
00098     Push(HI(PC));
00099     Push(LO(PC));
00100     PHP();
00101     B = true;
00102     PC = (ushort)(GetMemory(0xFFFE) + (GetMemory(0xFFFF) << 8));
00103     *p_bytes = 0;
00104 }
00105 
00106 static byte Subtract(byte reg, byte value, bool *p_overflow)
00107 {
00108     bool old_reg_neg = (reg & 0x80) != 0;
00109     bool value_neg = (value & 0x80) != 0;
00110     int result = reg - value - (C ? 0 : 1);
00111     N = (result & 0x80) != 0;
00112     C = (result >= 0);
00113     Z = (result == 0);
00114     bool result_neg = (result & 0x80) != 0;
00115     *p_overflow = (old_reg_neg && !value_neg && !result_neg) // neg - pos = pos
00116         || (!old_reg_neg && value_neg && result_neg); // pos - neg = neg
00117     return (byte)result;
00118 }
00119 
00120 static byte SubtractWithoutOverflow(byte reg, byte value)
00121 {
00122     C = true; // init for CMP, etc.
00123     bool unused;
00124     return Subtract(reg, value, &unused);
00125 }
00126 
00127 static void CMP(byte value)
00128 {
00129     SubtractWithoutOverflow(A, value);
00130 }
00131 
00132 static void CPX(byte value)
00133 {
00134     SubtractWithoutOverflow(X, value);
00135 }
00136 
00137 static void CPY(byte value)
00138 {
00139     SubtractWithoutOverflow(Y, value);
00140 }
00141 
00142 static void SetReg(byte *p_reg, int value)
00143 {
00144     *p_reg = (byte)value;
00145     Z = (*p_reg == 0);
00146     N = ((*p_reg & 0x80) != 0);
00147 }
00148 
00149 static void SetA(int value)
00150 {
00151     SetReg(&A, value);
00152 }
00153 
00154 static void SetX(int value)
00155 {
00156     SetReg(&X, value);
00157 }
00158 
00159 static void SetY(int value)
00160 {
00161     SetReg(&Y, value);
00162 }
00163 
00164 static void SBC(byte value)
00165 {
00166     if (D)
00167     {
00168         int A_dec = (A & 0xF) + ((A >> 4) * 10);
00169         int value_dec = (value & 0xF) + ((value >> 4) * 10);
00170         int result_dec = A_dec - value_dec - (C ? 0 : 1);
00171         C = (result_dec >= 0);
00172         if (!C)
00173             result_dec = -result_dec; // absolute value
00174         int result = (result_dec % 10) | (((result_dec / 10) % 10) << 4);
00175         SetA(result);
00176         N = false; // undefined?
00177         V = false; // undefined?
00178     }
00179     else
00180     {
00181         byte result = Subtract(A, value, &V);
00182         SetA(result);
00183     }
00184 }
00185 
00186 static void ADDC(byte value)
00187 {
00188     int result;
00189     if (D)
00190     {
00191         int A_dec = (A & 0xF) + ((A >> 4) * 10);
00192         int value_dec = (value & 0xF) + ((value >> 4) * 10);
00193         int result_dec = A_dec + value_dec + (C ? 1 : 0);
00194         C = (result_dec > 99);
00195         result = (result_dec % 10) | (((result_dec / 10) % 10) << 4);
00196         SetA(result);
00197         Z = (result_dec == 0); // BCD quirk -- 100 doesn't set Z
00198         V = false;
00199     }
00200     else
00201     {
00202         bool A_old_neg = (A & 0x80) != 0;
00203         bool value_neg = (value & 0x80) != 0;
00204         result = A + value + (C ? 1 : 0);
00205         C = (result & 0x100) != 0;
00206         SetA(result);
00207         bool result_neg = (result & 0x80) != 0;
00208         V = (!A_old_neg && !value_neg && result_neg) // pos + pos = neg: overflow
00209             || (A_old_neg && value_neg && !result_neg); // neg + neg = pos: overflow
00210     }
00211 }
00212 
00213 static void ORA(int value)
00214 {
00215     SetA(A | value);
00216 }
00217 
00218 static void EOR(int value)
00219 {
00220     SetA(A ^ value);
00221 }
00222 
00223 static void AND(int value)
00224 {
00225     SetA(A & value);
00226 }
00227 
00228 static void BIT(byte value)
00229 {
00230     Z = (A & value) == 0;
00231     N = (value & 0x80) != 0;
00232     V = (value & 0x40) != 0;
00233 }
00234 
00235 static byte ASL(int value)
00236 {
00237     C = (value & 0x80) != 0;
00238     value = (byte)(value << 1);
00239     Z = (value == 0);
00240     N = (value & 0x80) != 0;
00241     return (byte)value;
00242 }
00243 
00244 static byte LSR(int value)
00245 {
00246     C = (value & 0x01) != 0;
00247     value = (byte)(value >> 1);
00248     Z = (value == 0);
00249     N = false;
00250     return (byte)value;
00251 }
00252 
00253 static byte ROL(int value)
00254 {
00255     bool newC = (value & 0x80) != 0;
00256     value = (byte)((value << 1) | (C ? 1 : 0));
00257     C = newC;
00258     Z = (value == 0);
00259     N = (value & 0x80) != 0;
00260     return (byte)value;
00261 }
00262 
00263 static byte ROR(int value)
00264 {
00265     bool newC = (value & 0x01) != 0;
00266     N = C;
00267     value = (byte)((value >> 1) | (C ? 0x80 : 0));
00268     C = newC;
00269     Z = (value == 0);
00270     return (byte)value;
00271 }
00272 
00273 extern void Push(int value)
00274 {
00275     SetMemory((ushort)(0x100 + (S--)), (byte)value);
00276 }
00277 
00278 extern byte Pop(void)
00279 {
00280     return GetMemory((ushort)(0x100 + (++S)));
00281 }
00282 
00283 static void PLP()
00284 {
00285     int flags = Pop();
00286     N = (flags & 0x80) != 0;
00287     V = (flags & 0x40) != 0;
00288     B = (flags & 0x10) != 0;
00289     D = (flags & 0x08) != 0;
00290     I = (flags & 0x04) != 0;
00291     Z = (flags & 0x02) != 0;
00292     C = (flags & 0x01) != 0;
00293 }
00294 
00295 static void PHA()
00296 {
00297     Push(A);
00298 }
00299 
00300 static void PLA()
00301 {
00302     SetA(Pop());
00303 }
00304 
00305 static void CLC()
00306 {
00307     C = false;
00308 }
00309 
00310 static void CLD()
00311 {
00312     D = false;
00313 }
00314 
00315 static void CLI()
00316 {
00317     I = false;
00318 }
00319 
00320 static void CLV()
00321 {
00322     V = false;
00323 }
00324 
00325 static void SEC()
00326 {
00327     C = true;
00328 }
00329 
00330 static void SED()
00331 {
00332     D = true;
00333 }
00334 
00335 static void SEI()
00336 {
00337     I = true;
00338 }
00339 
00340 static byte INC(byte value)
00341 {
00342     ++value;
00343     Z = (value == 0);
00344     N = (value & 0x80) != 0;
00345     return (byte)value;
00346 }
00347 
00348 static void INX()
00349 {
00350     X = INC(X);
00351 }
00352 
00353 static void INY()
00354 {
00355     Y = INC(Y);
00356 }
00357 
00358 static byte DEC(byte value)
00359 {
00360     --value;
00361     Z = (value == 0);
00362     N = (value & 0x80) != 0;
00363     return (byte)value;
00364 }
00365 
00366 static void DEX()
00367 {
00368     X = DEC(X);
00369 }
00370 
00371 static void DEY()
00372 {
00373     Y = DEC(Y);
00374 }
00375 
00376 static void NOP()
00377 {
00378 }
00379 
00380 static void TXA()
00381 {
00382     SetReg(&A, X);
00383 }
00384 
00385 static void TAX()
00386 {
00387     SetReg(&X, A);
00388 }
00389 
00390 static void TYA()
00391 {
00392     SetReg(&A, Y);
00393 }
00394 
00395 static void TAY()
00396 {
00397     SetReg(&Y, A);
00398 }
00399 
00400 static void TXS()
00401 {
00402     S = X;
00403 }
00404 
00405 static void TSX()
00406 {
00407     SetReg(&X, S);
00408 }
00409 
00410 static ushort GetBR(ushort addr, bool *p_conditional, byte *p_bytes)
00411 {
00412     *p_conditional = true;
00413     *p_bytes = 2;
00414     sbyte offset = (sbyte)GetMemory((ushort)(addr + 1));
00415     ushort addr2 = (ushort)(addr + 2 + offset);
00416     return addr2;
00417 }
00418 
00419 static void BR(bool branch, ushort *p_addr, bool *p_conditional, byte *p_bytes)
00420 {
00421     ushort addr2 = GetBR(*p_addr, p_conditional, p_bytes);
00422     if (branch)
00423     {
00424         *p_addr = addr2;
00425         *p_bytes = 0; // don't advance addr
00426     }
00427 }
00428 
00429 static void BPL(ushort *p_addr, bool *p_conditional, byte *p_bytes)
00430 {
00431     BR(!N, p_addr, p_conditional, p_bytes);
00432 }
00433 
00434 static void BMI(ushort *p_addr, bool *p_conditional, byte *p_bytes)
00435 {
00436     BR(N, p_addr, p_conditional, p_bytes);
00437 }
00438 
00439 static void BCC(ushort *p_addr, bool *p_conditional, byte *p_bytes)
00440 {
00441     BR(!C, p_addr, p_conditional, p_bytes);
00442 }
00443 
00444 static void BCS(ushort *p_addr, bool *p_conditional, byte *p_bytes)
00445 {
00446     BR(C, p_addr, p_conditional, p_bytes);
00447 }
00448 
00449 static void BVC(ushort *p_addr, bool *p_conditional, byte *p_bytes)
00450 {
00451     BR(!V, p_addr, p_conditional, p_bytes);
00452 }
00453 
00454 static void BVS(ushort *p_addr, bool *p_conditional, byte *p_bytes)
00455 {
00456     BR(V, p_addr, p_conditional, p_bytes);
00457 }
00458 
00459 static void BNE(ushort *p_addr, bool *p_conditional, byte *p_bytes)
00460 {
00461     BR(!Z, p_addr, p_conditional, p_bytes);
00462 }
00463 
00464 static void BEQ(ushort *p_addr, bool *p_conditional, byte *p_bytes)
00465 {
00466     BR(Z, p_addr, p_conditional, p_bytes);
00467 }
00468 
00469 static void JSR(ushort *p_addr, byte *p_bytes)
00470 {
00471     *p_bytes = 3; // for next calculation
00472     ushort addr2 = (ushort)(*p_addr + *p_bytes - 1);
00473     ushort addr3 = (ushort)(GetMemory((ushort)(*p_addr + 1)) | (GetMemory((ushort)(*p_addr + 2)) << 8));
00474     Push(HI(addr2));
00475     Push(LO(addr2));
00476     *p_addr = addr3;
00477     *p_bytes = 0; // addr already changed
00478 }
00479 
00480 static void RTS(ushort *p_addr, byte *p_bytes)
00481 {
00482     byte lo = Pop();
00483     byte hi = Pop();
00484     *p_bytes = 1; // make sure caller increases addr by one
00485     *p_addr = (ushort)((hi << 8) | lo);
00486 }
00487 
00488 static void RTI(ushort *p_addr, byte *p_bytes)
00489 {
00490     PLP();
00491     byte lo = Pop();
00492     byte hi = Pop();
00493     *p_bytes = 0; // make sure caller does not increase addr by one
00494     *p_addr = (ushort)((hi << 8) | lo);
00495 }
00496 
00497 static void JMP(ushort *p_addr, byte *p_bytes)
00498 {
00499     *p_bytes = 0; // caller should not advance address
00500     ushort addr2 = (ushort)(GetMemory((ushort)(*p_addr + 1)) | (GetMemory((ushort)(*p_addr + 2)) << 8));
00501     *p_addr = addr2;
00502 }
00503 
00504 static void JMPIND(ushort *p_addr, byte *p_bytes)
00505 {
00506     *p_bytes = 0; // caller should not advance address
00507     ushort addr2 = (ushort)(GetMemory((ushort)(*p_addr + 1)) | (GetMemory((ushort)(*p_addr + 2)) << 8));
00508     ushort addr3;
00509     if ((addr2 & 0xFF) == 0xFF) // JMP($XXFF) won't go over page boundary
00510         addr3 = (ushort)(GetMemory(addr2) | (GetMemory((ushort)(addr2 - 0xFF)) << 8)); // 6502 "bug" - will use XXFF and XX00 as source of address
00511     else
00512         addr3 = (ushort)(GetMemory(addr2) | (GetMemory((ushort)(addr2 + 1)) << 8));
00513     *p_addr = addr3;
00514 }
00515 
00516 // "A:FF X:FF Y:FF S:FF P:XX-XXXXX"
00517 static void GetDisplayState(char *state, int state_size)
00518 {
00519     snprintf(state, state_size, "A:%02X X:%02X Y:%02X S:%02X P:%c%c-%c%c%c%c%c",
00520         A,
00521         X,
00522         Y,
00523         S,
00524         N ? 'N' : ' ',
00525         V ? 'V' : ' ',
00526         B ? 'B' : ' ',
00527         D ? 'D' : ' ',
00528         I ? 'I' : ' ',
00529         Z ? 'Z' : ' ',
00530         C ? 'C' : ' '
00531     );
00532 }
00533 
00534 static byte GetIndX(ushort addr, byte *p_bytes)
00535 {
00536     *p_bytes = 2;
00537     ushort addr2 = (ushort)(GetMemory((ushort)(addr + 1)) + X);
00538     return GetMemory((ushort)(GetMemory(addr2) | (GetMemory((ushort)(addr2 + 1)) << 8)));
00539 }
00540 
00541 static void SetIndX(byte value, ushort addr, byte *p_bytes)
00542 {
00543     *p_bytes = 2;
00544     ushort addr2 = (ushort)(GetMemory((ushort)(addr + 1)) + X);
00545     ushort addr3 = (ushort)(GetMemory(addr2) | (GetMemory((ushort)(addr2 + 1)) << 8));
00546     SetMemory(addr3, value);
00547 }
00548 
00549 static byte GetIndY(ushort addr, byte *p_bytes)
00550 {
00551     *p_bytes = 2;
00552     ushort addr2 = (ushort)(GetMemory((ushort)(addr + 1)));
00553     ushort addr3 = (ushort)((GetMemory(addr2) | (GetMemory((ushort)(addr2 + 1)) << 8)) + Y);
00554     return GetMemory(addr3);
00555 }
00556 
00557 static void SetIndY(byte value, ushort addr, byte *p_bytes)
00558 {
00559     *p_bytes = 2;
00560     ushort addr2 = (ushort)(GetMemory((ushort)(addr + 1)));
00561     ushort addr3 = (ushort)((GetMemory(addr2) | (GetMemory((ushort)(addr2 + 1)) << 8)) + Y);
00562     SetMemory(addr3, value);
00563 }
00564 
00565 static byte GetZP(ushort addr, byte *p_bytes)
00566 {
00567     *p_bytes = 2;
00568     ushort addr2 = GetMemory((ushort)(addr + 1));
00569     return GetMemory(addr2);
00570 }
00571 
00572 static void SetZP(byte value, ushort addr, byte *p_bytes)
00573 {
00574     *p_bytes = 2;
00575     ushort addr2 = GetMemory((ushort)(addr + 1));
00576     SetMemory(addr2, value);
00577 }
00578 
00579 static byte GetZPX(ushort addr, byte *p_bytes)
00580 {
00581     *p_bytes = 2;
00582     ushort addr2 = GetMemory((ushort)(addr + 1));
00583     return GetMemory((byte)(addr2 + X));
00584 }
00585 
00586 static void SetZPX(byte value, ushort addr, byte *p_bytes)
00587 {
00588     *p_bytes = 2;
00589     ushort addr2 = GetMemory((ushort)(addr + 1));
00590     SetMemory((byte)(addr2 + X), value);
00591 }
00592 
00593 static byte GetZPY(ushort addr, byte *p_bytes)
00594 {
00595     *p_bytes = 2;
00596     ushort addr2 = GetMemory((ushort)(addr + 1));
00597     return GetMemory((byte)(addr2 + Y));
00598 }
00599 
00600 static void SetZPY(byte value, ushort addr, byte *p_bytes)
00601 {
00602     *p_bytes = 2;
00603     ushort addr2 = GetMemory((ushort)(addr + 1));
00604     SetMemory((byte)(addr2 + Y), value);
00605 }
00606 
00607 static byte GetABS(ushort addr, byte *p_bytes)
00608 {
00609     *p_bytes = 3;
00610     ushort addr2 = (ushort)(GetMemory((ushort)(addr + 1)) | (GetMemory((ushort)(addr + 2)) << 8));
00611     return GetMemory(addr2);
00612 }
00613 
00614 static void SetABS(byte value, ushort addr, byte *p_bytes)
00615 {
00616     *p_bytes = 3;
00617     ushort addr2 = (ushort)(GetMemory((ushort)(addr + 1)) | (GetMemory((ushort)(addr + 2)) << 8));
00618     SetMemory(addr2, value);
00619 }
00620 
00621 static byte GetABSX(ushort addr, byte *p_bytes)
00622 {
00623     *p_bytes = 3;
00624     ushort addr2 = (ushort)(GetMemory((ushort)(addr + 1)) | (GetMemory((ushort)(addr + 2)) << 8));
00625     return GetMemory((ushort)(addr2 + X));
00626 }
00627 
00628 static void SetABSX(byte value, ushort addr, byte *p_bytes)
00629 {
00630     *p_bytes = 3;
00631     ushort addr2 = (ushort)((GetMemory((ushort)(addr + 1)) | (GetMemory((ushort)(addr + 2)) << 8)) + X);
00632     SetMemory(addr2, value);
00633 }
00634 
00635 static byte GetABSY(ushort addr, byte *p_bytes)
00636 {
00637     *p_bytes = 3;
00638     ushort addr2 = (ushort)(GetMemory((ushort)(addr + 1)) | (GetMemory((ushort)(addr + 2)) << 8));
00639     return GetMemory((ushort)(addr2 + Y));
00640 }
00641 
00642 static void SetABSY(byte value, ushort addr, byte *p_bytes)
00643 {
00644     *p_bytes = 3;
00645     ushort addr2 = (ushort)((GetMemory((ushort)(addr + 1)) | (GetMemory((ushort)(addr + 2)) << 8)) + Y);
00646     SetMemory(addr2, value);
00647 }
00648 
00649 static byte GetIM(ushort addr, byte *p_bytes)
00650 {
00651     *p_bytes = 2;
00652     return GetMemory((ushort)(addr + 1));
00653 }
00654 
00655 extern void Execute(ushort addr, bool (*ExecutePatch)(void))
00656 {
00657     bool conditional;
00658     byte bytes;
00659 
00660     Timer timer;
00661     const double interrupt_time = 1.0 / 60.0 ; // 60 times per second
00662     timer.start();
00663     double timer_then = timer.read();   
00664 
00665     PC = addr;
00666 
00667     while (true)
00668     {
00669         while (true)
00670         {
00671             if (!I && (timer.read()-timer_then) >= interrupt_time) // IRQ
00672             {
00673                 timer_then = timer.read(); // reset timer
00674                 Push(HI(PC));
00675                 Push(LO(PC));
00676                 PHP();
00677                 I = true;
00678                 PC = (GetMemory(0xfffe) | (GetMemory(0xffff) << 8));
00679             }
00680             else
00681             {
00682                 bytes = 1;
00683                 bool breakpoint = false;
00684                 //if (Breakpoints.Contains(PC))
00685                 //  breakpoint = true;
00686                 if (trace || breakpoint || step)
00687                 {
00688                     ushort addr2;
00689                     char line[27];
00690                     char dis[13];
00691                     DisassembleLong(PC, &conditional, &bytes, &addr2, dis, sizeof(dis), line, sizeof(line));
00692                     char state[33];
00693                     GetDisplayState(state, sizeof(state));
00694                     char full_line[80];
00695                     snprintf(full_line, sizeof(full_line), "%-30s%s\n", line, state);
00696     #ifdef WIN32
00697                     OutputDebugStringA(full_line);
00698     #else               
00699                     printf("%s", full_line);
00700     #endif              
00701                     if (step)
00702                         step = step; // user can put debug breakpoint here to allow stepping
00703                     if (breakpoint)
00704                         breakpoint = breakpoint; // user can put debug breakpoint here to allow break
00705                 }
00706                 if (ExecutePatch != 0 && !ExecutePatch()) // allow execute to be overriden at a specific address
00707                     break;
00708             }
00709         }
00710 
00711         switch (GetMemory(PC))
00712         {
00713         case 0x00: BRK(&bytes); break;
00714         case 0x01: ORA(GetIndX(PC, &bytes)); break;
00715         case 0x05: ORA(GetZP(PC, &bytes)); break;
00716         case 0x06: SetZP(ASL(GetZP(PC, &bytes)), PC, &bytes); break;
00717         case 0x08: PHP(); break;
00718         case 0x09: ORA(GetIM(PC, &bytes)); break;
00719         case 0x0A: SetA(ASL(A)); break;
00720         case 0x0D: ORA(GetABS(PC, &bytes)); break;
00721         case 0x0E: SetABS(ASL(GetABS(PC, &bytes)), PC, &bytes); break;
00722 
00723         case 0x10: BPL(&PC, &conditional, &bytes); break;
00724         case 0x11: ORA(GetIndY(PC, &bytes)); break;
00725         case 0x15: ORA(GetZPX(PC, &bytes)); break;
00726         case 0x16: SetZPX(ASL(GetZPX(PC, &bytes)), PC, &bytes); break;
00727         case 0x18: CLC(); break;
00728         case 0x19: ORA(GetABSY(PC, &bytes)); break;
00729         case 0x1D: ORA(GetABSX(PC, &bytes)); break;
00730         case 0x1E: SetABSX(ASL(GetABSX(PC, &bytes)), PC, &bytes); break;
00731 
00732         case 0x20: JSR(&PC, &bytes); break;
00733         case 0x21: AND(GetIndX(PC, &bytes)); break;
00734         case 0x24: BIT(GetZP(PC, &bytes)); break;
00735         case 0x25: AND(GetZP(PC, &bytes)); break;
00736         case 0x26: SetZP(ROL(GetZP(PC, &bytes)), PC, &bytes); break;
00737         case 0x28: PLP(); break;
00738         case 0x29: AND(GetIM(PC, &bytes)); break;
00739         case 0x2A: SetA(ROL(A)); break;
00740         case 0x2C: BIT(GetABS(PC, &bytes)); break;
00741         case 0x2D: AND(GetABS(PC, &bytes)); break;
00742         case 0x2E: ROL(GetABS(PC, &bytes)); break;
00743 
00744         case 0x30: BMI(&PC, &conditional, &bytes); break;
00745         case 0x31: AND(GetIndY(PC, &bytes)); break;
00746         case 0x35: AND(GetZPX(PC, &bytes)); break;
00747         case 0x36: SetZPX(ROL(GetZPX(PC, &bytes)), PC, &bytes); break;
00748         case 0x38: SEC(); break;
00749         case 0x39: AND(GetABSY(PC, &bytes)); break;
00750         case 0x3D: AND(GetABSX(PC, &bytes)); break;
00751         case 0x3E: SetABSX(ROL(GetABSX(PC, &bytes)), PC, &bytes); break;
00752 
00753         case 0x40: RTI(&PC, &bytes); break;
00754         case 0x41: EOR(GetIndX(PC, &bytes)); break;
00755         case 0x45: EOR(GetZP(PC, &bytes)); break;
00756         case 0x46: SetZP(LSR(GetZP(PC, &bytes)), PC, &bytes); break;
00757         case 0x48: PHA(); break;
00758         case 0x49: EOR(GetIM(PC, &bytes)); break;
00759         case 0x4A: SetA(LSR(A)); break;
00760         case 0x4C: JMP(&PC, &bytes); break;
00761         case 0x4D: EOR(GetABS(PC, &bytes)); break;
00762         case 0x4E: LSR(GetABS(PC, &bytes)); break;
00763 
00764         case 0x50: BVC(&PC, &conditional, &bytes); break;
00765         case 0x51: EOR(GetIndY(PC, &bytes)); break;
00766         case 0x55: EOR(GetZPX(PC, &bytes)); break;
00767         case 0x56: SetZPX(LSR(GetZPX(PC, &bytes)), PC, &bytes); break;
00768         case 0x58: CLI(); break;
00769         case 0x59: EOR(GetABSY(PC, &bytes)); break;
00770         case 0x5D: EOR(GetABSX(PC, &bytes)); break;
00771         case 0x5E: SetABSX(LSR(GetABSX(PC, &bytes)), PC, &bytes); break;
00772 
00773         case 0x60: RTS(&PC, &bytes); break;
00774         case 0x61: ADDC(GetIndX(PC, &bytes)); break;
00775         case 0x65: ADDC(GetZP(PC, &bytes)); break;
00776         case 0x66: SetZP(ROR(GetZP(PC, &bytes)), PC, &bytes); break;
00777         case 0x68: PLA(); break;
00778         case 0x69: ADDC(GetIM(PC, &bytes)); break;
00779         case 0x6A: SetA(ROR(A)); break;
00780         case 0x6C: JMPIND(&PC, &bytes); break;
00781         case 0x6D: ADDC(GetABS(PC, &bytes)); break;
00782         case 0x6E: SetABS(ROR(GetABS(PC, &bytes)), PC, &bytes); break;
00783 
00784         case 0x70: BVS(&PC, &conditional, &bytes); break;
00785         case 0x71: ADDC(GetIndY(PC, &bytes)); break;
00786         case 0x75: ADDC(GetZPX(PC, &bytes)); break;
00787         case 0x76: SetZPX(ROR(GetZPX(PC, &bytes)), PC, &bytes); break;
00788         case 0x78: SEI(); break;
00789         case 0x79: ADDC(GetABSY(PC, &bytes)); break;
00790         case 0x7D: ADDC(GetABSX(PC, &bytes)); break;
00791         case 0x7E: SetABSX(ROR(GetABSX(PC, &bytes)), PC, &bytes); break;
00792 
00793         case 0x81: SetIndX(A, PC, &bytes); break;
00794         case 0x84: SetZP(Y, PC, &bytes); break;
00795         case 0x85: SetZP(A, PC, &bytes); break;
00796         case 0x86: SetZP(X, PC, &bytes); break;
00797         case 0x88: DEY(); break;
00798         case 0x8A: TXA(); break;
00799         case 0x8C: SetABS(Y, PC, &bytes); break;
00800         case 0x8D: SetABS(A, PC, &bytes); break;
00801         case 0x8E: SetABS(X, PC, &bytes); break;
00802 
00803         case 0x90: BCC(&PC, &conditional, &bytes); break;
00804         case 0x91: SetIndY(A, PC, &bytes); break;
00805         case 0x94: SetZPX(Y, PC, &bytes); break;
00806         case 0x95: SetZPX(A, PC, &bytes); break;
00807         case 0x96: SetZPY(X, PC, &bytes); break;
00808         case 0x98: TYA(); break;
00809         case 0x99: SetABSY(A, PC, &bytes); break;
00810         case 0x9A: TXS(); break;
00811         case 0x9D: SetABSX(A, PC, &bytes); break;
00812 
00813         case 0xA0: SetY(GetIM(PC, &bytes)); break;
00814         case 0xA1: SetA(GetIndX(PC, &bytes)); break;
00815         case 0xA2: SetX(GetIM(PC, &bytes)); break;
00816         case 0xA4: SetY(GetZP(PC, &bytes)); break;
00817         case 0xA5: SetA(GetZP(PC, &bytes)); break;
00818         case 0xA6: SetX(GetZP(PC, &bytes)); break;
00819         case 0xA8: TAY(); break;
00820         case 0xA9: SetA(GetIM(PC, &bytes)); break;
00821         case 0xAA: TAX(); break;
00822         case 0xAC: SetY(GetABS(PC, &bytes)); break;
00823         case 0xAD: SetA(GetABS(PC, &bytes)); break;
00824         case 0xAE: SetX(GetABS(PC, &bytes)); break;
00825 
00826         case 0xB0: BCS(&PC, &conditional, &bytes); break;
00827         case 0xB1: SetA(GetIndY(PC, &bytes)); break;
00828         case 0xB4: SetY(GetZPX(PC, &bytes)); break;
00829         case 0xB5: SetA(GetZPX(PC, &bytes)); break;
00830         case 0xB6: SetX(GetZPY(PC, &bytes)); break;
00831         case 0xB8: CLV(); break;
00832         case 0xB9: SetA(GetABSY(PC, &bytes)); break;
00833         case 0xBA: TSX(); break;
00834         case 0xBC: SetY(GetABSX(PC, &bytes)); break;
00835         case 0xBD: SetA(GetABSX(PC, &bytes)); break;
00836         case 0xBE: SetX(GetABSY(PC, &bytes)); break;
00837 
00838         case 0xC0: CPY(GetIM(PC, &bytes)); break;
00839         case 0xC1: CMP(GetIndX(PC, &bytes)); break;
00840         case 0xC4: CPY(GetZP(PC, &bytes)); break;
00841         case 0xC5: CMP(GetZP(PC, &bytes)); break;
00842         case 0xC6: SetZP(DEC(GetZP(PC, &bytes)), PC, &bytes); break;
00843         case 0xC8: INY(); break;
00844         case 0xC9: CMP(GetIM(PC, &bytes)); break;
00845         case 0xCA: DEX(); break;
00846         case 0xCC: CPY(GetABS(PC, &bytes)); break;
00847         case 0xCD: CMP(GetABS(PC, &bytes)); break;
00848         case 0xCE: SetABS(DEC(GetABS(PC, &bytes)), PC, &bytes); break;
00849 
00850         case 0xD0: BNE(&PC, &conditional, &bytes); break;
00851         case 0xD1: CMP(GetIndY(PC, &bytes)); break;
00852         case 0xD5: CMP(GetZPX(PC, &bytes)); break;
00853         case 0xD6: SetZPX(DEC(GetZPX(PC, &bytes)), PC, &bytes); break;
00854         case 0xD8: CLD(); break;
00855         case 0xD9: CMP(GetABSY(PC, &bytes)); break;
00856         case 0xDD: CMP(GetABSX(PC, &bytes)); break;
00857         case 0xDE: SetABSX(DEC(GetABSX(PC, &bytes)), PC, &bytes); break;
00858 
00859         case 0xE0: CPX(GetIM(PC, &bytes)); break;
00860         case 0xE1: SBC(GetIndX(PC, &bytes)); break;
00861         case 0xE4: CPX(GetZP(PC, &bytes)); break;
00862         case 0xE5: SBC(GetZP(PC, &bytes)); break;
00863         case 0xE6: SetZP(INC(GetZP(PC, &bytes)), PC, &bytes); break;
00864         case 0xE8: INX(); break;
00865         case 0xE9: SBC(GetIM(PC, &bytes)); break;
00866         case 0xEA: NOP(); break;
00867         case 0xEC: CPX(GetABS(PC, &bytes)); break;
00868         case 0xED: SBC(GetABS(PC, &bytes)); break;
00869         case 0xEE: SetABS(INC(GetABS(PC, &bytes)), PC, &bytes); break;
00870 
00871         case 0xF0: BEQ(&PC, &conditional, &bytes); break;
00872         case 0xF1: SBC(GetIndY(PC, &bytes)); break;
00873         case 0xF5: SBC(GetZPX(PC, &bytes)); break;
00874         case 0xF6: SetZPX(INC(GetZPX(PC, &bytes)), PC, &bytes); break;
00875         case 0xF8: SED(); break;
00876         case 0xF9: SBC(GetABSY(PC, &bytes)); break;
00877         case 0xFD: SBC(GetABSX(PC, &bytes)); break;
00878         case 0xFE: SetABSX(INC(GetABSX(PC, &bytes)), PC, &bytes); break;
00879 
00880         default:
00881             {
00882                 printf("Invalid opcode %02X at %04X", GetMemory(PC), PC);
00883                 exit(1);
00884             }
00885         }
00886 
00887         PC += bytes;
00888     }
00889 }
00890 
00891 // Examples:
00892 // FFFF FF FF FF JMP ($FFFF)
00893 // FFFF FF FF FF LDA $FFFF,X
00894 extern void DisassembleLong(ushort addr, bool *p_conditional, byte *p_bytes, ushort *p_addr2, char *dis, int dis_size, char *line, int line_size)
00895 {
00896     DisassembleShort(addr, p_conditional, p_bytes, p_addr2, dis, dis_size);
00897     snprintf(line, line_size, "%04X ", addr);
00898     for (int i = 0; i < 3; ++i)
00899     {
00900         if (i < *p_bytes)
00901             snprintf(line+strlen(line), line_size-strlen(line), "%02X ", GetMemory((ushort)(addr + i)));
00902         else
00903             strcat_s(line, line_size, "   ");
00904     }
00905     strcat_s(line, line_size, dis);
00906 }
00907 
00908 static void Ind(char *dis, int dis_size, char* opcode, ushort addr, ushort *p_addr2, byte *p_bytes)
00909 {
00910     *p_bytes = 3;
00911     ushort addr1 = (ushort)(GetMemory((ushort)(addr + 1)) | (GetMemory((ushort)(addr + 2)) << 8));
00912     *p_addr2 = (ushort)(GetMemory(addr1) | (GetMemory((ushort)(addr1 + 1)) << 8));
00913     snprintf(dis, dis_size, "%s ($%0X4)", opcode, addr1);
00914 }
00915 
00916 static void IndX(char *dis, int dis_size, char* opcode, ushort addr, byte *p_bytes)
00917 {
00918     *p_bytes = 2;
00919     snprintf(dis, dis_size, "%s ($%02X,X)", opcode, GetMemory((ushort)(addr + 1)));
00920 }
00921 
00922 static void IndY(char *dis, int dis_size, char* opcode, ushort addr, byte *p_bytes)
00923 {
00924     *p_bytes = 2;
00925     snprintf(dis, dis_size, "%s ($%02X),Y", opcode, GetMemory((ushort)(addr + 1)));
00926 }
00927 
00928 static void ZP(char *dis, int dis_size, char* opcode, ushort addr, byte *p_bytes)
00929 {
00930     *p_bytes = 2;
00931     snprintf(dis, dis_size, "%s $%02X", opcode, GetMemory((ushort)(addr + 1)));
00932 }
00933 
00934 static void ZPX(char *dis, int dis_size, char* opcode, ushort addr, byte *p_bytes)
00935 {
00936     *p_bytes = 2;
00937     snprintf(dis, dis_size, "%s $%02X,X", opcode, GetMemory((ushort)(addr + 1)));
00938 }
00939 
00940 static void ZPY(char *dis, int dis_size, char* opcode, ushort addr, byte *p_bytes)
00941 {
00942     *p_bytes = 2;
00943     snprintf(dis, dis_size, "%s $%02X,Y", opcode, GetMemory((ushort)(addr + 1)));
00944 }
00945 
00946 static void ABS(char *dis, int dis_size, char* opcode, ushort addr, byte *p_bytes)
00947 {
00948     *p_bytes = 3;
00949     snprintf(dis, dis_size, "%s $%04X", opcode, GetMemory((ushort)(addr + 1)) | (GetMemory((ushort)(addr + 2)) << 8));
00950 }
00951 
00952 static void ABSAddr(char *dis, int dis_size, char* opcode, ushort addr, ushort *p_addr2, byte *p_bytes)
00953 {
00954     *p_bytes = 3;
00955     *p_addr2 = (ushort)(GetMemory((ushort)(addr + 1)) | (GetMemory((ushort)(addr + 2)) << 8));
00956     snprintf(dis, dis_size, "%s $%04X", opcode, *p_addr2);
00957 }
00958 
00959 static void ABSX(char *dis, int dis_size, char* opcode, ushort addr, byte *p_bytes)
00960 {
00961     *p_bytes = 3;
00962     snprintf(dis, dis_size, "%s $%04X,X", opcode, GetMemory((ushort)(addr + 1)) | (GetMemory((ushort)(addr + 2)) << 8));
00963 }
00964 
00965 static void ABSY(char *dis, int dis_size, char* opcode, ushort addr, byte *p_bytes)
00966 {
00967     *p_bytes = 3;
00968     snprintf(dis, dis_size, "%s $%04X,Y", opcode, GetMemory((ushort)(addr + 1)) | (GetMemory((ushort)(addr + 2)) << 8));
00969 }
00970 
00971 static void IM(char *dis, int dis_size, char* opcode, ushort addr, byte *p_bytes)
00972 {
00973     *p_bytes = 2;
00974     snprintf(dis, dis_size, "%s #$%02X", opcode, GetMemory((ushort)(addr + 1)));
00975 }
00976 
00977 static void BRX(char *dis, int dis_size, char* opcode, ushort addr, bool *p_conditional, ushort *p_addr2, byte *p_bytes)
00978 {
00979     *p_bytes = 2;
00980     *p_conditional = true;
00981     sbyte offset = (sbyte)GetMemory((ushort)(addr + 1));
00982     *p_addr2 = (ushort)(addr + 2 + offset);
00983     snprintf(dis, dis_size, "%s $%04X", opcode, *p_addr2);
00984 }
00985 
00986 // JMP ($FFFF)
00987 // LDA $FFFF,X
00988 extern void DisassembleShort(ushort addr, bool *p_conditional, byte *p_bytes, ushort *p_addr2, char *dis, int dis_size)
00989 {
00990     *p_conditional = false;
00991     *p_addr2 = 0;
00992     *p_bytes = 1;
00993 
00994     switch (GetMemory(addr))
00995     {
00996     case 0x00: strcpy_s(dis, dis_size, "BRK"); return;
00997     case 0x01: IndX(dis, dis_size, "ORA", addr, p_bytes); return;
00998     case 0x05: ZP(dis, dis_size, "ORA", addr, p_bytes); return;
00999     case 0x06: ZP(dis, dis_size, "ASL", addr, p_bytes); return;
01000     case 0x08: strcpy_s(dis, dis_size, "PHP"); return;
01001     case 0x09: IM(dis, dis_size, "ORA", addr, p_bytes); return;
01002     case 0x0A: strcpy_s(dis, dis_size, "ASL A"); return;
01003     case 0x0D: ABS(dis, dis_size, "ORA", addr, p_bytes); return;
01004     case 0x0E: ABS(dis, dis_size, "ASL", addr, p_bytes); return;
01005 
01006     case 0x10: BRX(dis, dis_size, "BPL", addr, p_conditional, p_addr2, p_bytes); return;
01007     case 0x11: IndY(dis, dis_size, "ORA", addr, p_bytes); return;
01008     case 0x15: ZPX(dis, dis_size, "ORA", addr, p_bytes); return;
01009     case 0x16: ZPX(dis, dis_size, "ASL", addr, p_bytes); return;
01010     case 0x18: strcpy_s(dis, dis_size, "CLC"); return;
01011     case 0x19: ABSY(dis, dis_size, "ORA", addr, p_bytes); return;
01012     case 0x1D: ABSX(dis, dis_size, "ORA", addr, p_bytes); return;
01013     case 0x1E: ABSX(dis, dis_size, "ASL", addr, p_bytes); return;
01014 
01015     case 0x20: ABSAddr(dis, dis_size, "JSR", addr, p_addr2, p_bytes); return;
01016     case 0x21: IndX(dis, dis_size, "AND", addr, p_bytes); return;
01017     case 0x24: ZP(dis, dis_size, "BIT", addr, p_bytes); return;
01018     case 0x25: ZP(dis, dis_size, "AND", addr, p_bytes); return;
01019     case 0x26: ZP(dis, dis_size, "ROL", addr, p_bytes); return;
01020     case 0x28: strcpy_s(dis, dis_size, "PLP"); return;
01021     case 0x29: IM(dis, dis_size, "AND", addr, p_bytes); return;
01022     case 0x2A: strcpy_s(dis, dis_size, "ROL A"); return;
01023     case 0x2C: ABS(dis, dis_size, "BIT", addr, p_bytes); return;
01024     case 0x2D: ABS(dis, dis_size, "AND", addr, p_bytes); return;
01025     case 0x2E: ABS(dis, dis_size, "ROL", addr, p_bytes); return;
01026 
01027     case 0x30: BRX(dis, dis_size, "BMI", addr, p_conditional, p_addr2, p_bytes); return;
01028     case 0x31: IndY(dis, dis_size, "AND", addr, p_bytes); return;
01029     case 0x35: ZPX(dis, dis_size, "AND", addr, p_bytes); return;
01030     case 0x36: ZPX(dis, dis_size, "ROL", addr, p_bytes); return;
01031     case 0x38: strcpy_s(dis, dis_size, "SEC"); return;
01032     case 0x39: ABSY(dis, dis_size, "AND", addr, p_bytes); return;
01033     case 0x3D: ABSX(dis, dis_size, "AND", addr, p_bytes); return;
01034     case 0x3E: ABSX(dis, dis_size, "ROL", addr, p_bytes); return;
01035 
01036     case 0x40: strcpy_s(dis, dis_size, "RTI"); return;
01037     case 0x41: IndX(dis, dis_size, "EOR", addr, p_bytes); return;
01038     case 0x45: ZP(dis, dis_size, "EOR", addr, p_bytes); return;
01039     case 0x46: ZP(dis, dis_size, "LSR", addr, p_bytes); return;
01040     case 0x48: strcpy_s(dis, dis_size, "PHA"); return;
01041     case 0x49: IM(dis, dis_size, "EOR", addr, p_bytes); return;
01042     case 0x4A: strcpy_s(dis, dis_size, "LSR A"); return;
01043     case 0x4C: ABSAddr(dis, dis_size, "JMP", addr, p_addr2, p_bytes); return;
01044     case 0x4D: ABS(dis, dis_size, "EOR", addr, p_bytes); return;
01045     case 0x4E: ABS(dis, dis_size, "LSR", addr, p_bytes); return;
01046 
01047     case 0x50: BRX(dis, dis_size, "BVC", addr, p_conditional, p_addr2, p_bytes); return;
01048     case 0x51: IndY(dis, dis_size, "EOR", addr, p_bytes); return;
01049     case 0x55: ZPX(dis, dis_size, "EOR", addr, p_bytes); return;
01050     case 0x56: ZPX(dis, dis_size, "LSR", addr, p_bytes); return;
01051     case 0x58: strcpy_s(dis, dis_size, "CLI"); return;
01052     case 0x59: ABSY(dis, dis_size, "EOR", addr, p_bytes); return;
01053     case 0x5D: ABSX(dis, dis_size, "EOR", addr, p_bytes); return;
01054     case 0x5E: ABSX(dis, dis_size, "LSR", addr, p_bytes); return;
01055 
01056     case 0x60: strcpy_s(dis, dis_size, "RTS"); return;
01057     case 0x61: IndX(dis, dis_size, "ADC", addr, p_bytes); return;
01058     case 0x65: ZP(dis, dis_size, "ADC", addr, p_bytes); return;
01059     case 0x66: ZP(dis, dis_size, "ROR", addr, p_bytes); return;
01060     case 0x68: strcpy_s(dis, dis_size, "PLA"); return;
01061     case 0x69: IM(dis, dis_size, "ADC", addr, p_bytes); return;
01062     case 0x6A: strcpy_s(dis, dis_size, "ROR A"); return;
01063     case 0x6C: Ind(dis, dis_size, "JMP", addr, p_addr2, p_bytes); return;
01064     case 0x6D: ABS(dis, dis_size, "ADC", addr, p_bytes); return;
01065     case 0x6E: ABS(dis, dis_size, "ROR", addr, p_bytes); return;
01066 
01067     case 0x70: BRX(dis, dis_size, "BVS", addr, p_conditional, p_addr2, p_bytes); return;
01068     case 0x71: IndY(dis, dis_size, "ADC", addr, p_bytes); return;
01069     case 0x75: ZPX(dis, dis_size, "ADC", addr, p_bytes); return;
01070     case 0x76: ZPX(dis, dis_size, "ROR", addr, p_bytes); return;
01071     case 0x78: strcpy_s(dis, dis_size, "SEI"); return;
01072     case 0x79: ABSY(dis, dis_size, "ADC", addr, p_bytes); return;
01073     case 0x7D: ABSX(dis, dis_size, "ADC", addr, p_bytes); return;
01074     case 0x7E: ABSX(dis, dis_size, "ROR", addr, p_bytes); return;
01075 
01076     case 0x81: IndX(dis, dis_size, "STA", addr, p_bytes); return;
01077     case 0x84: ZP(dis, dis_size, "STY", addr, p_bytes); return;
01078     case 0x85: ZP(dis, dis_size, "STA", addr, p_bytes); return;
01079     case 0x86: ZP(dis, dis_size, "STX", addr, p_bytes); return;
01080     case 0x88: strcpy_s(dis, dis_size, "DEY"); return;
01081     case 0x8A: strcpy_s(dis, dis_size, "TXA"); return;
01082     case 0x8C: ABS(dis, dis_size, "STY", addr, p_bytes); return;
01083     case 0x8D: ABS(dis, dis_size, "STA", addr, p_bytes); return;
01084     case 0x8E: ABS(dis, dis_size, "STX", addr, p_bytes); return;
01085 
01086     case 0x90: BRX(dis, dis_size, "BCC", addr, p_conditional, p_addr2, p_bytes); return;
01087     case 0x91: IndY(dis, dis_size, "STA", addr, p_bytes); return;
01088     case 0x94: ZPX(dis, dis_size, "STY", addr, p_bytes); return;
01089     case 0x95: ZPX(dis, dis_size, "STA", addr, p_bytes); return;
01090     case 0x96: ZPY(dis, dis_size, "STX", addr, p_bytes); return;
01091     case 0x98: strcpy_s(dis, dis_size, "TYA"); return;
01092     case 0x99: ABSY(dis, dis_size, "STA", addr, p_bytes); return;
01093     case 0x9A: strcpy_s(dis, dis_size, "TXS"); return;
01094     case 0x9D: ABSX(dis, dis_size, "STA", addr, p_bytes); return;
01095 
01096     case 0xA0: IM(dis, dis_size, "LDY", addr, p_bytes); return;
01097     case 0xA1: IndX(dis, dis_size, "LDA", addr, p_bytes); return;
01098     case 0xA2: IM(dis, dis_size, "LDX", addr, p_bytes); return;
01099     case 0xA4: ZP(dis, dis_size, "LDY", addr, p_bytes); return;
01100     case 0xA5: ZP(dis, dis_size, "LDA", addr, p_bytes); return;
01101     case 0xA6: ZP(dis, dis_size, "LDX", addr, p_bytes); return;
01102     case 0xA8: strcpy_s(dis, dis_size, "TAY"); return;
01103     case 0xA9: IM(dis, dis_size, "LDA", addr, p_bytes); return;
01104     case 0xAA: strcpy_s(dis, dis_size, "TAX"); return;
01105     case 0xAC: ABS(dis, dis_size, "LDY", addr, p_bytes); return;
01106     case 0xAD: ABS(dis, dis_size, "LDA", addr, p_bytes); return;
01107     case 0xAE: ABS(dis, dis_size, "LDX", addr, p_bytes); return;
01108 
01109     case 0xB0: BRX(dis, dis_size, "BCS", addr, p_conditional, p_addr2, p_bytes); return;
01110     case 0xB1: IndY(dis, dis_size, "LDA", addr, p_bytes); return;
01111     case 0xB4: ZPX(dis, dis_size, "LDY", addr, p_bytes); return;
01112     case 0xB5: ZPX(dis, dis_size, "LDA", addr, p_bytes); return;
01113     case 0xB6: ZPY(dis, dis_size, "LDX", addr, p_bytes); return;
01114     case 0xB8: strcpy_s(dis, dis_size, "CLV"); return;
01115     case 0xB9: ABSY(dis, dis_size, "LDA", addr, p_bytes); return;
01116     case 0xBA: strcpy_s(dis, dis_size, "TSX"); return;
01117     case 0xBC: ABSX(dis, dis_size, "LDY", addr, p_bytes); return;
01118     case 0xBD: ABSX(dis, dis_size, "LDA", addr, p_bytes); return;
01119     case 0xBE: ABSY(dis, dis_size, "LDX", addr, p_bytes); return;
01120 
01121     case 0xC0: IM(dis, dis_size, "CPY", addr, p_bytes); return;
01122     case 0xC1: IndX(dis, dis_size, "CMP", addr, p_bytes); return;
01123     case 0xC4: ZP(dis, dis_size, "CPY", addr, p_bytes); return;
01124     case 0xC5: ZP(dis, dis_size, "CMP", addr, p_bytes); return;
01125     case 0xC6: ZP(dis, dis_size, "DEC", addr, p_bytes); return;
01126     case 0xC8: strcpy_s(dis, dis_size, "INY"); return;
01127     case 0xC9: IM(dis, dis_size, "CMP", addr, p_bytes); return;
01128     case 0xCA: strcpy_s(dis, dis_size, "DEX"); return;
01129     case 0xCC: ABS(dis, dis_size, "CPY", addr, p_bytes); return;
01130     case 0xCD: ABS(dis, dis_size, "CMP", addr, p_bytes); return;
01131     case 0xCE: ABS(dis, dis_size, "DEC", addr, p_bytes); return;
01132 
01133     case 0xD0: BRX(dis, dis_size, "BNE", addr, p_conditional, p_addr2, p_bytes); return;
01134     case 0xD1: IndY(dis, dis_size, "CMP", addr, p_bytes); return;
01135     case 0xD5: ZPX(dis, dis_size, "CMP", addr, p_bytes); return;
01136     case 0xD6: ZPX(dis, dis_size, "DEC", addr, p_bytes); return;
01137     case 0xD8: strcpy_s(dis, dis_size, "CLD"); return;
01138     case 0xD9: ABSY(dis, dis_size, "CMP", addr, p_bytes); return;
01139     case 0xDD: ABSX(dis, dis_size, "CMP", addr, p_bytes); return;
01140     case 0xDE: ABSX(dis, dis_size, "DEC", addr, p_bytes); return;
01141 
01142     case 0xE0: IM(dis, dis_size, "CPX", addr, p_bytes); return;
01143     case 0xE1: IndX(dis, dis_size, "SBC", addr, p_bytes); return;
01144     case 0xE4: ZP(dis, dis_size, "CPX", addr, p_bytes); return;
01145     case 0xE5: ZP(dis, dis_size, "SBC", addr, p_bytes); return;
01146     case 0xE6: ZP(dis, dis_size, "INC", addr, p_bytes); return;
01147     case 0xE8: strcpy_s(dis, dis_size, "INX"); return;
01148     case 0xE9: IM(dis, dis_size, "SBC", addr, p_bytes); return;
01149     case 0xEA: strcpy_s(dis, dis_size, "NOP"); return;
01150     case 0xEC: ABS(dis, dis_size, "CPX", addr, p_bytes); return;
01151     case 0xED: ABS(dis, dis_size, "SBC", addr, p_bytes); return;
01152     case 0xEE: ABS(dis, dis_size, "INC", addr, p_bytes); return;
01153 
01154     case 0xF0: BRX(dis, dis_size, "BEQ", addr, p_conditional, p_addr2, p_bytes); return;
01155     case 0xF1: IndY(dis, dis_size, "SBC", addr, p_bytes); return;
01156     case 0xF5: ZPX(dis, dis_size, "SBC", addr, p_bytes); return;
01157     case 0xF6: ZPX(dis, dis_size, "INC", addr, p_bytes); return;
01158     case 0xF8: strcpy_s(dis, dis_size, "SED"); return;
01159     case 0xF9: ABSY(dis, dis_size, "SBC", addr, p_bytes); return;
01160     case 0xFD: ABSX(dis, dis_size, "SBC", addr, p_bytes); return;
01161     case 0xFE: ABSX(dis, dis_size, "INC", addr, p_bytes); return;
01162 
01163     default:
01164         strcpy_s(dis, dis_size, "???");
01165         return;
01166         //throw new Exception(string.Format("Invalid opcode {0:X2}", memory[addr]));
01167     }
01168 }