1
/*****************************************************************************
4
* Addressing mode and opcode macros for 6502,65c02,65sc02,6510,n2a03 CPUs
6
* Copyright Juergen Buchmueller, all rights reserved.
7
* 65sc02 core Copyright Peter Trauner, all rights reserved.
9
* - This source code is released as freeware for non-commercial purposes.
10
* - You are free to use and redistribute this code in modified or
11
* unmodified form, provided you list me in the credits.
12
* - If you modify this source code, you must add a notice to each modified
13
* source file that it has been changed. If you're a nice person, you
14
* will clearly mark each change too. :)
15
* - If you wish to use this for commercial purposes, please contact me at
16
* pullmoll@t-online.de
17
* - The author of this copywritten work reserves the right to change the
18
* terms of its usage and license at any time, including retroactively
19
* - This entire notice must remain in the source code.
21
*****************************************************************************/
34
/* some shortcuts for improved readability */
39
#define S cpustate->sp.b.l
40
#define SPD cpustate->sp.d
42
#define NZ cpustate->nz
45
if ((n) == 0) P = (P & ~F_N) | F_Z; else P = (P & ~(F_N | F_Z)) | ((n) & F_N)
48
if ((n) == 0) P |= F_Z; else P &= ~F_Z
50
#define EAL cpustate->ea.b.l
51
#define EAH cpustate->ea.b.h
52
#define EAW cpustate->ea.w.l
53
#define EAD cpustate->ea.d
55
#define ZPL cpustate->zp.b.l
56
#define ZPH cpustate->zp.b.h
57
#define ZPW cpustate->zp.w.l
58
#define ZPD cpustate->zp.d
60
#define PCL cpustate->pc.b.l
61
#define PCH cpustate->pc.b.h
62
#define PCW cpustate->pc.w.l
63
#define PCD cpustate->pc.d
65
#define PPC cpustate->ppc.d
67
#define RDMEM_ID(a) cpustate->rdmem_id(cpustate->space,a)
68
#define WRMEM_ID(a,d) cpustate->wrmem_id(cpustate->space,a,d)
70
/***************************************************************
72
***************************************************************/
73
#define RDOP() cpustate->direct->read_decrypted_byte(PCW++); cpustate->icount -= 1
74
#define PEEKOP() cpustate->direct->read_decrypted_byte(PCW)
76
/***************************************************************
77
* RDOPARG read an opcode argument
78
***************************************************************/
79
#define RDOPARG() cpustate->direct->read_raw_byte(PCW++); cpustate->icount -= 1
81
/***************************************************************
83
***************************************************************/
84
#define RDMEM(addr) cpustate->space->read_byte(addr); cpustate->icount -= 1
86
/***************************************************************
88
***************************************************************/
89
#define WRMEM(addr,data) cpustate->space->write_byte(addr,data); cpustate->icount -= 1
91
/***************************************************************
93
* extra cycle if page boundary is crossed
94
***************************************************************/
97
INT8 tmp2 = RDOPARG(); \
101
EAW = PCW + (signed char)tmp2; \
102
if ( EAH != PCH ) { \
103
RDMEM( (PCH << 8 ) | EAL) ; \
109
/***************************************************************
111
* Helper macros to build the effective address
113
***************************************************************/
115
/***************************************************************
116
* EA = zero page address
117
***************************************************************/
122
/***************************************************************
123
* EA = zero page address + X
124
***************************************************************/
131
/***************************************************************
132
* EA = zero page address + Y
133
***************************************************************/
140
/***************************************************************
141
* EA = absolute address
142
***************************************************************/
147
/***************************************************************
148
* EA = absolute address + X
149
* one additional read if page boundary is crossed
150
***************************************************************/
153
if ( EAL + X > 0xff ) { \
154
RDMEM( ( EAH << 8 ) | ( ( EAL + X ) & 0xff ) ); \
158
/***************************************************************
159
* EA = absolute address + X
160
***************************************************************/
163
RDMEM( ( EAH << 8 ) | ( ( EAL + X ) & 0xff ) ); \
166
/***************************************************************
167
* EA = absolute address + Y
168
* one additional read if page boundary is crossed
169
***************************************************************/
172
if ( EAL + Y > 0xff ) { \
173
RDMEM( ( EAH << 8 ) | ( ( EAL + Y ) & 0xff ) ); \
177
/***************************************************************
178
* EA = absolute address + Y
179
***************************************************************/
182
RDMEM( ( EAH << 8 ) | ( ( EAL + Y ) & 0xff ) ); \
185
/***************************************************************
186
* EA = zero page + X indirect (pre indexed)
187
***************************************************************/
196
/***************************************************************
197
* EA = zero page indirect + Y (post indexed)
198
* subtract 1 cycle if page boundary is crossed
199
***************************************************************/
205
if (EAL + Y > 0xff) { \
206
RDMEM( ( EAH << 8 ) | ( ( EAL + Y ) & 0xff ) ); \
210
/***************************************************************
211
* EA = zero page indirect + Y
212
***************************************************************/
218
RDMEM( ( EAH << 8 ) | ( ( EAL + Y ) & 0xff ) ); \
221
/***************************************************************
222
* EA = zero page indirect (65c02 pre indexed w/o X)
223
***************************************************************/
230
/***************************************************************
231
* EA = indirect (only used by JMP)
232
***************************************************************/
236
EAL++; /* booby trap: stay in same page! ;-) */ \
241
/* read a value into tmp */
242
/* Base number of cycles taken for each mode (including reading of opcode):
251
RD_ABX_NP/WR_ABX_NP 5
253
RD_ABY_NP/WR_ABY_NP 5
256
RD_IDY_NP/WR_IDY_NP 6
259
#define RD_IMM tmp = RDOPARG()
260
#define RD_IMM_DISCARD RDOPARG()
261
#define RD_DUM RDMEM(PCW)
262
#define RD_ACC tmp = A
263
#define RD_ZPG EA_ZPG; tmp = RDMEM(EAD)
264
#define RD_ZPG_DISCARD EA_ZPG; RDMEM(EAD)
265
#define RD_ZPX EA_ZPX; tmp = RDMEM(EAD)
266
#define RD_ZPX_DISCARD EA_ZPX; RDMEM(EAD)
267
#define RD_ZPY EA_ZPY; tmp = RDMEM(EAD)
268
#define RD_ABS EA_ABS; tmp = RDMEM(EAD)
269
#define RD_ABS_DISCARD EA_ABS; RDMEM(EAD)
270
#define RD_ABX_P EA_ABX_P; tmp = RDMEM(EAD)
271
#define RD_ABX_P_DISCARD EA_ABX_P; RDMEM(EAD);
272
#define RD_ABX_NP EA_ABX_NP; tmp = RDMEM(EAD)
273
#define RD_ABY_P EA_ABY_P; tmp = RDMEM(EAD)
274
#define RD_ABY_NP EA_ABY_NP; tmp = RDMEM(EAD)
275
#define RD_IDX EA_IDX; tmp = RDMEM_ID(EAD); cpustate->icount -= 1
276
#define RD_IDY_P EA_IDY_P; tmp = RDMEM_ID(EAD); cpustate->icount -= 1
277
#define RD_IDY_NP EA_IDY_NP; tmp = RDMEM_ID(EAD); cpustate->icount -= 1
278
#define RD_ZPI EA_ZPI; tmp = RDMEM(EAD)
280
/* write a value from tmp */
281
#define WR_ZPG EA_ZPG; WRMEM(EAD, tmp)
282
#define WR_ZPX EA_ZPX; WRMEM(EAD, tmp)
283
#define WR_ZPY EA_ZPY; WRMEM(EAD, tmp)
284
#define WR_ABS EA_ABS; WRMEM(EAD, tmp)
285
#define WR_ABX_NP EA_ABX_NP; WRMEM(EAD, tmp)
286
#define WR_ABY_NP EA_ABY_NP; WRMEM(EAD, tmp)
287
#define WR_IDX EA_IDX; WRMEM_ID(EAD, tmp); cpustate->icount -= 1
288
#define WR_IDY_NP EA_IDY_NP; WRMEM_ID(EAD, tmp); cpustate->icount -= 1
289
#define WR_ZPI EA_ZPI; WRMEM(EAD, tmp)
291
/* dummy read from the last EA */
292
#define RD_EA RDMEM(EAD)
294
/* write back a value from tmp to the last EA */
295
#define WB_ACC A = (UINT8)tmp;
296
#define WB_EA WRMEM(EAD, tmp)
298
/***************************************************************
299
***************************************************************
300
* Macros to emulate the plain 6502 opcodes
301
***************************************************************
302
***************************************************************/
304
/***************************************************************
305
* push a register onto the stack
306
***************************************************************/
307
#define PUSH(Rg) WRMEM(SPD, Rg); S--
309
/***************************************************************
310
* pull a register from the stack
311
***************************************************************/
312
#define PULL(Rg) S++; Rg = RDMEM(SPD)
314
/* 6502 ********************************************************
316
***************************************************************/
320
int lo = (A & 0x0f) + (tmp & 0x0f) + c; \
321
int hi = (A & 0xf0) + (tmp & 0xf0); \
322
P &= ~(F_V | F_C|F_N|F_Z); \
323
if (!((lo+hi)&0xff)) P|=F_Z; \
328
if (hi&0x80) P|=F_N; \
329
if (~(A^tmp) & (A^hi) & F_N) \
335
A = (lo & 0x0f) + (hi & 0xf0); \
338
int sum = A + tmp + c; \
340
if (~(A^tmp) & (A^sum) & F_N) \
348
/* 6502 ********************************************************
350
***************************************************************/
352
A = (UINT8)(A & tmp); \
355
/* 6502 ********************************************************
356
* ASL Arithmetic shift left
357
***************************************************************/
359
P = (P & ~F_C) | ((tmp >> 7) & F_C); \
360
tmp = (UINT8)(tmp << 1); \
363
/* 6502 ********************************************************
364
* BCC Branch if carry clear
365
***************************************************************/
366
#define BCC BRA(!(P & F_C))
368
/* 6502 ********************************************************
369
* BCS Branch if carry set
370
***************************************************************/
371
#define BCS BRA(P & F_C)
373
/* 6502 ********************************************************
374
* BEQ Branch if equal
375
***************************************************************/
376
#define BEQ BRA(P & F_Z)
378
/* 6502 ********************************************************
380
***************************************************************/
383
P &= ~(F_N|F_V|F_Z); \
384
P |= tmp & (F_N|F_V); \
385
if ((tmp & A) == 0) \
388
/* 6502 ********************************************************
389
* BMI Branch if minus
390
***************************************************************/
391
#define BMI BRA(P & F_N)
393
/* 6502 ********************************************************
394
* BNE Branch if not equal
395
***************************************************************/
396
#define BNE BRA(!(P & F_Z))
398
/* 6502 ********************************************************
400
***************************************************************/
401
#define BPL BRA(!(P & F_N))
403
/* 6502 ********************************************************
405
* increment PC, push PC hi, PC lo, flags (with B bit set),
406
* set I flag, jump via IRQ vector
407
***************************************************************/
414
PCL = RDMEM(M6502_IRQ_VEC); \
415
PCH = RDMEM(M6502_IRQ_VEC+1)
417
/* 6502 ********************************************************
418
* BVC Branch if overflow clear
419
***************************************************************/
420
#define BVC BRA(!(P & F_V))
422
/* 6502 ********************************************************
423
* BVS Branch if overflow set
424
***************************************************************/
425
#define BVS BRA(P & F_V)
427
/* 6502 ********************************************************
428
* CLC Clear carry flag
429
***************************************************************/
433
/* 6502 ********************************************************
434
* CLD Clear decimal flag
435
***************************************************************/
439
/* 6502 ********************************************************
440
* CLI Clear interrupt flag
441
***************************************************************/
443
if ((cpustate->irq_state != CLEAR_LINE) && (P & F_I)) { \
444
/* kludge for now until IRQ rewrite: ignore if RTI follows */ \
445
if (PEEKOP() != 0x40) \
446
cpustate->after_cli = 1; \
450
/* 6502 ********************************************************
451
* CLV Clear overflow flag
452
***************************************************************/
456
/* 6502 ********************************************************
457
* CMP Compare accumulator
458
***************************************************************/
463
SET_NZ((UINT8)(A - tmp))
465
/* 6502 ********************************************************
466
* CPX Compare index X
467
***************************************************************/
472
SET_NZ((UINT8)(X - tmp))
474
/* 6502 ********************************************************
475
* CPY Compare index Y
476
***************************************************************/
481
SET_NZ((UINT8)(Y - tmp))
483
/* 6502 ********************************************************
484
* DEC Decrement memory
485
***************************************************************/
487
tmp = (UINT8)(tmp-1); \
490
/* 6502 ********************************************************
491
* DEX Decrement index X
492
***************************************************************/
497
/* 6502 ********************************************************
498
* DEY Decrement index Y
499
***************************************************************/
504
/* 6502 ********************************************************
505
* EOR Logical exclusive or
506
***************************************************************/
508
A = (UINT8)(A ^ tmp); \
511
/* 6502 ********************************************************
513
***************************************************************/
515
logerror("M6502 illegal opcode %04x: %02x\n",(PCW-1)&0xffff, cpustate->direct->read_decrypted_byte((PCW-1)&0xffff))
517
/* 6502 ********************************************************
518
* INC Increment memory
519
***************************************************************/
521
tmp = (UINT8)(tmp+1); \
524
/* 6502 ********************************************************
525
* INX Increment index X
526
***************************************************************/
531
/* 6502 ********************************************************
532
* INY Increment index Y
533
***************************************************************/
538
/* 6502 ********************************************************
539
* JMP Jump to address
540
* set PC to the effective address
541
***************************************************************/
543
if( EAD == PPC && !cpustate->pending_irq && !cpustate->after_cli ) \
544
if( cpustate->icount > 0 ) cpustate->icount = 0; \
547
/* 6502 ********************************************************
548
* JSR Jump to subroutine
549
* decrement PC (sic!) push PC hi, push PC lo and set
550
* PC to the effective address
551
***************************************************************/
560
/* 6502 ********************************************************
561
* LDA Load accumulator
562
***************************************************************/
567
/* 6502 ********************************************************
569
***************************************************************/
574
/* 6502 ********************************************************
576
***************************************************************/
581
/* 6502 ********************************************************
582
* LSR Logic shift right
583
* 0 -> [7][6][5][4][3][2][1][0] -> C
584
***************************************************************/
586
P = (P & ~F_C) | (tmp & F_C); \
587
tmp = (UINT8)tmp >> 1; \
590
/* 6502 ********************************************************
592
***************************************************************/
595
/* 6502 ********************************************************
596
* ORA Logical inclusive or
597
***************************************************************/
599
A = (UINT8)(A | tmp); \
602
/* 6502 ********************************************************
603
* PHA Push accumulator
604
***************************************************************/
608
/* 6502 ********************************************************
609
* PHP Push processor status (flags)
610
***************************************************************/
614
/* 6502 ********************************************************
615
* PLA Pull accumulator
616
***************************************************************/
623
/* 6502 ********************************************************
624
* PLP Pull processor status (flags)
625
***************************************************************/
630
if ((cpustate->irq_state != CLEAR_LINE) && !(P & F_I)) { \
631
LOG(("M6502 '%s' PLP sets after_cli\n",cpustate->device->tag())); \
632
cpustate->after_cli = 1; \
639
/* 6502 ********************************************************
641
* new C <- [7][6][5][4][3][2][1][0] <- C
642
***************************************************************/
644
tmp = (tmp << 1) | (P & F_C); \
645
P = (P & ~F_C) | ((tmp >> 8) & F_C); \
649
/* 6502 ********************************************************
651
* C -> [7][6][5][4][3][2][1][0] -> new C
652
***************************************************************/
654
tmp |= (P & F_C) << 8; \
655
P = (P & ~F_C) | (tmp & F_C); \
656
tmp = (UINT8)(tmp >> 1); \
659
/* 6502 ********************************************************
660
* RTI Return from interrupt
661
* pull flags, pull PC lo, pull PC hi and increment PC
663
***************************************************************/
671
if( (cpustate->irq_state != CLEAR_LINE) && !(P & F_I) ) \
673
LOG(("M6502 '%s' RTI sets after_cli\n",cpustate->device->tag())); \
674
cpustate->after_cli = 1; \
677
/* 6502 ********************************************************
678
* RTS Return from subroutine
679
* pull PC lo, PC hi and increment PC
680
***************************************************************/
688
/* 6502 ********************************************************
689
* SBC Subtract with carry
690
***************************************************************/
694
int c = (P & F_C) ^ F_C; \
695
int sum = A - tmp - c; \
696
int lo = (A & 0x0f) - (tmp & 0x0f) - c; \
697
int hi = (A & 0xf0) - (tmp & 0xf0); \
703
P &= ~(F_V | F_C|F_Z|F_N); \
704
if( (A^tmp) & (A^sum) & F_N ) \
708
if( (sum & 0xff00) == 0 ) \
710
if( !((A-tmp-c) & 0xff) ) \
712
if( (A-tmp-c) & 0x80 ) \
714
A = (lo & 0x0f) | (hi & 0xf0); \
718
int c = (P & F_C) ^ F_C; \
719
int sum = A - tmp - c; \
721
if( (A^tmp) & (A^sum) & F_N ) \
723
if( (sum & 0xff00) == 0 ) \
729
/* 6502 ********************************************************
731
***************************************************************/
738
/* 6502 ********************************************************
739
* SED Set decimal flag
740
***************************************************************/
744
/* 6502 ********************************************************
745
* SEI Set interrupt flag
746
***************************************************************/
750
/* 6502 ********************************************************
751
* STA Store accumulator
752
***************************************************************/
756
/* 6502 ********************************************************
758
***************************************************************/
762
/* 6502 ********************************************************
764
***************************************************************/
768
/* 6502 ********************************************************
769
* TAX Transfer accumulator to index X
770
***************************************************************/
775
/* 6502 ********************************************************
776
* TAY Transfer accumulator to index Y
777
***************************************************************/
782
/* 6502 ********************************************************
783
* TSX Transfer stack LSB to index X
784
***************************************************************/
789
/* 6502 ********************************************************
790
* TXA Transfer index X to accumulator
791
***************************************************************/
796
/* 6502 ********************************************************
797
* TXS Transfer index X to stack LSB
798
* no flags changed (sic!)
799
***************************************************************/
803
/* 6502 ********************************************************
804
* TYA Transfer index Y to accumulator
805
***************************************************************/