1 /***********************************************************************************
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3
4 (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
5 Jerremy Koot (jkoot@snes9x.com)
6
7 (c) Copyright 2002 - 2004 Matthew Kendora
8
9 (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
10
11 (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
12
13 (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
14
15 (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
16 Kris Bleakley (codeviolation@hotmail.com)
17
18 (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
19 Nach (n-a-c-h@users.sourceforge.net),
20 zones (kasumitokoduck@yahoo.com)
21
22 (c) Copyright 2006 - 2007 nitsuja
23
24 (c) Copyright 2009 - 2010 BearOso,
25 OV2
26
27
28 BS-X C emulator code
29 (c) Copyright 2005 - 2006 Dreamer Nom,
30 zones
31
32 C4 x86 assembler and some C emulation code
33 (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
34 Nach,
35 zsKnight (zsknight@zsnes.com)
36
37 C4 C++ code
38 (c) Copyright 2003 - 2006 Brad Jorsch,
39 Nach
40
41 DSP-1 emulator code
42 (c) Copyright 1998 - 2006 _Demo_,
43 Andreas Naive (andreasnaive@gmail.com),
44 Gary Henderson,
45 Ivar (ivar@snes9x.com),
46 John Weidman,
47 Kris Bleakley,
48 Matthew Kendora,
49 Nach,
50 neviksti (neviksti@hotmail.com)
51
52 DSP-2 emulator code
53 (c) Copyright 2003 John Weidman,
54 Kris Bleakley,
55 Lord Nightmare (lord_nightmare@users.sourceforge.net),
56 Matthew Kendora,
57 neviksti
58
59 DSP-3 emulator code
60 (c) Copyright 2003 - 2006 John Weidman,
61 Kris Bleakley,
62 Lancer,
63 z80 gaiden
64
65 DSP-4 emulator code
66 (c) Copyright 2004 - 2006 Dreamer Nom,
67 John Weidman,
68 Kris Bleakley,
69 Nach,
70 z80 gaiden
71
72 OBC1 emulator code
73 (c) Copyright 2001 - 2004 zsKnight,
74 pagefault (pagefault@zsnes.com),
75 Kris Bleakley
76 Ported from x86 assembler to C by sanmaiwashi
77
78 SPC7110 and RTC C++ emulator code used in 1.39-1.51
79 (c) Copyright 2002 Matthew Kendora with research by
80 zsKnight,
81 John Weidman,
82 Dark Force
83
84 SPC7110 and RTC C++ emulator code used in 1.52+
85 (c) Copyright 2009 byuu,
86 neviksti
87
88 S-DD1 C emulator code
89 (c) Copyright 2003 Brad Jorsch with research by
90 Andreas Naive,
91 John Weidman
92
93 S-RTC C emulator code
94 (c) Copyright 2001 - 2006 byuu,
95 John Weidman
96
97 ST010 C++ emulator code
98 (c) Copyright 2003 Feather,
99 John Weidman,
100 Kris Bleakley,
101 Matthew Kendora
102
103 Super FX x86 assembler emulator code
104 (c) Copyright 1998 - 2003 _Demo_,
105 pagefault,
106 zsKnight
107
108 Super FX C emulator code
109 (c) Copyright 1997 - 1999 Ivar,
110 Gary Henderson,
111 John Weidman
112
113 Sound emulator code used in 1.5-1.51
114 (c) Copyright 1998 - 2003 Brad Martin
115 (c) Copyright 1998 - 2006 Charles Bilyue'
116
117 Sound emulator code used in 1.52+
118 (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
119
120 SH assembler code partly based on x86 assembler code
121 (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
122
123 2xSaI filter
124 (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
125
126 HQ2x, HQ3x, HQ4x filters
127 (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
128
129 NTSC filter
130 (c) Copyright 2006 - 2007 Shay Green
131
132 GTK+ GUI code
133 (c) Copyright 2004 - 2010 BearOso
134
135 Win32 GUI code
136 (c) Copyright 2003 - 2006 blip,
137 funkyass,
138 Matthew Kendora,
139 Nach,
140 nitsuja
141 (c) Copyright 2009 - 2010 OV2
142
143 Mac OS GUI code
144 (c) Copyright 1998 - 2001 John Stiles
145 (c) Copyright 2001 - 2010 zones
146
147 (c) Copyright 2010 - 2016 Daniel De Matteis. (UNDER NO CIRCUMSTANCE
148 WILL COMMERCIAL RIGHTS EVER BE APPROPRIATED TO ANY PARTY)
149
150 Specific ports contains the works of other authors. See headers in
151 individual files.
152
153
154 Snes9x homepage: http://www.snes9x.com/
155
156 Permission to use, copy, modify and/or distribute Snes9x in both binary
157 and source form, for non-commercial purposes, is hereby granted without
158 fee, providing that this license information and copyright notice appear
159 with all copies and any derived work.
160
161 This software is provided 'as-is', without any express or implied
162 warranty. In no event shall the authors be held liable for any damages
163 arising from the use of this software or it's derivatives.
164
165 Snes9x is freeware for PERSONAL USE only. Commercial users should
166 seek permission of the copyright holders first. Commercial use includes,
167 but is not limited to, charging money for Snes9x or software derived from
168 Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
169 using Snes9x as a promotion for your commercial product.
170
171 The copyright holders request that bug fixes and improvements to the code
172 should be forwarded to them so everyone can benefit from the modifications
173 in future versions.
174
175 Super NES and Super Nintendo Entertainment System are trademarks of
176 Nintendo Co., Limited and its subsidiary companies.
177 ***********************************************************************************/
178
179
180 #ifndef _CPUMACRO_H_
181 #define _CPUMACRO_H_
182
183 #define rOP8(OP, ADDR, WRAP, FUNC) \
184 static void Op##OP (void) \
185 { \
186 uint8 val = OpenBus = S9xGetByte(ADDR(READ)); \
187 FUNC##8(val); \
188 }
189
190 #define rOP16(OP, ADDR, WRAP, FUNC) \
191 static void Op##OP (void) \
192 { \
193 uint16 val = S9xGetWord(ADDR(READ), WRAP); \
194 OpenBus = (uint8) (val >> 8); \
195 FUNC(val); \
196 }
197
198 #define rOPC(OP, COND, ADDR, WRAP, FUNC) \
199 static void Op##OP (void) \
200 { \
201 if (Check##COND()) \
202 { \
203 uint8 val = OpenBus = S9xGetByte(ADDR(READ)); \
204 FUNC##8(val); \
205 } \
206 else \
207 { \
208 uint16 val = S9xGetWord(ADDR(READ), WRAP); \
209 OpenBus = (uint8) (val >> 8); \
210 FUNC##16(val); \
211 } \
212 }
213
214 #define rOPM(OP, ADDR, WRAP, FUNC) \
215 rOPC(OP, Memory, ADDR, WRAP, FUNC)
216
217 #define rOPX(OP, ADDR, WRAP, FUNC) \
218 rOPC(OP, Index, ADDR, WRAP, FUNC)
219
220 #define wOP8(OP, ADDR, WRAP, FUNC) \
221 static void Op##OP (void) \
222 { \
223 FUNC##8(ADDR(WRITE)); \
224 }
225
226 #define wOP16(OP, ADDR, WRAP, FUNC) \
227 static void Op##OP (void) \
228 { \
229 FUNC##16(ADDR(WRITE), WRAP); \
230 }
231
232 #define wOPC(OP, COND, ADDR, WRAP, FUNC) \
233 static void Op##OP (void) \
234 { \
235 if (Check##COND()) \
236 FUNC##8(ADDR(WRITE)); \
237 else \
238 FUNC##16(ADDR(WRITE), WRAP); \
239 }
240
241 #define wOPM(OP, ADDR, WRAP, FUNC) \
242 wOPC(OP, Memory, ADDR, WRAP, FUNC)
243
244 #define wOPX(OP, ADDR, WRAP, FUNC) \
245 wOPC(OP, Index, ADDR, WRAP, FUNC)
246
247 #define mOP8(OP, ADDR, WRAP, FUNC) \
248 static void Op##OP (void) \
249 { \
250 FUNC##8(ADDR(MODIFY)); \
251 }
252
253 #define mOP16(OP, ADDR, WRAP, FUNC) \
254 static void Op##OP (void) \
255 { \
256 FUNC##16(ADDR(MODIFY), WRAP); \
257 }
258
259 #define mOPC(OP, COND, ADDR, WRAP, FUNC) \
260 static void Op##OP (void) \
261 { \
262 if (Check##COND()) \
263 FUNC##8(ADDR(MODIFY)); \
264 else \
265 FUNC##16(ADDR(MODIFY), WRAP); \
266 }
267
268 #define mOPM(OP, ADDR, WRAP, FUNC) \
269 mOPC(OP, Memory, ADDR, WRAP, FUNC)
270
271 #define bOP(OP, REL, COND, CHK, E) \
272 static void Op##OP (void) \
273 { \
274 pair newPC; \
275 newPC.W = REL(JUMP); \
276 if (COND) \
277 { \
278 AddCycles(ONE_CYCLE); \
279 if (E && Registers.PCh != newPC.B.h) \
280 AddCycles(ONE_CYCLE); \
281 if ((Registers.PCw & ~MEMMAP_MASK) != (newPC.W & ~MEMMAP_MASK)) \
282 S9xSetPCBase(ICPU.ShiftedPB + newPC.W); \
283 else \
284 Registers.PCw = newPC.W; \
285 } \
286 }
287
288
289 #define SetZN16(Work16) \
290 ICPU._Zero = Work16 != 0; \
291 ICPU._Negative = (uint8) (Work16 >> 8);
292
293 #define SetZN8(Work8) \
294 ICPU._Zero = Work8; \
295 ICPU._Negative = Work8;
296
ADC16(uint16 Work16)297 static INLINE void ADC16(uint16 Work16)
298 {
299 if (CheckDecimal())
300 {
301 uint16 Ans16;
302 uint16 A1 = Registers.A.W & 0x000F;
303 uint16 A2 = Registers.A.W & 0x00F0;
304 uint16 A3 = Registers.A.W & 0x0F00;
305 uint32 A4 = Registers.A.W & 0xF000;
306 uint16 W1 = Work16 & 0x000F;
307 uint16 W2 = Work16 & 0x00F0;
308 uint16 W3 = Work16 & 0x0F00;
309 uint16 W4 = Work16 & 0xF000;
310
311 A1 += W1 + CheckCarry();
312 if (A1 > 0x0009)
313 {
314 A1 -= 0x000A;
315 A1 &= 0x000F;
316 A2 += 0x0010;
317 }
318
319 A2 += W2;
320 if (A2 > 0x0090)
321 {
322 A2 -= 0x00A0;
323 A2 &= 0x00F0;
324 A3 += 0x0100;
325 }
326
327 A3 += W3;
328 if (A3 > 0x0900)
329 {
330 A3 -= 0x0A00;
331 A3 &= 0x0F00;
332 A4 += 0x1000;
333 }
334
335 A4 += W4;
336 if (A4 > 0x9000)
337 {
338 A4 -= 0xA000;
339 A4 &= 0xF000;
340 SetCarry();
341 }
342 else
343 ClearCarry();
344
345 Ans16 = A4 | A3 | A2 | A1;
346
347 if (~(Registers.A.W ^ Work16) & (Work16 ^ Ans16) & 0x8000)
348 SetOverflow();
349 else
350 ClearOverflow();
351
352 Registers.A.W = Ans16;
353 }
354 else
355 {
356 uint32 Ans32 = Registers.A.W + Work16 + CheckCarry();
357
358 ICPU._Carry = Ans32 >= 0x10000;
359
360 if (~(Registers.A.W ^ Work16) & (Work16 ^ (uint16) Ans32) & 0x8000)
361 SetOverflow();
362 else
363 ClearOverflow();
364
365 Registers.A.W = (uint16) Ans32;
366 }
367 SetZN16(Registers.A.W);
368 }
369
ADC8(uint8 Work8)370 static INLINE void ADC8(uint8 Work8)
371 {
372 if (CheckDecimal())
373 {
374 uint8 A1, W1, W2, Ans8;
375 uint16 A2;
376
377 A1 = Registers.A.W & 0x0F;
378 A2 = Registers.A.W & 0xF0;
379 W1 = Work8 & 0x0F;
380 W2 = Work8 & 0xF0;
381
382 A1 += W1 + CheckCarry();
383 if (A1 > 0x09)
384 {
385 A1 -= 0x0A;
386 A1 &= 0x0F;
387 A2 += 0x10;
388 }
389
390 A2 += W2;
391 if (A2 > 0x90)
392 {
393 A2 -= 0xA0;
394 A2 &= 0xF0;
395 SetCarry();
396 }
397 else
398 ClearCarry();
399
400 Ans8 = A2 | A1;
401
402 if (~(Registers.AL ^ Work8) & (Work8 ^ Ans8) & 0x80)
403 SetOverflow();
404 else
405 ClearOverflow();
406
407 Registers.AL = Ans8;
408 }
409 else
410 {
411 uint16 Ans16 = Registers.AL + Work8 + CheckCarry();
412
413 ICPU._Carry = Ans16 >= 0x100;
414
415 if (~(Registers.AL ^ Work8) & (Work8 ^ (uint8) Ans16) & 0x80)
416 SetOverflow();
417 else
418 ClearOverflow();
419
420 Registers.AL = (uint8) Ans16;
421 }
422 SetZN8(Registers.AL);
423 }
424
AND16(uint16 Work16)425 static INLINE void AND16(uint16 Work16)
426 {
427 Registers.A.W &= Work16;
428 SetZN16(Registers.A.W);
429 }
430
AND8(uint8 Work8)431 static INLINE void AND8(uint8 Work8)
432 {
433 Registers.AL &= Work8;
434 SetZN8(Registers.AL);
435 }
436
ASL16(uint32 OpAddress,uint32 w)437 static INLINE void ASL16 (uint32 OpAddress, uint32 w)
438 {
439 uint16 Work16 = S9xGetWord(OpAddress, w);
440 ICPU._Carry = (Work16 & 0x8000) != 0;
441 Work16 <<= 1;
442 AddCycles(ONE_CYCLE);
443 S9xSetWord_Write1(Work16, OpAddress, w);
444 OpenBus = Work16 & 0xff;
445 SetZN16(Work16);
446 }
447
ASL8(uint32 OpAddress)448 static INLINE void ASL8 (uint32 OpAddress)
449 {
450 uint8 Work8 = S9xGetByte(OpAddress);
451 ICPU._Carry = (Work8 & 0x80) != 0;
452 Work8 <<= 1;
453 AddCycles(ONE_CYCLE);
454 S9xSetByte(Work8, OpAddress);
455 OpenBus = Work8;
456 SetZN8(Work8);
457 }
458
BIT16(uint16 Work16)459 static INLINE void BIT16(uint16 Work16)
460 {
461 ICPU._Overflow = (Work16 & 0x4000) != 0;
462 ICPU._Negative = (uint8) (Work16 >> 8);
463 ICPU._Zero = (Work16 & Registers.A.W) != 0;
464 }
465
BIT8(uint8 Work8)466 static INLINE void BIT8(uint8 Work8)
467 {
468 ICPU._Overflow = (Work8 & 0x40) != 0;
469 ICPU._Negative = Work8;
470 ICPU._Zero = Work8 & Registers.AL;
471 }
472
CMP16(uint16 val)473 static INLINE void CMP16(uint16 val)
474 {
475 int16 Int16;
476 int32 Int32;
477
478 Int32 = (int32) Registers.A.W - (int32) val;
479 ICPU._Carry = Int32 >= 0;
480 Int16 = Int32;
481 SetZN16(Int16);
482 }
483
CMP8(uint8 val)484 static INLINE void CMP8(uint8 val)
485 {
486 int16 Int16;
487 uint8 Int8;
488
489 Int16 = (int16) Registers.AL - (int16) val;
490 ICPU._Carry = Int16 >= 0;
491 Int8 = Int16;
492 SetZN8(Int8);
493 }
494
CPX16(uint16 val)495 static INLINE void CPX16(uint16 val)
496 {
497 int32 Int32;
498 uint16 Int16;
499
500 Int32 = (int32) Registers.X.W - (int32) val;
501 ICPU._Carry = Int32 >= 0;
502 Int16 = Int32;
503 SetZN16(Int16);
504 }
505
CPX8(uint8 val)506 static INLINE void CPX8(uint8 val)
507 {
508 int16 Int16;
509 uint8 Int8;
510
511 Int16 = (int16) Registers.XL - (int16) val;
512 ICPU._Carry = Int16 >= 0;
513 Int8 = Int16;
514 SetZN8(Int8);
515 }
516
CPY16(uint16 val)517 static INLINE void CPY16(uint16 val)
518 {
519 int32 Int32;
520 uint16 Int16;
521
522 Int32 = (int32) Registers.Y.W - (int32) val;
523 ICPU._Carry = Int32 >= 0;
524 Int16 = Int32;
525 SetZN16(Int16);
526 }
527
CPY8(uint8 val)528 static INLINE void CPY8(uint8 val)
529 {
530 int16 Int16;
531 uint8 Int8;
532
533 Int16 = (int16) Registers.YL - (int16) val;
534 ICPU._Carry = Int16 >= 0;
535 Int8 = Int16;
536 SetZN8(Int8);
537 }
538
DEC16(uint32 OpAddress,uint32 w)539 static INLINE void DEC16 (uint32 OpAddress, uint32 w)
540 {
541 uint16 Work16;
542
543 Work16 = S9xGetWord(OpAddress, w) - 1;
544 AddCycles(ONE_CYCLE);
545 S9xSetWord_Write1(Work16, OpAddress, w);
546 OpenBus = Work16 & 0xff;
547 SetZN16(Work16);
548 }
549
DEC8(uint32 OpAddress)550 static INLINE void DEC8 (uint32 OpAddress)
551 {
552 uint8 Work8 = S9xGetByte(OpAddress) - 1;
553 AddCycles(ONE_CYCLE);
554 S9xSetByte(Work8, OpAddress);
555 OpenBus = Work8;
556 SetZN8(Work8);
557 }
558
EOR16(uint16 val)559 static INLINE void EOR16(uint16 val)
560 {
561 Registers.A.W ^= val;
562 SetZN16(Registers.A.W);
563 }
564
EOR8(uint8 val)565 static INLINE void EOR8(uint8 val)
566 {
567 Registers.AL ^= val;
568 SetZN8(Registers.AL);
569 }
570
INC16(uint32 OpAddress,uint32 w)571 static INLINE void INC16 (uint32 OpAddress, uint32 w)
572 {
573 uint16 Work16 = S9xGetWord(OpAddress, w) + 1;
574 AddCycles(ONE_CYCLE);
575 S9xSetWord_Write1(Work16, OpAddress, w);
576 OpenBus = Work16 & 0xff;
577 SetZN16(Work16);
578 }
579
INC8(uint32 OpAddress)580 static INLINE void INC8 (uint32 OpAddress)
581 {
582 uint8 Work8 = S9xGetByte(OpAddress) + 1;
583 AddCycles(ONE_CYCLE);
584 S9xSetByte(Work8, OpAddress);
585 OpenBus = Work8;
586 SetZN8(Work8);
587 }
588
LDA16(uint16 val)589 static INLINE void LDA16(uint16 val)
590 {
591 Registers.A.W = val;
592 SetZN16(Registers.A.W);
593 }
594
LDA8(uint8 val)595 static INLINE void LDA8(uint8 val)
596 {
597 Registers.AL = val;
598 SetZN8(Registers.AL);
599 }
600
LDX16(uint16 val)601 static INLINE void LDX16(uint16 val)
602 {
603 Registers.X.W = val;
604 SetZN16(Registers.X.W);
605 }
606
LDX8(uint8 val)607 static INLINE void LDX8(uint8 val)
608 {
609 Registers.XL = val;
610 SetZN8(Registers.XL);
611 }
612
LDY16(uint16 val)613 static INLINE void LDY16(uint16 val)
614 {
615 Registers.Y.W = val;
616 SetZN16(Registers.Y.W);
617 }
618
LDY8(uint8 val)619 static INLINE void LDY8(uint8 val)
620 {
621 Registers.YL = val;
622 SetZN8(Registers.YL);
623 }
624
LSR16(uint32 OpAddress,uint32 w)625 static INLINE void LSR16 (uint32 OpAddress, uint32 w)
626 {
627 uint16 Work16 = S9xGetWord(OpAddress, w);
628 ICPU._Carry = Work16 & 1;
629 Work16 >>= 1;
630 AddCycles(ONE_CYCLE);
631 S9xSetWord_Write1(Work16, OpAddress, w);
632 OpenBus = Work16 & 0xff;
633 SetZN16(Work16);
634 }
635
LSR8(uint32 OpAddress)636 static INLINE void LSR8 (uint32 OpAddress)
637 {
638 uint8 Work8 = S9xGetByte(OpAddress);
639 ICPU._Carry = Work8 & 1;
640 Work8 >>= 1;
641 AddCycles(ONE_CYCLE);
642 S9xSetByte(Work8, OpAddress);
643 OpenBus = Work8;
644 SetZN8(Work8);
645 }
646
ORA16(uint16 val)647 static INLINE void ORA16(uint16 val)
648 {
649 Registers.A.W |= val;
650 SetZN16(Registers.A.W);
651 }
652
ORA8(uint8 val)653 static INLINE void ORA8(uint8 val)
654 {
655 Registers.AL |= val;
656 SetZN8(Registers.AL);
657 }
658
ROL16(uint32 OpAddress,uint32 w)659 static INLINE void ROL16 (uint32 OpAddress, uint32 w)
660 {
661 uint32 Work32 = (((uint32) S9xGetWord(OpAddress, w)) << 1) | CheckCarry();
662 ICPU._Carry = Work32 >= 0x10000;
663 AddCycles(ONE_CYCLE);
664 S9xSetWord_Write1((uint16) Work32, OpAddress, w);
665 OpenBus = Work32 & 0xff;
666 SetZN16((uint16) Work32);
667 }
668
ROL8(uint32 OpAddress)669 static INLINE void ROL8 (uint32 OpAddress)
670 {
671 uint16 Work16 = (((uint16) S9xGetByte(OpAddress)) << 1) | CheckCarry();
672 ICPU._Carry = Work16 >= 0x100;
673 AddCycles(ONE_CYCLE);
674 S9xSetByte((uint8) Work16, OpAddress);
675 OpenBus = Work16 & 0xff;
676 SetZN8((uint8) Work16);
677 }
678
ROR16(uint32 OpAddress,uint32 w)679 static INLINE void ROR16 (uint32 OpAddress, uint32 w)
680 {
681 uint32 Work32 = ((uint32) S9xGetWord(OpAddress, w)) | (((uint32) CheckCarry()) << 16);
682 ICPU._Carry = Work32 & 1;
683 Work32 >>= 1;
684 AddCycles(ONE_CYCLE);
685 S9xSetWord_Write1((uint16) Work32, OpAddress, w);
686 OpenBus = Work32 & 0xff;
687 SetZN16((uint16) Work32);
688 }
689
ROR8(uint32 OpAddress)690 static INLINE void ROR8 (uint32 OpAddress)
691 {
692 uint16 Work16 = ((uint16) S9xGetByte(OpAddress)) | (((uint16) CheckCarry()) << 8);
693 ICPU._Carry = Work16 & 1;
694 Work16 >>= 1;
695 AddCycles(ONE_CYCLE);
696 S9xSetByte((uint8) Work16, OpAddress);
697 OpenBus = Work16 & 0xff;
698 SetZN8((uint8) Work16);
699 }
700
SBC16(uint16 Work16)701 static INLINE void SBC16(uint16 Work16)
702 {
703 if (CheckDecimal())
704 {
705 uint16 Ans16;
706 uint16 A1 = Registers.A.W & 0x000F;
707 uint16 A2 = Registers.A.W & 0x00F0;
708 uint16 A3 = Registers.A.W & 0x0F00;
709 uint32 A4 = Registers.A.W & 0xF000;
710 uint16 W1 = Work16 & 0x000F;
711 uint16 W2 = Work16 & 0x00F0;
712 uint16 W3 = Work16 & 0x0F00;
713 uint16 W4 = Work16 & 0xF000;
714
715 A1 -= W1 + !CheckCarry();
716 A2 -= W2;
717 A3 -= W3;
718 A4 -= W4;
719
720 if (A1 > 0x000F)
721 {
722 A1 += 0x000A;
723 A1 &= 0x000F;
724 A2 -= 0x0010;
725 }
726
727 if (A2 > 0x00F0)
728 {
729 A2 += 0x00A0;
730 A2 &= 0x00F0;
731 A3 -= 0x0100;
732 }
733
734 if (A3 > 0x0F00)
735 {
736 A3 += 0x0A00;
737 A3 &= 0x0F00;
738 A4 -= 0x1000;
739 }
740
741 if (A4 > 0xF000)
742 {
743 A4 += 0xA000;
744 A4 &= 0xF000;
745 ClearCarry();
746 }
747 else
748 SetCarry();
749
750 Ans16 = A4 | A3 | A2 | A1;
751
752 if ((Registers.A.W ^ Work16) & (Registers.A.W ^ Ans16) & 0x8000)
753 SetOverflow();
754 else
755 ClearOverflow();
756
757 Registers.A.W = Ans16;
758 }
759 else
760 {
761 int32 Int32 = (int32) Registers.A.W - (int32) Work16 + (int32) CheckCarry() - 1;
762
763 ICPU._Carry = Int32 >= 0;
764
765 if ((Registers.A.W ^ Work16) & (Registers.A.W ^ (uint16) Int32) & 0x8000)
766 SetOverflow();
767 else
768 ClearOverflow();
769
770 Registers.A.W = (uint16) Int32;
771 }
772 SetZN16(Registers.A.W);
773 }
774
SBC8(uint8 Work8)775 static INLINE void SBC8(uint8 Work8)
776 {
777 if (CheckDecimal())
778 {
779 uint8 A1, W1, W2, Ans8;
780 uint16 A2;
781
782 A1 = Registers.A.W & 0x0F;
783 A2 = Registers.A.W & 0xF0;
784 W1 = Work8 & 0x0F;
785 W2 = Work8 & 0xF0;
786
787 A1 -= W1 + !CheckCarry();
788 A2 -= W2;
789
790 if (A1 > 0x0F)
791 {
792 A1 += 0x0A;
793 A1 &= 0x0F;
794 A2 -= 0x10;
795 }
796
797 if (A2 > 0xF0)
798 {
799 A2 += 0xA0;
800 A2 &= 0xF0;
801 ClearCarry();
802 }
803 else
804 SetCarry();
805
806 Ans8 = A2 | A1;
807
808 if ((Registers.AL ^ Work8) & (Registers.AL ^ Ans8) & 0x80)
809 SetOverflow();
810 else
811 ClearOverflow();
812
813 Registers.AL = Ans8;
814 }
815 else
816 {
817 int16 Int16 = (int16) Registers.AL - (int16) Work8 + (int16) CheckCarry() - 1;
818
819 ICPU._Carry = Int16 >= 0;
820
821 if ((Registers.AL ^ Work8) & (Registers.AL ^ (uint8) Int16) & 0x80)
822 SetOverflow();
823 else
824 ClearOverflow();
825
826 Registers.AL = (uint8) Int16;
827 }
828 SetZN8(Registers.AL);
829 }
830
STA16(uint32 OpAddress,uint32 w)831 static INLINE void STA16 (uint32 OpAddress, uint32 w)
832 {
833 S9xSetWord_Write0(Registers.A.W, OpAddress, w);
834 OpenBus = Registers.AH;
835 }
836
STA8(uint32 OpAddress)837 static INLINE void STA8 (uint32 OpAddress)
838 {
839 S9xSetByte(Registers.AL, OpAddress);
840 OpenBus = Registers.AL;
841 }
842
STX16(uint32 OpAddress,uint32 w)843 static INLINE void STX16 (uint32 OpAddress, uint32 w)
844 {
845 S9xSetWord_Write0(Registers.X.W, OpAddress, w);
846 OpenBus = Registers.XH;
847 }
848
STX8(uint32 OpAddress)849 static INLINE void STX8 (uint32 OpAddress)
850 {
851 S9xSetByte(Registers.XL, OpAddress);
852 OpenBus = Registers.XL;
853 }
854
STY16(uint32 OpAddress,uint32 w)855 static INLINE void STY16 (uint32 OpAddress, uint32 w)
856 {
857 S9xSetWord_Write0(Registers.Y.W, OpAddress, w);
858 OpenBus = Registers.YH;
859 }
860
STY8(uint32 OpAddress)861 static INLINE void STY8 (uint32 OpAddress)
862 {
863 S9xSetByte(Registers.YL, OpAddress);
864 OpenBus = Registers.YL;
865 }
866
STZ16(uint32 OpAddress,uint32 w)867 static INLINE void STZ16 (uint32 OpAddress, uint32 w)
868 {
869 S9xSetWord_Write0(0, OpAddress, w);
870 OpenBus = 0;
871 }
872
STZ8(uint32 OpAddress)873 static INLINE void STZ8 (uint32 OpAddress)
874 {
875 S9xSetByte(0, OpAddress);
876 OpenBus = 0;
877 }
878
TSB16(uint32 OpAddress,uint32 w)879 static INLINE void TSB16 (uint32 OpAddress, uint32 w)
880 {
881 uint16 Work16;
882
883 Work16 = S9xGetWord(OpAddress, w);
884 ICPU._Zero = (Work16 & Registers.A.W) != 0;
885 Work16 |= Registers.A.W;
886 AddCycles(ONE_CYCLE);
887 S9xSetWord_Write1(Work16, OpAddress, w);
888 OpenBus = Work16 & 0xff;
889 }
890
TSB8(uint32 OpAddress)891 static INLINE void TSB8 (uint32 OpAddress)
892 {
893 uint8 Work8;
894
895 Work8 = S9xGetByte(OpAddress);
896 ICPU._Zero = Work8 & Registers.AL;
897 Work8 |= Registers.AL;
898 AddCycles(ONE_CYCLE);
899 S9xSetByte(Work8, OpAddress);
900 OpenBus = Work8;
901 }
902
TRB16(uint32 OpAddress,uint32 w)903 static INLINE void TRB16 (uint32 OpAddress, uint32 w)
904 {
905 uint16 Work16;
906
907 Work16 = S9xGetWord(OpAddress, w);
908 ICPU._Zero = (Work16 & Registers.A.W) != 0;
909 Work16 &= ~Registers.A.W;
910 AddCycles(ONE_CYCLE);
911 S9xSetWord_Write1(Work16, OpAddress, w);
912 OpenBus = Work16 & 0xff;
913 }
914
TRB8(uint32 OpAddress)915 static INLINE void TRB8 (uint32 OpAddress)
916 {
917 uint8 Work8;
918
919 Work8 = S9xGetByte(OpAddress);
920 ICPU._Zero = Work8 & Registers.AL;
921 Work8 &= ~Registers.AL;
922 AddCycles(ONE_CYCLE);
923 S9xSetByte(Work8, OpAddress);
924 OpenBus = Work8;
925 }
926
927 #endif
928