Retirando os externs
[NesEmulator.git] / nes6502.c
blob56d4bd5a24c5822fb3deff73a430e5057468c16c
2 #include "nes6502.h"
3 #include "nes6502i.h"
4 #include "types.h"
7 static nes6502_context cpu;
8 static uint8 *ram = NULL, *stack = NULL;
9 static uint8 null_page[NES6502_BANKSIZE];
11 #define EXPAND_FLAGS() \
12 c_flag = (cpu.p_reg) & NES6502_C_FLAG; \
13 z_flag = (cpu.p_reg) & NES6502_Z_FLAG; \
14 i_flag = (cpu.p_reg) & NES6502_I_FLAG; \
15 d_flag = (cpu.p_reg) & NES6502_D_FLAG; \
16 b_flag = (cpu.p_reg) & NES6502_B_FLAG; \
17 v_flag = (cpu.p_reg) & NES6502_V_FLAG; \
18 n_flag = (cpu.p_reg) & NES6502_N_FLAG;
20 #define COMPACT_FLAGS() \
21 cpu.p_reg = NES6502_R_FLAG; \
22 if (c_flag) cpu.p_reg |= NES6502_C_FLAG; \
23 if (z_flag) cpu.p_reg |= NES6502_Z_FLAG; \
24 if (i_flag) cpu.p_reg |= NES6502_I_FLAG; \
25 if (d_flag) cpu.p_reg |= NES6502_D_FLAG; \
26 if (b_flag) cpu.p_reg |= NES6502_B_FLAG; \
27 if (v_flag) cpu.p_reg |= NES6502_V_FLAG; \
28 if (n_flag) cpu.p_reg |= NES6502_N_FLAG;
31 #define IF_BREAK() b_flag
32 #define IF_CARRY() c_flag
33 #define IF_DECIMAL() d_flag
34 #define IF_INTERRUPT() i_flag
35 #define IF_OVERFLOW() v_flag
36 #define IF_NEGATIVE() n_flag
37 #define IF_ZERO() z_flag
39 #define SET_BREAK(v) b_flag = (v);
40 #define SET_CARRY(v) c_flag = (v);
41 #define SET_DECIMAL(v) d_flag = (v);
42 #define SET_INTERRUPT(v) i_flag = (v);
43 #define SET_OVERFLOW(v) v_flag = (v);
44 #define SET_SIGN(v) n_flag = (v);
45 #define SET_ZERO(v) z_flag = (v);
47 #define BRANCH_ON(cond) \
48 if (cond) { \
49 cpu.total_cycles++; \
50 cpu.remaining_cycles--; \
51 if ((oper & 0xFF00) != (cpu.pc_reg & 0xFF00)) { \
52 cpu.total_cycles++; \
53 cpu.remaining_cycles--; \
54 } \
55 cpu.pc_reg = oper; \
58 #define CHECK_ZERO(v) SET_ZERO ((v) == 0)
59 #define CHECK_SIGN(v) SET_SIGN ((v) & 0x80)
61 #define CHECK_ZERO_AND_SIGN(v) CHECK_ZERO (v) CHECK_SIGN (v)
63 #define WB() \
64 if (opcode->addressing == ADDR_ACCUMULATOR) \
65 cpu.a_reg = oper; \
66 else \
67 WB_SIMPLE ()
69 #define WB_SIMPLE() nes6502_writebyte (operp, oper);
71 #define PULL(v) \
72 cpu.s_reg = (cpu.s_reg + 1) & 0xFF; \
73 (v) = stack[cpu.s_reg];
75 #define PULL_W(v) \
76 cpu.s_reg = (cpu.s_reg + 1) & 0xFF; \
77 (v) = stack[cpu.s_reg]; \
78 cpu.s_reg = (cpu.s_reg + 1) & 0xFF; \
79 (v) |= ((uint32) stack[cpu.s_reg]) << 8;
81 #define PUSH(v) \
82 stack[cpu.s_reg] = v; \
83 cpu.s_reg = (cpu.s_reg - 1) & 0xFF;
85 #define PUSH_W(v) \
86 stack[cpu.s_reg] = (v) >> 8; \
87 cpu.s_reg = (cpu.s_reg - 1) & 0xFF; \
88 stack[cpu.s_reg] = (v) & 0xFF; \
89 cpu.s_reg = (cpu.s_reg - 1) & 0xFF;
91 #define BANK(address) \
92 cpu.mem_page[(address) >> NES6502_BANKSHIFT][(address) & NES6502_BANKMASK]
94 #define BANK_W(address) \
95 (((uint32) BANK (address)) | (((uint32) BANK ((address) + 1)) << 8))
97 #define IRQ_PROC(vector) \
98 cpu.burn_cycles += NES6502_INT_CYCLES; \
99 PUSH_W (cpu.pc_reg) \
100 cpu.p_reg &= ~(NES6502_B_FLAG); \
101 PUSH (cpu.p_reg) \
102 cpu.p_reg |= NES6502_I_FLAG; \
103 cpu.pc_reg = BANK_W (vector);
106 void nes6502_power (void)
108 cpu.a_reg = 0;
109 cpu.x_reg = cpu.y_reg = 0;
110 cpu.s_reg = 0xFF;
111 cpu.total_cycles = 0;
112 nes6502_reset ();
115 void nes6502_reset (void)
117 cpu.pc_reg = BANK (NES6502_RESET_VECTOR);
118 cpu.pc_reg |= ((uint32) BANK (NES6502_RESET_VECTOR + 1)) << 8;
119 cpu.p_reg = NES6502_Z_FLAG | NES6502_R_FLAG;
120 cpu.burn_cycles = NES6502_RESET_CYCLES;
121 cpu.int_pending = FALSE;
122 cpu.halted = FALSE;
123 cpu.remaining_cycles = 0;
126 void nes6502_halt (void)
128 cpu.halted = TRUE;
129 cpu.remaining_cycles = 0;
132 int nes6502_ishalted (void)
134 return cpu.halted;
138 void nes6502_nmi (void)
140 if (cpu.halted) return;
141 cpu.remaining_cycles = 0;
142 IRQ_PROC (NES6502_NMI_VECTOR)
145 void nes6502_irq (void)
147 if (cpu.halted) return;
148 cpu.remaining_cycles = 0;
149 if (cpu.p_reg & NES6502_I_FLAG) {
150 cpu.int_pending = TRUE;
151 } else {
152 IRQ_PROC (NES6502_IRQ_VECTOR)
156 #ifdef DEBUGGER_ENABLED
157 static
158 int nes6502_checkaddr (uint32 addr, int32 flags)
160 uint32 i;
161 for (i = 0; i < cpu.num_bp; i++) {
162 if (cpu.bp_flags[i] & NES6502_DEBUG_DISABLED)
163 continue;
164 if (!(cpu.bp_flags[i] & flags))
165 continue;
166 if ((cpu.bp_mask[i] & addr) == cpu.bp_addr[i])
167 return 1;
169 return 0;
172 static
173 int nes6502_checkstack (uint32 count, int push)
175 uint32 operp = cpu.s_reg;
176 if (push) {
177 while (count--) {
178 if (nes6502_checkaddr (NES6502_STACK_OFFSET + operp, NES6502_DEBUG_WRITE))
179 return 1;
180 operp = (operp - 1) & 0xFF;
182 } else {
183 while (count--) {
184 operp = (operp + 1) & 0xFF;
185 if (nes6502_checkaddr (NES6502_STACK_OFFSET + operp, NES6502_DEBUG_READ))
186 return 1;
189 return 0;
192 static
193 void nes6502_debug (int first_insn)
195 uint8 opc;
196 uint32 operp, t1, t2;
197 int32 flags = 0;
198 struct nes6502_opcode *opcode;
199 enum nes6502_instruction insn;
200 int details;
202 if (nes6502_checkaddr (cpu.pc_reg, NES6502_DEBUG_READ))
203 goto bphit;
205 opc = BANK (cpu.pc_reg);
206 opcode = &nes6502_opcodes[opc];
208 for (t1 = 1; t1 < nes6502_addressing_length[opcode->addressing]; t1++) {
209 if (nes6502_checkaddr (cpu.pc_reg + t1, NES6502_DEBUG_READ))
210 goto bphit;
213 insn = opcode->instruction;
214 details = nes6502_instructions[insn].details;
216 if (details & I_RD) {
217 flags |= NES6502_DEBUG_READ;
219 if (details & I_WR) {
220 flags |= NES6502_DEBUG_WRITE;
223 switch (opcode->addressing) {
224 case ADDR_ZERO_PAGE:
225 operp = (uint32) BANK (cpu.pc_reg + 1);
226 if (nes6502_checkaddr (operp, flags)) goto bphit;
227 break;
228 case ADDR_ZERO_PAGE_X:
229 operp = (BANK (cpu.pc_reg + 1) + cpu.x_reg) & 0xFF;
230 if (nes6502_checkaddr (operp, flags)) goto bphit;
231 break;
232 case ADDR_ZERO_PAGE_Y:
233 operp = (BANK (cpu.pc_reg + 1) + cpu.y_reg) & 0xFF;
234 if (nes6502_checkaddr (operp, flags)) goto bphit;
235 break;
236 case ADDR_ABSOLUTE:
237 operp = BANK_W (cpu.pc_reg + 1);
238 if (nes6502_checkaddr (operp, flags)) goto bphit;
239 break;
240 case ADDR_ABSOLUTE_X:
241 operp = (BANK_W (cpu.pc_reg + 1) + cpu.x_reg) & 0xFFFF;
242 if (nes6502_checkaddr (operp, flags)) goto bphit;
243 break;
244 case ADDR_ABSOLUTE_Y:
245 operp = (BANK_W (cpu.pc_reg + 1) + cpu.y_reg) & 0xFFFF;
246 if (nes6502_checkaddr (operp, flags)) goto bphit;
247 break;
248 case ADDR_INDIRECT:
249 operp = BANK_W (cpu.pc_reg + 1);
250 if (nes6502_checkaddr (operp, NES6502_DEBUG_READ)) goto bphit;
251 if ((operp & 0xFF) == 0xFF) {
252 if (nes6502_checkaddr (operp - 0xFF, NES6502_DEBUG_READ)) goto bphit;
253 } else {
254 if (nes6502_checkaddr (operp + 1, NES6502_DEBUG_READ)) goto bphit;
256 break;
257 case ADDR_INDIRECT_X:
258 t1 = (BANK (cpu.pc_reg + 1) + cpu.x_reg) & 0xFF;
259 if (nes6502_checkaddr (t1, NES6502_DEBUG_READ)) goto bphit;
260 if (nes6502_checkaddr ((t1 + 1) & 0xFF, NES6502_DEBUG_READ)) goto bphit;
261 operp = (uint32) ram[t1];
262 operp |= ((uint32) ram[(t1 + 1) & 0xFF]) << 8;
263 if (nes6502_checkaddr (operp, flags)) goto bphit;
264 break;
265 case ADDR_INDIRECT_Y:
266 t1 = (BANK (cpu.pc_reg + 1)) & 0xFF;
267 if (nes6502_checkaddr (t1, NES6502_DEBUG_READ)) goto bphit;
268 if (nes6502_checkaddr ((t1 + 1) & 0xFF, NES6502_DEBUG_READ)) goto bphit;
269 operp = (uint32) ram[t1] + cpu.y_reg;
270 operp += ((uint32) ram[(t1 + 1) & 0xFF]) << 8;
271 operp &= 0xFFFF;
272 if (nes6502_checkaddr (operp, flags)) goto bphit;
273 break;
274 default:
275 break;
278 if (details & I_ST) {
279 if (details & I_JP) {
280 if (insn == INSN_BRK || insn == INSN_JSR) {
281 t1 = 1;
282 if (insn == INSN_BRK) t2 = 3;
283 else t2 = 2;
284 } else {
285 t1 = 0;
286 if (insn == INSN_RTI) t2 = 3;
287 else t2 = 2;
289 } else {
290 t2 = 1;
291 if (insn == INSN_PHA || insn == INSN_PHP) {
292 t1 = 1;
293 } else {
294 t1 = 0;
297 if (nes6502_checkstack (t2, t1))
298 goto bphit;
301 return;
303 bphit:
304 (*cpu.debug_handler) (first_insn);
306 return;
309 int nes6502_addbreakpoint (uint32 address, uint32 mask, int32 flags)
311 if (cpu.num_bp == NES6502_MAX_BREAKPOINTS) return -1;
312 nes6502_editbreakpoint (cpu.num_bp, address, mask, flags);
313 return cpu.num_bp++;
316 void nes6502_editbreakpoint (uint32 bp, uint32 address, uint32 mask, int32 flags)
318 if (bp >= NES6502_MAX_BREAKPOINTS) return;
319 cpu.bp_addr[bp] = address;
320 cpu.bp_mask[bp] = mask;
321 cpu.bp_flags[bp] = flags;
324 void nes6502_getbreakpoint (uint32 bp, uint32 *address, uint32 *mask, int32 *flags)
326 if (bp >= NES6502_MAX_BREAKPOINTS) return;
327 *address = cpu.bp_addr[bp];
328 *mask = cpu.bp_mask[bp];
329 *flags = cpu.bp_flags[bp];
332 void nes6502_removebreakpoint (uint32 bp)
334 uint32 i;
335 if (bp >= cpu.num_bp) return;
336 cpu.num_bp--;
337 for (i = bp; i < cpu.num_bp; i++) {
338 cpu.bp_addr[i] = cpu.bp_addr[i + 1];
339 cpu.bp_mask[i] = cpu.bp_mask[i + 1];
340 cpu.bp_flags[i] = cpu.bp_flags[i + 1];
344 uint32 nes6502_numbreakpoints (void)
346 return cpu.num_bp;
349 #endif
352 int32 nes6502_execute (int32 cycles)
354 int old_cycles;
355 int c_flag, z_flag, i_flag, d_flag;
356 int b_flag, v_flag, n_flag;
358 #ifdef DEBUGGER_ENABLED
359 int first_insn = TRUE;
360 #endif
362 if (cpu.halted) return 0;
363 old_cycles = cpu.total_cycles;
365 if (cycles <= 0)
366 cycles = cpu.burn_cycles + 1;
367 cpu.remaining_cycles = cycles;
369 EXPAND_FLAGS ()
371 if (!IF_INTERRUPT () && cpu.int_pending) {
372 cpu.int_pending = FALSE;
373 IRQ_PROC (NES6502_IRQ_VECTOR);
376 if (cpu.burn_cycles && cpu.remaining_cycles > 0) {
377 int burn_for;
379 burn_for = MIN (cpu.remaining_cycles, cpu.burn_cycles);
380 cpu.total_cycles += burn_for;
381 cpu.burn_cycles -= burn_for;
382 cpu.remaining_cycles -= burn_for;
385 while (cpu.remaining_cycles > 0) {
386 uint8 opc;
387 struct nes6502_opcode *opcode;
388 uint32 oper = 0, operp = 0, t;
389 enum nes6502_instruction insn;
390 int details;
392 opc = BANK (cpu.pc_reg);
393 opcode = &nes6502_opcodes[opc];
394 insn = opcode->instruction;
395 details = nes6502_instructions[insn].details;
397 #ifdef DEBUGGER_ENABLED
398 if (cpu.num_bp > 0) {
399 nes6502_debug (first_insn);
400 if (cpu.remaining_cycles <= 0) break;
402 first_insn = FALSE;
403 #endif
405 cpu.total_cycles += opcode->cycles;
406 cpu.remaining_cycles -= opcode->cycles;
407 cpu.pc_reg++;
409 switch (opcode->addressing) {
410 case ADDR_ACCUMULATOR:
411 oper = cpu.a_reg;
412 break;
413 case ADDR_IMMEDIATE:
414 oper = (uint32) BANK (cpu.pc_reg);
415 cpu.pc_reg++;
416 break;
417 case ADDR_ZERO_PAGE:
418 operp = (uint32) BANK (cpu.pc_reg);
419 oper = (uint32) ram[operp];
420 cpu.pc_reg++;
421 break;
422 case ADDR_ZERO_PAGE_X:
423 operp = (BANK (cpu.pc_reg) + cpu.x_reg) & 0xFF;
424 oper = ram[operp];
425 cpu.pc_reg++;
426 break;
427 case ADDR_ZERO_PAGE_Y:
428 operp = (BANK (cpu.pc_reg) + cpu.y_reg) & 0xFF;
429 oper = ram[operp];
430 cpu.pc_reg++;
431 break;
432 case ADDR_ABSOLUTE:
433 operp = BANK_W (cpu.pc_reg);
434 cpu.pc_reg += 2;
435 if (details & I_RD)
436 oper = nes6502_readbyte (operp);
437 break;
438 case ADDR_ABSOLUTE_X:
439 operp = (BANK (cpu.pc_reg) + cpu.x_reg);
440 cpu.pc_reg++;
441 if (operp & 0x100) cpu.total_cycles++;
442 operp += ((uint32) BANK (cpu.pc_reg)) << 8;
443 cpu.pc_reg++;
444 operp &= 0xFFFF;
445 if (details & I_RD)
446 oper = nes6502_readbyte (operp);
447 break;
448 case ADDR_ABSOLUTE_Y:
449 operp = (BANK (cpu.pc_reg) + cpu.y_reg);
450 cpu.pc_reg++;
451 if (operp & 0x100) cpu.total_cycles++;
452 operp += ((uint32) BANK (cpu.pc_reg)) << 8;
453 cpu.pc_reg++;
454 operp &= 0xFFFF;
455 if (details & I_RD)
456 oper = nes6502_readbyte (operp);
457 break;
458 case ADDR_INDIRECT:
459 t = BANK_W (cpu.pc_reg);
460 cpu.pc_reg += 2;
461 /* 6502 bug here! */
462 operp = BANK (t);
463 if ((t & 0xFF) == 0xFF)
464 operp |= ((uint32) BANK (t - 0xFF)) << 8;
465 else
466 operp |= ((uint32) BANK (t + 1)) << 8;
467 /* We don't need to eval "oper" because ADDR_INDIRECT
468 * is used only for the JMP instruction
469 * */
470 break;
471 case ADDR_INDIRECT_X:
472 t = (BANK (cpu.pc_reg) + cpu.x_reg) & 0xFF;
473 cpu.pc_reg++;
474 operp = (uint32) ram[t];
475 operp |= ((uint32) ram[(t + 1) & 0xFF]) << 8;
476 if (details & I_RD)
477 oper = nes6502_readbyte (operp);
478 break;
479 case ADDR_INDIRECT_Y:
480 t = BANK (cpu.pc_reg) & 0xFF;
481 cpu.pc_reg++;
482 operp = ((uint32) ram [t]) + cpu.y_reg;
483 if (operp & 0x100) cpu.total_cycles++;
484 operp += ((uint32) ram [(t + 1) & 0xFF]) << 8;
485 operp &= 0xFFFF;
486 if (details & I_RD)
487 oper = nes6502_readbyte (operp);
488 break;
489 case ADDR_RELATIVE:
490 t = BANK (cpu.pc_reg);
491 cpu.pc_reg++;
492 if (t & 0x80) t |= 0xFF00;
493 oper = (cpu.pc_reg + t) & 0xFFFF;
494 break;
495 case ADDR_IMPLIED:
496 default:
497 oper = 0;
498 break;
502 switch (insn) {
503 case INSN_AAC: /* Undocumented */
504 cpu.a_reg &= oper;
505 CHECK_ZERO_AND_SIGN (cpu.a_reg)
506 SET_CARRY (IF_ZERO ())
507 break;
508 case INSN_AAX: /* Undocumented */
509 oper = cpu.x_reg & cpu.a_reg;
510 WB_SIMPLE ()
511 break;
512 case INSN_ADC:
513 t = oper + cpu.a_reg;
514 if (IF_CARRY ()) t++;
515 SET_CARRY (t & 0x100)
516 SET_OVERFLOW (!((cpu.a_reg ^ oper) & 0x80) && ((cpu.a_reg ^ t) & 0x80))
517 cpu.a_reg = t & 0xFF;
518 CHECK_ZERO_AND_SIGN (cpu.a_reg)
519 break;
520 case INSN_AND:
521 cpu.a_reg &= oper;
522 CHECK_ZERO_AND_SIGN (cpu.a_reg)
523 break;
524 case INSN_ARR: /* Undocumented */
525 cpu.a_reg &= oper;
526 cpu.a_reg >>= 1;
527 if (IF_CARRY ()) cpu.a_reg |= 0x80;
528 SET_CARRY (cpu.a_reg & 0x40)
529 SET_OVERFLOW (((cpu.a_reg >> 1) ^ cpu.a_reg) & 0x20)
530 CHECK_ZERO_AND_SIGN (cpu.a_reg)
531 break;
532 case INSN_ASL:
533 SET_CARRY (oper & 0x80)
534 oper = (oper << 1) & 0xFF;
535 CHECK_ZERO_AND_SIGN (oper)
536 WB ()
537 break;
538 case INSN_ASR: /* Undocumented */
539 cpu.a_reg &= oper;
540 SET_CARRY (cpu.a_reg & 0x01)
541 cpu.a_reg >>= 1;
542 SET_ZERO (cpu.a_reg == 0)
543 SET_SIGN (0)
544 break;
545 case INSN_ATX: /* Undocumented */
546 cpu.a_reg = cpu.x_reg = ((cpu.a_reg | 0xEE) & oper); /* Unpredictable */
547 CHECK_ZERO_AND_SIGN (oper)
548 break;
549 case INSN_AXA: /* Undocumented */
550 oper = cpu.a_reg & cpu.x_reg & ((uint8) ((operp >> 8) + 1)); /* Unpredictable */
551 WB_SIMPLE ()
552 break;
553 case INSN_AXS: /* Undocumented */
554 cpu.x_reg = ((cpu.a_reg & cpu.x_reg) - oper);
555 SET_CARRY (cpu.x_reg < 0x100)
556 cpu.x_reg &= 0xFF;
557 CHECK_ZERO_AND_SIGN (cpu.x_reg)
558 break;
559 case INSN_BCC:
560 BRANCH_ON (!IF_CARRY ())
561 break;
562 case INSN_BCS:
563 BRANCH_ON (IF_CARRY ())
564 break;
565 case INSN_BEQ:
566 BRANCH_ON (IF_ZERO ())
567 break;
568 case INSN_BIT:
569 SET_SIGN (oper & 0x80)
570 SET_OVERFLOW (oper & 0x40)
571 SET_ZERO ((oper & cpu.a_reg) == 0)
572 break;
573 case INSN_BMI:
574 BRANCH_ON (IF_NEGATIVE ())
575 break;
576 case INSN_BNE:
577 BRANCH_ON (!IF_ZERO ())
578 break;
579 case INSN_BPL:
580 BRANCH_ON (!IF_NEGATIVE ())
581 break;
582 case INSN_BRK:
583 /* RTI from break causes the next instruction to be ignored */
584 cpu.pc_reg++;
585 PUSH_W (cpu.pc_reg)
586 SET_BREAK (1)
587 COMPACT_FLAGS ()
588 PUSH (cpu.p_reg)
589 SET_INTERRUPT (1)
590 cpu.pc_reg = BANK_W (NES6502_IRQ_VECTOR);
591 break;
592 case INSN_BVC:
593 BRANCH_ON (!IF_OVERFLOW ())
594 break;
595 case INSN_BVS:
596 BRANCH_ON (IF_OVERFLOW ())
597 break;
598 case INSN_CLC:
599 SET_CARRY (0)
600 break;
601 case INSN_CLD:
602 SET_DECIMAL (0)
603 break;
604 case INSN_CLI:
605 SET_INTERRUPT (0)
606 if (cpu.int_pending && cpu.remaining_cycles > 0) {
607 cpu.int_pending = FALSE;
608 COMPACT_FLAGS ()
609 IRQ_PROC (NES6502_IRQ_VECTOR)
611 break;
612 case INSN_CLV:
613 SET_OVERFLOW (0)
614 break;
615 case INSN_CMP:
616 oper = cpu.a_reg - oper;
617 SET_CARRY (oper < 0x100)
618 oper &= 0xff;
619 CHECK_ZERO_AND_SIGN (oper)
620 break;
621 case INSN_CPX:
622 oper = cpu.x_reg - oper;
623 SET_CARRY (oper < 0x100)
624 oper &= 0xff;
625 CHECK_ZERO_AND_SIGN (oper)
626 break;
627 case INSN_CPY:
628 oper = cpu.y_reg - oper;
629 SET_CARRY (oper < 0x100)
630 oper &= 0xff;
631 CHECK_ZERO_AND_SIGN (oper)
632 break;
633 case INSN_DCP: /* Undocumented */
634 oper = (oper - 1) & 0xFF;
635 WB_SIMPLE ()
636 oper = cpu.a_reg - oper;
637 SET_CARRY (oper < 0x100)
638 oper &= 0xff;
639 CHECK_ZERO_AND_SIGN (oper)
640 break;
641 case INSN_DEC:
642 oper = (oper - 1) & 0xFF;
643 CHECK_ZERO_AND_SIGN (oper)
644 WB_SIMPLE ()
645 break;
646 case INSN_DEX:
647 cpu.x_reg = (cpu.x_reg - 1) & 0xFF;
648 CHECK_ZERO_AND_SIGN (cpu.x_reg)
649 break;
650 case INSN_DEY:
651 cpu.y_reg = (cpu.y_reg - 1) & 0xFF;
652 CHECK_ZERO_AND_SIGN (cpu.y_reg)
653 break;
654 case INSN_DOP: /* Undocumented */
655 /* Do nothing */
656 break;
657 case INSN_EOR:
658 cpu.a_reg ^= oper;
659 CHECK_ZERO_AND_SIGN (cpu.a_reg)
660 break;
661 case INSN_HLT:
662 cpu.remaining_cycles = 0;
663 cpu.halted = TRUE;
664 break;
665 case INSN_INC:
666 oper = (oper + 1) & 0xFF;
667 CHECK_ZERO_AND_SIGN (oper)
668 WB_SIMPLE ()
669 break;
670 case INSN_INX:
671 cpu.x_reg = (cpu.x_reg + 1) & 0xFF;
672 CHECK_ZERO_AND_SIGN (cpu.x_reg)
673 break;
674 case INSN_INY:
675 cpu.y_reg = (cpu.y_reg + 1) & 0xFF;
676 CHECK_ZERO_AND_SIGN (cpu.y_reg)
677 break;
678 case INSN_ISC: /* Undocumented */
679 oper = (oper + 1) & 0xFF;
680 WB_SIMPLE ()
681 t = cpu.a_reg - oper;
682 if (!IF_CARRY ()) t--;
683 SET_CARRY (t < 0x100)
684 SET_OVERFLOW (((cpu.a_reg ^ oper) & 0x80) && ((cpu.a_reg ^ t) & 0x80))
685 cpu.a_reg = t & 0xFF;
686 CHECK_ZERO_AND_SIGN (cpu.a_reg)
687 break;
688 case INSN_JMP:
689 cpu.pc_reg = operp;
690 break;
691 case INSN_JSR:
692 cpu.pc_reg--;
693 PUSH_W (cpu.pc_reg)
694 cpu.pc_reg = operp;
695 break;
696 case INSN_LAR: /* Undocumented */
697 cpu.a_reg = cpu.x_reg = cpu.s_reg = ((cpu.s_reg) & oper);
698 CHECK_ZERO_AND_SIGN (cpu.a_reg)
699 break;
700 case INSN_LAX: /* Undocumented */
701 cpu.a_reg = cpu.x_reg = oper;
702 CHECK_ZERO_AND_SIGN (cpu.a_reg)
703 break;
704 case INSN_LDA:
705 cpu.a_reg = oper;
706 CHECK_ZERO_AND_SIGN (cpu.a_reg)
707 break;
708 case INSN_LDX:
709 cpu.x_reg = oper;
710 CHECK_ZERO_AND_SIGN (cpu.x_reg)
711 break;
712 case INSN_LDY:
713 cpu.y_reg = oper;
714 CHECK_ZERO_AND_SIGN (cpu.y_reg)
715 break;
716 case INSN_LSR:
717 SET_CARRY (oper & 0x01)
718 oper >>= 1;
719 SET_ZERO (oper == 0)
720 SET_SIGN (0)
721 WB ()
722 break;
723 case INSN_NOP:
724 break;
725 case INSN_ORA:
726 cpu.a_reg |= oper;
727 CHECK_ZERO_AND_SIGN (cpu.a_reg)
728 break;
729 case INSN_PHA:
730 PUSH (cpu.a_reg)
731 break;
732 case INSN_PHP:
733 COMPACT_FLAGS ()
734 PUSH (cpu.p_reg)
735 break;
736 case INSN_PLA:
737 PULL (cpu.a_reg)
738 CHECK_ZERO_AND_SIGN (cpu.a_reg)
739 break;
740 case INSN_PLP:
741 PULL (cpu.p_reg)
742 EXPAND_FLAGS ()
743 break;
744 case INSN_RLA: /* Undocumented */
745 oper <<= 1;
746 if (IF_CARRY ()) oper |= 0x01;
747 SET_CARRY (oper & 0x100)
748 oper = oper & 0xFF;
749 WB_SIMPLE ()
750 cpu.a_reg &= oper;
751 CHECK_ZERO_AND_SIGN (cpu.a_reg)
752 break;
753 case INSN_ROL:
754 oper <<= 1;
755 if (IF_CARRY ()) oper |= 0x01;
756 SET_CARRY (oper & 0x100)
757 oper = oper & 0xFF;
758 CHECK_ZERO_AND_SIGN (oper)
759 WB ()
760 break;
761 case INSN_ROR:
762 if (IF_CARRY ()) oper |= 0x100;
763 SET_CARRY (oper & 0x01)
764 oper >>= 1;
765 CHECK_ZERO_AND_SIGN (oper)
766 WB ()
767 break;
768 case INSN_RRA: /* Undocumented */
769 if (IF_CARRY ()) oper |= 0x100;
770 SET_CARRY (oper & 0x01)
771 oper >>= 1;
772 WB_SIMPLE ()
773 t = oper + cpu.a_reg;
774 if (IF_CARRY ()) t++;
775 SET_CARRY (t & 0x100)
776 SET_OVERFLOW (!((cpu.a_reg ^ oper) & 0x80) && ((cpu.a_reg ^ t) & 0x80))
777 cpu.a_reg = t & 0xFF;
778 CHECK_ZERO_AND_SIGN (cpu.a_reg)
779 break;
780 case INSN_RTI:
781 PULL (cpu.p_reg)
782 EXPAND_FLAGS ()
783 PULL_W (cpu.pc_reg)
784 if (!IF_INTERRUPT () && cpu.int_pending && cpu.remaining_cycles > 0) {
785 cpu.int_pending = FALSE;
786 IRQ_PROC (NES6502_IRQ_VECTOR)
788 break;
789 case INSN_RTS:
790 PULL_W (cpu.pc_reg)
791 cpu.pc_reg++;
792 break;
793 case INSN_SBC:
794 t = cpu.a_reg - oper;
795 if (!IF_CARRY ()) t--;
796 SET_CARRY (t < 0x100)
797 SET_OVERFLOW (((cpu.a_reg ^ oper) & 0x80) && ((cpu.a_reg ^ t) & 0x80))
798 cpu.a_reg = t & 0xFF;
799 CHECK_ZERO_AND_SIGN (cpu.a_reg)
800 break;
801 case INSN_SEC:
802 SET_CARRY (1)
803 break;
804 case INSN_SED:
805 SET_DECIMAL (1)
806 break;
807 case INSN_SEI:
808 SET_INTERRUPT (1)
809 break;
810 case INSN_SLO: /* Undocumented */
811 SET_CARRY (oper & 0x80)
812 oper = (oper << 1) & 0xFF;
813 WB_SIMPLE ()
814 cpu.a_reg |= oper;
815 CHECK_ZERO_AND_SIGN (cpu.a_reg)
816 break;
817 case INSN_SRE: /* Undocumented */
818 SET_CARRY (oper & 0x01)
819 oper >>= 1;
820 WB_SIMPLE ()
821 cpu.a_reg ^= oper;
822 CHECK_ZERO_AND_SIGN (cpu.a_reg)
823 break;
824 case INSN_STA:
825 nes6502_writebyte (operp, cpu.a_reg);
826 break;
827 case INSN_STX:
828 nes6502_writebyte (operp, cpu.x_reg);
829 break;
830 case INSN_STY:
831 nes6502_writebyte (operp, cpu.y_reg);
832 break;
833 case INSN_SXA: /* Undocumented */
834 oper = cpu.x_reg & ((operp >> 8) + 1); /* Unpredictable */
835 WB_SIMPLE ()
836 break;
837 case INSN_SYA: /* Undocumented */
838 oper = cpu.y_reg & ((operp >> 8) + 1); /* Unpredictable */
839 WB_SIMPLE ()
840 break;
841 case INSN_TAX:
842 cpu.x_reg = cpu.a_reg;
843 CHECK_ZERO_AND_SIGN (cpu.x_reg)
844 break;
845 case INSN_TAY:
846 cpu.y_reg = cpu.a_reg;
847 CHECK_ZERO_AND_SIGN (cpu.y_reg)
848 break;
849 case INSN_TOP: /* Undocumented */
850 /* Do nothing */
851 break;
852 case INSN_TSX:
853 cpu.x_reg = cpu.s_reg;
854 CHECK_ZERO_AND_SIGN (cpu.x_reg)
855 break;
856 case INSN_TXA:
857 cpu.a_reg = cpu.x_reg;
858 CHECK_ZERO_AND_SIGN (cpu.a_reg)
859 break;
860 case INSN_TXS:
861 cpu.s_reg = cpu.x_reg;
862 break;
863 case INSN_TYA:
864 cpu.a_reg = cpu.y_reg;
865 CHECK_ZERO_AND_SIGN (cpu.a_reg)
866 break;
867 case INSN_XAA: /* Undocumented */
868 cpu.a_reg = (cpu.a_reg | 0xEE) & cpu.x_reg & oper;
869 CHECK_ZERO_AND_SIGN (cpu.a_reg)
870 break;
871 case INSN_XAS: /* Undocumented */
872 cpu.s_reg = cpu.x_reg & cpu.a_reg;
873 oper = cpu.s_reg & ((operp >> 8) + 1);
874 WB_SIMPLE ()
875 break;
880 COMPACT_FLAGS ()
881 return (cpu.total_cycles - old_cycles);
884 /* read a byte from 6502 memory */
885 uint8 nes6502_readbyte (uint32 address)
887 if (address < 0x800) {
888 return ram[address];
889 } else if (address < 0x8000) {
890 nes6502_memread *mr;
891 for (mr = cpu.read_handler; mr->min_range != 0xFFFFFFFF; mr++) {
892 if (address >= mr->min_range && address <= mr->max_range)
893 return mr->read_func (address);
897 return BANK (address);
900 /* write a byte of data to 6502 memory */
901 void nes6502_writebyte (uint32 address, uint8 value)
903 if (address < 0x800) {
904 ram[address] = value;
905 return;
906 } else {
907 nes6502_memwrite *mw;
908 for (mw = cpu.write_handler; mw->min_range != 0xFFFFFFFF; mw++) {
909 if (address >= mw->min_range && address <= mw->max_range) {
910 mw->write_func (address, value);
911 return;
916 BANK (address) = value;
919 uint8 nes6502_getbyte (uint32 address)
921 return BANK (address);
924 void nes6502_putbyte (uint32 address, uint8 value)
926 BANK (address) = value;
930 void nes6502_burn (int32 cycles)
932 cpu.burn_cycles += cycles;
935 void nes6502_release (void)
937 cpu.remaining_cycles = 0;
940 void nes6502_getcontext (nes6502_context *state)
942 int loop;
943 *state = cpu;
944 for (loop = 0; loop < NES6502_NUMBANKS; loop++) {
945 if (null_page == state->mem_page[loop])
946 state->mem_page[loop] = NULL;
950 void nes6502_setcontext (nes6502_context *state)
952 int loop;
953 cpu = *state;
954 /* set dead page for all pages not pointed at anything */
955 for (loop = 0; loop < NES6502_NUMBANKS; loop++) {
956 if (NULL == cpu.mem_page[loop])
957 cpu.mem_page[loop] = null_page;
960 ram = cpu.mem_page[0];
961 stack = &ram[NES6502_STACK_OFFSET];
963 #ifdef DEBUGGER_ENABLED
964 cpu.num_bp = 0;
965 #endif