]> Shamusworld >> Repos - apple2/blob - src/v65c02.cpp
Moved CPU cycle subtraction into CPU core.
[apple2] / src / v65c02.cpp
1 //
2 // Virtual 65C02 Emulator v1.0
3 //
4 // by James L. Hammons
5 // (c) 2005 Underground Software
6 //
7 // JLH = James L. Hammons <jlhamm@acm.org>
8 //
9 // WHO  WHEN        WHAT
10 // ---  ----------  ------------------------------------------------------------
11 // JLH  01/04/2006  Added changelog ;-)
12 //
13
14 //OK, the wraparound bug exists in both the Apple and Atari versions of Ultima II.
15 //However, the Atari version *does* occassionally pick strength while the Apple
16 //versions do not--which would seem to indicate a bug either in the RNG algorithm,
17 //the 65C02 core, or the Apple hardware. Need to investigate all three!
18
19 #define __DEBUG__
20 //#define __DEBUGMON__
21
22 #include "v65c02.h"
23
24 #ifdef __DEBUG__
25 #include "dis65c02.h"
26 #include "log.h"
27 #endif
28
29 // Various macros
30
31 #define CLR_Z                           (regs.cc &= ~FLAG_Z)
32 #define CLR_ZN                          (regs.cc &= ~(FLAG_Z | FLAG_N))
33 #define CLR_ZNC                         (regs.cc &= ~(FLAG_Z | FLAG_N | FLAG_C))
34 #define CLR_V                           (regs.cc &= ~FLAG_V)
35 #define CLR_N                           (regs.cc &= ~FLAG_N)
36 #define SET_Z(r)                        (regs.cc = ((r) == 0 ? regs.cc | FLAG_Z : regs.cc & ~FLAG_Z))
37 #define SET_N(r)                        (regs.cc = ((r) & 0x80 ? regs.cc | FLAG_N : regs.cc & ~FLAG_N))
38
39 //Not sure that this code is computing the carry correctly... Investigate! [Seems to be]
40 #define SET_C_ADD(a,b)          (regs.cc = ((uint8)(b) > (uint8)(~(a)) ? regs.cc | FLAG_C : regs.cc & ~FLAG_C))
41 //#define SET_C_SUB(a,b)                (regs.cc = ((uint8)(b) >= (uint8)(a) ? regs.cc | FLAG_C : regs.cc & ~FLAG_C))
42 #define SET_C_CMP(a,b)          (regs.cc = ((uint8)(b) >= (uint8)(a) ? regs.cc | FLAG_C : regs.cc & ~FLAG_C))
43 #define SET_ZN(r)                       SET_N(r); SET_Z(r)
44 #define SET_ZNC_ADD(a,b,r)      SET_N(r); SET_Z(r); SET_C_ADD(a,b)
45 //#define SET_ZNC_SUB(a,b,r)    SET_N(r); SET_Z(r); SET_C_SUB(a,b)
46 #define SET_ZNC_CMP(a,b,r)      SET_N(r); SET_Z(r); SET_C_CMP(a,b)
47
48 //Small problem with the EA_ macros: ABS macros don't increment the PC!!! !!! FIX !!!
49 #define EA_IMM                          regs.pc++
50 #define EA_ZP                           regs.RdMem(regs.pc++)
51 #define EA_ZP_X                         (regs.RdMem(regs.pc++) + regs.x) & 0xFF
52 #define EA_ZP_Y                         (regs.RdMem(regs.pc++) + regs.y) & 0xFF
53 #define EA_ABS                          RdMemW(regs.pc)
54 #define EA_ABS_X                        RdMemW(regs.pc) + regs.x
55 #define EA_ABS_Y                        RdMemW(regs.pc) + regs.y
56 #define EA_IND_ZP_X                     RdMemW((regs.RdMem(regs.pc++) + regs.x) & 0xFF)
57 #define EA_IND_ZP_Y                     RdMemW(regs.RdMem(regs.pc++)) + regs.y
58 #define EA_IND_ZP                       RdMemW(regs.RdMem(regs.pc++))
59
60 #define READ_IMM                        regs.RdMem(EA_IMM)
61 #define READ_ZP                         regs.RdMem(EA_ZP)
62 #define READ_ZP_X                       regs.RdMem(EA_ZP_X)
63 #define READ_ZP_Y                       regs.RdMem(EA_ZP_Y)
64 #define READ_ABS                        regs.RdMem(EA_ABS);     regs.pc += 2
65 #define READ_ABS_X                      regs.RdMem(EA_ABS_X);   regs.pc += 2
66 #define READ_ABS_Y                      regs.RdMem(EA_ABS_Y);   regs.pc += 2
67 #define READ_IND_ZP_X           regs.RdMem(EA_IND_ZP_X)
68 #define READ_IND_ZP_Y           regs.RdMem(EA_IND_ZP_Y)
69 #define READ_IND_ZP                     regs.RdMem(EA_IND_ZP)
70
71 #define READ_IMM_WB(v)          uint16 addr = EA_IMM;      v = regs.RdMem(addr)
72 #define READ_ZP_WB(v)           uint16 addr = EA_ZP;       v = regs.RdMem(addr)
73 #define READ_ZP_X_WB(v)         uint16 addr = EA_ZP_X;     v = regs.RdMem(addr)
74 #define READ_ABS_WB(v)          uint16 addr = EA_ABS;      v = regs.RdMem(addr); regs.pc += 2
75 #define READ_ABS_X_WB(v)        uint16 addr = EA_ABS_X;    v = regs.RdMem(addr); regs.pc += 2
76 #define READ_ABS_Y_WB(v)        uint16 addr = EA_ABS_Y;    v = regs.RdMem(addr); regs.pc += 2
77 #define READ_IND_ZP_X_WB(v)     uint16 addr = EA_IND_ZP_X; v = regs.RdMem(addr)
78 #define READ_IND_ZP_Y_WB(v)     uint16 addr = EA_IND_ZP_Y; v = regs.RdMem(addr)
79 #define READ_IND_ZP_WB(v)       uint16 addr = EA_IND_ZP;   v = regs.RdMem(addr)
80
81 #define WRITE_BACK(d)           regs.WrMem(addr, (d))
82
83 // Private global variables
84
85 static V65C02REGS regs;
86
87 //This is probably incorrect, at least WRT to the $x7 and $xF opcodes... !!! FIX !!!
88 //Also this doesn't take into account the extra cycle it takes when an indirect fetch
89 //(ABS, ABS X/Y, ZP) crosses a page boundary, or extra cycle for BCD add/subtract...
90 #warning Cycle counts are not accurate--!!! FIX !!!
91 static uint8 CPUCycles[256] = {
92         7, 6, 1, 1, 5, 3, 5, 1, 3, 2, 2, 1, 6, 4, 6, 1,
93         2, 5, 5, 1, 5, 4, 6, 1, 2, 4, 2, 1, 6, 4, 6, 1,
94         6, 6, 1, 1, 3, 3, 5, 1, 4, 2, 2, 1, 4, 4, 6, 1,
95         2, 5, 5, 1, 4, 4, 6, 1, 2, 4, 2, 1, 4, 4, 6, 1,
96         6, 6, 1, 1, 1, 3, 5, 1, 3, 2, 2, 1, 3, 4, 6, 1,
97         2, 5, 5, 1, 1, 4, 6, 1, 2, 4, 3, 1, 1, 4, 6, 1,
98         6, 6, 1, 1, 3, 3, 5, 1, 4, 2, 2, 1, 6, 4, 6, 1,
99         2, 5, 5, 1, 4, 4, 6, 1, 2, 4, 4, 1, 6, 4, 6, 1,
100         2, 6, 1, 1, 3, 3, 3, 1, 2, 2, 2, 1, 4, 4, 4, 1,
101         2, 6, 5, 1, 4, 4, 4, 1, 2, 5, 2, 1, 4, 5, 5, 1,
102         2, 6, 2, 1, 3, 3, 3, 1, 2, 2, 2, 1, 4, 4, 4, 1,
103         2, 5, 5, 1, 4, 4, 4, 1, 2, 4, 2, 1, 4, 4, 4, 1,
104         2, 6, 1, 1, 3, 3, 5, 1, 2, 2, 2, 1, 4, 4, 6, 1,
105         2, 5, 5, 1, 1, 4, 6, 1, 2, 4, 3, 1, 1, 4, 6, 1,
106         2, 6, 1, 1, 3, 3, 5, 1, 2, 2, 2, 1, 4, 4, 6, 1,
107         2, 5, 5, 1, 1, 4, 6, 1, 2, 4, 4, 1, 1, 4, 6, 1 };
108
109 // Private function prototypes
110
111 static uint16 RdMemW(uint16);
112
113 //
114 // Read a uint16 out of 65C02 memory (big endian format)
115 //
116 static uint16 RdMemW(uint16 address)
117 {
118         return (uint16)(regs.RdMem(address + 1) << 8) | regs.RdMem(address + 0);
119 }
120
121
122 //
123 // 65C02 OPCODE IMPLEMENTATION
124 //
125 // NOTE: Lots of macros are used here to save a LOT of typing. Also
126 //       helps speed the debugging process. :-) Because of this, combining
127 //       certain lines may look like a good idea but would end in disaster.
128 //       You have been warned! ;-)
129 //
130
131 /*
132 Mnemonic        Addressing mode Form            Opcode  Size    Timing
133
134 ADC                     Immediate               ADC #Oper       69              2               2
135                         Zero Page               ADC Zpg         65              2               3
136                         Zero Page,X             ADC Zpg,X       75              2               4
137                         Absolute                ADC Abs         6D              3               4
138                         Absolute,X              ADC Abs,X       7D              3               4
139                         Absolute,Y              ADC Abs,Y       79              3               4
140                         (Zero Page,X)   ADC (Zpg,X)     61              2               6
141                         (Zero Page),Y   ADC (Zpg),Y     71              2               5
142                         (Zero Page)             ADC (Zpg)       72              2               5
143 */
144
145 // ADC opcodes
146
147 //This is non-optimal, but it works--optimize later. :-)
148 #define OP_ADC_HANDLER(m) \
149         uint16 sum = (uint16)regs.a + (m) + (uint16)(regs.cc & FLAG_C); \
150 \
151         if (regs.cc & FLAG_D) \
152         { \
153                 if ((sum & 0x0F) > 0x09) \
154                         sum += 0x06; \
155 \
156                 if ((sum & 0xF0) > 0x90) \
157                         sum += 0x60; \
158         } \
159 \
160         regs.cc = (regs.cc & ~FLAG_C) | (sum >> 8); \
161         regs.cc = (~(regs.a ^ (m)) & (regs.a ^ sum) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V); \
162         regs.a = sum & 0xFF; \
163         SET_ZN(regs.a)
164
165 //OLD V detection: regs.cc = ((regs.a ^ (m) ^ sum ^ (regs.cc << 7)) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V);
166
167 static void Op69(void)                                                  // ADC #
168 {
169         uint16 m = READ_IMM;
170         OP_ADC_HANDLER(m);
171 }
172
173 static void Op65(void)                                                  // ADC ZP
174 {
175         uint16 m = READ_ZP;
176         OP_ADC_HANDLER(m);
177 }
178
179 static void Op75(void)                                                  // ADC ZP, X
180 {
181         uint16 m = READ_ZP_X;
182         OP_ADC_HANDLER(m);
183 }
184
185 static void Op6D(void)                                                  // ADC ABS
186 {
187         uint16 m = READ_ABS;
188         OP_ADC_HANDLER(m);
189 }
190
191 static void Op7D(void)                                                  // ADC ABS, X
192 {
193         uint16 m = READ_ABS_X;
194         OP_ADC_HANDLER(m);
195 }
196
197 static void Op79(void)                                                  // ADC ABS, Y
198 {
199         uint16 m = READ_ABS_Y;
200         OP_ADC_HANDLER(m);
201 }
202
203 static void Op61(void)                                                  // ADC (ZP, X)
204 {
205         uint16 m = READ_IND_ZP_X;
206         OP_ADC_HANDLER(m);
207 }
208
209 static void Op71(void)                                                  // ADC (ZP), Y
210 {
211         uint16 m = READ_IND_ZP_Y;
212         OP_ADC_HANDLER(m);
213 }
214
215 static void Op72(void)                                                  // ADC (ZP)
216 {
217         uint16 m = READ_IND_ZP;
218         OP_ADC_HANDLER(m);
219 }
220
221 /*
222 AND     Immediate       AND #Oper       29      2       2
223 Zero Page               AND Zpg         25      2       3
224 Zero Page,X             AND Zpg,X       35      2       4
225 Absolute                AND Abs         2D      3       4
226 Absolute,X              AND Abs,X       3D      3       4
227 Absolute,Y              AND Abs,Y       39      3       4
228 (Zero Page,X)   AND (Zpg,X)     21      2       6
229 (Zero Page),Y   AND (Zpg),Y     31      2       5
230 (Zero Page)             AND (Zpg)       32      2       5
231 */
232
233 // AND opcodes
234
235 #define OP_AND_HANDLER(m) \
236         regs.a &= m; \
237         SET_ZN(regs.a)
238
239 static void Op29(void)                                                  // AND #
240 {
241         uint8 m = READ_IMM;
242         OP_AND_HANDLER(m);
243 }
244
245 static void Op25(void)                                                  // AND ZP
246 {
247         uint8 m = READ_ZP;
248         OP_AND_HANDLER(m);
249 }
250
251 static void Op35(void)                                                  // AND ZP, X
252 {
253         uint8 m = READ_ZP_X;
254         OP_AND_HANDLER(m);
255 }
256
257 static void Op2D(void)                                                  // AND ABS
258 {
259         uint8 m = READ_ABS;
260         OP_AND_HANDLER(m);
261 }
262
263 static void Op3D(void)                                                  // AND ABS, X
264 {
265         uint8 m = READ_ABS_X;
266         OP_AND_HANDLER(m);
267 }
268
269 static void Op39(void)                                                  // AND ABS, Y
270 {
271         uint8 m = READ_ABS_Y;
272         OP_AND_HANDLER(m);
273 }
274
275 static void Op21(void)                                                  // AND (ZP, X)
276 {
277         uint8 m = READ_IND_ZP_X;
278         OP_AND_HANDLER(m);
279 }
280
281 static void Op31(void)                                                  // AND (ZP), Y
282 {
283         uint8 m = READ_IND_ZP_Y;
284         OP_AND_HANDLER(m);
285 }
286
287 static void Op32(void)                                                  // AND (ZP)
288 {
289         uint8 m = READ_IND_ZP;
290         OP_AND_HANDLER(m);
291 }
292
293 /*
294 ASL     Accumulator     ASL A           0A      1       2
295 Zero Page               ASL Zpg         06      2       5
296 Zero Page,X             ASL Zpg,X       16      2       6
297 Absolute                ASL Abs         0E      3       6
298 Absolute,X              ASL Abs,X       1E      3       7
299 */
300
301 /*static void Op78(void)  // LSL ABS
302 {
303         uint8 tmp;  uint16 addr;
304         addr = FetchW();
305         tmp = regs.RdMem(addr);
306         (tmp&0x80 ? regs.cc |= 0x01 : regs.cc &= 0xFE);  // Shift hi bit into Carry
307         tmp <<= 1;
308         regs.WrMem(addr, tmp);
309         (tmp == 0 ? regs.cc |= 0x04 : regs.cc &= 0xFB);  // Adjust Zero flag
310         (tmp&0x80 ? regs.cc |= 0x08 : regs.cc &= 0xF7);  // Adjust Negative flag
311 }*/
312
313 // ASL opcodes
314
315 #define OP_ASL_HANDLER(m) \
316         regs.cc = ((m) & 0x80 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C); \
317         (m) <<= 1; \
318         SET_ZN((m))
319
320 static void Op0A(void)                                                  // ASL A
321 {
322         OP_ASL_HANDLER(regs.a);
323 }
324
325 static void Op06(void)                                                  // ASL ZP
326 {
327         uint8 m;
328         READ_ZP_WB(m);
329         OP_ASL_HANDLER(m);
330         WRITE_BACK(m);
331 }
332
333 static void Op16(void)                                                  // ASL ZP, X
334 {
335         uint8 m;
336         READ_ZP_X_WB(m);
337         OP_ASL_HANDLER(m);
338         WRITE_BACK(m);
339 }
340
341 static void Op0E(void)                                                  // ASL ABS
342 {
343         uint8 m;
344         READ_ABS_WB(m);
345         OP_ASL_HANDLER(m);
346         WRITE_BACK(m);
347 }
348
349 static void Op1E(void)                                                  // ASL ABS, X
350 {
351         uint8 m;
352         READ_ABS_X_WB(m);
353         OP_ASL_HANDLER(m);
354         WRITE_BACK(m);
355 }
356
357 /*
358 BBR0    Relative        BBR0 Oper       0F      2       2
359 BBR1    Relative        BBR1 Oper       1F      2       2
360 BBR2    Relative        BBR2 Oper       2F      2       2
361 BBR3    Relative        BBR3 Oper       3F      2       2
362 BBR4    Relative        BBR4 Oper       4F      2       2
363 BBR5    Relative        BBR5 Oper       5F      2       2
364 BBR6    Relative        BBR6 Oper       6F      2       2
365 BBR7    Relative        BBR7 Oper       7F      2       2
366 BBS0    Relative        BBS0 Oper       8F      2       2
367 BBS1    Relative        BBS1 Oper       9F      2       2
368 BBS2    Relative        BBS2 Oper       AF      2       2
369 BBS3    Relative        BBS3 Oper       BF      2       2
370 BBS4    Relative        BBS4 Oper       CF      2       2
371 BBS5    Relative        BBS5 Oper       DF      2       2
372 BBS6    Relative        BBS6 Oper       EF      2       2
373 BBS7    Relative        BBS7 Oper       FF      2       2
374 */
375
376 // BBR/Sn opcodes
377
378 static void Op0F(void)                                                  // BBR0
379 {
380         int16 m = (int16)(int8)READ_IMM;
381
382         if (!(regs.a & 0x01))
383                 regs.pc += m;
384 }
385
386 static void Op1F(void)                                                  // BBR1
387 {
388         int16 m = (int16)(int8)READ_IMM;
389
390         if (!(regs.a & 0x02))
391                 regs.pc += m;
392 }
393
394 static void Op2F(void)                                                  // BBR2
395 {
396         int16 m = (int16)(int8)READ_IMM;
397
398         if (!(regs.a & 0x04))
399                 regs.pc += m;
400 }
401
402 static void Op3F(void)                                                  // BBR3
403 {
404         int16 m = (int16)(int8)READ_IMM;
405
406         if (!(regs.a & 0x08))
407                 regs.pc += m;
408 }
409
410 static void Op4F(void)                                                  // BBR4
411 {
412         int16 m = (int16)(int8)READ_IMM;
413
414         if (!(regs.a & 0x10))
415                 regs.pc += m;
416 }
417
418 static void Op5F(void)                                                  // BBR5
419 {
420         int16 m = (int16)(int8)READ_IMM;
421
422         if (!(regs.a & 0x20))
423                 regs.pc += m;
424 }
425
426 static void Op6F(void)                                                  // BBR6
427 {
428         int16 m = (int16)(int8)READ_IMM;
429
430         if (!(regs.a & 0x40))
431                 regs.pc += m;
432 }
433
434 static void Op7F(void)                                                  // BBR7
435 {
436         int16 m = (int16)(int8)READ_IMM;
437
438         if (!(regs.a & 0x80))
439                 regs.pc += m;
440 }
441
442 static void Op8F(void)                                                  // BBS0
443 {
444         int16 m = (int16)(int8)READ_IMM;
445
446         if (regs.a & 0x01)
447                 regs.pc += m;
448 }
449
450 static void Op9F(void)                                                  // BBS1
451 {
452         int16 m = (int16)(int8)READ_IMM;
453
454         if (regs.a & 0x02)
455                 regs.pc += m;
456 }
457
458 static void OpAF(void)                                                  // BBS2
459 {
460         int16 m = (int16)(int8)READ_IMM;
461
462         if (regs.a & 0x04)
463                 regs.pc += m;
464 }
465
466 static void OpBF(void)                                                  // BBS3
467 {
468         int16 m = (int16)(int8)READ_IMM;
469
470         if (regs.a & 0x08)
471                 regs.pc += m;
472 }
473
474 static void OpCF(void)                                                  // BBS4
475 {
476         int16 m = (int16)(int8)READ_IMM;
477
478         if (regs.a & 0x10)
479                 regs.pc += m;
480 }
481
482 static void OpDF(void)                                                  // BBS5
483 {
484         int16 m = (int16)(int8)READ_IMM;
485
486         if (regs.a & 0x20)
487                 regs.pc += m;
488 }
489
490 static void OpEF(void)                                                  // BBS6
491 {
492         int16 m = (int16)(int8)READ_IMM;
493
494         if (regs.a & 0x40)
495                 regs.pc += m;
496 }
497
498 static void OpFF(void)                                                  // BBS7
499 {
500         int16 m = (int16)(int8)READ_IMM;
501
502         if (regs.a & 0x80)
503                 regs.pc += m;
504 }
505
506 /*
507 BCC     Relative        BCC Oper        90      2       2
508 BCS     Relative        BCS Oper        B0      2       2
509 BEQ     Relative        BEQ Oper        F0      2       2
510 */
511
512 // Branch opcodes
513
514 static void Op90(void)                                                  // BCC
515 {
516         int16 m = (int16)(int8)READ_IMM;
517
518         if (!(regs.cc & FLAG_C))
519                 regs.pc += m;
520 }
521
522 static void OpB0(void)                                                  // BCS
523 {
524         int16 m = (int16)(int8)READ_IMM;
525
526         if (regs.cc & FLAG_C)
527                 regs.pc += m;
528 }
529
530 static void OpF0(void)                                                  // BEQ
531 {
532         int16 m = (int16)(int8)READ_IMM;
533
534         if (regs.cc & FLAG_Z)
535                 regs.pc += m;
536 }
537
538 /*
539 BIT     Immediate       BIT #Oper       89      2       2
540 Zero Page               BIT Zpg         24      2       3
541 Zero Page,X             BIT Zpg,X       34      2       4
542 Absolute                BIT Abs         2C      3       4
543 Absolute,X              BIT Abs,X       3C      3       4
544 */
545
546 // BIT opcodes
547
548 /* 1. The BIT instruction copies bit 6 to the V flag, and bit 7 to the N flag (except in immediate
549       addressing mode where V & N are untouched.) The accumulator and the operand are ANDed and the
550       Z flag is set appropriately. */
551
552 #define OP_BIT_HANDLER(m) \
553         int8 result = regs.a & (m); \
554         regs.cc &= ~(FLAG_N | FLAG_V); \
555         regs.cc |= ((m) & 0xC0); \
556         SET_Z(result)
557
558 static void Op89(void)                                                  // BIT #
559 {
560         int8 m = READ_IMM;
561         int8 result = regs.a & m;
562         SET_Z(result);
563 }
564
565 static void Op24(void)                                                  // BIT ZP
566 {
567         int8 m = READ_ZP;
568         OP_BIT_HANDLER(m);
569 }
570
571 static void Op34(void)                                                  // BIT ZP, X
572 {
573         uint8 m = READ_ZP_X;
574         OP_BIT_HANDLER(m);
575 }
576
577 static void Op2C(void)                                                  // BIT ABS
578 {
579         uint8 m = READ_ABS;
580         OP_BIT_HANDLER(m);
581 }
582
583 static void Op3C(void)                                                  // BIT ABS, X
584 {
585         uint8 m = READ_ABS_X;
586         OP_BIT_HANDLER(m);
587 }
588
589 /*
590 BMI     Relative        BMI Oper        30      2       2
591 BNE     Relative        BNE Oper        D0      2       2
592 BPL     Relative        BPL Oper        10      2       2
593 BRA     Relative        BRA Oper        80      2       3
594 */
595
596 // More branch opcodes
597
598 static void Op30(void)                                                  // BMI
599 {
600         int16 m = (int16)(int8)READ_IMM;
601
602         if (regs.cc & FLAG_N)
603                 regs.pc += m;
604 }
605
606 static void OpD0(void)                                                  // BNE
607 {
608         int16 m = (int16)(int8)READ_IMM;
609
610         if (!(regs.cc & FLAG_Z))
611                 regs.pc += m;
612 }
613
614 static void Op10(void)                                                  // BPL
615 {
616         int16 m = (int16)(int8)READ_IMM;
617
618         if (!(regs.cc & FLAG_N))
619                 regs.pc += m;
620 }
621
622 static void Op80(void)                                                  // BRA
623 {
624         int16 m = (int16)(int8)READ_IMM;
625         regs.pc += m;
626 }
627
628 /*
629 BRK     Implied         BRK                     00      1       7
630 */
631
632 static void Op00(void)                                                  // BRK
633 {
634         regs.cc |= FLAG_B;                                                      // Set B
635         regs.pc++;                                                                      // RTI comes back to the instruction one byte after the BRK
636         regs.WrMem(0x0100 + regs.sp--, regs.pc >> 8);   // Save PC and CC
637         regs.WrMem(0x0100 + regs.sp--, regs.pc & 0xFF);
638         regs.WrMem(0x0100 + regs.sp--, regs.cc);
639         regs.cc |= FLAG_I;                                                      // Set I
640         regs.cc &= ~FLAG_D;                                                     // & clear D
641         regs.pc = RdMemW(0xFFFE);                                       // Grab the IRQ vector & go...
642 }
643
644 /*
645 BVC     Relative        BVC Oper        50      2       2
646 BVS     Relative        BVS Oper        70      2       2
647 */
648
649 // Even more branch opcodes
650
651 static void Op50(void)                                                  // BVC
652 {
653         int16 m = (int16)(int8)READ_IMM;
654
655         if (!(regs.cc & FLAG_V))
656                 regs.pc += m;
657 }
658
659 static void Op70(void)                                                  // BVS
660 {
661         int16 m = (int16)(int8)READ_IMM;
662
663         if (regs.cc & FLAG_V)
664                 regs.pc += m;
665 }
666
667 /*
668 CLC     Implied         CLC                     18      1       2
669 */
670
671 static void Op18(void)                                                  // CLC
672 {
673         regs.cc &= ~FLAG_C;
674 }
675
676 /*
677 CLD     Implied         CLD                     D8      1       2
678 */
679
680 static void OpD8(void)                                                  // CLD
681 {
682         regs.cc &= ~FLAG_D;
683 }
684
685 /*
686 CLI     Implied         CLI                     58      1       2
687 */
688
689 static void Op58(void)                                                  // CLI
690 {
691         regs.cc &= ~FLAG_I;
692 }
693
694 /*
695 CLV     Implied         CLV                     B8      1       2
696 */
697
698 static void OpB8(void)                                                  // CLV
699 {
700         regs.cc &= ~FLAG_V;
701 }
702
703 /*
704 CMP     Immediate       CMP #Oper       C9      2       2
705 Zero Page               CMP Zpg         C5      2       3
706 Zero Page,X             CMP Zpg         D5      2       4
707 Absolute                CMP Abs         CD      3       4
708 Absolute,X              CMP Abs,X       DD      3       4
709 Absolute,Y              CMP Abs,Y       D9      3       4
710 (Zero Page,X)   CMP (Zpg,X)     C1      2       6
711 (Zero Page),Y   CMP (Zpg),Y     D1      2       5
712 (Zero Page)             CMP (Zpg)       D2      2       5
713 */
714
715 // CMP opcodes
716
717 /*
718 Here's the latest: The CMP is NOT generating the Z flag when A=$C0!
719
720 FABA: A0 07          LDY   #$07                 [PC=FABC, SP=01FF, CC=---B-IZ-, A=00, X=00, Y=07]
721 FABC: C6 01          DEC   $01          [PC=FABE, SP=01FF, CC=N--B-I--, A=00, X=00, Y=07]
722 FABE: A5 01          LDA   $01          [PC=FAC0, SP=01FF, CC=N--B-I--, A=C0, X=00, Y=07]
723 FAC0: C9 C0          CMP   #$C0                 [PC=FAC2, SP=01FF, CC=N--B-I--, A=C0, X=00, Y=07]
724 FAC2: F0 D7          BEQ   $FA9B                [PC=FAC4, SP=01FF, CC=N--B-I--, A=C0, X=00, Y=07]
725 FAC4: 8D F8 07       STA   $07F8                [PC=FAC7, SP=01FF, CC=N--B-I--, A=C0, X=00, Y=07]
726 FAC7: B1 00          LDA   ($00),Y
727 *** Read at I/O address C007
728                 [PC=FAC9, SP=01FF, CC=---B-IZ-, A=00, X=00, Y=07]
729 FAC9: D9 01 FB       CMP   $FB01,Y              [PC=FACC, SP=01FF, CC=---B-I--, A=00, X=00, Y=07]
730 FACC: D0 EC          BNE   $FABA                [PC=FABA, SP=01FF, CC=---B-I--, A=00, X=00, Y=07]
731
732 Should be fixed now... (was adding instead of subtracting!)
733
734 Small problem here... First two should set the carry while the last one should clear it. !!! FIX !!! [DONE]
735
736 FDF0: C9 A0          CMP   #$A0                 [PC=FDF2, SP=01F1, CC=---B-IZ-, A=A0, X=02, Y=03]
737 FD7E: C9 E0          CMP   #$E0                 [PC=FD80, SP=01F4, CC=N--B-I--, A=A0, X=02, Y=03]
738 FD38: C9 9B          CMP   #$9B                 [PC=FD3A, SP=01F2, CC=---B-I-C, A=A0, X=02, Y=03]
739
740 Compare sets flags as if a subtraction had been carried out. If the value in the accumulator is equal or greater than the compared value, the Carry will be set. The equal (Z) and sign (S) flags will be set based on equality or lack thereof and the sign (i.e. A>=$80) of the accumulator.
741 */
742
743 #define OP_CMP_HANDLER(m) \
744         uint8 result = regs.a - (m); \
745         SET_ZNC_CMP(m, regs.a, result)
746
747 static void OpC9(void)                                                  // CMP #
748 {
749         uint8 m = READ_IMM;
750         OP_CMP_HANDLER(m);
751 }
752
753 static void OpC5(void)                                                  // CMP ZP
754 {
755         uint8 m = READ_ZP;
756         OP_CMP_HANDLER(m);
757 }
758
759 static void OpD5(void)                                                  // CMP ZP, X
760 {
761         uint8 m = READ_ZP_X;
762         OP_CMP_HANDLER(m);
763 }
764
765 static void OpCD(void)                                                  // CMP ABS
766 {
767         uint8 m = READ_ABS;
768         OP_CMP_HANDLER(m);
769 }
770
771 static void OpDD(void)                                                  // CMP ABS, X
772 {
773         uint8 m = READ_ABS_X;
774         OP_CMP_HANDLER(m);
775 }
776
777 static void OpD9(void)                                                  // CMP ABS, Y
778 {
779         uint8 m = READ_ABS_Y;
780         OP_CMP_HANDLER(m);
781 }
782
783 static void OpC1(void)                                                  // CMP (ZP, X)
784 {
785         uint8 m = READ_IND_ZP_X;
786         OP_CMP_HANDLER(m);
787 }
788
789 static void OpD1(void)                                                  // CMP (ZP), Y
790 {
791         uint8 m = READ_IND_ZP_Y;
792         OP_CMP_HANDLER(m);
793 }
794
795 static void OpD2(void)                                                  // CMP (ZP)
796 {
797         uint8 m = READ_IND_ZP;
798         OP_CMP_HANDLER(m);
799 }
800
801 /*
802 CPX     Immediate       CPX #Oper       E0      2       2
803 Zero Page               CPX Zpg         E4      2       3
804 Absolute                CPX Abs         EC      3       4
805 */
806
807 // CPX opcodes
808
809 #define OP_CPX_HANDLER(m) \
810         uint8 result = regs.x - (m); \
811         SET_ZNC_CMP(m, regs.x, result)
812
813 static void OpE0(void)                                                  // CPX #
814 {
815         uint8 m = READ_IMM;
816         OP_CPX_HANDLER(m);
817 }
818
819 static void OpE4(void)                                                  // CPX ZP
820 {
821         uint8 m = READ_ZP;
822         OP_CPX_HANDLER(m);
823 }
824
825 static void OpEC(void)                                                  // CPX ABS
826 {
827         uint8 m = READ_ABS;
828         OP_CPX_HANDLER(m);
829 }
830
831 /*
832 CPY     Immediate       CPY #Oper       C0      2       2
833 Zero Page               CPY Zpg         C4      2       3
834 Absolute                CPY Abs         CC      3       4
835 */
836
837 // CPY opcodes
838
839 #define OP_CPY_HANDLER(m) \
840         uint8 result = regs.y - (m); \
841         SET_ZNC_CMP(m, regs.y, result)
842
843 static void OpC0(void)                                                  // CPY #
844 {
845         uint8 m = READ_IMM;
846         OP_CPY_HANDLER(m);
847 }
848
849 static void OpC4(void)                                                  // CPY ZP
850 {
851         uint8 m = READ_ZP;
852         OP_CPY_HANDLER(m);
853 }
854
855 static void OpCC(void)                                                  // CPY ABS
856 {
857         uint8 m = READ_ABS;
858         OP_CPY_HANDLER(m);
859 }
860
861 /*
862 DEA     Accumulator     DEA                     3A      1       2
863 */
864
865 static void Op3A(void)                                                  // DEA
866 {
867         regs.a--;
868         SET_ZN(regs.a);
869 }
870
871 /*
872 DEC     Zero Page       DEC Zpg         C6      2       5
873 Zero Page,X             DEC Zpg,X       D6      2       6
874 Absolute                DEC Abs         CE      3       6
875 Absolute,X              DEC Abs,X       DE      3       7
876 */
877
878 // DEC opcodes
879
880 #define OP_DEC_HANDLER(m) \
881         m--; \
882         SET_ZN(m)
883
884 static void OpC6(void)                                                  // DEC ZP
885 {
886         uint8 m;
887         READ_ZP_WB(m);
888         OP_DEC_HANDLER(m);
889         WRITE_BACK(m);
890 }
891
892 static void OpD6(void)                                                  // DEC ZP, X
893 {
894         uint8 m;
895         READ_ZP_X_WB(m);
896         OP_DEC_HANDLER(m);
897         WRITE_BACK(m);
898 }
899
900 static void OpCE(void)                                                  // DEC ABS
901 {
902         uint8 m;
903         READ_ABS_WB(m);
904         OP_DEC_HANDLER(m);
905         WRITE_BACK(m);
906 }
907
908 static void OpDE(void)                                                  // DEC ABS, X
909 {
910         uint8 m;
911         READ_ABS_X_WB(m);
912         OP_DEC_HANDLER(m);
913         WRITE_BACK(m);
914 }
915
916 /*
917 Here's one problem: DEX is setting the N flag!
918
919 D3EE: A2 09          LDX   #$09                 [PC=D3F0, SP=01F7, CC=---B-I-C, A=01, X=09, Y=08]
920 D3F0: 98             TYA                [PC=D3F1, SP=01F7, CC=N--B-I-C, A=08, X=09, Y=08]
921 D3F1: 48             PHA                [PC=D3F2, SP=01F6, CC=N--B-I-C, A=08, X=09, Y=08]
922 D3F2: B5 93          LDA   $93,X                [PC=D3F4, SP=01F6, CC=---B-IZC, A=00, X=09, Y=08]
923 D3F4: CA             DEX                [PC=D3F5, SP=01F6, CC=N--B-I-C, A=00, X=08, Y=08]
924 D3F5: 10 FA          BPL   $D3F1                [PC=D3F7, SP=01F6, CC=N--B-I-C, A=00, X=08, Y=08]
925 D3F7: 20 84 E4       JSR   $E484                [PC=E484, SP=01F4, CC=N--B-I-C, A=00, X=08, Y=08]
926
927 should be fixed now...
928 */
929
930 /*
931 DEX     Implied         DEX                     CA      1       2
932 */
933
934 static void OpCA(void)                                                  // DEX
935 {
936         regs.x--;
937         SET_ZN(regs.x);
938 }
939
940 /*
941 DEY     Implied         DEY                     88      1       2
942 */
943
944 static void Op88(void)                                                  // DEY
945 {
946         regs.y--;
947         SET_ZN(regs.y);
948 }
949
950 /*
951 EOR     Immediate       EOR #Oper       49      2       2
952 Zero Page               EOR Zpg         45      2       3
953 Zero Page,X             EOR Zpg,X       55      2       4
954 Absolute                EOR Abs         4D      3       4
955 Absolute,X              EOR Abs,X       5D      3       4
956 Absolute,Y              EOR Abs,Y       59      3       4
957 (Zero Page,X)   EOR (Zpg,X)     41      2       6
958 (Zero Page),Y   EOR (Zpg),Y     51      2       5
959 (Zero Page)             EOR (Zpg)       52      2       5
960 */
961
962 // EOR opcodes
963
964 #define OP_EOR_HANDLER(m) \
965         regs.a ^= m; \
966         SET_ZN(regs.a)
967
968 static void Op49(void)                                                  // EOR #
969 {
970         uint8 m = READ_IMM;
971         OP_EOR_HANDLER(m);
972 }
973
974 static void Op45(void)                                                  // EOR ZP
975 {
976         uint8 m = READ_ZP;
977         OP_EOR_HANDLER(m);
978 }
979
980 static void Op55(void)                                                  // EOR ZP, X
981 {
982         uint8 m = READ_ZP_X;
983         OP_EOR_HANDLER(m);
984 }
985
986 static void Op4D(void)                                                  // EOR ABS
987 {
988         uint8 m = READ_ABS;
989         OP_EOR_HANDLER(m);
990 }
991
992 static void Op5D(void)                                                  // EOR ABS, X
993 {
994         uint8 m = READ_ABS_X;
995         OP_EOR_HANDLER(m);
996 }
997
998 static void Op59(void)                                                  // EOR ABS, Y
999 {
1000         uint8 m = READ_ABS_Y;
1001         OP_EOR_HANDLER(m);
1002 }
1003
1004 static void Op41(void)                                                  // EOR (ZP, X)
1005 {
1006         uint8 m = READ_IND_ZP_X;
1007         OP_EOR_HANDLER(m);
1008 }
1009
1010 static void Op51(void)                                                  // EOR (ZP), Y
1011 {
1012         uint8 m = READ_IND_ZP_Y;
1013         OP_EOR_HANDLER(m);
1014 }
1015
1016 static void Op52(void)                                                  // EOR (ZP)
1017 {
1018         uint8 m = READ_IND_ZP;
1019         OP_EOR_HANDLER(m);
1020 }
1021
1022 /*
1023 INA     Accumulator     INA                     1A      1       2
1024 */
1025
1026 static void Op1A(void)                                                  // INA
1027 {
1028         regs.a++;
1029         SET_ZN(regs.a);
1030 }
1031
1032 /*
1033 INC     Zero Page       INC Zpg         E6      2       5
1034 Zero Page,X             INC Zpg,X       F6      2       6
1035 Absolute                INC Abs         EE      3       6
1036 Absolute,X              INC Abs,X       FE      3       7
1037 */
1038
1039 // INC opcodes
1040
1041 #define OP_INC_HANDLER(m) \
1042         m++; \
1043         SET_ZN(m)
1044
1045 static void OpE6(void)                                                  // INC ZP
1046 {
1047         uint8 m;
1048         READ_ZP_WB(m);
1049         OP_INC_HANDLER(m);
1050         WRITE_BACK(m);
1051 }
1052
1053 static void OpF6(void)                                                  // INC ZP, X
1054 {
1055         uint8 m;
1056         READ_ZP_X_WB(m);
1057         OP_INC_HANDLER(m);
1058         WRITE_BACK(m);
1059 }
1060
1061 static void OpEE(void)                                                  // INC ABS
1062 {
1063         uint8 m;
1064         READ_ABS_WB(m);
1065         OP_INC_HANDLER(m);
1066         WRITE_BACK(m);
1067 }
1068
1069 static void OpFE(void)                                                  // INC ABS, X
1070 {
1071         uint8 m;
1072         READ_ABS_X_WB(m);
1073         OP_INC_HANDLER(m);
1074         WRITE_BACK(m);
1075 }
1076
1077 /*
1078 INX     Implied         INX                     E8      1       2
1079 */
1080
1081 static void OpE8(void)                                                  // INX
1082 {
1083         regs.x++;
1084         SET_ZN(regs.x);
1085 }
1086
1087 /*
1088 INY     Implied         INY                     C8      1       2
1089 */
1090
1091 static void OpC8(void)                                                  // INY
1092 {
1093         regs.y++;
1094         SET_ZN(regs.y);
1095 }
1096
1097 /*
1098 JMP     Absolute        JMP Abs         4C      3       3
1099 (Absolute)              JMP (Abs)       6C      3       5
1100 (Absolute,X)    JMP (Abs,X)     7C      3       6
1101 */
1102
1103 // JMP opcodes
1104
1105 static void Op4C(void)                                                  // JMP ABS
1106 {
1107         regs.pc = RdMemW(regs.pc);
1108 }
1109
1110 static void Op6C(void)                                                  // JMP (ABS)
1111 {
1112 //      uint16 addr = RdMemW(regs.pc);
1113 //#ifdef __DEBUG__
1114 //WriteLog("\n[JMP ABS]: addr fetched = %04X, bytes at %04X = %02X %02X (RdMemw=%04X)\n",
1115 //      addr, addr, regs.RdMem(addr), regs.RdMem(addr+1), RdMemW(addr));
1116 //#endif
1117 //      addr = RdMemW(addr);
1118         regs.pc = RdMemW(RdMemW(regs.pc));
1119 }
1120
1121 static void Op7C(void)                                                  // JMP (ABS, X)
1122 {
1123         regs.pc = RdMemW(RdMemW(regs.pc) + regs.x);
1124 }
1125
1126 /*
1127 JSR     Absolute        JSR Abs         20      3       6
1128 */
1129
1130 //This is not jumping to the correct address... !!! FIX !!! [DONE]
1131 static void Op20(void)                                                  // JSR
1132 {
1133         uint16 addr = RdMemW(regs.pc);
1134         regs.pc++;                                                                      // Since it pushes return address - 1...
1135         regs.WrMem(0x0100 + regs.sp--, regs.pc >> 8);
1136         regs.WrMem(0x0100 + regs.sp--, regs.pc & 0xFF);
1137         regs.pc = addr;
1138 }
1139
1140 /*
1141 LDA     Immediate       LDA #Oper       A9      2       2
1142 Zero Page               LDA Zpg         A5      2       3
1143 Zero Page,X             LDA Zpg,X       B5      2       4
1144 Absolute                LDA Abs         AD      3       4
1145 Absolute,X              LDA Abs,X       BD      3       4
1146 Absolute,Y              LDA Abs,Y       B9      3       4
1147 (Zero Page,X)   LDA (Zpg,X)     A1      2       6
1148 (Zero Page),Y   LDA (Zpg),Y     B1      2       5
1149 (Zero Page)             LDA (Zpg)       B2      2       5
1150 */
1151
1152 // LDA opcodes
1153
1154 #define OP_LDA_HANDLER(m) \
1155         regs.a = m; \
1156         SET_ZN(regs.a)
1157
1158 static void OpA9(void)                                                  // LDA #
1159 {
1160         uint8 m = READ_IMM;
1161         OP_LDA_HANDLER(m);
1162 }
1163
1164 static void OpA5(void)                                                  // LDA ZP
1165 {
1166         uint8 m = READ_ZP;
1167         OP_LDA_HANDLER(m);
1168 }
1169
1170 static void OpB5(void)                                                  // LDA ZP, X
1171 {
1172         uint8 m = READ_ZP_X;
1173         OP_LDA_HANDLER(m);
1174 }
1175
1176 static void OpAD(void)                                                  // LDA ABS
1177 {
1178         uint8 m = READ_ABS;
1179         OP_LDA_HANDLER(m);
1180 }
1181
1182 static void OpBD(void)                                                  // LDA ABS, X
1183 {
1184         uint8 m = READ_ABS_X;
1185         OP_LDA_HANDLER(m);
1186 }
1187
1188 static void OpB9(void)                                                  // LDA ABS, Y
1189 {
1190         uint8 m = READ_ABS_Y;
1191         OP_LDA_HANDLER(m);
1192 }
1193
1194 static void OpA1(void)                                                  // LDA (ZP, X)
1195 {
1196         uint8 m = READ_IND_ZP_X;
1197         OP_LDA_HANDLER(m);
1198 }
1199
1200 static void OpB1(void)                                                  // LDA (ZP), Y
1201 {
1202         uint8 m = READ_IND_ZP_Y;
1203         OP_LDA_HANDLER(m);
1204 }
1205
1206 static void OpB2(void)                                                  // LDA (ZP)
1207 {
1208         uint8 m = READ_IND_ZP;
1209         OP_LDA_HANDLER(m);
1210 }
1211
1212 /*
1213 LDX     Immediate       LDX #Oper       A2      2       2
1214 Zero Page               LDX Zpg         A6      2       3
1215 Zero Page,Y             LDX Zpg,Y       B6      2       4
1216 Absolute                LDX Abs         AE      3       4
1217 Absolute,Y              LDX Abs,Y       BE      3       4
1218 */
1219
1220 // LDX opcodes
1221
1222 #define OP_LDX_HANDLER(m) \
1223         regs.x = m; \
1224         SET_ZN(regs.x)
1225
1226 static void OpA2(void)                                                  // LDX #
1227 {
1228         uint8 m = READ_IMM;
1229         OP_LDX_HANDLER(m);
1230 }
1231
1232 static void OpA6(void)                                                  // LDX ZP
1233 {
1234         uint8 m = READ_ZP;
1235         OP_LDX_HANDLER(m);
1236 }
1237
1238 static void OpB6(void)                                                  // LDX ZP, Y
1239 {
1240         uint8 m = READ_ZP_Y;
1241         OP_LDX_HANDLER(m);
1242 }
1243
1244 static void OpAE(void)                                                  // LDX ABS
1245 {
1246         uint8 m = READ_ABS;
1247         OP_LDX_HANDLER(m);
1248 }
1249
1250 static void OpBE(void)                                                  // LDX ABS, Y
1251 {
1252         uint8 m = READ_ABS_Y;
1253         OP_LDX_HANDLER(m);
1254 }
1255
1256 /*
1257 LDY     Immediate       LDY #Oper       A0      2       2
1258 Zero Page               LDY Zpg         A4      2       3
1259 Zero Page,Y             LDY Zpg,X       B4      2       4
1260 Absolute                LDY Abs         AC      3       4
1261 Absolute,Y              LDY Abs,X       BC      3       4
1262 */
1263
1264 // LDY opcodes
1265
1266 #define OP_LDY_HANDLER(m) \
1267         regs.y = m; \
1268         SET_ZN(regs.y)
1269
1270 static void OpA0(void)                                                  // LDY #
1271 {
1272         uint8 m = READ_IMM;
1273         OP_LDY_HANDLER(m);
1274 }
1275
1276 static void OpA4(void)                                                  // LDY ZP
1277 {
1278         uint8 m = READ_ZP;
1279         OP_LDY_HANDLER(m);
1280 }
1281
1282 static void OpB4(void)                                                  // LDY ZP, X
1283 {
1284         uint8 m = READ_ZP_X;
1285         OP_LDY_HANDLER(m);
1286 }
1287
1288 static void OpAC(void)                                                  // LDY ABS
1289 {
1290         uint8 m = READ_ABS;
1291         OP_LDY_HANDLER(m);
1292 }
1293
1294 static void OpBC(void)                                                  // LDY ABS, X
1295 {
1296         uint8 m = READ_ABS_X;
1297         OP_LDY_HANDLER(m);
1298 }
1299
1300 /*
1301 LSR     Accumulator     LSR A           4A      1       2
1302 Zero Page               LSR Zpg         46      2       5
1303 Zero Page,X             LSR Zpg,X       56      2       6
1304 Absolute                LSR Abs         4E      3       6
1305 Absolute,X              LSR Abs,X       5E      3       7
1306 */
1307
1308 // LSR opcodes
1309
1310 #define OP_LSR_HANDLER(m) \
1311         regs.cc = ((m) & 0x01 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C); \
1312         (m) >>= 1; \
1313         CLR_N; SET_Z((m))
1314
1315 static void Op4A(void)                                                  // LSR A
1316 {
1317         OP_LSR_HANDLER(regs.a);
1318 }
1319
1320 static void Op46(void)                                                  // LSR ZP
1321 {
1322         uint8 m;
1323         READ_ZP_WB(m);
1324         OP_LSR_HANDLER(m);
1325         WRITE_BACK(m);
1326 }
1327
1328 static void Op56(void)                                                  // LSR ZP, X
1329 {
1330         uint8 m;
1331         READ_ZP_X_WB(m);
1332         OP_LSR_HANDLER(m);
1333         WRITE_BACK(m);
1334 }
1335
1336 static void Op4E(void)                                                  // LSR ABS
1337 {
1338         uint8 m;
1339         READ_ABS_WB(m);
1340         OP_LSR_HANDLER(m);
1341         WRITE_BACK(m);
1342 }
1343
1344 static void Op5E(void)                                                  // LSR ABS, X
1345 {
1346         uint8 m;
1347         READ_ABS_X_WB(m);
1348         OP_LSR_HANDLER(m);
1349         WRITE_BACK(m);
1350 }
1351
1352 /*
1353 NOP     Implied         NOP                     EA      1       2
1354 */
1355
1356 static void OpEA(void)                                                  // NOP
1357 {
1358 }
1359
1360 /*
1361 ORA     Immediate       ORA #Oper       09      2       2
1362 Zero Page               ORA Zpg         05      2       3
1363 Zero Page,X             ORA Zpg,X       15      2       4
1364 Absolute                ORA Abs         0D      3       4
1365 Absolute,X              ORA Abs,X       1D      3       4
1366 Absolute,Y              ORA Abs,Y       19      3       4
1367 (Zero Page,X)   ORA (Zpg,X)     01      2       6
1368 (Zero Page),Y   ORA (Zpg),Y     11      2       5
1369 (Zero Page)             ORA (Zpg)       12      2       5
1370 */
1371
1372 // ORA opcodes
1373
1374 #define OP_ORA_HANDLER(m) \
1375         regs.a |= m; \
1376         SET_ZN(regs.a)
1377
1378 static void Op09(void)                                                  // ORA #
1379 {
1380         uint8 m = READ_IMM;
1381         OP_ORA_HANDLER(m);
1382 }
1383
1384 static void Op05(void)                                                  // ORA ZP
1385 {
1386         uint8 m = READ_ZP;
1387         OP_ORA_HANDLER(m);
1388 }
1389
1390 static void Op15(void)                                                  // ORA ZP, X
1391 {
1392         uint8 m = READ_ZP_X;
1393         OP_ORA_HANDLER(m);
1394 }
1395
1396 static void Op0D(void)                                                  // ORA ABS
1397 {
1398         uint8 m = READ_ABS;
1399         OP_ORA_HANDLER(m);
1400 }
1401
1402 static void Op1D(void)                                                  // ORA ABS, X
1403 {
1404         uint8 m = READ_ABS_X;
1405         OP_ORA_HANDLER(m);
1406 }
1407
1408 static void Op19(void)                                                  // ORA ABS, Y
1409 {
1410         uint8 m = READ_ABS_Y;
1411         OP_ORA_HANDLER(m);
1412 }
1413
1414 static void Op01(void)                                                  // ORA (ZP, X)
1415 {
1416         uint8 m = READ_IND_ZP_X;
1417         OP_ORA_HANDLER(m);
1418 }
1419
1420 static void Op11(void)                                                  // ORA (ZP), Y
1421 {
1422         uint8 m = READ_IND_ZP_Y;
1423         OP_ORA_HANDLER(m);
1424 }
1425
1426 static void Op12(void)                                                  // ORA (ZP)
1427 {
1428         uint8 m = READ_IND_ZP;
1429         OP_ORA_HANDLER(m);
1430 }
1431
1432 /*
1433 PHA     Implied         PHA                     48      1       3
1434 */
1435
1436 static void Op48(void)                                                  // PHA
1437 {
1438         regs.WrMem(0x0100 + regs.sp--, regs.a);
1439 }
1440
1441 static void Op08(void)                                                  // PHP
1442 {
1443         regs.cc |= FLAG_UNK;                                            // Make sure that the unused bit is always set
1444         regs.WrMem(0x0100 + regs.sp--, regs.cc);
1445 }
1446
1447 /*
1448 PHX     Implied         PHX                     DA      1       3
1449 */
1450
1451 static void OpDA(void)                                                  // PHX
1452 {
1453         regs.WrMem(0x0100 + regs.sp--, regs.x);
1454 }
1455
1456 /*
1457 PHY     Implied         PHY                     5A      1       3
1458 */
1459
1460 static void Op5A(void)                                                  // PHY
1461 {
1462         regs.WrMem(0x0100 + regs.sp--, regs.y);
1463 }
1464
1465 /*
1466 PLA     Implied         PLA                     68      1       4
1467 */
1468
1469 static void Op68(void)                                                  // PLA
1470 {
1471         regs.a = regs.RdMem(0x0100 + ++regs.sp);
1472         SET_ZN(regs.a);
1473 }
1474
1475 static void Op28(void)                                                  // PLP
1476 {
1477         regs.cc = regs.RdMem(0x0100 + ++regs.sp);
1478 }
1479
1480 /*
1481 PLX     Implied         PLX                     FA      1       4
1482 */
1483
1484 static void OpFA(void)                                                  // PLX
1485 {
1486         regs.x = regs.RdMem(0x0100 + ++regs.sp);
1487         SET_ZN(regs.x);
1488 }
1489
1490 /*
1491 PLY     Implied         PLY                     7A      1       4
1492 */
1493
1494 static void Op7A(void)                                                  // PLY
1495 {
1496         regs.y = regs.RdMem(0x0100 + ++regs.sp);
1497         SET_ZN(regs.y);
1498 }
1499
1500 /*
1501 The bit set and clear instructions have the form xyyy0111, where x is 0 to clear a bit or 1 to set it, and yyy is which bit at the memory location to set or clear. 
1502    RMB0  RMB1  RMB2  RMB3  RMB4  RMB5  RMB6  RMB7
1503   zp  07  17  27  37  47  57  67  77
1504      SMB0  SMB1  SMB2  SMB3  SMB4  SMB5  SMB6  SMB7
1505   zp  87  97  A7  B7  C7  D7  E7  F7
1506 */
1507
1508 // RMB opcodes
1509
1510 static void Op07(void)                                                  // RMB0 ZP
1511 {
1512         uint8 m;
1513         READ_ZP_WB(m);
1514         m &= 0xFE;
1515         WRITE_BACK(m);
1516 }
1517
1518 static void Op17(void)                                                  // RMB1 ZP
1519 {
1520         uint8 m;
1521         READ_ZP_WB(m);
1522         m &= 0xFD;
1523         WRITE_BACK(m);
1524 }
1525
1526 static void Op27(void)                                                  // RMB2 ZP
1527 {
1528         uint8 m;
1529         READ_ZP_WB(m);
1530         m &= 0xFB;
1531         WRITE_BACK(m);
1532 }
1533
1534 static void Op37(void)                                                  // RMB3 ZP
1535 {
1536         uint8 m;
1537         READ_ZP_WB(m);
1538         m &= 0xF7;
1539         WRITE_BACK(m);
1540 }
1541
1542 static void Op47(void)                                                  // RMB4 ZP
1543 {
1544         uint8 m;
1545         READ_ZP_WB(m);
1546         m &= 0xEF;
1547         WRITE_BACK(m);
1548 }
1549
1550 static void Op57(void)                                                  // RMB5 ZP
1551 {
1552         uint8 m;
1553         READ_ZP_WB(m);
1554         m &= 0xDF;
1555         WRITE_BACK(m);
1556 }
1557
1558 static void Op67(void)                                                  // RMB6 ZP
1559 {
1560         uint8 m;
1561         READ_ZP_WB(m);
1562         m &= 0xBF;
1563         WRITE_BACK(m);
1564 }
1565
1566 static void Op77(void)                                                  // RMB7 ZP
1567 {
1568         uint8 m;
1569         READ_ZP_WB(m);
1570         m &= 0x7F;
1571         WRITE_BACK(m);
1572 }
1573
1574 /*
1575 ROL     Accumulator     ROL A           2A      1       2
1576 Zero Page               ROL Zpg         26      2       5
1577 Zero Page,X             ROL Zpg,X       36      2       6
1578 Absolute                ROL Abs         2E      3       6
1579 Absolute,X              ROL Abs,X       3E      3       7
1580 */
1581
1582 // ROL opcodes
1583
1584 #define OP_ROL_HANDLER(m) \
1585         uint8 tmp = regs.cc & 0x01; \
1586         regs.cc = ((m) & 0x80 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C); \
1587         (m) = ((m) << 1) | tmp; \
1588         SET_ZN((m))
1589
1590 static void Op2A(void)                                                  // ROL A
1591 {
1592         OP_ROL_HANDLER(regs.a);
1593 }
1594
1595 static void Op26(void)                                                  // ROL ZP
1596 {
1597         uint8 m;
1598         READ_ZP_WB(m);
1599         OP_ROL_HANDLER(m);
1600         WRITE_BACK(m);
1601 }
1602
1603 static void Op36(void)                                                  // ROL ZP, X
1604 {
1605         uint8 m;
1606         READ_ZP_X_WB(m);
1607         OP_ROL_HANDLER(m);
1608         WRITE_BACK(m);
1609 }
1610
1611 static void Op2E(void)                                                  // ROL ABS
1612 {
1613         uint8 m;
1614         READ_ABS_WB(m);
1615         OP_ROL_HANDLER(m);
1616         WRITE_BACK(m);
1617 }
1618
1619 static void Op3E(void)                                                  // ROL ABS, X
1620 {
1621         uint8 m;
1622         READ_ABS_X_WB(m);
1623         OP_ROL_HANDLER(m);
1624         WRITE_BACK(m);
1625 }
1626
1627 /*
1628 ROR     Accumulator     ROR A           6A      1       2
1629 Zero Page               ROR Zpg         66      2       5
1630 Zero Page,X             ROR Zpg,X       76      2       6
1631 Absolute                ROR Abs         6E      3       6
1632 Absolute,X              ROR Abs,X       7E      3       7
1633 */
1634
1635 // ROR opcodes
1636
1637 #define OP_ROR_HANDLER(m) \
1638         uint8 tmp = (regs.cc & 0x01) << 7; \
1639         regs.cc = ((m) & 0x01 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C); \
1640         (m) = ((m) >> 1) | tmp; \
1641         SET_ZN((m))
1642
1643 static void Op6A(void)                                                  // ROR A
1644 {
1645         OP_ROR_HANDLER(regs.a);
1646 }
1647
1648 static void Op66(void)                                                  // ROR ZP
1649 {
1650         uint8 m;
1651         READ_ZP_WB(m);
1652         OP_ROR_HANDLER(m);
1653         WRITE_BACK(m);
1654 }
1655
1656 static void Op76(void)                                                  // ROR ZP, X
1657 {
1658         uint8 m;
1659         READ_ZP_X_WB(m);
1660         OP_ROR_HANDLER(m);
1661         WRITE_BACK(m);
1662 }
1663
1664 static void Op6E(void)                                                  // ROR ABS
1665 {
1666         uint8 m;
1667         READ_ABS_WB(m);
1668         OP_ROR_HANDLER(m);
1669         WRITE_BACK(m);
1670 }
1671
1672 static void Op7E(void)                                                  // ROR ABS, X
1673 {
1674         uint8 m;
1675         READ_ABS_X_WB(m);
1676         OP_ROR_HANDLER(m);
1677         WRITE_BACK(m);
1678 }
1679
1680 /*
1681 RTI     Implied         RTI                     40      1       6
1682 */
1683
1684 static void Op40(void)                                                  // RTI
1685 {
1686         regs.cc = regs.RdMem(0x0100 + ++regs.sp);
1687         regs.pc = regs.RdMem(0x0100 + ++regs.sp);
1688         regs.pc |= (uint16)(regs.RdMem(0x0100 + ++regs.sp)) << 8;
1689 }
1690
1691 /*
1692 RTS     Implied         RTS                     60      1       6
1693 */
1694
1695 static void Op60(void)                                                  // RTS
1696 {
1697         regs.pc = regs.RdMem(0x0100 + ++regs.sp);
1698         regs.pc |= (uint16)(regs.RdMem(0x0100 + ++regs.sp)) << 8;
1699         regs.pc++;                                                                      // Since it pushes return address - 1...
1700 //printf("*** RTS: PC = $%04X, SP= $1%02X\n", regs.pc, regs.sp);
1701 //fflush(stdout);
1702 }
1703
1704 /*
1705 SBC     Immediate       SBC #Oper       E9      2       2
1706 Zero Page               SBC Zpg         E5      2       3
1707 Zero Page,X             SBC Zpg,X       F5      2       4
1708 Absolute                SBC Abs         ED      3       4
1709 Absolute,X              SBC Abs,X       FD      3       4
1710 Absolute,Y              SBC Abs,Y       F9      3       4
1711 (Zero Page,X)   SBC (Zpg,X)     E1      2       6
1712 (Zero Page),Y   SBC (Zpg),Y     F1      2       5
1713 (Zero Page)             SBC (Zpg)       F2      2       5
1714 */
1715
1716 // SBC opcodes
1717
1718 //This is non-optimal, but it works--optimize later. :-)
1719 //This is correct except for the BCD handling... !!! FIX !!! [Possibly DONE]
1720 #define OP_SBC_HANDLER(m) \
1721         uint16 sum = (uint16)regs.a - (m) - (uint16)((regs.cc & FLAG_C) ^ 0x01); \
1722 \
1723         if (regs.cc & FLAG_D) \
1724         { \
1725                 if ((sum & 0x0F) > 0x09) \
1726                         sum -= 0x06; \
1727 \
1728                 if ((sum & 0xF0) > 0x90) \
1729                         sum -= 0x60; \
1730         } \
1731 \
1732         regs.cc = (regs.cc & ~FLAG_C) | (((sum >> 8) ^ 0x01) & FLAG_C); \
1733         regs.cc = ((regs.a ^ (m)) & (regs.a ^ sum) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V); \
1734         regs.a = sum & 0xFF; \
1735         SET_ZN(regs.a)
1736
1737 /*
1738 D5AF: 38             SEC                [PC=D5B0, SP=01F6, CC=---B-I-C, A=4C, X=00, Y=06]
1739
1740 *** HERE'S where it sets the D flag on a subtract... Arg!
1741
1742 D5B0: F1 9D          SBC   ($9D),Y      [PC=D5B2, SP=01F6, CC=N--BDI--, A=FE, X=00, Y=06]
1743
1744 Fixed. :-)
1745 */
1746
1747 //OLD V detection: regs.cc = ((regs.a ^ (m) ^ sum ^ (regs.cc << 7)) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V);
1748
1749 static void OpE9(void)                                                  // SBC #
1750 {
1751         uint16 m = READ_IMM;
1752         OP_SBC_HANDLER(m);
1753 }
1754
1755 static void OpE5(void)                                                  // SBC ZP
1756 {
1757         uint16 m = READ_ZP;
1758         OP_SBC_HANDLER(m);
1759 }
1760
1761 static void OpF5(void)                                                  // SBC ZP, X
1762 {
1763         uint16 m = READ_ZP_X;
1764         OP_SBC_HANDLER(m);
1765 }
1766
1767 static void OpED(void)                                                  // SBC ABS
1768 {
1769         uint16 m = READ_ABS;
1770         OP_SBC_HANDLER(m);
1771 }
1772
1773 static void OpFD(void)                                                  // SBC ABS, X
1774 {
1775         uint16 m = READ_ABS_X;
1776         OP_SBC_HANDLER(m);
1777 }
1778
1779 static void OpF9(void)                                                  // SBC ABS, Y
1780 {
1781         uint16 m = READ_ABS_Y;
1782         OP_SBC_HANDLER(m);
1783 }
1784
1785 static void OpE1(void)                                                  // SBC (ZP, X)
1786 {
1787         uint16 m = READ_IND_ZP_X;
1788         OP_SBC_HANDLER(m);
1789 }
1790
1791 static void OpF1(void)                                                  // SBC (ZP), Y
1792 {
1793         uint16 m = READ_IND_ZP_Y;
1794         OP_SBC_HANDLER(m);
1795 }
1796
1797 static void OpF2(void)                                                  // SBC (ZP)
1798 {
1799         uint16 m = READ_IND_ZP;
1800         OP_SBC_HANDLER(m);
1801 }
1802
1803 /*
1804 SEC     Implied         SEC                     38      1       2
1805 */
1806
1807 static void Op38(void)                                                  // SEC
1808 {
1809         regs.cc |= FLAG_C;
1810 }
1811
1812 /*
1813 SED     Implied         SED                     F8      1       2
1814 */
1815
1816 static void OpF8(void)                                                  // SED
1817 {
1818         regs.cc |= FLAG_D;
1819 }
1820
1821 /*
1822 SEI     Implied         SEI                     78      1       2
1823 */
1824
1825 static void Op78(void)                                                  // SEI
1826 {
1827         regs.cc |= FLAG_I;
1828 }
1829
1830 /*
1831 The bit set and clear instructions have the form xyyy0111, where x is 0 to clear a bit or 1 to set it, and yyy is which bit at the memory location to set or clear. 
1832    RMB0  RMB1  RMB2  RMB3  RMB4  RMB5  RMB6  RMB7
1833   zp  07  17  27  37  47  57  67  77
1834      SMB0  SMB1  SMB2  SMB3  SMB4  SMB5  SMB6  SMB7
1835   zp  87  97  A7  B7  C7  D7  E7  F7
1836 */
1837
1838 // SMB opcodes
1839
1840 static void Op87(void)                                                  // SMB0 ZP
1841 {
1842         uint8 m;
1843         READ_ZP_WB(m);
1844         m |= 0x01;
1845         WRITE_BACK(m);
1846 }
1847
1848 static void Op97(void)                                                  // SMB1 ZP
1849 {
1850         uint8 m;
1851         READ_ZP_WB(m);
1852         m |= 0x02;
1853         WRITE_BACK(m);
1854 }
1855
1856 static void OpA7(void)                                                  // SMB2 ZP
1857 {
1858         uint8 m;
1859         READ_ZP_WB(m);
1860         m |= 0x04;
1861         WRITE_BACK(m);
1862 }
1863
1864 static void OpB7(void)                                                  // SMB3 ZP
1865 {
1866         uint8 m;
1867         READ_ZP_WB(m);
1868         m |= 0x08;
1869         WRITE_BACK(m);
1870 }
1871
1872 static void OpC7(void)                                                  // SMB4 ZP
1873 {
1874         uint8 m;
1875         READ_ZP_WB(m);
1876         m |= 0x10;
1877         WRITE_BACK(m);
1878 }
1879
1880 static void OpD7(void)                                                  // SMB5 ZP
1881 {
1882         uint8 m;
1883         READ_ZP_WB(m);
1884         m |= 0x20;
1885         WRITE_BACK(m);
1886 }
1887
1888 static void OpE7(void)                                                  // SMB6 ZP
1889 {
1890         uint8 m;
1891         READ_ZP_WB(m);
1892         m |= 0x40;
1893         WRITE_BACK(m);
1894 }
1895
1896 static void OpF7(void)                                                  // SMB7 ZP
1897 {
1898         uint8 m;
1899         READ_ZP_WB(m);
1900         m |= 0x80;
1901         WRITE_BACK(m);
1902 }
1903
1904 /*
1905 STA     Zero Page       STA Zpg         85      2       3
1906 Zero Page,X             STA Zpg,X       95      2       4
1907 Absolute                STA Abs         8D      3       4
1908 Absolute,X              STA Abs,X       9D      3       5
1909 Absolute,Y              STA Abs,Y       99      3       5
1910 (Zero Page,X)   STA (Zpg,X)     81      2       6
1911 (Zero Page),Y   STA (Zpg),Y     91      2       6
1912 (Zero Page)             STA (Zpg)       92      2       5
1913 */
1914
1915 // STA opcodes
1916
1917 static void Op85(void)
1918 {
1919         regs.WrMem(EA_ZP, regs.a);
1920 }
1921
1922 static void Op95(void)
1923 {
1924         regs.WrMem(EA_ZP_X, regs.a);
1925 }
1926
1927 static void Op8D(void)
1928 {
1929         regs.WrMem(EA_ABS, regs.a);
1930         regs.pc += 2;
1931 }
1932
1933 static void Op9D(void)
1934 {
1935         regs.WrMem(EA_ABS_X, regs.a);
1936         regs.pc += 2;
1937 }
1938
1939 static void Op99(void)
1940 {
1941         regs.WrMem(EA_ABS_Y, regs.a);
1942         regs.pc += 2;
1943 }
1944
1945 static void Op81(void)
1946 {
1947         regs.WrMem(EA_IND_ZP_X, regs.a);
1948 }
1949
1950 static void Op91(void)
1951 {
1952         regs.WrMem(EA_IND_ZP_Y, regs.a);
1953 }
1954
1955 static void Op92(void)
1956 {
1957         regs.WrMem(EA_IND_ZP, regs.a);
1958 }
1959
1960 /*
1961 STX     Zero Page       STX Zpg         86      2       3
1962 Zero Page,Y             STX Zpg,Y       96      2       4
1963 Absolute                STX Abs         8E      3       4
1964 */
1965
1966 // STX opcodes
1967
1968 static void Op86(void)
1969 {
1970         regs.WrMem(EA_ZP, regs.x);
1971 }
1972
1973 static void Op96(void)
1974 {
1975         regs.WrMem(EA_ZP_X, regs.x);
1976 }
1977
1978 static void Op8E(void)
1979 {
1980         regs.WrMem(EA_ABS, regs.x);
1981         regs.pc += 2;
1982 }
1983
1984 /*
1985 STY     Zero Page       STY Zpg         84      2       3
1986 Zero Page,X             STY Zpg,X       94      2       4
1987 Absolute                STY Abs         8C      3       4
1988 */
1989
1990 // STY opcodes
1991
1992 static void Op84(void)
1993 {
1994         regs.WrMem(EA_ZP, regs.y);
1995 }
1996
1997 static void Op94(void)
1998 {
1999         regs.WrMem(EA_ZP_X, regs.y);
2000 }
2001
2002 static void Op8C(void)
2003 {
2004         regs.WrMem(EA_ABS, regs.y);
2005         regs.pc += 2;
2006 }
2007
2008 /*
2009 STZ     Zero Page       STZ Zpg         64      2       3
2010 Zero Page,X             STZ Zpg,X       74      2       4
2011 Absolute                STZ Abs         9C      3       4
2012 Absolute,X              STZ Abs,X       9E      3       5
2013 */
2014
2015 // STZ opcodes
2016
2017 static void Op64(void)
2018 {
2019         regs.WrMem(EA_ZP, 0x00);
2020 }
2021
2022 static void Op74(void)
2023 {
2024         regs.WrMem(EA_ZP_X, 0x00);
2025 }
2026
2027 static void Op9C(void)
2028 {
2029         regs.WrMem(EA_ABS, 0x00);
2030         regs.pc += 2;
2031 }
2032
2033 static void Op9E(void)
2034 {
2035         regs.WrMem(EA_ABS_X, 0x00);
2036         regs.pc += 2;
2037 }
2038
2039 /*
2040 TAX     Implied         TAX                     AA      1       2
2041 */
2042
2043 static void OpAA(void)                                                  // TAX
2044 {
2045         regs.x = regs.a;
2046         SET_ZN(regs.x);
2047 }
2048
2049 /*
2050 TAY     Implied         TAY                     A8      1       2
2051 */
2052
2053 static void OpA8(void)                                                  // TAY
2054 {
2055         regs.y = regs.a;
2056         SET_ZN(regs.y);
2057 }
2058
2059 /*
2060 TRB     Zero Page       TRB Zpg         14      2       5
2061 Absolute                TRB Abs         1C      3       6
2062 */
2063
2064 // TRB opcodes
2065
2066 #define OP_TRB_HANDLER(m) \
2067         SET_Z(m & regs.a); \
2068         m &= ~regs.a
2069
2070 static void Op14(void)                                                  // TRB ZP
2071 {
2072         uint8 m;
2073         READ_ZP_WB(m);
2074         OP_TRB_HANDLER(m);
2075         WRITE_BACK(m);
2076 }
2077
2078 static void Op1C(void)                                                  // TRB ABS
2079 {
2080         uint8 m;
2081         READ_ABS_WB(m);
2082         OP_TRB_HANDLER(m);
2083         WRITE_BACK(m);
2084 }
2085
2086 /*
2087 TSB     Zero Page       TSB Zpg         04      2       5
2088 Absolute                TSB Abs         0C      3       6
2089 */
2090
2091 // TSB opcodes
2092
2093 #define OP_TSB_HANDLER(m) \
2094         SET_Z(m & regs.a); \
2095         m |= regs.a
2096
2097 static void Op04(void)                                                  // TSB ZP
2098 {
2099         uint8 m;
2100         READ_ZP_WB(m);
2101         OP_TSB_HANDLER(m);
2102         WRITE_BACK(m);
2103 }
2104
2105 static void Op0C(void)                                                  // TSB ABS
2106 {
2107         uint8 m;
2108         READ_ABS_WB(m);
2109         OP_TSB_HANDLER(m);
2110         WRITE_BACK(m);
2111 }
2112
2113 /*
2114 TSX     Implied         TSX                     BA      1       2
2115 */
2116
2117 static void OpBA(void)                                                  // TSX
2118 {
2119         regs.x = regs.sp;
2120         SET_ZN(regs.x);
2121 }
2122
2123 /*
2124 TXA     Implied         TXA                     8A      1       2
2125 */
2126
2127 static void Op8A(void)                                                  // TXA
2128 {
2129         regs.a = regs.x;
2130         SET_ZN(regs.a);
2131 }
2132
2133 /*
2134 TXS     Implied         TXS                     9A      1       2
2135 */
2136
2137 static void Op9A(void)                                                  // TXS
2138 {
2139         regs.sp = regs.x;
2140 }
2141
2142 /*
2143 TYA     Implied         TYA                     98      1       2
2144 */
2145 static void Op98(void)                                                  // TYA
2146 {
2147         regs.a = regs.y;
2148         SET_ZN(regs.a);
2149 }
2150
2151 static void Op__(void)
2152 {
2153         regs.cpuFlags |= V65C02_STATE_ILLEGAL_INST;
2154 }
2155
2156
2157 //
2158 // Ok, the exec_op[] array is globally defined here basically to save
2159 // a LOT of unnecessary typing.  Sure it's ugly, but hey, it works!
2160 //
2161 void (* exec_op[256])() = {
2162         Op00, Op01, Op__, Op__, Op04, Op05, Op06, Op07, Op08, Op09, Op0A, Op__, Op0C, Op0D, Op0E, Op0F,
2163         Op10, Op11, Op12, Op__, Op14, Op15, Op16, Op17, Op18, Op19, Op1A, Op__, Op1C, Op1D, Op1E, Op1F,
2164         Op20, Op21, Op__, Op__, Op24, Op25, Op26, Op27, Op28, Op29, Op2A, Op__, Op2C, Op2D, Op2E, Op2F,
2165         Op30, Op31, Op32, Op__, Op34, Op35, Op36, Op37, Op38, Op39, Op3A, Op__, Op3C, Op3D, Op3E, Op3F,
2166         Op40, Op41, Op__, Op__, Op__, Op45, Op46, Op47, Op48, Op49, Op4A, Op__, Op4C, Op4D, Op4E, Op4F,
2167         Op50, Op51, Op52, Op__, Op__, Op55, Op56, Op57, Op58, Op59, Op5A, Op__, Op__, Op5D, Op5E, Op5F,
2168         Op60, Op61, Op__, Op__, Op64, Op65, Op66, Op67, Op68, Op69, Op6A, Op__, Op6C, Op6D, Op6E, Op6F,
2169         Op70, Op71, Op72, Op__, Op74, Op75, Op76, Op77, Op78, Op79, Op7A, Op__, Op7C, Op7D, Op7E, Op7F,
2170         Op80, Op81, Op__, Op__, Op84, Op85, Op86, Op87, Op88, Op89, Op8A, Op__, Op8C, Op8D, Op8E, Op8F,
2171         Op90, Op91, Op92, Op__, Op94, Op95, Op96, Op97, Op98, Op99, Op9A, Op__, Op9C, Op9D, Op9E, Op9F,
2172         OpA0, OpA1, OpA2, Op__, OpA4, OpA5, OpA6, OpA7, OpA8, OpA9, OpAA, Op__, OpAC, OpAD, OpAE, OpAF,
2173         OpB0, OpB1, OpB2, Op__, OpB4, OpB5, OpB6, OpB7, OpB8, OpB9, OpBA, Op__, OpBC, OpBD, OpBE, OpBF,
2174         OpC0, OpC1, Op__, Op__, OpC4, OpC5, OpC6, OpC7, OpC8, OpC9, OpCA, Op__, OpCC, OpCD, OpCE, OpCF,
2175         OpD0, OpD1, OpD2, Op__, Op__, OpD5, OpD6, OpD7, OpD8, OpD9, OpDA, Op__, Op__, OpDD, OpDE, OpDF,
2176         OpE0, OpE1, Op__, Op__, OpE4, OpE5, OpE6, OpE7, OpE8, OpE9, OpEA, Op__, OpEC, OpED, OpEE, OpEF,
2177         OpF0, OpF1, OpF2, Op__, Op__, OpF5, OpF6, OpF7, OpF8, OpF9, OpFA, Op__, Op__, OpFD, OpFE, OpFF
2178 };
2179
2180 //
2181 // Internal "memcpy" (so we don't have to link with any external libraries!)
2182 //
2183 static void myMemcpy(void * dst, void * src, uint32 size)
2184 {
2185         uint8 * d = (uint8 *)dst, * s = (uint8 *)src;
2186
2187         for(uint32 i=0; i<size; i++)
2188                 d[i] = s[i];
2189 }
2190
2191 /*
2192 FCA8: 38        698  WAIT     SEC
2193 FCA9: 48        699  WAIT2    PHA
2194 FCAA: E9 01     700  WAIT3    SBC   #$01
2195 FCAC: D0 FC     701           BNE   WAIT3      ;1.0204 USEC
2196 FCAE: 68        702           PLA              ;(13+27/2*A+5/2*A*A)
2197 FCAF: E9 01     703           SBC   #$01
2198 FCB1: D0 F6     704           BNE   WAIT2
2199 FCB3: 60        705           RTS
2200
2201 FBD9: C9 87     592  BELL1    CMP   #$87       ;BELL CHAR? (CNTRL-G)
2202 FBDB: D0 12     593           BNE   RTS2B      ;  NO, RETURN
2203 FBDD: A9 40     594           LDA   #$40       ;DELAY .01 SECONDS
2204 FBDF: 20 A8 FC  595           JSR   WAIT
2205 FBE2: A0 C0     596           LDY   #$C0
2206 FBE4: A9 0C     597  BELL2    LDA   #$0C       ;TOGGLE SPEAKER AT
2207 FBE6: 20 A8 FC  598           JSR   WAIT       ;  1 KHZ FOR .1 SEC.
2208 FBE9: AD 30 C0  599           LDA   SPKR
2209 FBEC: 88        600           DEY
2210 FBED: D0 F5     601           BNE   BELL2
2211 FBEF: 60        602  RTS2B    RTS
2212 */
2213 //int instCount[256];
2214 #ifdef __DEBUG__
2215 bool dumpDis = false;
2216 #endif
2217
2218 //Note: could enforce regs.clock to zero on starting the CPU with an Init() function...
2219 //bleh.
2220 //static uint32 limit = 0;
2221
2222 //
2223 // Function to execute 65C02 for "cycles" cycles
2224 //
2225 void Execute65C02(V65C02REGS * context, uint32 cycles)
2226 {
2227         myMemcpy(&regs, context, sizeof(V65C02REGS));
2228
2229         // Execute here...
2230 // NOTE: There *must* be some way of doing this without requiring the caller to subtract out
2231 //       the previous run's cycles. !!! FIX !!!
2232 // Could try:
2233 //      while (regs.clock < regs.clock + cycles) <-- won't work
2234 /*
2235         // This isn't as accurate as subtracting out cycles from regs.clock...
2236         // Unless limit is a static variable, adding cycles to it each time through...
2237         uint32 limit = regs.clock + cycles;
2238         while (regs.clock < limit)
2239 */
2240 // but have wraparound to deal with. :-/
2241 /*
2242 Let's see...
2243
2244         if (regs.clock + cycles > 0xFFFFFFFF)
2245                 wraparound = true;
2246 */
2247
2248         while (regs.clock < cycles)
2249         {
2250 #if 0
2251 /*if (regs.pc == 0x4007)
2252 {
2253         dumpDis = true;
2254 }//*/
2255 if (regs.pc == 0x444B)
2256 {
2257         WriteLog("\n*** End of wait...\n\n");
2258         dumpDis = true;
2259 }//*/
2260 if (regs.pc == 0x444E)
2261 {
2262         WriteLog("\n*** Start of wait...\n\n");
2263         dumpDis = false;
2264 }//*/
2265 #endif
2266
2267 #ifdef __DEBUGMON__
2268 //WAIT is commented out here because it's called by BELL1...
2269 if (regs.pc == 0xFCA8)
2270 {
2271         WriteLog("\n*** WAIT subroutine...\n\n");
2272         dumpDis = false;
2273 }//*/
2274 if (regs.pc == 0xFBD9)
2275 {
2276         WriteLog("\n*** BELL1 subroutine...\n\n");
2277 //      dumpDis = false;
2278 }//*/
2279 if (regs.pc == 0xFC58)
2280 {
2281         WriteLog("\n*** HOME subroutine...\n\n");
2282 //      dumpDis = false;
2283 }//*/
2284 if (regs.pc == 0xFDED)
2285 {
2286         WriteLog("\n*** COUT subroutine...\n\n");
2287         dumpDis = false;
2288 }
2289 #endif
2290
2291 #ifdef __DEBUG__
2292 if (dumpDis)
2293         Decode65C02(regs.pc);
2294 #endif
2295                 uint8 opcode = regs.RdMem(regs.pc++);
2296
2297 //if (!(regs.cpuFlags & V65C02_STATE_ILLEGAL_INST))
2298 //instCount[opcode]++;
2299
2300                 exec_op[opcode]();                                                              // Execute that opcode...
2301                 regs.clock += CPUCycles[opcode];
2302 #ifdef __DEBUG__
2303 if (dumpDis)
2304         WriteLog(" [PC=%04X, SP=%04X, CC=%s%s-%s%s%s%s%s, A=%02X, X=%02X, Y=%02X]\n",
2305                 regs.pc, 0x0100 + regs.sp,
2306                 (regs.cc & FLAG_N ? "N" : "-"), (regs.cc & FLAG_V ? "V" : "-"),
2307                 (regs.cc & FLAG_B ? "B" : "-"), (regs.cc & FLAG_D ? "D" : "-"),
2308                 (regs.cc & FLAG_I ? "I" : "-"), (regs.cc & FLAG_Z ? "Z" : "-"),
2309                 (regs.cc & FLAG_C ? "C" : "-"), regs.a, regs.x, regs.y);
2310 #endif
2311
2312 #ifdef __DEBUGMON__
2313 if (regs.pc == 0xFCB3)  // WAIT exit point
2314 {
2315         dumpDis = true;
2316 }//*/
2317 /*if (regs.pc == 0xFBEF)        // BELL1 exit point
2318 {
2319         dumpDis = true;
2320 }//*/
2321 /*if (regs.pc == 0xFC22)        // HOME exit point
2322 {
2323         dumpDis = true;
2324 }//*/
2325 if (regs.pc == 0xFDFF)  // COUT exit point
2326 {
2327         dumpDis = true;
2328 }
2329 if (regs.pc == 0xFBD8)
2330 {
2331         WriteLog("\n*** BASCALC set BASL/H = $%04X\n\n", RdMemW(0x0028));
2332 }//*/
2333 #endif
2334
2335 //These should be correct now...
2336                 if (regs.cpuFlags & V65C02_ASSERT_LINE_RESET)
2337                 {
2338 #ifdef __DEBUG__
2339 WriteLog("\n*** RESET ***\n\n");
2340 #endif
2341                         // Not sure about this...
2342                         regs.sp = 0xFF;
2343                         regs.cc = FLAG_B | FLAG_I;                                      // Reset the CC register
2344                         regs.pc = RdMemW(0xFFFC);                                       // And load PC with the RESET vector
2345
2346                         context->cpuFlags &= ~V65C02_ASSERT_LINE_RESET;
2347                         regs.cpuFlags &= ~V65C02_ASSERT_LINE_RESET;
2348                 }
2349                 else if (regs.cpuFlags & V65C02_ASSERT_LINE_NMI)
2350                 {
2351 #ifdef __DEBUG__
2352 WriteLog("\n*** NMI ***\n\n");
2353 #endif
2354                         regs.WrMem(0x0100 + regs.sp--, regs.pc >> 8);   // Save PC and CC
2355                         regs.WrMem(0x0100 + regs.sp--, regs.pc & 0xFF);
2356                         regs.WrMem(0x0100 + regs.sp--, regs.cc);
2357                         regs.cc |= FLAG_I;                                                      // Set I
2358                         regs.cc &= ~FLAG_D;                                                     // & clear D
2359                         regs.pc = RdMemW(0xFFFA);                                       // And do it!
2360
2361                         regs.clock += 7;
2362                         context->cpuFlags &= ~V65C02_ASSERT_LINE_NMI;// Reset the asserted line (NMI)...
2363                         regs.cpuFlags &= ~V65C02_ASSERT_LINE_NMI;       // Reset the asserted line (NMI)...
2364                 }
2365                 else if (regs.cpuFlags & V65C02_ASSERT_LINE_IRQ)
2366                 {
2367                         if (!(regs.cc & FLAG_I))                                        // Process an interrupt (I=0)?
2368                         {
2369 #ifdef __DEBUG__
2370 WriteLog("\n*** IRQ ***\n\n");
2371 #endif
2372                                 regs.WrMem(0x0100 + regs.sp--, regs.pc >> 8);   // Save PC and CC
2373                                 regs.WrMem(0x0100 + regs.sp--, regs.pc & 0xFF);
2374                                 regs.WrMem(0x0100 + regs.sp--, regs.cc);
2375                                 regs.cc |= FLAG_I;                                              // Set I
2376                                 regs.cc &= ~FLAG_D;                                             // & clear D
2377                                 regs.pc = RdMemW(0xFFFE);                               // And do it!
2378
2379                                 regs.clock += 7;
2380                                 context->cpuFlags &= ~V65C02_ASSERT_LINE_IRQ;   // Reset the asserted line (IRQ)...
2381                                 regs.cpuFlags &= ~V65C02_ASSERT_LINE_IRQ;       // Reset the asserted line (IRQ)...
2382                         }
2383                 }
2384         }
2385
2386 //This is a lame way of doing it, but in the end the simplest--however, it destroys any
2387 //record of elasped CPU time. Not sure that it's important to keep track, but there it is.
2388         regs.clock -= cycles;
2389
2390         myMemcpy(context, &regs, sizeof(V65C02REGS));
2391 }
2392
2393 //
2394 // Get the clock of the currently executing CPU
2395 //
2396 uint32 GetCurrentV65C02Clock(void)
2397 {
2398         return regs.clock;
2399 }