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) \
50 cpu.remaining_cycles--; \
51 if ((oper & 0xFF00) != (cpu.pc_reg & 0xFF00)) { \
53 cpu.remaining_cycles--; \
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)
64 if (opcode->addressing == ADDR_ACCUMULATOR) \
69 #define WB_SIMPLE() nes6502_writebyte (operp, oper);
72 cpu.s_reg = (cpu.s_reg + 1) & 0xFF; \
73 (v) = stack[cpu.s_reg];
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;
82 stack[cpu.s_reg] = v; \
83 cpu.s_reg = (cpu.s_reg - 1) & 0xFF;
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; \
100 cpu.p_reg &= ~(NES6502_B_FLAG); \
102 cpu.p_reg |= NES6502_I_FLAG; \
103 cpu.pc_reg = BANK_W (vector);
106 void nes6502_power (void)
109 cpu
.x_reg
= cpu
.y_reg
= 0;
111 cpu
.total_cycles
= 0;
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
;
123 cpu
.remaining_cycles
= 0;
126 void nes6502_halt (void)
129 cpu
.remaining_cycles
= 0;
132 int nes6502_ishalted (void)
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
;
152 IRQ_PROC (NES6502_IRQ_VECTOR
)
156 #ifdef DEBUGGER_ENABLED
158 int nes6502_checkaddr (uint32 addr
, int32 flags
)
161 for (i
= 0; i
< cpu
.num_bp
; i
++) {
162 if (cpu
.bp_flags
[i
] & NES6502_DEBUG_DISABLED
)
164 if (!(cpu
.bp_flags
[i
] & flags
))
166 if ((cpu
.bp_mask
[i
] & addr
) == cpu
.bp_addr
[i
])
173 int nes6502_checkstack (uint32 count
, int push
)
175 uint32 operp
= cpu
.s_reg
;
178 if (nes6502_checkaddr (NES6502_STACK_OFFSET
+ operp
, NES6502_DEBUG_WRITE
))
180 operp
= (operp
- 1) & 0xFF;
184 operp
= (operp
+ 1) & 0xFF;
185 if (nes6502_checkaddr (NES6502_STACK_OFFSET
+ operp
, NES6502_DEBUG_READ
))
193 void nes6502_debug (int first_insn
)
196 uint32 operp
, t1
, t2
;
198 struct nes6502_opcode
*opcode
;
199 enum nes6502_instruction insn
;
202 if (nes6502_checkaddr (cpu
.pc_reg
, NES6502_DEBUG_READ
))
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
))
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
) {
225 operp
= (uint32
) BANK (cpu
.pc_reg
+ 1);
226 if (nes6502_checkaddr (operp
, flags
)) goto bphit
;
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
;
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
;
237 operp
= BANK_W (cpu
.pc_reg
+ 1);
238 if (nes6502_checkaddr (operp
, flags
)) goto bphit
;
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
;
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
;
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
;
254 if (nes6502_checkaddr (operp
+ 1, NES6502_DEBUG_READ
)) goto bphit
;
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
;
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;
272 if (nes6502_checkaddr (operp
, flags
)) goto bphit
;
278 if (details
& I_ST
) {
279 if (details
& I_JP
) {
280 if (insn
== INSN_BRK
|| insn
== INSN_JSR
) {
282 if (insn
== INSN_BRK
) t2
= 3;
286 if (insn
== INSN_RTI
) t2
= 3;
291 if (insn
== INSN_PHA
|| insn
== INSN_PHP
) {
297 if (nes6502_checkstack (t2
, t1
))
304 (*cpu
.debug_handler
) (first_insn
);
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
);
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
)
335 if (bp
>= cpu
.num_bp
) return;
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)
352 int32
nes6502_execute (int32 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
;
362 if (cpu
.halted
) return 0;
363 old_cycles
= cpu
.total_cycles
;
366 cycles
= cpu
.burn_cycles
+ 1;
367 cpu
.remaining_cycles
= cycles
;
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) {
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) {
387 struct nes6502_opcode
*opcode
;
388 uint32 oper
= 0, operp
= 0, t
;
389 enum nes6502_instruction insn
;
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;
405 cpu
.total_cycles
+= opcode
->cycles
;
406 cpu
.remaining_cycles
-= opcode
->cycles
;
409 switch (opcode
->addressing
) {
410 case ADDR_ACCUMULATOR
:
414 oper
= (uint32
) BANK (cpu
.pc_reg
);
418 operp
= (uint32
) BANK (cpu
.pc_reg
);
419 oper
= (uint32
) ram
[operp
];
422 case ADDR_ZERO_PAGE_X
:
423 operp
= (BANK (cpu
.pc_reg
) + cpu
.x_reg
) & 0xFF;
427 case ADDR_ZERO_PAGE_Y
:
428 operp
= (BANK (cpu
.pc_reg
) + cpu
.y_reg
) & 0xFF;
433 operp
= BANK_W (cpu
.pc_reg
);
436 oper
= nes6502_readbyte (operp
);
438 case ADDR_ABSOLUTE_X
:
439 operp
= (BANK (cpu
.pc_reg
) + cpu
.x_reg
);
441 if (operp
& 0x100) cpu
.total_cycles
++;
442 operp
+= ((uint32
) BANK (cpu
.pc_reg
)) << 8;
446 oper
= nes6502_readbyte (operp
);
448 case ADDR_ABSOLUTE_Y
:
449 operp
= (BANK (cpu
.pc_reg
) + cpu
.y_reg
);
451 if (operp
& 0x100) cpu
.total_cycles
++;
452 operp
+= ((uint32
) BANK (cpu
.pc_reg
)) << 8;
456 oper
= nes6502_readbyte (operp
);
459 t
= BANK_W (cpu
.pc_reg
);
463 if ((t
& 0xFF) == 0xFF)
464 operp
|= ((uint32
) BANK (t
- 0xFF)) << 8;
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
471 case ADDR_INDIRECT_X
:
472 t
= (BANK (cpu
.pc_reg
) + cpu
.x_reg
) & 0xFF;
474 operp
= (uint32
) ram
[t
];
475 operp
|= ((uint32
) ram
[(t
+ 1) & 0xFF]) << 8;
477 oper
= nes6502_readbyte (operp
);
479 case ADDR_INDIRECT_Y
:
480 t
= BANK (cpu
.pc_reg
) & 0xFF;
482 operp
= ((uint32
) ram
[t
]) + cpu
.y_reg
;
483 if (operp
& 0x100) cpu
.total_cycles
++;
484 operp
+= ((uint32
) ram
[(t
+ 1) & 0xFF]) << 8;
487 oper
= nes6502_readbyte (operp
);
490 t
= BANK (cpu
.pc_reg
);
492 if (t
& 0x80) t
|= 0xFF00;
493 oper
= (cpu
.pc_reg
+ t
) & 0xFFFF;
503 case INSN_AAC
: /* Undocumented */
505 CHECK_ZERO_AND_SIGN (cpu
.a_reg
)
506 SET_CARRY (IF_ZERO ())
508 case INSN_AAX
: /* Undocumented */
509 oper
= cpu
.x_reg
& cpu
.a_reg
;
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
)
522 CHECK_ZERO_AND_SIGN (cpu
.a_reg
)
524 case INSN_ARR
: /* Undocumented */
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
)
533 SET_CARRY (oper
& 0x80)
534 oper
= (oper
<< 1) & 0xFF;
535 CHECK_ZERO_AND_SIGN (oper
)
538 case INSN_ASR
: /* Undocumented */
540 SET_CARRY (cpu
.a_reg
& 0x01)
542 SET_ZERO (cpu
.a_reg
== 0)
545 case INSN_ATX
: /* Undocumented */
546 cpu
.a_reg
= cpu
.x_reg
= ((cpu
.a_reg
| 0xEE) & oper
); /* Unpredictable */
547 CHECK_ZERO_AND_SIGN (oper
)
549 case INSN_AXA
: /* Undocumented */
550 oper
= cpu
.a_reg
& cpu
.x_reg
& ((uint8
) ((operp
>> 8) + 1)); /* Unpredictable */
553 case INSN_AXS
: /* Undocumented */
554 cpu
.x_reg
= ((cpu
.a_reg
& cpu
.x_reg
) - oper
);
555 SET_CARRY (cpu
.x_reg
< 0x100)
557 CHECK_ZERO_AND_SIGN (cpu
.x_reg
)
560 BRANCH_ON (!IF_CARRY ())
563 BRANCH_ON (IF_CARRY ())
566 BRANCH_ON (IF_ZERO ())
569 SET_SIGN (oper
& 0x80)
570 SET_OVERFLOW (oper
& 0x40)
571 SET_ZERO ((oper
& cpu
.a_reg
) == 0)
574 BRANCH_ON (IF_NEGATIVE ())
577 BRANCH_ON (!IF_ZERO ())
580 BRANCH_ON (!IF_NEGATIVE ())
583 /* RTI from break causes the next instruction to be ignored */
590 cpu
.pc_reg
= BANK_W (NES6502_IRQ_VECTOR
);
593 BRANCH_ON (!IF_OVERFLOW ())
596 BRANCH_ON (IF_OVERFLOW ())
606 if (cpu
.int_pending
&& cpu
.remaining_cycles
> 0) {
607 cpu
.int_pending
= FALSE
;
609 IRQ_PROC (NES6502_IRQ_VECTOR
)
616 oper
= cpu
.a_reg
- oper
;
617 SET_CARRY (oper
< 0x100)
619 CHECK_ZERO_AND_SIGN (oper
)
622 oper
= cpu
.x_reg
- oper
;
623 SET_CARRY (oper
< 0x100)
625 CHECK_ZERO_AND_SIGN (oper
)
628 oper
= cpu
.y_reg
- oper
;
629 SET_CARRY (oper
< 0x100)
631 CHECK_ZERO_AND_SIGN (oper
)
633 case INSN_DCP
: /* Undocumented */
634 oper
= (oper
- 1) & 0xFF;
636 oper
= cpu
.a_reg
- oper
;
637 SET_CARRY (oper
< 0x100)
639 CHECK_ZERO_AND_SIGN (oper
)
642 oper
= (oper
- 1) & 0xFF;
643 CHECK_ZERO_AND_SIGN (oper
)
647 cpu
.x_reg
= (cpu
.x_reg
- 1) & 0xFF;
648 CHECK_ZERO_AND_SIGN (cpu
.x_reg
)
651 cpu
.y_reg
= (cpu
.y_reg
- 1) & 0xFF;
652 CHECK_ZERO_AND_SIGN (cpu
.y_reg
)
654 case INSN_DOP
: /* Undocumented */
659 CHECK_ZERO_AND_SIGN (cpu
.a_reg
)
662 cpu
.remaining_cycles
= 0;
666 oper
= (oper
+ 1) & 0xFF;
667 CHECK_ZERO_AND_SIGN (oper
)
671 cpu
.x_reg
= (cpu
.x_reg
+ 1) & 0xFF;
672 CHECK_ZERO_AND_SIGN (cpu
.x_reg
)
675 cpu
.y_reg
= (cpu
.y_reg
+ 1) & 0xFF;
676 CHECK_ZERO_AND_SIGN (cpu
.y_reg
)
678 case INSN_ISC
: /* Undocumented */
679 oper
= (oper
+ 1) & 0xFF;
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
)
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
)
700 case INSN_LAX
: /* Undocumented */
701 cpu
.a_reg
= cpu
.x_reg
= oper
;
702 CHECK_ZERO_AND_SIGN (cpu
.a_reg
)
706 CHECK_ZERO_AND_SIGN (cpu
.a_reg
)
710 CHECK_ZERO_AND_SIGN (cpu
.x_reg
)
714 CHECK_ZERO_AND_SIGN (cpu
.y_reg
)
717 SET_CARRY (oper
& 0x01)
727 CHECK_ZERO_AND_SIGN (cpu
.a_reg
)
738 CHECK_ZERO_AND_SIGN (cpu
.a_reg
)
744 case INSN_RLA
: /* Undocumented */
746 if (IF_CARRY ()) oper
|= 0x01;
747 SET_CARRY (oper
& 0x100)
751 CHECK_ZERO_AND_SIGN (cpu
.a_reg
)
755 if (IF_CARRY ()) oper
|= 0x01;
756 SET_CARRY (oper
& 0x100)
758 CHECK_ZERO_AND_SIGN (oper
)
762 if (IF_CARRY ()) oper
|= 0x100;
763 SET_CARRY (oper
& 0x01)
765 CHECK_ZERO_AND_SIGN (oper
)
768 case INSN_RRA
: /* Undocumented */
769 if (IF_CARRY ()) oper
|= 0x100;
770 SET_CARRY (oper
& 0x01)
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
)
784 if (!IF_INTERRUPT () && cpu
.int_pending
&& cpu
.remaining_cycles
> 0) {
785 cpu
.int_pending
= FALSE
;
786 IRQ_PROC (NES6502_IRQ_VECTOR
)
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
)
810 case INSN_SLO
: /* Undocumented */
811 SET_CARRY (oper
& 0x80)
812 oper
= (oper
<< 1) & 0xFF;
815 CHECK_ZERO_AND_SIGN (cpu
.a_reg
)
817 case INSN_SRE
: /* Undocumented */
818 SET_CARRY (oper
& 0x01)
822 CHECK_ZERO_AND_SIGN (cpu
.a_reg
)
825 nes6502_writebyte (operp
, cpu
.a_reg
);
828 nes6502_writebyte (operp
, cpu
.x_reg
);
831 nes6502_writebyte (operp
, cpu
.y_reg
);
833 case INSN_SXA
: /* Undocumented */
834 oper
= cpu
.x_reg
& ((operp
>> 8) + 1); /* Unpredictable */
837 case INSN_SYA
: /* Undocumented */
838 oper
= cpu
.y_reg
& ((operp
>> 8) + 1); /* Unpredictable */
842 cpu
.x_reg
= cpu
.a_reg
;
843 CHECK_ZERO_AND_SIGN (cpu
.x_reg
)
846 cpu
.y_reg
= cpu
.a_reg
;
847 CHECK_ZERO_AND_SIGN (cpu
.y_reg
)
849 case INSN_TOP
: /* Undocumented */
853 cpu
.x_reg
= cpu
.s_reg
;
854 CHECK_ZERO_AND_SIGN (cpu
.x_reg
)
857 cpu
.a_reg
= cpu
.x_reg
;
858 CHECK_ZERO_AND_SIGN (cpu
.a_reg
)
861 cpu
.s_reg
= cpu
.x_reg
;
864 cpu
.a_reg
= cpu
.y_reg
;
865 CHECK_ZERO_AND_SIGN (cpu
.a_reg
)
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
)
871 case INSN_XAS
: /* Undocumented */
872 cpu
.s_reg
= cpu
.x_reg
& cpu
.a_reg
;
873 oper
= cpu
.s_reg
& ((operp
>> 8) + 1);
881 return (cpu
.total_cycles
- old_cycles
);
884 /* read a byte from 6502 memory */
885 uint8
nes6502_readbyte (uint32 address
)
887 if (address
< 0x800) {
889 } else if (address
< 0x8000) {
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
;
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
);
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
)
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
)
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