1/*****************************************************************************\
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3 This file is licensed under the Snes9x License.
4 For further information, consult the LICENSE file in the root directory.
5\*****************************************************************************/
6
7#ifndef _CPUMACRO_H_
8#define _CPUMACRO_H_
9
10#define rOP8(OP, ADDR, WRAP, FUNC) \
11static void Op##OP (void) \
12{ \
13 uint8 val = OpenBus = S9xGetByte(ADDR(READ)); \
14 FUNC(val); \
15}
16
17#define rOP16(OP, ADDR, WRAP, FUNC) \
18static void Op##OP (void) \
19{ \
20 uint16 val = S9xGetWord(ADDR(READ), WRAP); \
21 OpenBus = (uint8) (val >> 8); \
22 FUNC(val); \
23}
24
25#define rOPC(OP, COND, ADDR, WRAP, FUNC) \
26static void Op##OP (void) \
27{ \
28 if (Check##COND()) \
29 { \
30 uint8 val = OpenBus = S9xGetByte(ADDR(READ)); \
31 FUNC(val); \
32 } \
33 else \
34 { \
35 uint16 val = S9xGetWord(ADDR(READ), WRAP); \
36 OpenBus = (uint8) (val >> 8); \
37 FUNC(val); \
38 } \
39}
40
41#define rOPM(OP, ADDR, WRAP, FUNC) \
42rOPC(OP, Memory, ADDR, WRAP, FUNC)
43
44#define rOPX(OP, ADDR, WRAP, FUNC) \
45rOPC(OP, Index, ADDR, WRAP, FUNC)
46
47#define wOP8(OP, ADDR, WRAP, FUNC) \
48static void Op##OP (void) \
49{ \
50 FUNC##8(ADDR(WRITE)); \
51}
52
53#define wOP16(OP, ADDR, WRAP, FUNC) \
54static void Op##OP (void) \
55{ \
56 FUNC##16(ADDR(WRITE), WRAP); \
57}
58
59#define wOPC(OP, COND, ADDR, WRAP, FUNC) \
60static void Op##OP (void) \
61{ \
62 if (Check##COND()) \
63 FUNC##8(ADDR(WRITE)); \
64 else \
65 FUNC##16(ADDR(WRITE), WRAP); \
66}
67
68#define wOPM(OP, ADDR, WRAP, FUNC) \
69wOPC(OP, Memory, ADDR, WRAP, FUNC)
70
71#define wOPX(OP, ADDR, WRAP, FUNC) \
72wOPC(OP, Index, ADDR, WRAP, FUNC)
73
74#define mOP8(OP, ADDR, WRAP, FUNC) \
75static void Op##OP (void) \
76{ \
77 FUNC##8(ADDR(MODIFY)); \
78}
79
80#define mOP16(OP, ADDR, WRAP, FUNC) \
81static void Op##OP (void) \
82{ \
83 FUNC##16(ADDR(MODIFY), WRAP); \
84}
85
86#define mOPC(OP, COND, ADDR, WRAP, FUNC) \
87static void Op##OP (void) \
88{ \
89 if (Check##COND()) \
90 FUNC##8(ADDR(MODIFY)); \
91 else \
92 FUNC##16(ADDR(MODIFY), WRAP); \
93}
94
95#define mOPM(OP, ADDR, WRAP, FUNC) \
96mOPC(OP, Memory, ADDR, WRAP, FUNC)
97
98#define bOP(OP, REL, COND, CHK, E) \
99static void Op##OP (void) \
100{ \
101 pair newPC; \
102 newPC.W = REL(JUMP); \
103 if (COND) \
104 { \
105 AddCycles(ONE_CYCLE); \
106 if (E && Registers.PCh != newPC.B.h) \
107 AddCycles(ONE_CYCLE); \
108 if ((Registers.PCw & ~MEMMAP_MASK) != (newPC.W & ~MEMMAP_MASK)) \
109 S9xSetPCBase(ICPU.ShiftedPB + newPC.W); \
110 else \
111 Registers.PCw = newPC.W; \
112 } \
113}
114
115
116static inline void SetZN (uint16 Work16)
117{
118 ICPU._Zero = Work16 != 0;
119 ICPU._Negative = (uint8) (Work16 >> 8);
120}
121
122static inline void SetZN (uint8 Work8)
123{
124 ICPU._Zero = Work8;
125 ICPU._Negative = Work8;
126}
127
128static inline void ADC (uint16 Work16)
129{
130 if (CheckDecimal())
131 {
132 uint32 result;
133 uint32 carry = CheckCarry();
134
135 result = (Registers.A.W & 0x000F) + (Work16 & 0x000F) + carry;
136 if (result > 0x0009)
137 result += 0x0006;
138 carry = (result > 0x000F);
139
140 result = (Registers.A.W & 0x00F0) + (Work16 & 0x00F0) + (result & 0x000F) + carry * 0x10;
141 if (result > 0x009F)
142 result += 0x0060;
143 carry = (result > 0x00FF);
144
145 result = (Registers.A.W & 0x0F00) + (Work16 & 0x0F00) + (result & 0x00FF) + carry * 0x100;
146 if (result > 0x09FF)
147 result += 0x0600;
148 carry = (result > 0x0FFF);
149
150 result = (Registers.A.W & 0xF000) + (Work16 & 0xF000) + (result & 0x0FFF) + carry * 0x1000;
151
152 if ((Registers.A.W & 0x8000) == (Work16 & 0x8000) && (Registers.A.W & 0x8000) != (result & 0x8000))
153 SetOverflow();
154 else
155 ClearOverflow();
156
157 if (result > 0x9FFF)
158 result += 0x6000;
159
160 if (result > 0xFFFF)
161 SetCarry();
162 else
163 ClearCarry();
164
165 Registers.A.W = result & 0xFFFF;
166 SetZN(Registers.A.W);
167 }
168 else
169 {
170 uint32 Ans32 = Registers.A.W + Work16 + CheckCarry();
171
172 ICPU._Carry = Ans32 >= 0x10000;
173
174 if (~(Registers.A.W ^ Work16) & (Work16 ^ (uint16) Ans32) & 0x8000)
175 SetOverflow();
176 else
177 ClearOverflow();
178
179 Registers.A.W = (uint16) Ans32;
180 SetZN(Registers.A.W);
181 }
182}
183
184static inline void ADC (uint8 Work8)
185{
186 if (CheckDecimal())
187 {
188 uint32 result;
189 uint32 carry = CheckCarry();
190
191 result = (Registers.AL & 0x0F) + (Work8 & 0x0F) + carry;
192 if ( result > 0x09 )
193 result += 0x06;
194 carry = (result > 0x0F);
195
196 result = (Registers.AL & 0xF0) + (Work8 & 0xF0) + (result & 0x0F) + (carry * 0x10);
197
198 if ((Registers.AL & 0x80) == (Work8 & 0x80) && (Registers.AL & 0x80) != (result & 0x80))
199 SetOverflow();
200 else
201 ClearOverflow();
202
203 if (result > 0x9F)
204 result += 0x60;
205
206 if (result > 0xFF)
207 SetCarry();
208 else
209 ClearCarry();
210
211 Registers.AL = result & 0xFF;
212 SetZN(Registers.AL);
213 }
214 else
215 {
216 uint16 Ans16 = Registers.AL + Work8 + CheckCarry();
217
218 ICPU._Carry = Ans16 >= 0x100;
219
220 if (~(Registers.AL ^ Work8) & (Work8 ^ (uint8) Ans16) & 0x80)
221 SetOverflow();
222 else
223 ClearOverflow();
224
225 Registers.AL = (uint8) Ans16;
226 SetZN(Registers.AL);
227 }
228}
229
230static inline void AND (uint16 Work16)
231{
232 Registers.A.W &= Work16;
233 SetZN(Registers.A.W);
234}
235
236static inline void AND (uint8 Work8)
237{
238 Registers.AL &= Work8;
239 SetZN(Registers.AL);
240}
241
242static inline void ASL16 (uint32 OpAddress, s9xwrap_t w)
243{
244 uint16 Work16 = S9xGetWord(OpAddress, w);
245 ICPU._Carry = (Work16 & 0x8000) != 0;
246 Work16 <<= 1;
247 AddCycles(ONE_CYCLE);
248 S9xSetWord(Work16, OpAddress, w, WRITE_10);
249 OpenBus = Work16 & 0xff;
250 SetZN(Work16);
251}
252
253static inline void ASL8 (uint32 OpAddress)
254{
255 uint8 Work8 = S9xGetByte(OpAddress);
256 ICPU._Carry = (Work8 & 0x80) != 0;
257 Work8 <<= 1;
258 AddCycles(ONE_CYCLE);
259 S9xSetByte(Work8, OpAddress);
260 OpenBus = Work8;
261 SetZN(Work8);
262}
263
264static inline void BIT (uint16 Work16)
265{
266 ICPU._Overflow = (Work16 & 0x4000) != 0;
267 ICPU._Negative = (uint8) (Work16 >> 8);
268 ICPU._Zero = (Work16 & Registers.A.W) != 0;
269}
270
271static inline void BIT (uint8 Work8)
272{
273 ICPU._Overflow = (Work8 & 0x40) != 0;
274 ICPU._Negative = Work8;
275 ICPU._Zero = Work8 & Registers.AL;
276}
277
278static inline void CMP (uint16 val)
279{
280 int32 Int32 = (int32) Registers.A.W - (int32) val;
281 ICPU._Carry = Int32 >= 0;
282 SetZN((uint16) Int32);
283}
284
285static inline void CMP (uint8 val)
286{
287 int16 Int16 = (int16) Registers.AL - (int16) val;
288 ICPU._Carry = Int16 >= 0;
289 SetZN((uint8) Int16);
290}
291
292static inline void CPX (uint16 val)
293{
294 int32 Int32 = (int32) Registers.X.W - (int32) val;
295 ICPU._Carry = Int32 >= 0;
296 SetZN((uint16) Int32);
297}
298
299static inline void CPX (uint8 val)
300{
301 int16 Int16 = (int16) Registers.XL - (int16) val;
302 ICPU._Carry = Int16 >= 0;
303 SetZN((uint8) Int16);
304}
305
306static inline void CPY (uint16 val)
307{
308 int32 Int32 = (int32) Registers.Y.W - (int32) val;
309 ICPU._Carry = Int32 >= 0;
310 SetZN((uint16) Int32);
311}
312
313static inline void CPY (uint8 val)
314{
315 int16 Int16 = (int16) Registers.YL - (int16) val;
316 ICPU._Carry = Int16 >= 0;
317 SetZN((uint8) Int16);
318}
319
320static inline void DEC16 (uint32 OpAddress, s9xwrap_t w)
321{
322 uint16 Work16 = S9xGetWord(OpAddress, w) - 1;
323 AddCycles(ONE_CYCLE);
324 S9xSetWord(Work16, OpAddress, w, WRITE_10);
325 OpenBus = Work16 & 0xff;
326 SetZN(Work16);
327}
328
329static inline void DEC8 (uint32 OpAddress)
330{
331 uint8 Work8 = S9xGetByte(OpAddress) - 1;
332 AddCycles(ONE_CYCLE);
333 S9xSetByte(Work8, OpAddress);
334 OpenBus = Work8;
335 SetZN(Work8);
336}
337
338static inline void EOR (uint16 val)
339{
340 Registers.A.W ^= val;
341 SetZN(Registers.A.W);
342}
343
344static inline void EOR (uint8 val)
345{
346 Registers.AL ^= val;
347 SetZN(Registers.AL);
348}
349
350static inline void INC16 (uint32 OpAddress, s9xwrap_t w)
351{
352 uint16 Work16 = S9xGetWord(OpAddress, w) + 1;
353 AddCycles(ONE_CYCLE);
354 S9xSetWord(Work16, OpAddress, w, WRITE_10);
355 OpenBus = Work16 & 0xff;
356 SetZN(Work16);
357}
358
359static inline void INC8 (uint32 OpAddress)
360{
361 uint8 Work8 = S9xGetByte(OpAddress) + 1;
362 AddCycles(ONE_CYCLE);
363 S9xSetByte(Work8, OpAddress);
364 OpenBus = Work8;
365 SetZN(Work8);
366}
367
368static inline void LDA (uint16 val)
369{
370 Registers.A.W = val;
371 SetZN(Registers.A.W);
372}
373
374static inline void LDA (uint8 val)
375{
376 Registers.AL = val;
377 SetZN(Registers.AL);
378}
379
380static inline void LDX (uint16 val)
381{
382 Registers.X.W = val;
383 SetZN(Registers.X.W);
384}
385
386static inline void LDX (uint8 val)
387{
388 Registers.XL = val;
389 SetZN(Registers.XL);
390}
391
392static inline void LDY (uint16 val)
393{
394 Registers.Y.W = val;
395 SetZN(Registers.Y.W);
396}
397
398static inline void LDY (uint8 val)
399{
400 Registers.YL = val;
401 SetZN(Registers.YL);
402}
403
404static inline void LSR16 (uint32 OpAddress, s9xwrap_t w)
405{
406 uint16 Work16 = S9xGetWord(OpAddress, w);
407 ICPU._Carry = Work16 & 1;
408 Work16 >>= 1;
409 AddCycles(ONE_CYCLE);
410 S9xSetWord(Work16, OpAddress, w, WRITE_10);
411 OpenBus = Work16 & 0xff;
412 SetZN(Work16);
413}
414
415static inline void LSR8 (uint32 OpAddress)
416{
417 uint8 Work8 = S9xGetByte(OpAddress);
418 ICPU._Carry = Work8 & 1;
419 Work8 >>= 1;
420 AddCycles(ONE_CYCLE);
421 S9xSetByte(Work8, OpAddress);
422 OpenBus = Work8;
423 SetZN(Work8);
424}
425
426static inline void ORA (uint16 val)
427{
428 Registers.A.W |= val;
429 SetZN(Registers.A.W);
430}
431
432static inline void ORA (uint8 val)
433{
434 Registers.AL |= val;
435 SetZN(Registers.AL);
436}
437
438static inline void ROL16 (uint32 OpAddress, s9xwrap_t w)
439{
440 uint32 Work32 = (((uint32) S9xGetWord(OpAddress, w)) << 1) | CheckCarry();
441 ICPU._Carry = Work32 >= 0x10000;
442 AddCycles(ONE_CYCLE);
443 S9xSetWord((uint16) Work32, OpAddress, w, WRITE_10);
444 OpenBus = Work32 & 0xff;
445 SetZN((uint16) Work32);
446}
447
448static inline void ROL8 (uint32 OpAddress)
449{
450 uint16 Work16 = (((uint16) S9xGetByte(OpAddress)) << 1) | CheckCarry();
451 ICPU._Carry = Work16 >= 0x100;
452 AddCycles(ONE_CYCLE);
453 S9xSetByte((uint8) Work16, OpAddress);
454 OpenBus = Work16 & 0xff;
455 SetZN((uint8) Work16);
456}
457
458static inline void ROR16 (uint32 OpAddress, s9xwrap_t w)
459{
460 uint32 Work32 = ((uint32) S9xGetWord(OpAddress, w)) | (((uint32) CheckCarry()) << 16);
461 ICPU._Carry = Work32 & 1;
462 Work32 >>= 1;
463 AddCycles(ONE_CYCLE);
464 S9xSetWord((uint16) Work32, OpAddress, w, WRITE_10);
465 OpenBus = Work32 & 0xff;
466 SetZN((uint16) Work32);
467}
468
469static inline void ROR8 (uint32 OpAddress)
470{
471 uint16 Work16 = ((uint16) S9xGetByte(OpAddress)) | (((uint16) CheckCarry()) << 8);
472 ICPU._Carry = Work16 & 1;
473 Work16 >>= 1;
474 AddCycles(ONE_CYCLE);
475 S9xSetByte((uint8) Work16, OpAddress);
476 OpenBus = Work16 & 0xff;
477 SetZN((uint8) Work16);
478}
479
480static inline void SBC (uint16 Work16)
481{
482 if (CheckDecimal())
483 {
484 int result;
485 int carry = CheckCarry();
486
487 Work16 ^= 0xFFFF;
488
489 result = (Registers.A.W & 0x000F) + (Work16 & 0x000F) + carry;
490 if (result < 0x0010)
491 result -= 0x0006;
492 carry = (result > 0x000F);
493
494 result = (Registers.A.W & 0x00F0) + (Work16 & 0x00F0) + (result & 0x000F) + carry * 0x10;
495 if (result < 0x0100)
496 result -= 0x0060;
497 carry = (result > 0x00FF);
498
499 result = (Registers.A.W & 0x0F00) + (Work16 & 0x0F00) + (result & 0x00FF) + carry * 0x100;
500 if (result < 0x1000)
501 result -= 0x0600;
502 carry = (result > 0x0FFF);
503
504 result = (Registers.A.W & 0xF000) + (Work16 & 0xF000) + (result & 0x0FFF) + carry * 0x1000;
505
506 if (((Registers.A.W ^ Work16) & 0x8000) == 0 && ((Registers.A.W ^ result) & 0x8000))
507 SetOverflow();
508 else
509 ClearOverflow();
510
511 if (result < 0x10000)
512 result -= 0x6000;
513
514 if (result > 0xFFFF)
515 SetCarry();
516 else
517 ClearCarry();
518
519 Registers.A.W = result & 0xFFFF;
520 SetZN(Registers.A.W);
521 }
522 else
523 {
524 int32 Int32 = (int32) Registers.A.W - (int32) Work16 + (int32) CheckCarry() - 1;
525
526 ICPU._Carry = Int32 >= 0;
527
528 if ((Registers.A.W ^ Work16) & (Registers.A.W ^ (uint16) Int32) & 0x8000)
529 SetOverflow();
530 else
531 ClearOverflow();
532
533 Registers.A.W = (uint16) Int32;
534 SetZN(Registers.A.W);
535 }
536}
537
538static inline void SBC (uint8 Work8)
539{
540 if (CheckDecimal())
541 {
542 int result;
543 int carry = CheckCarry();
544
545 Work8 ^= 0xFF;
546
547 result = (Registers.AL & 0x0F) + (Work8 & 0x0F) + carry;
548 if (result < 0x10)
549 result -= 0x06;
550 carry = (result > 0x0F);
551
552 result = (Registers.AL & 0xF0) + (Work8 & 0xF0) + (result & 0x0F) + carry * 0x10;
553
554 if ((Registers.AL & 0x80) == (Work8 & 0x80) && (Registers.AL & 0x80) != (result & 0x80))
555 SetOverflow();
556 else
557 ClearOverflow();
558
559 if (result < 0x100 )
560 result -= 0x60;
561
562 if (result > 0xFF)
563 SetCarry();
564 else
565 ClearCarry();
566
567 Registers.AL = result & 0xFF;
568 SetZN(Registers.AL);
569 }
570 else
571 {
572 int16 Int16 = (int16) Registers.AL - (int16) Work8 + (int16) CheckCarry() - 1;
573
574 ICPU._Carry = Int16 >= 0;
575
576 if ((Registers.AL ^ Work8) & (Registers.AL ^ (uint8) Int16) & 0x80)
577 SetOverflow();
578 else
579 ClearOverflow();
580
581 Registers.AL = (uint8) Int16;
582 SetZN(Registers.AL);
583 }
584}
585
586static inline void STA16 (uint32 OpAddress, enum s9xwrap_t w)
587{
588 S9xSetWord(Registers.A.W, OpAddress, w);
589 OpenBus = Registers.AH;
590}
591
592static inline void STA8 (uint32 OpAddress)
593{
594 S9xSetByte(Registers.AL, OpAddress);
595 OpenBus = Registers.AL;
596}
597
598static inline void STX16 (uint32 OpAddress, enum s9xwrap_t w)
599{
600 S9xSetWord(Registers.X.W, OpAddress, w);
601 OpenBus = Registers.XH;
602}
603
604static inline void STX8 (uint32 OpAddress)
605{
606 S9xSetByte(Registers.XL, OpAddress);
607 OpenBus = Registers.XL;
608}
609
610static inline void STY16 (uint32 OpAddress, enum s9xwrap_t w)
611{
612 S9xSetWord(Registers.Y.W, OpAddress, w);
613 OpenBus = Registers.YH;
614}
615
616static inline void STY8 (uint32 OpAddress)
617{
618 S9xSetByte(Registers.YL, OpAddress);
619 OpenBus = Registers.YL;
620}
621
622static inline void STZ16 (uint32 OpAddress, enum s9xwrap_t w)
623{
624 S9xSetWord(0, OpAddress, w);
625 OpenBus = 0;
626}
627
628static inline void STZ8 (uint32 OpAddress)
629{
630 S9xSetByte(0, OpAddress);
631 OpenBus = 0;
632}
633
634static inline void TSB16 (uint32 OpAddress, enum s9xwrap_t w)
635{
636 uint16 Work16 = S9xGetWord(OpAddress, w);
637 ICPU._Zero = (Work16 & Registers.A.W) != 0;
638 Work16 |= Registers.A.W;
639 AddCycles(ONE_CYCLE);
640 S9xSetWord(Work16, OpAddress, w, WRITE_10);
641 OpenBus = Work16 & 0xff;
642}
643
644static inline void TSB8 (uint32 OpAddress)
645{
646 uint8 Work8 = S9xGetByte(OpAddress);
647 ICPU._Zero = Work8 & Registers.AL;
648 Work8 |= Registers.AL;
649 AddCycles(ONE_CYCLE);
650 S9xSetByte(Work8, OpAddress);
651 OpenBus = Work8;
652}
653
654static inline void TRB16 (uint32 OpAddress, enum s9xwrap_t w)
655{
656 uint16 Work16 = S9xGetWord(OpAddress, w);
657 ICPU._Zero = (Work16 & Registers.A.W) != 0;
658 Work16 &= ~Registers.A.W;
659 AddCycles(ONE_CYCLE);
660 S9xSetWord(Work16, OpAddress, w, WRITE_10);
661 OpenBus = Work16 & 0xff;
662}
663
664static inline void TRB8 (uint32 OpAddress)
665{
666 uint8 Work8 = S9xGetByte(OpAddress);
667 ICPU._Zero = Work8 & Registers.AL;
668 Work8 &= ~Registers.AL;
669 AddCycles(ONE_CYCLE);
670 S9xSetByte(Work8, OpAddress);
671 OpenBus = Work8;
672}
673
674#endif
675