1
//============================================================================
3
// MM MM 6666 555555 0000 2222
4
// MMMM MMMM 66 66 55 00 00 22 22
5
// MM MMM MM 66 55 00 00 22
6
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
7
// MM MM 66 66 55 00 00 22
8
// MM MM 66 66 55 55 00 00 22
9
// MM MM 6666 5555 0000 222222
11
// Copyright (c) 1995-2010 by Bradford W. Mott, Stephen Anthony
12
// and the Stella Team
14
// See the file "License.txt" for information on usage and redistribution of
15
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
17
// $Id: M6502.m4 2001 2010-04-10 21:37:23Z stephena $
18
//============================================================================
21
Code and cases to emulate each of the 6502 instructions.
23
Recompile with the following:
24
'm4 M6502.m4 > M6502.ins'
26
@author Bradford W. Mott
27
@version $Id: M6502.m4 2001 2010-04-10 21:37:23Z stephena $
31
#define NOTSAMEPAGE(_addr1, _addr2) (((_addr1) ^ (_addr2)) & 0xff00)
34
define(M6502_IMPLIED, `{
38
define(M6502_IMMEDIATE_READ, `{
42
define(M6502_ABSOLUTE_READ, `{
43
uInt16 address = peek(PC++);
44
address |= ((uInt16)peek(PC++) << 8);
45
operand = peek(address);
48
define(M6502_ABSOLUTE_WRITE, `{
49
operandAddress = peek(PC++);
50
operandAddress |= ((uInt16)peek(PC++) << 8);
53
define(M6502_ABSOLUTE_READMODIFYWRITE, `{
54
operandAddress = peek(PC++);
55
operandAddress |= ((uInt16)peek(PC++) << 8);
56
operand = peek(operandAddress);
57
poke(operandAddress, operand);
60
define(M6502_ABSOLUTEX_READ, `{
61
uInt16 low = peek(PC++);
62
uInt16 high = ((uInt16)peek(PC++) << 8);
63
operand = peek(high | (uInt8)(low + X));
65
operand = peek((high | low) + X);
68
define(M6502_ABSOLUTEX_WRITE, `{
69
uInt16 low = peek(PC++);
70
uInt16 high = ((uInt16)peek(PC++) << 8);
71
peek(high | (uInt8)(low + X));
72
operandAddress = (high | low) + X;
75
define(M6502_ABSOLUTEX_READMODIFYWRITE, `{
76
uInt16 low = peek(PC++);
77
uInt16 high = ((uInt16)peek(PC++) << 8);
78
peek(high | (uInt8)(low + X));
79
operandAddress = (high | low) + X;
80
operand = peek(operandAddress);
81
poke(operandAddress, operand);
84
define(M6502_ABSOLUTEY_READ, `{
85
uInt16 low = peek(PC++);
86
uInt16 high = ((uInt16)peek(PC++) << 8);
87
operand = peek(high | (uInt8)(low + Y));
89
operand = peek((high | low) + Y);
92
define(M6502_ABSOLUTEY_WRITE, `{
93
uInt16 low = peek(PC++);
94
uInt16 high = ((uInt16)peek(PC++) << 8);
95
peek(high | (uInt8)(low + Y));
96
operandAddress = (high | low) + Y;
99
define(M6502_ABSOLUTEY_READMODIFYWRITE, `{
100
uInt16 low = peek(PC++);
101
uInt16 high = ((uInt16)peek(PC++) << 8);
102
peek(high | (uInt8)(low + Y));
103
operandAddress = (high | low) + Y;
104
operand = peek(operandAddress);
105
poke(operandAddress, operand);
108
define(M6502_ZERO_READ, `{
109
operand = peek(peek(PC++));
112
define(M6502_ZERO_WRITE, `{
113
operandAddress = peek(PC++);
116
define(M6502_ZERO_READMODIFYWRITE, `{
117
operandAddress = peek(PC++);
118
operand = peek(operandAddress);
119
poke(operandAddress, operand);
122
define(M6502_ZEROX_READ, `{
123
uInt8 address = peek(PC++);
126
operand = peek(address);
129
define(M6502_ZEROX_WRITE, `{
130
operandAddress = peek(PC++);
131
peek(operandAddress);
132
operandAddress = (operandAddress + X) & 0xFF;
135
define(M6502_ZEROX_READMODIFYWRITE, `{
136
operandAddress = peek(PC++);
137
peek(operandAddress);
138
operandAddress = (operandAddress + X) & 0xFF;
139
operand = peek(operandAddress);
140
poke(operandAddress, operand);
143
define(M6502_ZEROY_READ, `{
144
uInt8 address = peek(PC++);
147
operand = peek(address);
150
define(M6502_ZEROY_WRITE, `{
151
operandAddress = peek(PC++);
152
peek(operandAddress);
153
operandAddress = (operandAddress + Y) & 0xFF;
156
define(M6502_ZEROY_READMODIFYWRITE, `{
157
operandAddress = peek(PC++);
158
peek(operandAddress);
159
operandAddress = (operandAddress + Y) & 0xFF;
160
operand = peek(operandAddress);
161
poke(operandAddress, operand);
164
define(M6502_INDIRECT, `{
165
uInt16 addr = peek(PC++);
166
addr |= ((uInt16)peek(PC++) << 8);
168
// Simulate the error in the indirect addressing mode!
169
uInt16 high = NOTSAMEPAGE(addr, addr + 1) ? (addr & 0xff00) : (addr + 1);
171
operandAddress = peek(addr);
172
operandAddress |= ((uInt16)peek(high) << 8);
175
define(M6502_INDIRECTX_READ, `{
176
uInt8 pointer = peek(PC++);
179
uInt16 address = peek(pointer++);
180
address |= ((uInt16)peek(pointer) << 8);
181
operand = peek(address);
184
define(M6502_INDIRECTX_WRITE, `{
185
uInt8 pointer = peek(PC++);
188
operandAddress = peek(pointer++);
189
operandAddress |= ((uInt16)peek(pointer) << 8);
192
define(M6502_INDIRECTX_READMODIFYWRITE, `{
193
uInt8 pointer = peek(PC++);
196
operandAddress = peek(pointer++);
197
operandAddress |= ((uInt16)peek(pointer) << 8);
198
operand = peek(operandAddress);
199
poke(operandAddress, operand);
202
define(M6502_INDIRECTY_READ, `{
203
uInt8 pointer = peek(PC++);
204
uInt16 low = peek(pointer++);
205
uInt16 high = ((uInt16)peek(pointer) << 8);
206
operand = peek(high | (uInt8)(low + Y));
208
operand = peek((high | low) + Y);
211
define(M6502_INDIRECTY_WRITE, `{
212
uInt8 pointer = peek(PC++);
213
uInt16 low = peek(pointer++);
214
uInt16 high = ((uInt16)peek(pointer) << 8);
215
peek(high | (uInt8)(low + Y));
216
operandAddress = (high | low) + Y;
219
define(M6502_INDIRECTY_READMODIFYWRITE, `{
220
uInt8 pointer = peek(PC++);
221
uInt16 low = peek(pointer++);
222
uInt16 high = ((uInt16)peek(pointer) << 8);
223
peek(high | (uInt8)(low + Y));
224
operandAddress = (high | low) + Y;
225
operand = peek(operandAddress);
226
poke(operandAddress, operand);
234
uInt16 address = PC + (Int8)operand;
235
if(NOTSAMEPAGE(PC, address))
236
peek((PC & 0xFF00) | (address & 0x00FF));
245
uInt16 address = PC + (Int8)operand;
246
if(NOTSAMEPAGE(PC, address))
247
peek((PC & 0xFF00) | (address & 0x00FF));
256
uInt16 address = PC + (Int8)operand;
257
if(NOTSAMEPAGE(PC, address))
258
peek((PC & 0xFF00) | (address & 0x00FF));
267
uInt16 address = PC + (Int8)operand;
268
if(NOTSAMEPAGE(PC, address))
269
peek((PC & 0xFF00) | (address & 0x00FF));
278
uInt16 address = PC + (Int8)operand;
279
if(NOTSAMEPAGE(PC, address))
280
peek((PC & 0xFF00) | (address & 0x00FF));
289
uInt16 address = PC + (Int8)operand;
290
if(NOTSAMEPAGE(PC, address))
291
peek((PC & 0xFF00) | (address & 0x00FF));
300
uInt16 address = PC + (Int8)operand;
301
if(NOTSAMEPAGE(PC, address))
302
peek((PC & 0xFF00) | (address & 0x00FF));
311
uInt16 address = PC + (Int8)operand;
312
if(NOTSAMEPAGE(PC, address))
313
peek((PC & 0xFF00) | (address & 0x00FF));
321
Int32 sum = A + operand + (C ? 1 : 0);
323
V = ~(A ^ operand) & (A ^ sum) & 0x80;
331
Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0);
332
Int32 hi = (A & 0xf0) + (operand & 0xf0);
333
notZ = (lo+hi) & 0xff;
340
V = ~(A ^ operand) & (A ^ hi) & 0x80;
345
A = (lo & 0x0f) + (hi & 0xf0);
363
// NOTE: The implementation of this instruction is based on
364
// information from the 64doc.txt file. This instruction is
365
// reported to be unstable!
366
A = (A | 0xee) & X & operand;
372
// NOTE: The implementation of this instruction is based on
373
// information from the 64doc.txt file. There are mixed
374
// reports on its operation!
378
A = ((A >> 1) & 0x7f) | (C ? 0x80 : 0x00);
381
V = (A & 0x40) ^ ((A & 0x20) << 1);
388
uInt8 value = A & operand;
390
A = ((value >> 1) & 0x7f) | (C ? 0x80 : 0x00);
393
V = (value ^ A) & 0x40;
395
if(((value & 0x0f) + (value & 0x01)) > 0x05)
397
A = (A & 0xf0) | ((A + 0x06) & 0x0f);
400
if(((value & 0xf0) + (value & 0x10)) > 0x50)
402
A = (A + 0x60) & 0xff;
413
// Set carry flag according to the left-most bit in value
417
poke(operandAddress, operand);
423
define(M6502_ASLA, `{
424
// Set carry flag according to the left-most bit in A
436
// Set carry flag according to the right-most bit
446
notZ = (A & operand);
456
poke(0x0100 + SP--, PC >> 8);
457
poke(0x0100 + SP--, PC & 0x00ff);
458
poke(0x0100 + SP--, PS());
463
PC |= ((uInt16)peek(0xffff) << 8);
483
uInt16 value = (uInt16)A - (uInt16)operand;
487
C = !(value & 0x0100);
491
uInt16 value = (uInt16)X - (uInt16)operand;
495
C = !(value & 0x0100);
499
uInt16 value = (uInt16)Y - (uInt16)operand;
503
C = !(value & 0x0100);
507
uInt8 value = operand - 1;
508
poke(operandAddress, value);
510
uInt16 value2 = (uInt16)A - (uInt16)value;
513
C = !(value2 & 0x0100);
517
uInt8 value = operand - 1;
518
poke(operandAddress, value);
546
uInt8 value = operand + 1;
547
poke(operandAddress, value);
566
operand = operand + 1;
567
poke(operandAddress, operand);
569
// N, V, Z, C flags are the same in either mode (C calculated at the end)
570
Int32 sum = A - operand - (C ? 0 : 1);
572
V = (A ^ operand) & (A ^ sum) & 0x80;
581
Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1);
582
Int32 hi = (A & 0xf0) - (operand & 0xf0);
591
A = (lo & 0x0f) | (hi & 0xf0);
593
C = (sum & 0xff00) == 0;
601
uInt8 low = peek(PC++);
604
// It seems that the 650x does not push the address of the next instruction
605
// on the stack it actually pushes the address of the next instruction
606
// minus one. This is compensated for in the RTS instruction
607
poke(0x0100 + SP--, PC >> 8);
608
poke(0x0100 + SP--, PC & 0xff);
610
PC = low | ((uInt16)peek(PC++) << 8);
614
A = X = SP = SP & operand;
645
// Set carry flag according to the right-most bit in value
648
operand = (operand >> 1) & 0x7f;
649
poke(operandAddress, operand);
655
define(M6502_LSRA, `{
656
// Set carry flag according to the right-most bit
666
// NOTE: The implementation of this instruction is based on
667
// information from the 64doc.txt file. This instruction is
668
// reported to be very unstable!
669
A = X = (A | 0xee) & operand;
684
poke(0x0100 + SP--, A);
688
poke(0x0100 + SP--, PS());
693
A = peek(0x0100 + SP);
700
PS(peek(0x0100 + SP));
704
uInt8 value = (operand << 1) | (C ? 1 : 0);
705
poke(operandAddress, value);
716
// Set carry flag according to the left-most bit in operand
719
operand = (operand << 1) | (oldC ? 1 : 0);
720
poke(operandAddress, operand);
726
define(M6502_ROLA, `{
729
// Set carry flag according to the left-most bit
732
A = (A << 1) | (oldC ? 1 : 0);
741
// Set carry flag according to the right-most bit
744
operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00);
745
poke(operandAddress, operand);
751
define(M6502_RORA, `{
754
// Set carry flag according to the right-most bit
757
A = ((A >> 1) & 0x7f) | (oldC ? 0x80 : 0x00);
766
// Set carry flag according to the right-most bit
769
operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00);
770
poke(operandAddress, operand);
774
Int32 sum = A + operand + (C ? 1 : 0);
776
V = ~(A ^ operand) & (A ^ sum) & 0x80;
784
Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0);
785
Int32 hi = (A & 0xf0) + (operand & 0xf0);
786
notZ = (lo+hi) & 0xff;
793
V = ~(A ^ operand) & (A ^ hi) & 0x80;
798
A = (lo & 0x0f) + (hi & 0xf0);
804
PS(peek(0x0100 + SP++));
805
PC = peek(0x0100 + SP++);
806
PC |= ((uInt16)peek(0x0100 + SP) << 8);
811
PC = peek(0x0100 + SP++);
812
PC |= ((uInt16)peek(0x0100 + SP) << 8);
817
poke(operandAddress, A & X);
821
// N, V, Z, C flags are the same in either mode (C calculated at the end)
822
Int32 sum = A - operand - (C ? 0 : 1);
824
V = (A ^ operand) & (A ^ sum) & 0x80;
833
Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1);
834
Int32 hi = (A & 0xf0) - (operand & 0xf0);
843
A = (lo & 0x0f) | (hi & 0xf0);
845
C = (sum & 0xff00) == 0;
849
uInt16 value = (uInt16)(X & A) - (uInt16)operand;
854
C = !(value & 0x0100);
870
// NOTE: There are mixed reports on the actual operation
871
// of this instruction!
872
poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1));
876
// NOTE: There are mixed reports on the actual operation
877
// of this instruction!
879
poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1));
883
// NOTE: There are mixed reports on the actual operation
884
// of this instruction!
885
poke(operandAddress, X & (((operandAddress >> 8) & 0xff) + 1));
889
// NOTE: There are mixed reports on the actual operation
890
// of this instruction!
891
poke(operandAddress, Y & (((operandAddress >> 8) & 0xff) + 1));
895
// Set carry flag according to the left-most bit in value
899
poke(operandAddress, operand);
907
// Set carry flag according to the right-most bit in value
910
operand = (operand >> 1) & 0x7f;
911
poke(operandAddress, operand);
919
poke(operandAddress, A);
923
poke(operandAddress, X);
927
poke(operandAddress, Y);
1001
M6502_INDIRECTY_READ
1007
M6502_IMMEDIATE_READ
1014
M6502_IMMEDIATE_READ
1020
M6502_IMMEDIATE_READ
1040
M6502_ABSOLUTEX_READ
1045
M6502_ABSOLUTEY_READ
1050
M6502_INDIRECTX_READ
1055
M6502_INDIRECTY_READ
1061
M6502_IMMEDIATE_READ
1067
M6502_IMMEDIATE_READ
1078
M6502_ZERO_READMODIFYWRITE
1083
M6502_ZEROX_READMODIFYWRITE
1088
M6502_ABSOLUTE_READMODIFYWRITE
1093
M6502_ABSOLUTEX_READMODIFYWRITE
1099
M6502_IMMEDIATE_READ
1105
M6502_IMMEDIATE_READ
1111
M6502_IMMEDIATE_READ
1128
M6502_IMMEDIATE_READ
1134
M6502_IMMEDIATE_READ
1140
M6502_IMMEDIATE_READ
1151
M6502_IMMEDIATE_READ
1157
M6502_IMMEDIATE_READ
1187
M6502_IMMEDIATE_READ
1207
M6502_ABSOLUTEX_READ
1212
M6502_ABSOLUTEY_READ
1217
M6502_INDIRECTX_READ
1222
M6502_INDIRECTY_READ
1228
M6502_IMMEDIATE_READ
1244
M6502_IMMEDIATE_READ
1260
M6502_ABSOLUTE_READMODIFYWRITE
1265
M6502_ABSOLUTEX_READMODIFYWRITE
1270
M6502_ABSOLUTEY_READMODIFYWRITE
1275
M6502_ZERO_READMODIFYWRITE
1280
M6502_ZEROX_READMODIFYWRITE
1285
M6502_INDIRECTX_READMODIFYWRITE
1290
M6502_INDIRECTY_READMODIFYWRITE
1296
M6502_ZERO_READMODIFYWRITE
1301
M6502_ZEROX_READMODIFYWRITE
1306
M6502_ABSOLUTE_READMODIFYWRITE
1311
M6502_ABSOLUTEX_READMODIFYWRITE
1329
M6502_IMMEDIATE_READ
1349
M6502_ABSOLUTEX_READ
1354
M6502_ABSOLUTEY_READ
1359
M6502_INDIRECTX_READ
1364
M6502_INDIRECTY_READ
1370
M6502_ZERO_READMODIFYWRITE
1375
M6502_ZEROX_READMODIFYWRITE
1380
M6502_ABSOLUTE_READMODIFYWRITE
1385
M6502_ABSOLUTEX_READMODIFYWRITE
1403
M6502_ABSOLUTE_READMODIFYWRITE
1408
M6502_ABSOLUTEX_READMODIFYWRITE
1413
M6502_ABSOLUTEY_READMODIFYWRITE
1418
M6502_ZERO_READMODIFYWRITE
1423
M6502_ZEROX_READMODIFYWRITE
1428
M6502_INDIRECTX_READMODIFYWRITE
1433
M6502_INDIRECTY_READMODIFYWRITE
1439
M6502_ABSOLUTE_WRITE
1455
M6502_ABSOLUTEY_READ
1466
M6502_ABSOLUTEY_READ
1481
M6502_INDIRECTX_READ
1486
M6502_INDIRECTY_READ
1492
M6502_IMMEDIATE_READ
1512
M6502_ABSOLUTEX_READ
1517
M6502_ABSOLUTEY_READ
1522
M6502_INDIRECTX_READ
1527
M6502_INDIRECTY_READ
1533
M6502_IMMEDIATE_READ
1553
M6502_ABSOLUTEY_READ
1559
M6502_IMMEDIATE_READ
1579
M6502_ABSOLUTEX_READ
1591
M6502_ZERO_READMODIFYWRITE
1596
M6502_ZEROX_READMODIFYWRITE
1601
M6502_ABSOLUTE_READMODIFYWRITE
1606
M6502_ABSOLUTEX_READMODIFYWRITE
1612
M6502_IMMEDIATE_READ
1633
M6502_IMMEDIATE_READ
1665
M6502_ABSOLUTEX_READ
1671
M6502_IMMEDIATE_READ
1691
M6502_ABSOLUTEX_READ
1696
M6502_ABSOLUTEY_READ
1701
M6502_INDIRECTX_READ
1706
M6502_INDIRECTY_READ
1736
M6502_ABSOLUTE_READMODIFYWRITE
1741
M6502_ABSOLUTEX_READMODIFYWRITE
1746
M6502_ABSOLUTEY_READMODIFYWRITE
1751
M6502_ZERO_READMODIFYWRITE
1756
M6502_ZEROX_READMODIFYWRITE
1761
M6502_INDIRECTX_READMODIFYWRITE
1766
M6502_INDIRECTY_READMODIFYWRITE
1778
M6502_ZERO_READMODIFYWRITE
1783
M6502_ZEROX_READMODIFYWRITE
1788
M6502_ABSOLUTE_READMODIFYWRITE
1793
M6502_ABSOLUTEX_READMODIFYWRITE
1804
M6502_ZERO_READMODIFYWRITE
1809
M6502_ZEROX_READMODIFYWRITE
1814
M6502_ABSOLUTE_READMODIFYWRITE
1819
M6502_ABSOLUTEX_READMODIFYWRITE
1825
M6502_ABSOLUTE_READMODIFYWRITE
1830
M6502_ABSOLUTEX_READMODIFYWRITE
1835
M6502_ABSOLUTEY_READMODIFYWRITE
1840
M6502_ZERO_READMODIFYWRITE
1845
M6502_ZEROX_READMODIFYWRITE
1850
M6502_INDIRECTX_READMODIFYWRITE
1855
M6502_INDIRECTY_READMODIFYWRITE
1873
M6502_ABSOLUTE_WRITE
1888
M6502_INDIRECTX_WRITE
1895
M6502_IMMEDIATE_READ
1915
M6502_ABSOLUTEX_READ
1920
M6502_ABSOLUTEY_READ
1925
M6502_INDIRECTX_READ
1930
M6502_INDIRECTY_READ
1936
M6502_IMMEDIATE_READ
1960
M6502_ABSOLUTEY_WRITE
1965
M6502_INDIRECTY_WRITE
1971
M6502_ABSOLUTEY_WRITE
1977
M6502_ABSOLUTEY_WRITE
1983
M6502_ABSOLUTEX_WRITE
1989
M6502_ABSOLUTE_READMODIFYWRITE
1994
M6502_ABSOLUTEX_READMODIFYWRITE
1999
M6502_ABSOLUTEY_READMODIFYWRITE
2004
M6502_ZERO_READMODIFYWRITE
2009
M6502_ZEROX_READMODIFYWRITE
2014
M6502_INDIRECTX_READMODIFYWRITE
2019
M6502_INDIRECTY_READMODIFYWRITE
2025
M6502_ABSOLUTE_READMODIFYWRITE
2030
M6502_ABSOLUTEX_READMODIFYWRITE
2035
M6502_ABSOLUTEY_READMODIFYWRITE
2040
M6502_ZERO_READMODIFYWRITE
2045
M6502_ZEROX_READMODIFYWRITE
2050
M6502_INDIRECTX_READMODIFYWRITE
2055
M6502_INDIRECTY_READMODIFYWRITE
2071
M6502_ABSOLUTE_WRITE
2076
M6502_ABSOLUTEX_WRITE
2081
M6502_ABSOLUTEY_WRITE
2086
M6502_INDIRECTX_WRITE
2091
M6502_INDIRECTY_WRITE
2107
M6502_ABSOLUTE_WRITE
2123
M6502_ABSOLUTE_WRITE