update the asap codec to version 2.1.2
[kugel-rb.git] / apps / codecs / libasap / acpu.c
blob0e91f9083aed25d279294dc871b779ac841d9b0e
1 /*
2 * acpu.c - another 6502 CPU emulator
4 * Copyright (C) 2007-2010 Piotr Fusik
6 * This file is part of ASAP (Another Slight Atari Player),
7 * see http://asap.sourceforge.net
9 * ASAP is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published
11 * by the Free Software Foundation; either version 2 of the License,
12 * or (at your option) any later version.
14 * ASAP is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty
16 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 * See the GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with ASAP; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 /* How 6502 registers are stored in this emulator:
25 All variables are int, because modern processors (and Java bytecode)
26 tend to operate more effectively on these type than narrower ones.
27 pc is really an unsigned 16-bit integer.
28 a, x, y and s are unsigned 8-bit integers.
29 Flags are decomposed into three variables for improved performance.
30 c is either 0 or 1.
31 nz contains 6502 flags N and Z.
32 N is set if (nz >= 0x80). Z is set if ((nz & 0xff) == 0).
33 Usually nz is simply assigned the unsigned 8-bit operation result.
34 There are just a few operations (ADC in decimal mode, BIT, PLP and RTI)
35 where both N and Z may be set. In these cases, N is reflected by the 8th
36 (not 7th) bit of nz.
37 vdi contains rarely used flags V, D and I, as a combination
38 of V_FLAG, D_FLAG and I_FLAG. Other vdi bits are clear.
40 "Unofficial" opcodes are not documented as "legal" 6502 opcodes.
41 Their operation has been reverse-engineered on Atari 800XL and Atari 65XE.
42 Unofficial opcodes are identical to C64's 6510, except for 0x8b and 0xab.
43 The operation of "unstable" opcodes is partially uncertain.
44 Explanation is welcome.
46 Emulation of POKEY timer interrupts is included.
48 Two preprocessor symbols may be used to strip the size of this emulator.
49 Define ACPU_NO_DECIMAL to disable emulation of the BCD mode.
50 Define ACPU_NO_UNOFFICIAL to disable emulation of unofficial opcodes. */
52 #include "asap_internal.h"
54 CONST_ARRAY(int, opcode_cycles)
55 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
56 7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6, /* 0x */
57 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 1x */
58 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6, /* 2x */
59 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 3x */
60 6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6, /* 4x */
61 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 5x */
62 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6, /* 6x */
63 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 7x */
64 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* 8x */
65 2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5, /* 9x */
66 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* Ax */
67 2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 4, 4, 4, 4, 4, /* Bx */
68 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* Cx */
69 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* Dx */
70 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* Ex */
71 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7 /* Fx */
72 END_CONST_ARRAY;
74 #ifdef ACPU_NO_DECIMAL
76 #define DO_ADC \
77 { \
78 /* binary mode */ \
79 V(int, tmp) = a + data + c; \
80 vdi = (vdi & (D_FLAG | I_FLAG)) + (((~(data ^ a) & (a ^ tmp)) >> 1) & V_FLAG); \
81 c = tmp >> 8; \
82 nz = a = tmp & 0xff; \
85 #define DO_SBC \
86 { \
87 /* binary mode */ \
88 V(int, tmp) = a - data - 1 + c; \
89 vdi = (vdi & (D_FLAG | I_FLAG)) + ((((data ^ a) & (a ^ tmp)) >> 1) & V_FLAG); \
90 c = (tmp >= 0) ? 1 : 0; \
91 nz = a = tmp & 0xff; \
94 #else /* ACPU_NO_DECIMAL */
96 #define DO_ADC \
97 { \
98 V(int, tmp) = a + data + c; \
99 nz = tmp & 0xff; \
100 if ((vdi & D_FLAG) == 0) { \
101 /* binary mode */ \
102 vdi = (vdi & (D_FLAG | I_FLAG)) + (((~(data ^ a) & (a ^ tmp)) >> 1) & V_FLAG); \
103 c = tmp >> 8; \
104 a = nz; \
106 else { \
107 /* decimal mode */ \
108 V(int, al) = (a & 0x0f) + (data & 0x0f) + c; \
109 if (al >= 10) \
110 tmp += (al < 26) ? 6 : -10; \
111 nz = ((tmp & 0x80) << 1) + (nz != 0 ? 1 : 0); \
112 vdi = (vdi & (D_FLAG | I_FLAG)) + (((~(data ^ a) & (a ^ tmp)) >> 1) & V_FLAG); \
113 if (tmp >= 0xa0) { \
114 c = 1; \
115 a = (tmp + 0x60) & 0xff; \
117 else { \
118 c = 0; \
119 a = tmp; \
124 #define DO_SBC \
126 V(int, tmp) = a - data - 1 + c; \
127 V(int, al) = (a & 0x0f) - (data & 0x0f) - 1 + c; \
128 vdi = (vdi & (D_FLAG | I_FLAG)) + ((((data ^ a) & (a ^ tmp)) >> 1) & V_FLAG); \
129 c = (tmp >= 0) ? 1 : 0; \
130 nz = a = tmp & 0xff; \
131 if ((vdi & D_FLAG) != 0) { \
132 /* decimal mode */ \
133 if (al < 0) \
134 a += (al < -10) ? 10 : -6; \
135 if (c == 0) \
136 a = (a - 0x60) & 0xff; \
140 #endif /* ACPU_NO_DECIMAL */
142 #define zGetByte(addr) dGetByte((addr) & 0xff)
144 #define PEEK dGetByte(pc)
145 #define FETCH dGetByte(pc++)
147 #define ABSOLUTE addr = FETCH; addr += FETCH << 8
148 #define ABSOLUTE_X addr = FETCH; addr = (addr + (FETCH << 8) + x) & 0xffff
149 #define ABSOLUTE_Y addr = FETCH; addr = (addr + (FETCH << 8) + y) & 0xffff
150 #define ZPAGE addr = FETCH
151 #define ZPAGE_X addr = (FETCH + x) & 0xff
152 #define ZPAGE_Y addr = (FETCH + y) & 0xff
153 #define INDIRECT_X addr = (FETCH + x) & 0xff; addr = dGetByte(addr) + (zGetByte(addr + 1) << 8)
154 #define INDIRECT_Y addr = FETCH; addr = (dGetByte(addr) + (zGetByte(addr + 1) << 8) + y) & 0xffff
155 #define NCYCLES_X if ((addr & 0xff) < x) ast _ cycle++
156 #define NCYCLES_Y if ((addr & 0xff) < y) ast _ cycle++
158 #define PL(dest) s = (s + 1) & 0xff; dest = dGetByte(0x0100 + s)
159 #define PLP PL(vdi); nz = ((vdi & 0x80) << 1) + (~vdi & Z_FLAG); c = vdi & 1; vdi &= V_FLAG | D_FLAG | I_FLAG
160 #define PH(data) dPutByte(0x0100 + s, data); s = (s - 1) & 0xff
161 #define PHW(data) PH((data) >> 8); PH(TO_BYTE(data))
162 #define PHP(bflag) PH(((nz | (nz >> 1)) & 0x80) + vdi + ((nz & 0xff) == 0 ? Z_FLAG : 0) + c + bflag)
163 #define PHPB0 PHP(0x20) /* push flags with B flag clear (NMI, IRQ) */
164 #define PHPB1 PHP(0x30) /* push flags with B flag set (PHP, BRK) */
165 #define PHPC PHW(pc)
167 #define LDA nz = a = GetByte(addr)
168 #define LDA_ZP nz = a = dGetByte(addr)
169 #define LDX nz = x = GetByte(addr)
170 #define LDX_ZP nz = x = dGetByte(addr)
171 #define LDY nz = y = GetByte(addr)
172 #define LDY_ZP nz = y = dGetByte(addr)
173 #define LAX nz = x = a = GetByte(addr)
174 #define LAX_ZP nz = x = a = dGetByte(addr)
175 #define STA PutByte(addr, a)
176 #define STA_ZP dPutByte(addr, a)
177 #define STX PutByte(addr, x)
178 #define STX_ZP dPutByte(addr, x)
179 #define STY PutByte(addr, y)
180 #define STY_ZP dPutByte(addr, y)
181 #define SAX data = a & x; PutByte(addr, data)
182 #define SAX_ZP data = a & x; dPutByte(addr, data)
183 #define CMP nz = GetByte(addr); c = (a >= nz) ? 1 : 0; nz = (a - nz) & 0xff
184 #define CMP_ZP nz = dGetByte(addr); c = (a >= nz) ? 1 : 0; nz = (a - nz) & 0xff
185 #define CPX nz = GetByte(addr); c = (x >= nz) ? 1 : 0; nz = (x - nz) & 0xff
186 #define CPX_ZP nz = dGetByte(addr); c = (x >= nz) ? 1 : 0; nz = (x - nz) & 0xff
187 #define CPY nz = GetByte(addr); c = (y >= nz) ? 1 : 0; nz = (y - nz) & 0xff
188 #define CPY_ZP nz = dGetByte(addr); c = (y >= nz) ? 1 : 0; nz = (y - nz) & 0xff
189 #define AND nz = a &= GetByte(addr)
190 #define AND_ZP nz = a &= dGetByte(addr)
191 #define ORA nz = a |= GetByte(addr)
192 #define ORA_ZP nz = a |= dGetByte(addr)
193 #define EOR nz = a ^= GetByte(addr)
194 #define EOR_ZP nz = a ^= dGetByte(addr)
195 #define ADC data = GetByte(addr); DO_ADC
196 #define ADC_ZP data = dGetByte(addr); DO_ADC
197 #define SBC data = GetByte(addr); DO_SBC
198 #define SBC_ZP data = dGetByte(addr); DO_SBC
200 #define ASL RMW_GetByte(nz, addr); c = nz >> 7; nz = (nz << 1) & 0xff; PutByte(addr, nz)
201 #define ASL_ZP nz = dGetByte(addr); c = nz >> 7; nz = (nz << 1) & 0xff; dPutByte(addr, nz)
202 #define ROL RMW_GetByte(nz, addr); nz = (nz << 1) + c; c = nz >> 8; nz &= 0xff; PutByte(addr, nz)
203 #define ROL_ZP nz = dGetByte(addr); nz = (nz << 1) + c; c = nz >> 8; nz &= 0xff; dPutByte(addr, nz)
204 #define LSR RMW_GetByte(nz, addr); c = nz & 1; nz >>= 1; PutByte(addr, nz)
205 #define LSR_ZP nz = dGetByte(addr); c = nz & 1; nz >>= 1; dPutByte(addr, nz)
206 #define ROR RMW_GetByte(nz, addr); nz += c << 8; c = nz & 1; nz >>= 1; PutByte(addr, nz)
207 #define ROR_ZP nz = dGetByte(addr) + (c << 8); c = nz & 1; nz >>= 1; dPutByte(addr, nz)
208 #define DEC RMW_GetByte(nz, addr); nz = (nz - 1) & 0xff; PutByte(addr, nz)
209 #define DEC_ZP nz = dGetByte(addr); nz = (nz - 1) & 0xff; dPutByte(addr, nz)
210 #define INC RMW_GetByte(nz, addr); nz = (nz + 1) & 0xff; PutByte(addr, nz)
211 #define INC_ZP nz = dGetByte(addr); nz = (nz + 1) & 0xff; dPutByte(addr, nz)
213 #define ASO ASL; nz = a |= nz
214 #define ASO_ZP ASL_ZP; nz = a |= nz
215 #define RLA ROL; nz = a &= nz
216 #define RLA_ZP ROL_ZP; nz = a &= nz
217 #define LSE LSR; nz = a ^= nz
218 #define LSE_ZP LSR_ZP; nz = a ^= nz
219 #define RRA ROR; data = nz; DO_ADC
220 #define RRA_ZP ROR_ZP; data = nz; DO_ADC
221 #define DCM DEC; c = (a >= nz) ? 1 : 0; nz = (a - nz) & 0xff
222 #define DCM_ZP DEC_ZP; c = (a >= nz) ? 1 : 0; nz = (a - nz) & 0xff
223 #define INS INC; data = nz; DO_SBC
224 #define INS_ZP INC_ZP; data = nz; DO_SBC
226 #define BRANCH(cond) \
227 if (cond) { \
228 addr = SBYTE(PEEK); \
229 pc++; \
230 addr += pc; \
231 if ((addr ^ pc) >> 8 != 0) \
232 ast _ cycle++; \
233 ast _ cycle++; \
234 pc = addr; \
235 break; \
237 pc++; \
238 break
240 #define CHECK_IRQ \
241 if ((vdi & I_FLAG) == 0 && ast _ irqst != 0xff) { \
242 PHPC; \
243 PHPB0; \
244 vdi |= I_FLAG; \
245 pc = dGetWord(0xfffe); \
246 ast _ cycle += 7; \
249 /* Runs 6502 emulation for the specified number of Atari scanlines.
250 Each scanline is 114 cycles of which 9 is taken by ANTIC for memory refresh. */
251 FUNC(void, Cpu_RunScanlines, (P(ASAP_State PTR, ast), P(int, scanlines)))
253 /* copy registers from ASAP_State to local variables for improved performance */
254 V(int, pc);
255 V(int, nz);
256 V(int, a);
257 V(int, x);
258 V(int, y);
259 V(int, c);
260 V(int, s);
261 V(int, vdi);
262 V(int, next_event_cycle);
263 V(int, cycle_limit);
264 pc = ast _ cpu_pc;
265 nz = ast _ cpu_nz;
266 a = ast _ cpu_a;
267 x = ast _ cpu_x;
268 y = ast _ cpu_y;
269 c = ast _ cpu_c;
270 s = ast _ cpu_s;
271 vdi = ast _ cpu_vdi;
272 ast _ next_scanline_cycle = 114;
273 next_event_cycle = 114;
274 cycle_limit = 114 * scanlines;
275 if (next_event_cycle > ast _ timer1_cycle)
276 next_event_cycle = ast _ timer1_cycle;
277 if (next_event_cycle > ast _ timer2_cycle)
278 next_event_cycle = ast _ timer2_cycle;
279 if (next_event_cycle > ast _ timer4_cycle)
280 next_event_cycle = ast _ timer4_cycle;
281 ast _ nearest_event_cycle = next_event_cycle;
282 for (;;) {
283 V(int, cycle);
284 V(int, addr);
285 V(int, data);
286 cycle = ast _ cycle;
287 if (cycle >= ast _ nearest_event_cycle) {
288 if (cycle >= ast _ next_scanline_cycle) {
289 if (++ast _ scanline_number == (ast _ module_info.ntsc ? 262 : 312))
290 ast _ scanline_number = 0;
291 ast _ cycle = cycle += 9;
292 ast _ next_scanline_cycle += 114;
293 if (--scanlines <= 0)
294 break;
296 next_event_cycle = ast _ next_scanline_cycle;
297 #define CHECK_TIMER_IRQ(ch) \
298 if (cycle >= ast _ timer##ch##_cycle) { \
299 ast _ irqst &= ~ch; \
300 ast _ timer##ch##_cycle = NEVER; \
302 else if (next_event_cycle > ast _ timer##ch##_cycle) \
303 next_event_cycle = ast _ timer##ch##_cycle;
304 CHECK_TIMER_IRQ(1);
305 CHECK_TIMER_IRQ(2);
306 CHECK_TIMER_IRQ(4);
307 ast _ nearest_event_cycle = next_event_cycle;
308 CHECK_IRQ;
310 #ifdef ASAPSCAN
311 if (cpu_trace != 0)
312 trace_cpu(ast, pc, a, x, y, s, nz, vdi, c);
313 #endif
314 data = FETCH;
315 ast _ cycle += opcode_cycles[data];
316 switch (data) {
317 case 0x00: /* BRK */
318 pc++;
319 PHPC;
320 PHPB1;
321 vdi |= I_FLAG;
322 pc = dGetWord(0xfffe);
323 break;
324 case 0x01: /* ORA (ab,x) */
325 INDIRECT_X;
326 ORA;
327 break;
328 case 0x02: /* CIM [unofficial] */
329 case 0x12:
330 case 0x22:
331 case 0x32:
332 case 0x42:
333 case 0x52:
334 case 0x62:
335 case 0x72:
336 case 0x92:
337 case 0xb2:
338 case 0xd2:
339 case 0xf2:
340 ast _ scanline_number = (ast _ scanline_number + scanlines - 1) % (ast _ module_info.ntsc ? 262 : 312);
341 scanlines = 1;
342 ast _ cycle = cycle_limit;
343 break;
344 #ifndef ACPU_NO_UNOFFICIAL
345 case 0x03: /* ASO (ab,x) [unofficial] */
346 INDIRECT_X;
347 ASO;
348 break;
349 case 0x04: /* NOP ab [unofficial] */
350 case 0x44:
351 case 0x64:
352 case 0x14: /* NOP ab,x [unofficial] */
353 case 0x34:
354 case 0x54:
355 case 0x74:
356 case 0xd4:
357 case 0xf4:
358 case 0x80: /* NOP #ab [unofficial] */
359 case 0x82:
360 case 0x89:
361 case 0xc2:
362 case 0xe2:
363 pc++;
364 break;
365 case 0x07: /* ASO ab [unofficial] */
366 ZPAGE;
367 ASO_ZP;
368 break;
369 case 0x0b: /* ANC #ab [unofficial] */
370 case 0x2b:
371 nz = a &= FETCH;
372 c = nz >> 7;
373 break;
374 case 0x0c: /* NOP abcd [unofficial] */
375 pc += 2;
376 break;
377 case 0x0f: /* ASO abcd [unofficial] */
378 ABSOLUTE;
379 ASO;
380 break;
381 case 0x13: /* ASO (ab),y [unofficial] */
382 INDIRECT_Y;
383 ASO;
384 break;
385 case 0x17: /* ASO ab,x [unofficial] */
386 ZPAGE_X;
387 ASO_ZP;
388 break;
389 case 0x1b: /* ASO abcd,y [unofficial] */
390 ABSOLUTE_Y;
391 ASO;
392 break;
393 case 0x1c: /* NOP abcd,x [unofficial] */
394 case 0x3c:
395 case 0x5c:
396 case 0x7c:
397 case 0xdc:
398 case 0xfc:
399 if (FETCH + x >= 0x100)
400 ast _ cycle++;
401 pc++;
402 break;
403 case 0x1f: /* ASO abcd,x [unofficial] */
404 ABSOLUTE_X;
405 ASO;
406 break;
407 case 0x23: /* RLA (ab,x) [unofficial] */
408 INDIRECT_X;
409 RLA;
410 break;
411 case 0x27: /* RLA ab [unofficial] */
412 ZPAGE;
413 RLA_ZP;
414 break;
415 case 0x2f: /* RLA abcd [unofficial] */
416 ABSOLUTE;
417 RLA;
418 break;
419 case 0x33: /* RLA (ab),y [unofficial] */
420 INDIRECT_Y;
421 RLA;
422 break;
423 case 0x37: /* RLA ab,x [unofficial] */
424 ZPAGE_X;
425 RLA_ZP;
426 break;
427 case 0x3b: /* RLA abcd,y [unofficial] */
428 ABSOLUTE_Y;
429 RLA;
430 break;
431 case 0x3f: /* RLA abcd,x [unofficial] */
432 ABSOLUTE_X;
433 RLA;
434 break;
435 case 0x43: /* LSE (ab,x) [unofficial] */
436 INDIRECT_X;
437 LSE;
438 break;
439 case 0x47: /* LSE ab [unofficial] */
440 ZPAGE;
441 LSE_ZP;
442 break;
443 case 0x4b: /* ALR #ab [unofficial] */
444 a &= FETCH;
445 c = a & 1;
446 nz = a >>= 1;
447 break;
448 case 0x4f: /* LSE abcd [unofficial] */
449 ABSOLUTE;
450 LSE;
451 break;
452 case 0x53: /* LSE (ab),y [unofficial] */
453 INDIRECT_Y;
454 LSE;
455 break;
456 case 0x57: /* LSE ab,x [unofficial] */
457 ZPAGE_X;
458 LSE_ZP;
459 break;
460 case 0x5b: /* LSE abcd,y [unofficial] */
461 ABSOLUTE_Y;
462 LSE;
463 break;
464 case 0x5f: /* LSE abcd,x [unofficial] */
465 ABSOLUTE_X;
466 LSE;
467 break;
468 case 0x63: /* RRA (ab,x) [unofficial] */
469 INDIRECT_X;
470 RRA;
471 break;
472 case 0x67: /* RRA ab [unofficial] */
473 ZPAGE;
474 RRA_ZP;
475 break;
476 case 0x6b: /* ARR #ab [unofficial] */
477 data = a & FETCH;
478 nz = a = (data >> 1) + (c << 7);
479 vdi = (vdi & (D_FLAG | I_FLAG)) + ((a ^ data) & V_FLAG);
480 #ifdef ACPU_NO_DECIMAL
481 c = data >> 7;
482 #else
483 if ((vdi & D_FLAG) == 0)
484 c = data >> 7;
485 else {
486 if ((data & 0xf) >= 5)
487 a = (a & 0xf0) + ((a + 6) & 0xf);
488 if (data >= 0x50) {
489 a = (a + 0x60) & 0xff;
490 c = 1;
492 else
493 c = 0;
495 #endif
496 break;
497 case 0x6f: /* RRA abcd [unofficial] */
498 ABSOLUTE;
499 RRA;
500 break;
501 case 0x73: /* RRA (ab),y [unofficial] */
502 INDIRECT_Y;
503 RRA;
504 break;
505 case 0x77: /* RRA ab,x [unofficial] */
506 ZPAGE_X;
507 RRA_ZP;
508 break;
509 case 0x7b: /* RRA abcd,y [unofficial] */
510 ABSOLUTE_Y;
511 RRA;
512 break;
513 case 0x7f: /* RRA abcd,x [unofficial] */
514 ABSOLUTE_X;
515 RRA;
516 break;
517 case 0x83: /* SAX (ab,x) [unofficial] */
518 INDIRECT_X;
519 SAX;
520 break;
521 case 0x87: /* SAX ab [unofficial] */
522 ZPAGE;
523 SAX_ZP;
524 break;
525 case 0x8b: /* ANE #ab [unofficial] */
526 data = FETCH;
527 a &= x;
528 nz = a & data;
529 a &= data | 0xef;
530 break;
531 case 0x8f: /* SAX abcd [unofficial] */
532 ABSOLUTE;
533 SAX;
534 break;
535 case 0x93: /* SHA (ab),y [unofficial, unstable] */
536 ZPAGE;
537 data = zGetByte(addr + 1);
538 addr = (dGetByte(addr) + (data << 8) + y) & 0xffff;
539 data = a & x & (data + 1);
540 PutByte(addr, data);
541 break;
542 case 0x97: /* SAX ab,y [unofficial] */
543 ZPAGE_Y;
544 SAX_ZP;
545 break;
546 case 0x9b: /* SHS abcd,y [unofficial, unstable] */
547 /* S seems to be stable, only memory values vary */
548 addr = FETCH;
549 data = FETCH;
550 addr = (addr + (data << 8) + y) & 0xffff;
551 s = a & x;
552 data = s & (data + 1);
553 PutByte(addr, data);
554 break;
555 case 0x9c: /* SHY abcd,x [unofficial] */
556 addr = FETCH;
557 data = FETCH;
558 addr = (addr + (data << 8) + x) & 0xffff;
559 data = y & (data + 1);
560 PutByte(addr, data);
561 break;
562 case 0x9e: /* SHX abcd,y [unofficial] */
563 addr = FETCH;
564 data = FETCH;
565 addr = (addr + (data << 8) + y) & 0xffff;
566 data = x & (data + 1);
567 PutByte(addr, data);
568 break;
569 case 0x9f: /* SHA abcd,y [unofficial, unstable] */
570 addr = FETCH;
571 data = FETCH;
572 addr = (addr + (data << 8) + y) & 0xffff;
573 data = a & x & (data + 1);
574 PutByte(addr, data);
575 break;
576 case 0xa3: /* LAX (ab,x) [unofficial] */
577 INDIRECT_X;
578 LAX;
579 break;
580 case 0xa7: /* LAX ab [unofficial] */
581 ZPAGE;
582 LAX_ZP;
583 break;
584 case 0xab: /* ANX #ab [unofficial] */
585 nz = x = a &= FETCH;
586 break;
587 case 0xaf: /* LAX abcd [unofficial] */
588 ABSOLUTE;
589 LAX;
590 break;
591 case 0xb3: /* LAX (ab),y [unofficial] */
592 INDIRECT_Y;
593 NCYCLES_Y;
594 LAX;
595 break;
596 case 0xb7: /* LAX ab,y [unofficial] */
597 ZPAGE_Y;
598 LAX_ZP;
599 break;
600 case 0xbb: /* LAS abcd,y [unofficial] */
601 ABSOLUTE_Y;
602 NCYCLES_Y;
603 nz = x = a = s &= GetByte(addr);
604 break;
605 case 0xbf: /* LAX abcd,y [unofficial] */
606 ABSOLUTE_Y;
607 NCYCLES_Y;
608 LAX;
609 break;
610 case 0xc3: /* DCM (ab,x) [unofficial] */
611 INDIRECT_X;
612 DCM;
613 break;
614 case 0xc7: /* DCM ab [unofficial] */
615 ZPAGE;
616 DCM_ZP;
617 break;
618 case 0xcb: /* SBX #ab [unofficial] */
619 nz = FETCH;
620 x &= a;
621 c = (x >= nz) ? 1 : 0;
622 nz = x = (x - nz) & 0xff;
623 break;
624 case 0xcf: /* DCM abcd [unofficial] */
625 ABSOLUTE;
626 DCM;
627 break;
628 case 0xd3: /* DCM (ab),y [unofficial] */
629 INDIRECT_Y;
630 DCM;
631 break;
632 case 0xd7: /* DCM ab,x [unofficial] */
633 ZPAGE_X;
634 DCM_ZP;
635 break;
636 case 0xdb: /* DCM abcd,y [unofficial] */
637 ABSOLUTE_Y;
638 DCM;
639 break;
640 case 0xdf: /* DCM abcd,x [unofficial] */
641 ABSOLUTE_X;
642 DCM;
643 break;
644 case 0xe3: /* INS (ab,x) [unofficial] */
645 INDIRECT_X;
646 INS;
647 break;
648 case 0xe7: /* INS ab [unofficial] */
649 ZPAGE;
650 INS_ZP;
651 break;
652 case 0xef: /* INS abcd [unofficial] */
653 ABSOLUTE;
654 INS;
655 break;
656 case 0xf3: /* INS (ab),y [unofficial] */
657 INDIRECT_Y;
658 INS;
659 break;
660 case 0xf7: /* INS ab,x [unofficial] */
661 ZPAGE_X;
662 INS_ZP;
663 break;
664 case 0xfb: /* INS abcd,y [unofficial] */
665 ABSOLUTE_Y;
666 INS;
667 break;
668 case 0xff: /* INS abcd,x [unofficial] */
669 ABSOLUTE_X;
670 INS;
671 break;
672 #endif /* ACPU_NO_UNOFFICIAL */
673 case 0x05: /* ORA ab */
674 ZPAGE;
675 ORA_ZP;
676 break;
677 case 0x06: /* ASL ab */
678 ZPAGE;
679 ASL_ZP;
680 break;
681 case 0x08: /* PHP */
682 PHPB1;
683 break;
684 case 0x09: /* ORA #ab */
685 nz = a |= FETCH;
686 break;
687 case 0x0a: /* ASL */
688 c = a >> 7;
689 nz = a = (a << 1) & 0xff;
690 break;
691 case 0x0d: /* ORA abcd */
692 ABSOLUTE;
693 ORA;
694 break;
695 case 0x0e: /* ASL abcd */
696 ABSOLUTE;
697 ASL;
698 break;
699 case 0x10: /* BPL */
700 BRANCH(nz < 0x80);
701 case 0x11: /* ORA (ab),y */
702 INDIRECT_Y;
703 NCYCLES_Y;
704 ORA;
705 break;
706 case 0x15: /* ORA ab,x */
707 ZPAGE_X;
708 ORA_ZP;
709 break;
710 case 0x16: /* ASL ab,x */
711 ZPAGE_X;
712 ASL_ZP;
713 break;
714 case 0x18: /* CLC */
715 c = 0;
716 break;
717 case 0x19: /* ORA abcd,y */
718 ABSOLUTE_Y;
719 NCYCLES_Y;
720 ORA;
721 break;
722 case 0x1d: /* ORA abcd,x */
723 ABSOLUTE_X;
724 NCYCLES_X;
725 ORA;
726 break;
727 case 0x1e: /* ASL abcd,x */
728 ABSOLUTE_X;
729 ASL;
730 break;
731 case 0x20: /* JSR abcd */
732 addr = FETCH;
733 PHPC;
734 pc = addr + (PEEK << 8);
735 break;
736 case 0x21: /* AND (ab,x) */
737 INDIRECT_X;
738 AND;
739 break;
740 case 0x24: /* BIT ab */
741 ZPAGE;
742 nz = dGetByte(addr);
743 vdi = (vdi & (D_FLAG | I_FLAG)) + (nz & V_FLAG);
744 nz = ((nz & 0x80) << 1) + (nz & a);
745 break;
746 case 0x25: /* AND ab */
747 ZPAGE;
748 AND_ZP;
749 break;
750 case 0x26: /* ROL ab */
751 ZPAGE;
752 ROL_ZP;
753 break;
754 case 0x28: /* PLP */
755 PLP;
756 CHECK_IRQ;
757 break;
758 case 0x29: /* AND #ab */
759 nz = a &= FETCH;
760 break;
761 case 0x2a: /* ROL */
762 a = (a << 1) + c;
763 c = a >> 8;
764 nz = a &= 0xff;
765 break;
766 case 0x2c: /* BIT abcd */
767 ABSOLUTE;
768 nz = GetByte(addr);
769 vdi = (vdi & (D_FLAG | I_FLAG)) + (nz & V_FLAG);
770 nz = ((nz & 0x80) << 1) + (nz & a);
771 break;
772 case 0x2d: /* AND abcd */
773 ABSOLUTE;
774 AND;
775 break;
776 case 0x2e: /* ROL abcd */
777 ABSOLUTE;
778 ROL;
779 break;
780 case 0x30: /* BMI */
781 BRANCH(nz >= 0x80);
782 case 0x31: /* AND (ab),y */
783 INDIRECT_Y;
784 NCYCLES_Y;
785 AND;
786 break;
787 case 0x35: /* AND ab,x */
788 ZPAGE_X;
789 AND_ZP;
790 break;
791 case 0x36: /* ROL ab,x */
792 ZPAGE_X;
793 ROL_ZP;
794 break;
795 case 0x38: /* SEC */
796 c = 1;
797 break;
798 case 0x39: /* AND abcd,y */
799 ABSOLUTE_Y;
800 NCYCLES_Y;
801 AND;
802 break;
803 case 0x3d: /* AND abcd,x */
804 ABSOLUTE_X;
805 NCYCLES_X;
806 AND;
807 break;
808 case 0x3e: /* ROL abcd,x */
809 ABSOLUTE_X;
810 ROL;
811 break;
812 case 0x40: /* RTI */
813 PLP;
814 PL(pc);
815 PL(addr);
816 pc += addr << 8;
817 CHECK_IRQ;
818 break;
819 case 0x41: /* EOR (ab,x) */
820 INDIRECT_X;
821 EOR;
822 break;
823 case 0x45: /* EOR ab */
824 ZPAGE;
825 EOR_ZP;
826 break;
827 case 0x46: /* LSR ab */
828 ZPAGE;
829 LSR_ZP;
830 break;
831 case 0x48: /* PHA */
832 PH(a);
833 break;
834 case 0x49: /* EOR #ab */
835 nz = a ^= FETCH;
836 break;
837 case 0x4a: /* LSR */
838 c = a & 1;
839 nz = a >>= 1;
840 break;
841 case 0x4c: /* JMP abcd */
842 addr = FETCH;
843 pc = addr + (PEEK << 8);
844 break;
845 case 0x4d: /* EOR abcd */
846 ABSOLUTE;
847 EOR;
848 break;
849 case 0x4e: /* LSR abcd */
850 ABSOLUTE;
851 LSR;
852 break;
853 case 0x50: /* BVC */
854 BRANCH((vdi & V_FLAG) == 0);
855 case 0x51: /* EOR (ab),y */
856 INDIRECT_Y;
857 NCYCLES_Y;
858 EOR;
859 break;
860 case 0x55: /* EOR ab,x */
861 ZPAGE_X;
862 EOR_ZP;
863 break;
864 case 0x56: /* LSR ab,x */
865 ZPAGE_X;
866 LSR_ZP;
867 break;
868 case 0x58: /* CLI */
869 vdi &= V_FLAG | D_FLAG;
870 CHECK_IRQ;
871 break;
872 case 0x59: /* EOR abcd,y */
873 ABSOLUTE_Y;
874 NCYCLES_Y;
875 EOR;
876 break;
877 case 0x5d: /* EOR abcd,x */
878 ABSOLUTE_X;
879 NCYCLES_X;
880 EOR;
881 break;
882 case 0x5e: /* LSR abcd,x */
883 ABSOLUTE_X;
884 LSR;
885 break;
886 case 0x60: /* RTS */
887 PL(pc);
888 PL(addr);
889 pc += (addr << 8) + 1;
890 break;
891 case 0x61: /* ADC (ab,x) */
892 INDIRECT_X;
893 ADC;
894 break;
895 case 0x65: /* ADC ab */
896 ZPAGE;
897 ADC_ZP;
898 break;
899 case 0x66: /* ROR ab */
900 ZPAGE;
901 ROR_ZP;
902 break;
903 case 0x68: /* PLA */
904 PL(a);
905 nz = a;
906 break;
907 case 0x69: /* ADC #ab */
908 data = FETCH;
909 DO_ADC;
910 break;
911 case 0x6a: /* ROR */
912 nz = (c << 7) + (a >> 1);
913 c = a & 1;
914 a = nz;
915 break;
916 case 0x6c: /* JMP (abcd) */
917 ABSOLUTE;
918 if ((addr & 0xff) == 0xff)
919 pc = (dGetByte(addr - 0xff) << 8) + dGetByte(addr);
920 else
921 pc = dGetWord(addr);
922 break;
923 case 0x6d: /* ADC abcd */
924 ABSOLUTE;
925 ADC;
926 break;
927 case 0x6e: /* ROR abcd */
928 ABSOLUTE;
929 ROR;
930 break;
931 case 0x70: /* BVS */
932 BRANCH((vdi & V_FLAG) != 0);
933 case 0x71: /* ADC (ab),y */
934 INDIRECT_Y;
935 NCYCLES_Y;
936 ADC;
937 break;
938 case 0x75: /* ADC ab,x */
939 ZPAGE_X;
940 ADC_ZP;
941 break;
942 case 0x76: /* ROR ab,x */
943 ZPAGE_X;
944 ROR_ZP;
945 break;
946 case 0x78: /* SEI */
947 vdi |= I_FLAG;
948 break;
949 case 0x79: /* ADC abcd,y */
950 ABSOLUTE_Y;
951 NCYCLES_Y;
952 ADC;
953 break;
954 case 0x7d: /* ADC abcd,x */
955 ABSOLUTE_X;
956 NCYCLES_X;
957 ADC;
958 break;
959 case 0x7e: /* ROR abcd,x */
960 ABSOLUTE_X;
961 ROR;
962 break;
963 case 0x81: /* STA (ab,x) */
964 INDIRECT_X;
965 STA;
966 break;
967 case 0x84: /* STY ab */
968 ZPAGE;
969 STY_ZP;
970 break;
971 case 0x85: /* STA ab */
972 ZPAGE;
973 STA_ZP;
974 break;
975 case 0x86: /* STX ab */
976 ZPAGE;
977 STX_ZP;
978 break;
979 case 0x88: /* DEY */
980 nz = y = (y - 1) & 0xff;
981 break;
982 case 0x8a: /* TXA */
983 nz = a = x;
984 break;
985 case 0x8c: /* STY abcd */
986 ABSOLUTE;
987 STY;
988 break;
989 case 0x8d: /* STA abcd */
990 ABSOLUTE;
991 STA;
992 break;
993 case 0x8e: /* STX abcd */
994 ABSOLUTE;
995 STX;
996 break;
997 case 0x90: /* BCC */
998 BRANCH(c == 0);
999 case 0x91: /* STA (ab),y */
1000 INDIRECT_Y;
1001 STA;
1002 break;
1003 case 0x94: /* STY ab,x */
1004 ZPAGE_X;
1005 STY_ZP;
1006 break;
1007 case 0x95: /* STA ab,x */
1008 ZPAGE_X;
1009 STA_ZP;
1010 break;
1011 case 0x96: /* STX ab,y */
1012 ZPAGE_Y;
1013 STX_ZP;
1014 break;
1015 case 0x98: /* TYA */
1016 nz = a = y;
1017 break;
1018 case 0x99: /* STA abcd,y */
1019 ABSOLUTE_Y;
1020 STA;
1021 break;
1022 case 0x9a: /* TXS */
1023 s = x;
1024 break;
1025 case 0x9d: /* STA abcd,x */
1026 ABSOLUTE_X;
1027 STA;
1028 break;
1029 case 0xa0: /* LDY #ab */
1030 nz = y = FETCH;
1031 break;
1032 case 0xa1: /* LDA (ab,x) */
1033 INDIRECT_X;
1034 LDA;
1035 break;
1036 case 0xa2: /* LDX #ab */
1037 nz = x = FETCH;
1038 break;
1039 case 0xa4: /* LDY ab */
1040 ZPAGE;
1041 LDY_ZP;
1042 break;
1043 case 0xa5: /* LDA ab */
1044 ZPAGE;
1045 LDA_ZP;
1046 break;
1047 case 0xa6: /* LDX ab */
1048 ZPAGE;
1049 LDX_ZP;
1050 break;
1051 case 0xa8: /* TAY */
1052 nz = y = a;
1053 break;
1054 case 0xa9: /* LDA #ab */
1055 nz = a = FETCH;
1056 break;
1057 case 0xaa: /* TAX */
1058 nz = x = a;
1059 break;
1060 case 0xac: /* LDY abcd */
1061 ABSOLUTE;
1062 LDY;
1063 break;
1064 case 0xad: /* LDA abcd */
1065 ABSOLUTE;
1066 LDA;
1067 break;
1068 case 0xae: /* LDX abcd */
1069 ABSOLUTE;
1070 LDX;
1071 break;
1072 case 0xb0: /* BCS */
1073 BRANCH(c != 0);
1074 case 0xb1: /* LDA (ab),y */
1075 INDIRECT_Y;
1076 NCYCLES_Y;
1077 LDA;
1078 break;
1079 case 0xb4: /* LDY ab,x */
1080 ZPAGE_X;
1081 LDY_ZP;
1082 break;
1083 case 0xb5: /* LDA ab,x */
1084 ZPAGE_X;
1085 LDA_ZP;
1086 break;
1087 case 0xb6: /* LDX ab,y */
1088 ZPAGE_Y;
1089 LDX_ZP;
1090 break;
1091 case 0xb8: /* CLV */
1092 vdi &= D_FLAG | I_FLAG;
1093 break;
1094 case 0xb9: /* LDA abcd,y */
1095 ABSOLUTE_Y;
1096 NCYCLES_Y;
1097 LDA;
1098 break;
1099 case 0xba: /* TSX */
1100 nz = x = s;
1101 break;
1102 case 0xbc: /* LDY abcd,x */
1103 ABSOLUTE_X;
1104 NCYCLES_X;
1105 LDY;
1106 break;
1107 case 0xbd: /* LDA abcd,x */
1108 ABSOLUTE_X;
1109 NCYCLES_X;
1110 LDA;
1111 break;
1112 case 0xbe: /* LDX abcd,y */
1113 ABSOLUTE_Y;
1114 NCYCLES_Y;
1115 LDX;
1116 break;
1117 case 0xc0: /* CPY #ab */
1118 nz = FETCH;
1119 c = (y >= nz) ? 1 : 0;
1120 nz = (y - nz) & 0xff;
1121 break;
1122 case 0xc1: /* CMP (ab,x) */
1123 INDIRECT_X;
1124 CMP;
1125 break;
1126 case 0xc4: /* CPY ab */
1127 ZPAGE;
1128 CPY_ZP;
1129 break;
1130 case 0xc5: /* CMP ab */
1131 ZPAGE;
1132 CMP_ZP;
1133 break;
1134 case 0xc6: /* DEC ab */
1135 ZPAGE;
1136 DEC_ZP;
1137 break;
1138 case 0xc8: /* INY */
1139 nz = y = (y + 1) & 0xff;
1140 break;
1141 case 0xc9: /* CMP #ab */
1142 nz = FETCH;
1143 c = (a >= nz) ? 1 : 0;
1144 nz = (a - nz) & 0xff;
1145 break;
1146 case 0xca: /* DEX */
1147 nz = x = (x - 1) & 0xff;
1148 break;
1149 case 0xcc: /* CPY abcd */
1150 ABSOLUTE;
1151 CPY;
1152 break;
1153 case 0xcd: /* CMP abcd */
1154 ABSOLUTE;
1155 CMP;
1156 break;
1157 case 0xce: /* DEC abcd */
1158 ABSOLUTE;
1159 DEC;
1160 break;
1161 case 0xd0: /* BNE */
1162 BRANCH((nz & 0xff) != 0);
1163 case 0xd1: /* CMP (ab),y */
1164 INDIRECT_Y;
1165 NCYCLES_Y;
1166 CMP;
1167 break;
1168 case 0xd5: /* CMP ab,x */
1169 ZPAGE_X;
1170 CMP_ZP;
1171 break;
1172 case 0xd6: /* DEC ab,x */
1173 ZPAGE_X;
1174 DEC_ZP;
1175 break;
1176 case 0xd8: /* CLD */
1177 vdi &= V_FLAG | I_FLAG;
1178 break;
1179 case 0xd9: /* CMP abcd,y */
1180 ABSOLUTE_Y;
1181 NCYCLES_Y;
1182 CMP;
1183 break;
1184 case 0xdd: /* CMP abcd,x */
1185 ABSOLUTE_X;
1186 NCYCLES_X;
1187 CMP;
1188 break;
1189 case 0xde: /* DEC abcd,x */
1190 ABSOLUTE_X;
1191 DEC;
1192 break;
1193 case 0xe0: /* CPX #ab */
1194 nz = FETCH;
1195 c = (x >= nz) ? 1 : 0;
1196 nz = (x - nz) & 0xff;
1197 break;
1198 case 0xe1: /* SBC (ab,x) */
1199 INDIRECT_X;
1200 SBC;
1201 break;
1202 case 0xe4: /* CPX ab */
1203 ZPAGE;
1204 CPX_ZP;
1205 break;
1206 case 0xe5: /* SBC ab */
1207 ZPAGE;
1208 SBC_ZP;
1209 break;
1210 case 0xe6: /* INC ab */
1211 ZPAGE;
1212 INC_ZP;
1213 break;
1214 case 0xe8: /* INX */
1215 nz = x = (x + 1) & 0xff;
1216 break;
1217 case 0xe9: /* SBC #ab */
1218 case 0xeb: /* SBC #ab [unofficial] */
1219 data = FETCH;
1220 DO_SBC;
1221 break;
1222 case 0xea: /* NOP */
1223 case 0x1a: /* NOP [unofficial] */
1224 case 0x3a:
1225 case 0x5a:
1226 case 0x7a:
1227 case 0xda:
1228 case 0xfa:
1229 break;
1230 case 0xec: /* CPX abcd */
1231 ABSOLUTE;
1232 CPX;
1233 break;
1234 case 0xed: /* SBC abcd */
1235 ABSOLUTE;
1236 SBC;
1237 break;
1238 case 0xee: /* INC abcd */
1239 ABSOLUTE;
1240 INC;
1241 break;
1242 case 0xf0: /* BEQ */
1243 BRANCH((nz & 0xff) == 0);
1244 case 0xf1: /* SBC (ab),y */
1245 INDIRECT_Y;
1246 NCYCLES_Y;
1247 SBC;
1248 break;
1249 case 0xf5: /* SBC ab,x */
1250 ZPAGE_X;
1251 SBC_ZP;
1252 break;
1253 case 0xf6: /* INC ab,x */
1254 ZPAGE_X;
1255 INC_ZP;
1256 break;
1257 case 0xf8: /* SED */
1258 vdi |= D_FLAG;
1259 break;
1260 case 0xf9: /* SBC abcd,y */
1261 ABSOLUTE_Y;
1262 NCYCLES_Y;
1263 SBC;
1264 break;
1265 case 0xfd: /* SBC abcd,x */
1266 ABSOLUTE_X;
1267 NCYCLES_X;
1268 SBC;
1269 break;
1270 case 0xfe: /* INC abcd,x */
1271 ABSOLUTE_X;
1272 INC;
1273 break;
1276 ast _ cpu_pc = pc;
1277 ast _ cpu_nz = nz;
1278 ast _ cpu_a = a;
1279 ast _ cpu_x = x;
1280 ast _ cpu_y = y;
1281 ast _ cpu_c = c;
1282 ast _ cpu_s = s;
1283 ast _ cpu_vdi = vdi;
1284 ast _ cycle -= cycle_limit;
1285 if (ast _ timer1_cycle != NEVER)
1286 ast _ timer1_cycle -= cycle_limit;
1287 if (ast _ timer2_cycle != NEVER)
1288 ast _ timer2_cycle -= cycle_limit;
1289 if (ast _ timer4_cycle != NEVER)
1290 ast _ timer4_cycle -= cycle_limit;