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