Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
cpu65.c
Go to the documentation of this file.
1 /* Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
2  Copyright (C)2016-2022 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
3 
4  THIS IS AN UGLY PIECE OF SOURCE REALLY.
5 
6  Quite confusing comment section even at the beginning, from this point ...
7 
8  | This file tries to implement a 65C02, 65CE02 (as the form used in 4510 in C65,
9  | also with its extension in the MEGA65) and the NMOS 6502. This is kinda buggy
10  | overal-behavioural emulation, ie there is some on-going tries for correct number
11  | of cycles execution, but not for in-opcode timing.
12  |
13  | Note: the original solution was *generated* source, that can explain the structure.
14  | Note: it was written in JavaScript, but the conversion to C and custom modification
15  | Note: does not use this generation scheme anymore.
16  |
17  | BUGS/TODO:
18  |
19  | * Unimplemented illegal NMOS opcodes
20  | * Incorrect timings in many cases
21  | * Future plan to support NMOS CPU persona for MEGA65 in C64 mode
22  | * At many cases, emulation should be tested for correct opcode emulation behaviour
23 
24 This program is free software; you can redistribute it and/or modify
25 it under the terms of the GNU General Public License as published by
26 the Free Software Foundation; either version 2 of the License, or
27 (at your option) any later version.
28 
29 This program is distributed in the hope that it will be useful,
30 but WITHOUT ANY WARRANTY; without even the implied warranty of
31 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 GNU General Public License for more details.
33 
34 You should have received a copy of the GNU General Public License
35 along with this program; if not, write to the Free Software
36 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
37 
38 /* Original information/copyright (also written by me):
39  * Commodore LCD emulator, C version.
40  * (C)2013,2014 LGB Gabor Lenart
41  * Visit my site (the better, JavaScript version of the emu is here too): http://commodore-lcd.lgb.hu/
42  * Can be distributed/used/modified under the terms of GNU/GPL 2 (or later), please see file COPYING
43  * or visit this page: http://www.gnu.org/licenses/gpl-2.0.html
44  */
45 
47 #ifndef CPU_CUSTOM_INCLUDED
48 #include "xemu/cpu65.h"
49 #endif
50 
51 #ifdef MEGA65
52 #include "hypervisor.h"
53 #endif
54 
55 #ifdef DEBUG_CPU
57 #endif
58 
59 
60 struct cpu65_st CPU65;
61 
62 
63 #ifdef CPU_65CE02
64 #define SP_HI CPU65.sphi
65 #define ZP_HI CPU65.bphi
66 #define ZERO_REG CPU65.z
67 #define CPU_TYPE "65CE02"
68 #else
69 #define SP_HI 0x100
70 #define ZP_HI 0
71 #ifdef CPU_6502_NMOS_ONLY
72 #define CPU_TYPE "6502"
73 #else
74 #define CPU_TYPE "65C02"
75 #endif
76 #define ZERO_REG 0
77 #endif
78 
79 #define A_OP(op,dat) CPU65.a = CPU65.a op dat
80 
81 
82 #ifdef MEGA65
83 static int mega65_fastclock_1_penalty;
84 static int mega65_fastclock_2_penalty;
85 #define PREFIX_NOTHING 0
86 #define PREFIX_NOP 1
87 #define PREFIX_NEG_NEG 2
88 // Note: it's important to tell here, that NEG NEG NOP prefix still can mean only NOP, in case of a GS opcode
89 // does not support the NEG NEG NOP but does the NOP. If there is any of those ...
90 // That is, you can interpret bit 0 of PREFIX signal to test if there is NOP prefix, and bit 1 for NEG NEG, both bits
91 // for NEG NEG NOP, other higher bits MUST be excluded (see PREFIX_NEG alone, below!)
92 #define PREFIX_NEG_NEG_NOP 3
93 // Note: NEG itself is not a prefix, but needed as a stage to get to NEG_NEG if the second NEG appears after
94 #define PREFIX_NEG 4
95 static XEMU_INLINE Uint32 AXYZ_GET ( void ) {
96  return (Uint32)CPU65.a | ((Uint32)CPU65.x << 8) | ((Uint32)CPU65.y << 16) | ((Uint32)CPU65.z << 24);
97 }
98 static XEMU_INLINE Uint32 AXYZ_SET ( const Uint32 val ) {
99  CPU65.a = val & 0xFF;
100  CPU65.x = (val >> 8) & 0xFF;
101  CPU65.y = (val >> 16) & 0xFF;
102  CPU65.z = (val >> 24);
103  return val;
104 }
105 #endif
106 
107 
108 #ifdef CPU_65CE02
109 # ifdef DEBUG_CPU
110 # define OPC_65CE02(w) DEBUG("CPU: 65CE02 opcode: %s" NL, w)
111 # else
112 # define OPC_65CE02(w)
113 # endif
114 #endif
115 
116 #define TIMINGS_65CE02_ {7,5,2,2,4,3,4,4,3,2,1,1,5,4,5,4,2,5,5,3,4,3,4,4,1,4,1,1,5,4,5,4,5,5,7,7,3,3,4,4,3,2,1,1,4,4,5,4,2,5,5,3,3,3,4,4,1,4,1,1,4,4,5,4,5,5,2,2,4,3,4,4,3,2,1,1,3,4,5,4,2,5,5,3,4,3,4,4,2,4,3,1,4,4,5,4,4,5,7,5,3,3,4,4,3,2,1,1,5,4,5,4,2,5,5,3,3,3,4,4,2,4,3,1,5,4,5,4,2,5,6,3,3,3,3,4,1,2,1,4,4,4,4,4,2,5,5,3,3,3,3,4,1,4,1,4,4,4,4,4,2,5,2,2,3,3,3,4,1,2,1,4,4,4,4,4,2,5,5,3,3,3,3,4,1,4,1,4,4,4,4,4,2,5,2,6,3,3,4,4,1,2,1,7,4,4,5,4,2,5,5,3,3,3,4,4,1,4,3,3,4,4,5,4,2,5,6,6,3,3,4,4,1,2,1,7,4,4,5,4,2,5,5,3,5,3,4,4,1,4,3,3,7,4,5,4} // 65CE02 timing (my findings)
117 #define TIMINGS_65CE02 {7,5,2,2,4,3,4,4,3,2,1,1,5,4,5,4,2,5,5,3,4,3,4,4,1,4,1,1,5,4,5,4,2,5,7,7,4,3,4,4,3,2,1,1,5,4,4,4,2,5,5,3,4,3,4,4,1,4,1,1,5,4,5,4,5,5,2,2,4,3,4,4,3,2,1,1,3,4,5,4,2,5,5,3,4,3,4,4,1,4,3,3,4,4,5,4,4,5,7,5,3,3,4,4,3,2,1,1,5,4,5,4,2,5,5,3,3,3,4,4,2,4,3,1,5,4,5,4,2,5,6,3,3,3,3,4,1,2,1,4,4,4,4,4,2,5,5,3,3,3,3,4,1,4,1,4,4,4,4,4,2,5,2,2,3,3,3,4,1,2,1,4,4,4,4,4,2,5,5,3,3,3,3,4,1,4,1,4,4,4,4,4,2,5,2,6,3,3,4,4,1,2,1,7,4,4,5,4,2,5,5,3,3,3,4,4,1,4,3,3,4,4,5,4,2,5,6,6,3,3,4,4,1,2,1,6,4,4,5,4,2,5,5,3,5,3,4,4,1,4,3,3,7,4,5,4} // 65CE02 timing (from gs4510.vhdl)
118 #define TIMINGS_6502C65 {7,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,2,5,5,8,4,4,6,6,2,4,2,7,4,4,7,7,6,6,7,8,3,3,5,5,4,2,2,2,4,4,6,6,2,5,5,8,4,4,6,6,2,4,2,7,4,4,7,7,6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,2,5,5,8,4,4,6,6,2,4,2,7,4,4,7,7,6,6,7,8,3,3,5,5,4,2,2,2,5,4,6,6,2,5,5,8,4,4,6,6,2,4,2,7,4,4,7,7,2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,2,6,5,6,4,4,4,4,2,5,2,5,5,5,5,5,2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,2,5,5,5,4,4,4,4,2,4,2,4,4,4,4,4,2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,2,5,5,8,4,4,6,6,2,4,2,7,4,4,7,7,2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,2,5,5,8,4,4,6,6,2,4,2,7,4,4,7,7} // 65CE02 with "dead cycles" to mimic NMOS 6502
119 #define TIMINGS_6502MOS {7,6,0,8,3,3,5,5,3,2,2,2,4,4,6,6,2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,6,6,0,8,3,3,5,5,4,2,2,2,4,4,6,6,2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,6,6,0,8,3,3,5,5,3,2,2,2,3,4,6,6,2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,6,6,0,8,3,3,5,5,4,2,2,2,5,4,6,6,2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,2,6,0,6,4,4,4,4,2,5,2,5,5,5,5,5,2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,2,5,0,5,4,4,4,4,2,4,2,4,4,4,4,4,2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7} // NMOS timing
120 #define TIMINGS_65C02 {7,6,2,2,5,3,5,5,3,2,2,2,6,4,6,2,2,5,5,2,5,4,6,5,2,4,2,2,6,4,7,2,6,6,2,2,3,3,5,5,4,2,2,2,4,4,6,2,2,5,5,2,4,4,6,5,2,4,2,2,4,4,7,2,6,6,2,2,3,3,5,5,3,2,2,2,3,4,6,2,2,5,5,2,4,4,6,5,2,4,3,2,2,4,7,2,6,6,2,2,3,3,5,5,4,2,2,2,5,4,6,2,2,5,5,2,4,4,6,5,2,4,4,2,6,4,7,2,3,6,2,2,3,3,3,5,2,2,2,2,4,4,4,2,2,6,5,2,4,4,4,5,2,5,2,2,4,5,5,2,2,6,2,2,3,3,3,5,2,2,2,2,4,4,4,2,2,5,5,2,4,4,4,5,2,4,2,2,4,4,4,2,2,6,2,2,3,3,5,5,2,2,2,2,4,4,6,2,2,5,5,2,4,4,6,5,2,4,3,2,2,4,7,2,2,6,2,2,3,3,5,5,2,2,2,2,4,4,6,2,2,5,5,2,4,4,6,5,2,4,4,2,2,4,7,2} // 65C02 timing
121 
122 #ifdef CPU_65CE02
123 # ifdef CPU65_65CE02_6502NMOS_TIMING_EMULATION
124  static const Uint8 opcycles_slow_mode[0x100] = TIMINGS_6502C65;
125  // static const Uint8 opcycles_fast_mode[0x100] = TIMINGS_65CE02_;
126  static const Uint8 opcycles_fast_mode[0x100] = TIMINGS_65CE02;
127  static const Uint8 *opcycles = opcycles_fast_mode;
128 # ifdef MEGA65
129  static Uint8 opcycles_ultra_mode[0x100]; // "ultra" = MEGA65-fast (~40MHz) timing, compared to C65-fast (~3.5MHz) timing. We want to calculate this
130 # endif
131  // FIXME: this must be extended to support three different modes, one additional for MEGA65 native speed!
132  // as regular 65CE02 opcodes can be LONGER at native MEGA65 fast mode than on 65CE02!!!!!
133  void cpu65_set_timing ( unsigned int mode ) {
134  switch (mode) {
135  case 0:
136  opcycles = opcycles_slow_mode;
137 # ifdef MEGA65
138  mega65_fastclock_1_penalty = 0;
139  mega65_fastclock_2_penalty = 0;
140 # endif
141  break;
142  default:
143  opcycles = opcycles_fast_mode;
144 # ifdef MEGA65
145  mega65_fastclock_1_penalty = 0;
146  mega65_fastclock_2_penalty = 0;
147 # endif
148  break;
149 # ifdef MEGA65
150  case 2:
151  opcycles = opcycles_fast_mode; // FIXME: XXX see the next line and its comment ;)
152  //opcycles = opcycles_ultra_mode; // FIXME: XXX constuct the "ultra" (ie 40MHz timing) table for MEGA65 and use here!!
153  mega65_fastclock_1_penalty = 1;
154  mega65_fastclock_2_penalty = 2;
155  break;
156 # endif
157  }
158  }
159 # else
160  //static const Uint8 opcycles[0x100] = TIMINGS_65CE02_;
161  static const Uint8 opcycles[0x100] = TIMINGS_65CE02;
162 #endif
163 #else
164 # ifdef CPU_6502_NMOS_ONLY
165  static const Uint8 opcycles[0x100] = TIMINGS_6502MOS;
166 # else
167  static const Uint8 opcycles[0x100] = TIMINGS_65C02;
168 # endif
169 #endif
170 
171 #ifdef MEGA65
172 void cpu65_init_mega_specific ( void )
173 {
174  for (int a = 0; a < 0x100; a++) {
175  opcycles_ultra_mode[a] = opcycles_fast_mode[a];
176  }
177 }
178 #endif
179 
180 #ifndef CPU65_DISCRETE_PF_NZ
181 #define VALUE_TO_PF_ZERO(a) ((a) ? 0 : CPU65_PF_Z)
182 #endif
183 
184 #ifdef CPU65_DISCRETE_PF_NZ
185 # define ASSIGN_PF_Z_BY_COND(a) CPU65.pf_z = (a)
186 # define ASSIGN_PF_N_BY_COND(a) CPU65.pf_n = (a)
187 #else
188 # define ASSIGN_PF_Z_BY_COND(a) do { if (a) CPU65.pf_nz |= CPU65_PF_Z; else CPU65.pf_nz &= ~CPU65_PF_Z; } while(0)
189 # define ASSIGN_PF_N_BY_COND(a) do { if (a) CPU65.pf_nz |= CPU65_PF_N; else CPU65.pf_nz &= ~CPU65_PF_N; } while(0)
190 #endif
191 
192 
193 #define writeFlatAddressedByte(d) cpu65_write_linear_opcode_callback(d)
194 #define readFlatAddressedByte() cpu65_read_linear_opcode_callback()
195 
196 #define writeFlatAddressedQuadWithZ(d) cpu65_write_linear_long_opcode_callback(CPU65.z, d)
197 #define readFlatAddressedQuadWithZ() cpu65_read_linear_long_opcode_callback(CPU65.z)
198 #define writeFlatAddressedQuadWithoutZ(d) cpu65_write_linear_long_opcode_callback(0, d)
199 #define readFlatAddressedQuadWithoutZ() cpu65_read_linear_long_opcode_callback(0)
200 #ifdef CPU65_NO_RMW_EMULATION
201 #define writeByteTwice(a,od,nd) cpu65_write_callback(a,nd)
202 #else
203 #define writeByteTwice(a,od,nd) cpu65_write_rmw_callback(a,od,nd)
204 #endif
205 #define writeByte(a,d) cpu65_write_callback(a,d)
206 #define readByte(a) cpu65_read_callback(a)
207 
208 
209 /* Three possible behaviour in term of operating mode:
210  * NMOS 6502 CPU core only (CPU_6502_NMOS_ONLY is defined)
211  * 65C02/65CE02 mode only (real 65CE02 - Commodore 65 - or 65C02 - Commodore LCD) depending to CPU_65CE02 defined or not
212  * MEGA65, having NMOS persona _AS_WELL_ (CPU_65CE02 and MEGA65 macros are defined) */
213 
214 #ifdef CPU_6502_NMOS_ONLY
215 /* NMOS CPU mode only, for emulators like VIC-20, etc. We define IS_CPU_NMOS as a constant 1, hopefully the C compiler is smart enough
216  to see, that is an always true statement used with 'if', thus it won't generate any condition when used that way */
217 #define IS_CPU_NMOS 1
218 #define NMOS_JAM_OPCODE() cpu65_illegal_opcode_callback()
219 #define HAS_NMOS_BUG_JMP_INDIRECT 1
220 #define HAS_NMOS_BUG_NO_PFD_RES_ON_INT 1
221 #define HAS_NMOS_BUG_BCD 1
222 #else
223 #ifdef MEGA65
224 /* MEGA65 supports NMOS CPU persona as well, however the main performance bottleneck is more like the 50MHz 4510 mode, thus it's hinted as "unlikely" for the C compiler */
225 #define IS_CPU_NMOS XEMU_UNLIKELY(CPU65.nmos_mode)
226 #define NMOS_JAM_OPCODE() cpu65_illegal_opcode_callback()
227 #define HAS_NMOS_BUG_JMP_INDIRECT M65_CPU_ALWAYS_BUG_JMP_INDIRECT || (M65_CPU_NMOS_ONLY_BUG_JMP_INDIRECT && CPU65.nmos_mode)
228 #define HAS_NMOS_BUG_NO_PFD_RES_ON_INT M65_CPU_ALWAYS_BUG_NO_RESET_PFD_ON_INT || (M65_CPU_NMOS_ONLY_BUG_NO_RESET_PFD_ON_INT && CPU65.nmos_mode)
229 //#define HAS_NMOS_BUG_BCD M65_CPU_ALWAYS_BUG_BCD || (M65_CPU_NMOS_ONLY_BUG_BCD && CPU65.nmos_mode)
230 // Note: it seems MEGA65 is special, and would have the 6502-semantic of BCD even in native, etc mode!! This is NOT true for C65, for example!
231 #define HAS_NMOS_BUG_BCD 1
232 #else
233 /* 65C02 mode, eg for Commodore LCD or 65CE02 mode for Commodore 65 (based on the macro of CPU_65CE02). We define IS_CPU_NMOS as a constant 0, hopefully the C compiler is smart enough
234  to see, that is an always true statement used with 'if', thus it won't generate any condition when used that way.
235  NMOS_JAM_OPCODE() is a null-op, as it won't be ever referenced. */
236 #define IS_CPU_NMOS 0
237 #define NMOS_JAM_OPCODE()
238 #define HAS_NMOS_BUG_JMP_INDIRECT 0
239 #define HAS_NMOS_BUG_NO_PFD_RES_ON_INT 0
240 #define HAS_NMOS_BUG_BCD 0
241 #endif
242 #endif
243 
244 
245 
246 static XEMU_INLINE Uint16 readWord ( const Uint16 addr ) {
247  return readByte(addr) | (readByte(addr + 1) << 8);
248 }
249 
250 
251 #ifdef MEGA65
252 static inline Uint32 readQuad ( const Uint16 addr ) {
253  return
254  readByte(addr ) |
255  (readByte(addr + 1) << 8) |
256  (readByte(addr + 2) << 16) |
257  (readByte(addr + 3) << 24)
258  ;
259 }
260 
261 static inline void writeQuad ( const Uint16 addr, const Uint32 data ) {
262  writeByte(addr , data & 0xFF);
263  writeByte(addr + 1, (data >> 8) & 0xFF);
264  writeByte(addr + 2, (data >> 16) & 0xFF);
265  writeByte(addr + 3, (data >> 24) & 0xFF);
266 }
267 #endif
268 
269 
270 #ifdef CPU_65CE02
271 /* The stack pointer is a 16 bit register that has two modes. It can be programmed to be either an 8-bit page Programmable pointer, or a full 16-bit pointer.
272  The processor status E bit selects which mode will be used. When set, the E bit selects the 8-bit mode. When reset, the E bit selects the 16-bit mode. */
273 
274 static XEMU_INLINE void push ( const Uint8 data )
275 {
276  writeByte(CPU65.s | CPU65.sphi, data);
277  CPU65.s--;
278  if (XEMU_UNLIKELY(CPU65.s == 0xFF && (!CPU65.pf_e))) {
279  CPU65.sphi -= 0x100;
280 #ifdef DEBUG_CPU
281  DEBUG("CPU: 65CE02: SPHI changed to $%04X" NL, CPU65.sphi);
282 #endif
283  }
284 }
285 static XEMU_INLINE Uint8 pop ( void )
286 {
287  CPU65.s++;
288  if (XEMU_UNLIKELY(CPU65.s == 0 && (!CPU65.pf_e))) {
289  CPU65.sphi += 0x100;
290 #ifdef DEBUG_CPU
291  DEBUG("CPU: 65CE02: SPHI changed to $%04X" NL, CPU65.sphi);
292 #endif
293  }
294  return readByte(CPU65.s | CPU65.sphi);
295 }
296 #else
297 #define push(data) writeByte(((Uint8)(CPU65.s--)) | SP_HI, data)
298 #define pop() readByte(((Uint8)(++CPU65.s)) | SP_HI)
299 #endif
300 
301 static XEMU_INLINE void pushWord ( const Uint16 data ) { push(data >> 8); push(data & 0xFF); }
302 static XEMU_INLINE Uint16 popWord ( void ) { const Uint16 temp = pop(); return temp | (pop() << 8); }
303 
304 
305 #ifdef CPU_65CE02
306 // FIXME: remove this, if we don't need!
307 // NOTE!! Interesting, it seems PHW opcodes pushes the word the OPPOSITE direction as eg JSR would push the PC ...
308 #define PUSH_FOR_PHW pushWord_rev
309 static XEMU_INLINE void pushWord_rev ( const Uint16 data ) { push(data & 0xFF); push(data >> 8); }
310 #endif
311 
312 
313 void cpu65_set_pf ( const Uint8 st ) {
314 #ifdef CPU65_DISCRETE_PF_NZ
315  CPU65.pf_n = st & CPU65_PF_N;
316  CPU65.pf_z = st & CPU65_PF_Z;
317 #else
319 #endif
320  CPU65.pf_v = st & CPU65_PF_V;
321 #ifdef CPU_65CE02
322  // Note: E bit cannot be changed by PLP/RTI, so it's commented out here ...
323  // At least *I* think :) FIXME?
324  // CPU65.pf_e = st & CPU65_PF_E;
325 #endif
326  CPU65.pf_d = st & CPU65_PF_D;
327  CPU65.pf_i = st & CPU65_PF_I;
328  CPU65.pf_c = st & CPU65_PF_C;
329 }
330 
331 Uint8 cpu65_get_pf ( void ) {
332  return
333 #ifdef CPU65_DISCRETE_PF_NZ
334  (CPU65.pf_n ? CPU65_PF_N : 0) | (CPU65.pf_z ? CPU65_PF_Z : 0)
335 #else
336  CPU65.pf_nz
337 #endif
338  |
339  (CPU65.pf_v ? CPU65_PF_V : 0) |
340 #ifdef CPU_65CE02
341  // FIXME: for M65 in NMOS-persona, some should always force '1' here,
342  // however, that's a bit cryptic for me, as it would be simplier to actual E flag
343  // would be 1, as for NMOS, the stack should be not in 16 bits mode, I guess ...
344  (CPU65.pf_e ? CPU65_PF_E : 0) |
345 #else
346  CPU65_PF_E |
347 #endif
348  (CPU65.pf_d ? CPU65_PF_D : 0) |
349  (CPU65.pf_i ? CPU65_PF_I : 0) |
350  (CPU65.pf_c ? CPU65_PF_C : 0);
351 }
352 
353 void cpu65_reset ( void ) {
354  cpu65_set_pf(0x34);
355  CPU65.s = 0xFF;
356  CPU65.irqLevel = CPU65.nmiEdge = 0;
357  CPU65.op_cycles = 0;
358  CPU65.a = 0;
359  CPU65.x = 0;
360  CPU65.y = 0;
361 #ifdef CPU_65CE02
362  CPU65.pf_e = 1;
363  CPU65.z = 0;
364  CPU65.bphi = 0x0000;
365  CPU65.sphi = 0x0100;
366  CPU65.cpu_inhibit_interrupts = 0;
367 #endif
368 #ifdef MEGA65
369  CPU65.nmos_mode = 0;
370  CPU65.prefix = PREFIX_NOTHING;
371 #endif
372  CPU65.pc = readWord(0xFFFC);
373  DEBUGPRINT("CPU[" CPU_TYPE "]: RESET, PC=%04X, BCD_behaviour=%s" NL,
374  CPU65.pc, // FIXME
375  HAS_NMOS_BUG_BCD ? "NMOS-6502" : "65C02+"
376  );
377 }
378 
379 
380 static XEMU_INLINE void SET_NZ ( const Uint8 st ) {
381 #ifdef CPU65_DISCRETE_PF_NZ
382  CPU65.pf_n = st & CPU65_PF_N;
383  CPU65.pf_z = !st;
384 #else
386 #endif
387 }
388 
389 #ifdef CPU_65CE02
390 static XEMU_INLINE void SET_NZ16 ( const Uint16 st ) {
391 #ifdef CPU65_DISCRETE_PF_NZ
392  CPU65.pf_n = st & 0x8000;
393  CPU65.pf_z = !st;
394 #else
395  CPU65.pf_nz = ((st & 0x8000) >> 8) | VALUE_TO_PF_ZERO(st);
396 #endif
397 }
398 #endif
399 
400 #ifdef MEGA65
401 #define BIT31 0x80000000U
402 #define BIT30 0x40000000U
403 static XEMU_INLINE void SET_NZ32 ( const Uint32 st ) {
404 #ifdef CPU65_DISCRETE_PF_NZ
405  CPU65.pf_n = st & BIT31;
406  CPU65.pf_z = !st;
407 #else
408  CPU65.pf_nz = ((st & BIT31) >> 24) | VALUE_TO_PF_ZERO(st);
409 #endif
410 }
411 #endif
412 
413 
414 #define _imm() (CPU65.pc++)
415 static XEMU_INLINE Uint16 _abs ( void ) {
416  Uint16 o = readByte(CPU65.pc++);
417  return o | (readByte(CPU65.pc++) << 8);
418 }
419 #define _absx() ((Uint16)(_abs() + CPU65.x))
420 #define _absy() ((Uint16)(_abs() + CPU65.y))
421 #define _absi() readWord(_abs())
422 #define _absxi() readWord(_absx())
423 #define _zp() (readByte(CPU65.pc++) | ZP_HI)
424 
425 static XEMU_INLINE Uint16 _zpi ( void ) {
426  Uint8 a = readByte(CPU65.pc++);
427 #ifdef CPU_65CE02
428  return (readByte(a | ZP_HI) | (readByte(((a + 1) & 0xFF) | ZP_HI) << 8)) + CPU65.z;
429 #else
430  return readByte(a | ZP_HI) | (readByte(((a + 1) & 0xFF) | ZP_HI) << 8);
431 #endif
432 }
433 
434 #ifdef MEGA65
435 static XEMU_INLINE Uint16 _zpi_noz ( void ) {
436  const Uint8 a = readByte(CPU65.pc++);
437  return readByte(a | ZP_HI) | (readByte(((a + 1) & 0xFF) | ZP_HI) << 8);
438 }
439 #endif
440 
441 static XEMU_INLINE Uint16 _zpiy ( void ) {
442  Uint8 a = readByte(CPU65.pc++);
443  return (readByte(a | ZP_HI) | (readByte(((a + 1) & 0xFF) | ZP_HI) << 8)) + CPU65.y;
444 }
445 
446 
447 #define _zpx() (((readByte(CPU65.pc++) + CPU65.x) & 0xFF) | ZP_HI)
448 #define _zpy() (((readByte(CPU65.pc++) + CPU65.y) & 0xFF) | ZP_HI)
449 
450 static XEMU_INLINE Uint16 _zpxi ( void ) {
451  Uint8 a = readByte(CPU65.pc++) + CPU65.x;
452  return readByte(a | ZP_HI) | (readByte(((a + 1) & 0xFF) | ZP_HI) << 8);
453 }
454 
455 static XEMU_INLINE void _BRA ( const int cond ) {
456  if (cond) {
457  int temp = readByte(CPU65.pc);
458  if (temp & 128) temp = CPU65.pc - (temp ^ 0xFF);
459  else temp = CPU65.pc + temp + 1;
460  if ((temp & 0xFF00) != (CPU65.pc & 0xFF00)) CPU65.op_cycles++;
461  CPU65.pc = temp;
462  CPU65.op_cycles++;
463  } else
464  CPU65.pc++;
465 }
466 #ifdef CPU_65CE02
467 static XEMU_INLINE void _BRA16 ( const int cond ) {
468  if (cond) {
469  // Note: 16 bit PC relative stuffs works a bit differently as 8 bit ones, not the same base of the offsets!
470  CPU65.pc += 1 + (Sint16)(readByte(CPU65.pc) | (readByte(CPU65.pc + 1) << 8));
471  CPU65.op_cycles++;
472  } else
473  CPU65.pc += 2;
474 }
475 // Used by LDA/STA (nn,SP), Y opcodes
476 /* Big fat NOTE/FIXME/TODO:
477  See the question #1/2, even two places where stack 'warping around' effect can
478  be an interesting question in 8 bit stack mode.
479 */
480 static XEMU_INLINE Uint16 _GET_SP_INDIRECT_ADDR ( void )
481 {
482  int tmp2;
483  int tmp = CPU65.s + readByte(CPU65.pc++);
484  if (CPU65.pf_e) // FIXME: question #1: is E flag affects this addressing mode this way
485  tmp &= 0xFF;
486  tmp2 = readByte((CPU65.sphi + tmp) & 0xFFFF);
487  tmp++;
488  if (CPU65.pf_e) // FIXME: question #2: what happens if lo/hi bytes would be used at exactly at 'wrapping the stack' around case, with 8 bit stack mode?
489  tmp &= 0xFF;
490  tmp2 |= readByte((CPU65.sphi + tmp) & 0xFFFF) << 8;
491  return (Uint16)(tmp2 + CPU65.y);
492 }
493 #endif
494 static XEMU_INLINE void _CMP ( const Uint8 reg, const Uint8 data ) {
495  Uint16 temp = reg - data;
496  CPU65.pf_c = temp < 0x100;
497  SET_NZ(temp);
498 }
499 static XEMU_INLINE void _TSB ( const int addr ) {
500  Uint8 m = readByte(addr);
501 #ifdef CPU65_DISCRETE_PF_NZ
502  CPU65.pf_z = (!(m & CPU65.a));
503 #else
504  if (m & CPU65.a) CPU65.pf_nz &= (~CPU65_PF_Z); else CPU65.pf_nz |= CPU65_PF_Z;
505 #endif
506  writeByte(addr, m | CPU65.a);
507 }
508 static XEMU_INLINE void _TRB ( const int addr ) {
509  Uint8 m = readByte(addr);
510 #ifdef CPU65_DISCRETE_PF_NZ
511  CPU65.pf_z = (!(m & CPU65.a));
512 #else
513  if (m & CPU65.a) CPU65.pf_nz &= (~CPU65_PF_Z); else CPU65.pf_nz |= CPU65_PF_Z;
514 #endif
515  writeByte(addr, m & (255 - CPU65.a));
516 }
517 static XEMU_INLINE void _ASL ( const int addr ) {
518  Uint8 t = (addr == -1 ? CPU65.a : readByte(addr));
519  Uint8 o = t;
520  CPU65.pf_c = t & 128;
521  //t = (t << 1) & 0xFF;
522  t <<= 1;
523  SET_NZ(t);
524  if (addr == -1) CPU65.a = t; else writeByteTwice(addr, o, t);
525 }
526 static XEMU_INLINE void _LSR ( const int addr ) {
527  Uint8 t = (addr == -1 ? CPU65.a : readByte(addr));
528  Uint8 o = t;
529  CPU65.pf_c = t & 1;
530  //t = (t >> 1) & 0xFF;
531  t >>= 1;
532  SET_NZ(t);
533  if (addr == -1) CPU65.a = t; else writeByteTwice(addr, o, t);
534 }
535 #ifdef CPU_65CE02
536 static XEMU_INLINE void _ASR ( const int addr ) {
537  Uint8 t = (addr == -1 ? CPU65.a : readByte(addr));
538  Uint8 o = t;
539  CPU65.pf_c = t & 1;
540  t = (t >> 1) | (t & 0x80);
541  SET_NZ(t);
542  if (addr == -1) CPU65.a = t; else writeByteTwice(addr, o, t);
543 }
544 #endif
545 static XEMU_INLINE void _BIT ( const Uint8 data ) {
546  CPU65.pf_v = data & 64;
547 #ifdef CPU65_DISCRETE_PF_NZ
548  CPU65.pf_n = data & CPU65_PF_N;
549  CPU65.pf_z = (!(CPU65.a & data));
550 #else
552 #endif
553 }
554 static XEMU_INLINE void _ADC ( const unsigned int data ) {
555  if (XEMU_UNLIKELY(CPU65.pf_d)) {
556  if (HAS_NMOS_BUG_BCD) {
557  /* This algorithm was written according the one found in VICE: 6510core.c */
558  unsigned int temp = (CPU65.a & 0xF) + (data & 0xF) + (CPU65.pf_c ? 1 : 0);
559  if (temp > 0x9)
560  temp += 6;
561  if (temp <= 0x0F)
562  temp = (temp & 0xF) + (CPU65.a & 0xF0) + (data & 0xF0);
563  else
564  temp = (temp & 0xF) + (CPU65.a & 0xF0) + (data & 0xF0) + 0x10;
565  ASSIGN_PF_Z_BY_COND(!((CPU65.a + data + (CPU65.pf_c ? 1 : 0)) & 0xFF));
566  ASSIGN_PF_N_BY_COND(temp & 0x80);
567  CPU65.pf_v = (((CPU65.a ^ temp) & 0x80) && !((CPU65.a ^ data) & 0x80));
568  if ((temp & 0x1F0) > 0x90)
569  temp += 0x60;
570  CPU65.pf_c = ((temp & 0xFF0) > 0xF0);
571  CPU65.a = temp & 0xFF;
572  } else {
573  /* This algorithm was written according the one found in VICE: 65c02core.c */
574  unsigned int temp = (CPU65.a & 0x0F) + (data & 0x0F) + (CPU65.pf_c ? 1 : 0);
575  unsigned int temp2 = (CPU65.a & 0xF0) + (data & 0xF0);
576  if (temp > 9) { temp2 += 0x10; temp += 6; }
577  CPU65.pf_v = (~(CPU65.a ^ data) & (CPU65.a ^ temp) & 0x80);
578  if (temp2 > 0x90) temp2 += 0x60;
579  CPU65.pf_c = (temp2 & 0xFF00);
580  CPU65.a = (temp & 0x0F) + (temp2 & 0xF0);
581  SET_NZ(CPU65.a);
582  }
583  } else {
584  unsigned int temp = data + CPU65.a + (CPU65.pf_c ? 1 : 0);
585  CPU65.pf_c = temp > 0xFF;
586  CPU65.pf_v = (!((CPU65.a ^ data) & 0x80) && ((CPU65.a ^ temp) & 0x80));
587  CPU65.a = temp & 0xFF;
588  SET_NZ(CPU65.a);
589  }
590 }
591 static XEMU_INLINE void _SBC ( const Uint16 data ) {
592  if (XEMU_UNLIKELY(CPU65.pf_d)) {
593  if (HAS_NMOS_BUG_BCD) {
594  /* This algorithm was written according the one found in VICE: 6510core.c */
595  Uint16 temp = CPU65.a - data - (CPU65.pf_c ? 0 : 1);
596  unsigned int temp_a = (CPU65.a & 0xF) - (data & 0xF) - (CPU65.pf_c ? 0 : 1);
597  if (temp_a & 0x10)
598  temp_a = ((temp_a - 6) & 0xf) | ((CPU65.a & 0xf0) - (data & 0xf0) - 0x10);
599  else
600  temp_a = (temp_a & 0xf) | ((CPU65.a & 0xf0) - (data & 0xf0));
601  if (temp_a & 0x100)
602  temp_a -= 0x60;
603  CPU65.pf_c = (temp < 0x100);
604  SET_NZ(temp & 0xFF);
605  CPU65.pf_v = (((CPU65.a ^ temp) & 0x80) && ((CPU65.a ^ data) & 0x80));
606  CPU65.a = temp_a & 0xFF;
607  } else {
608  /* This algorithm was written according the one found in VICE: 65c02core.c */
609  Uint16 temp = CPU65.a - (data & 0x0F) - (CPU65.pf_c ? 0 : 1);
610  if ((temp & 0x0F) > (CPU65.a & 0x0F)) temp -= 6;
611  temp -= (data & 0xF0);
612  if ((temp & 0xF0) > (CPU65.a & 0xF0)) temp -= 0x60;
613  CPU65.pf_v = (!(temp > CPU65.a));
614  CPU65.pf_c = (!(temp > CPU65.a));
615  CPU65.a = temp & 0xFF;
616  SET_NZ(CPU65.a);
617  }
618  } else {
619  Uint16 temp = CPU65.a - data - (CPU65.pf_c ? 0 : 1);
620  CPU65.pf_c = temp < 0x100;
621  CPU65.pf_v = ((CPU65.a ^ temp) & 0x80) && ((CPU65.a ^ data) & 0x80);
622  CPU65.a = temp & 0xFF;
623  SET_NZ(CPU65.a);
624  }
625 }
626 static XEMU_INLINE void _ROR ( const int addr ) {
627  Uint16 t = ((addr == -1) ? CPU65.a : readByte(addr));
628  Uint8 o = t;
629  if (CPU65.pf_c) t |= 0x100;
630  CPU65.pf_c = t & 1;
631  t >>= 1;
632  SET_NZ(t);
633  if (addr == -1) CPU65.a = t; else writeByteTwice(addr, o, t);
634 }
635 static XEMU_INLINE void _ROL ( const int addr ) {
636  Uint16 t = ((addr == -1) ? CPU65.a : readByte(addr));
637  Uint8 o = t;
638  t = (t << 1) | (CPU65.pf_c ? 1 : 0);
639  CPU65.pf_c = t & 0x100;
640  t &= 0xFF;
641  SET_NZ(t);
642  if (addr == -1) CPU65.a = t; else writeByteTwice(addr, o, t);
643 }
644 
645 #ifdef MEGA65
646 
647 // Thanks to lydon on MEGA65-discord for his extensive work on the Q-opcodes on the
648 // mega65-core VHDL, and for giving some hints here and there to me as well for emulation.
649 
650 static XEMU_INLINE void _SBCQ ( const Uint32 m ) {
651  const Uint32 q = AXYZ_GET();
652  const Uint64 result64 = (Uint64)q - (Uint64)m - (Uint64)1 + (Uint64)!!CPU65.pf_c;
653  CPU65.pf_c = (result64 < 0x100000000UL);
654  const Uint32 result = result64 & 0xFFFFFFFFUL;
655  CPU65.pf_v = ((result ^ q) & BIT31) && ((q ^ m) & BIT31);
656  SET_NZ32(AXYZ_SET(result));
657 }
658 static XEMU_INLINE void _CMPQ ( const Uint32 m ) {
659  const Uint64 result64 = (Uint64)AXYZ_GET() - (Uint64)m;
660  const Uint32 result = result64 & 0xFFFFFFFFUL;
661  SET_NZ32(result);
662  CPU65.pf_c = (result64 < 0x100000000UL);
663 }
664 static XEMU_INLINE void _ADCQ ( const Uint32 m ) {
665  const Uint32 q = AXYZ_GET();
666  const Uint64 result64 = (Uint64)q + (Uint64)m + (Uint64)!!CPU65.pf_c;
667  CPU65.pf_c = (result64 >= 0x100000000UL);
668  const Uint32 result = result64 & 0xFFFFFFFFUL;
669  CPU65.pf_v = ((result ^ q) & BIT31) && !((q ^ m) & BIT31);
670  SET_NZ32(AXYZ_SET(result));
671 }
672 static XEMU_INLINE void _BITQ ( const Uint32 m ) {
673  CPU65.pf_v = (m & BIT30);
674 #ifdef CPU65_DISCRETE_PF_NZ
675  CPU65.pf_n = (m & BIT31);
676  CPU65.pf_z = (!(AXYZ_GET() & m));
677 #else
678  CPU65.pf_nz = ((m & BIT31) ? CPU65_PF_N : 0) | VALUE_TO_PF_ZERO(AXYZ_GET() & m);
679 #endif
680 }
681 
682 // RMW kind of MEGA65 Q-opcodes, operates on memory address (argument is address, not data!)
683 
684 static XEMU_INLINE void _INQ_RMW ( const Uint16 addr ) {
685  Uint32 q = readQuad(addr);
686  q++;
687  SET_NZ32(q);
688  writeQuad(addr, q);
689 }
690 static XEMU_INLINE void _DEQ_RMW ( const Uint16 addr ) {
691  Uint32 q = readQuad(addr);
692  q--;
693  SET_NZ32(q);
694  writeQuad(addr, q);
695 }
696 static XEMU_INLINE void _ASLQ_RMW ( const Uint16 addr ) {
697  Uint32 q = readQuad(addr);
698  CPU65.pf_c = q & BIT31;
699  q <<= 1;
700  SET_NZ32(q);
701  writeQuad(addr, q);
702 }
703 static XEMU_INLINE void _LSRQ_RMW ( const Uint16 addr ) {
704  Uint32 q = readQuad(addr);
705  CPU65.pf_c = q & 1;
706  q >>= 1;
707  SET_NZ32(q);
708  writeQuad(addr, q);
709 }
710 static XEMU_INLINE void _ASRQ_RMW ( const Uint16 addr ) {
711  Uint32 q = readQuad(addr);
712  CPU65.pf_c = q & 1;
713  q = (q >> 1) | (q & BIT31);
714  SET_NZ32(q);
715  writeQuad(addr, q);
716 }
717 static XEMU_INLINE void _ROLQ_RMW ( const Uint16 addr ) {
718  Uint32 q = readQuad(addr);
719  const int new_carry = q & BIT31;
720  q = (q << 1) | (!!CPU65.pf_c);
721  CPU65.pf_c = new_carry;
722  SET_NZ32(q);
723  writeQuad(addr, q);
724 }
725 static XEMU_INLINE void _RORQ_RMW ( const Uint16 addr ) {
726  Uint32 q = readQuad(addr);
727  const int new_carry = q & 1;
728  q = (q >> 1) | (CPU65.pf_c ? BIT31 : 0);
729  CPU65.pf_c = new_carry;
730  SET_NZ32(q);
731  writeQuad(addr, q);
732 
733 }
734 
735 // Q-register opcodes (no memory operation is involved)
736 
737 static XEMU_INLINE void _INQ_Q ( void ) {
738  SET_NZ32(AXYZ_SET(AXYZ_GET() + 1));
739 }
740 static XEMU_INLINE void _DEQ_Q ( void ) {
741  SET_NZ32(AXYZ_SET(AXYZ_GET() - 1));
742 }
743 static XEMU_INLINE void _ASLQ_Q ( void ) {
744  Uint32 q = AXYZ_GET();
745  CPU65.pf_c = q & BIT31;
746  q <<= 1;
747  SET_NZ32(q);
748  AXYZ_SET(q);
749 }
750 static XEMU_INLINE void _LSRQ_Q ( void ) {
751  Uint32 q = AXYZ_GET();
752  CPU65.pf_c = q & 1;
753  q >>= 1;
754  SET_NZ32(q);
755  AXYZ_SET(q);
756 }
757 static XEMU_INLINE void _ASRQ_Q ( void ) {
758  Uint32 q = AXYZ_GET();
759  CPU65.pf_c = q & 1;
760  q = (q >> 1) | (q & BIT31);
761  SET_NZ32(q);
762  AXYZ_SET(q);
763 }
764 static XEMU_INLINE void _ROLQ_Q ( void ) {
765  Uint32 q = AXYZ_GET();
766  const int new_carry = q & BIT31;
767  q = (q << 1) | (!!CPU65.pf_c);
768  CPU65.pf_c = new_carry;
769  SET_NZ32(q);
770  AXYZ_SET(q);
771 }
772 static XEMU_INLINE void _RORQ_Q ( void ) {
773  Uint32 q = AXYZ_GET();
774  const int new_carry = q & 1;
775  q = (q >> 1) | (CPU65.pf_c ? BIT31 : 0);
776  CPU65.pf_c = new_carry;
777  SET_NZ32(q);
778  AXYZ_SET(q);
779 
780 }
781 
782 // TODO / FIXME ?? What happens if NEG NEG NOP prefix is tried to be applied on an opcode only supports NEG NEG?
783 // Whole prefix sequence is ignored, or it will be treated as NEG NEG only (thus the "NOP part" of prefix is ignored only)?
784 #define IS_NEG_NEG_OP() XEMU_UNLIKELY(CPU65.prefix == PREFIX_NEG_NEG)
785 #define IS_NOP_OP() XEMU_UNLIKELY(CPU65.prefix == PREFIX_NOP)
786 #define IS_NEG_NEG_NOP_OP() XEMU_UNLIKELY(CPU65.prefix == PREFIX_NEG_NEG_NOP)
787 
788 #endif
789 
790 
791 /* ------------------------------------------------------------------------ *
792  * CPU EMULATION, OPCODE DECODING + RUN *
793  * ------------------------------------------------------------------------ */
794 
795 
797 #ifdef CPU_STEP_MULTI_OPS
798  const int run_for_cycles
799 #else
800  void
801 #endif
802 ) {
803 #ifdef CPU_STEP_MULTI_OPS
804  int all_cycles = 0;
805  do {
806 #endif
808 #ifdef CPU_65CE02
809  && CPU65.op_cycles != 1 && !CPU65.cpu_inhibit_interrupts
810 #endif
811 #ifdef MEGA65
812  && !in_hypervisor && CPU65.prefix == PREFIX_NOTHING
813 #endif
814  )) {
815 #ifdef DEBUG_CPU
816  DEBUG("CPU: serving NMI on NMI edge at PC $%04X" NL, CPU65.pc);
817 #endif
818  CPU65.nmiEdge = 0;
819  pushWord(CPU65.pc);
820  push(cpu65_get_pf()); // no CPU65_PF_B is pushed!
821  CPU65.pf_i = 1;
822  CPU65.pf_d = 0; // NOTE: D flag clearing was not done on the original 6502 I guess, but indeed on the 65C02 already
823  CPU65.pc = readWord(0xFFFA);
824 #ifdef CPU_STEP_MULTI_OPS
825  all_cycles += 7;
826  continue;
827 #else
828  return 7;
829 #endif
830  }
832 #ifdef CPU_65CE02
833  && CPU65.op_cycles != 1 && !CPU65.cpu_inhibit_interrupts
834 #endif
835 #ifdef MEGA65
836  && !in_hypervisor && CPU65.prefix == PREFIX_NOTHING
837 #endif
838  )) {
839 #ifdef DEBUG_CPU
840  DEBUG("CPU: serving IRQ on IRQ level at PC $%04X" NL, CPU65.pc);
841 #endif
842  pushWord(CPU65.pc);
843  push(cpu65_get_pf()); // no CPU65_PF_B is pushed!
844  CPU65.pf_i = 1;
845  CPU65.pf_d = 0;
846  CPU65.pc = readWord(0xFFFE);
847 #ifdef CPU_STEP_MULTI_OPS
848  all_cycles += 7;
849  continue;
850 #else
851  return 7;
852 #endif
853  }
854  CPU65.old_pc = CPU65.pc;
855 #ifdef DEBUG_CPU
856  if (CPU65.pc == 0)
857  DEBUG("CPU: WARN: PC at zero!" NL);
858 #endif
859  CPU65.op = readByte(CPU65.pc++);
860 #ifdef DEBUG_CPU
861  DEBUG("CPU: at $%04X opcode = $%02X %s %s A=%02X X=%02X Y=%02X Z=%02X SP=%02X" NL, (CPU65.pc - 1) & 0xFFFF, CPU65.op, opcode_names[CPU65.op], opcode_adm_names[opcode_adms[CPU65.op]],
862  CPU65.a, CPU65.x, CPU65.y, CPU65.z, CPU65.s
863  );
864  if (CPU65.op == 0x60)
865  DEBUG("CPU: SP before RTS is (SPHI=$%04X) SP=$%02X" NL, CPU65.sphi, CPU65.s);
866 #endif
867 #ifdef CPU65_TRAP_OPCODE
870  if (ret > 0)
871  return ret;
872  }
873 #endif
874  CPU65.op_cycles = opcycles[CPU65.op];
875  switch (CPU65.op) {
876  case 0x00: /* BRK Implied */
877 #ifdef DEBUG_CPU
878  DEBUG("CPU: WARN: BRK is about executing at PC=$%04X" NL, (CPU65.pc - 1) & 0xFFFF);
879 #ifdef MEGA65
880  DEBUG("CPU: BRK opcode linear address is $%X" NL, memory_cpurd2linear_xlat((CPU65.pc - 1) & 0xFFFF));
881 #endif
882 #endif
883  pushWord(CPU65.pc + 1);
884  push(cpu65_get_pf() | CPU65_PF_B); // BRK always pushes 'B' bit set (like PHP too, unlike hardware interrupts)
885  CPU65.pf_d = 0; // actually, NMOS CPU does not do this for real, only 65C02+
886  CPU65.pf_i = 1;
887  CPU65.pc = readWord(0xFFFE);
888  break;
889  case 0x01: /* ORA (Zero_Page,X) */
890  SET_NZ(A_OP(|,readByte(_zpxi())));
891  break;
892  case 0x02: /* 65C02: NOP imm (non-std NOP with addr mode), 65CE02: CLE
893  NMOS: KIL */
894  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
895 #ifdef CPU_65CE02
896  OPC_65CE02("CLE");
897  CPU65.pf_e = 0; // 65CE02: CLE
898 #ifdef DEBUG_CPU
899  DEBUG("CPU: WARN: E flag is cleared!" NL);
900 #endif
901 #else
902  CPU65.pc++; /* NOP imm (non-std NOP with addr mode) */
903 #endif
904  }
905  break;
906  case 0x03: /* $03 65C02: NOP (nonstd loc, implied), 65CE02: SEE
907  NMOS: SLO ($00,X) -> TODO */
908  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
909 #ifdef CPU_65CE02
910  OPC_65CE02("SEE");
911  CPU65.pf_e = 1; // 65CE02: SEE
912 #endif
913  }
914  break;
915  case 0x04: /* TSB Zero_Page */
916  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else { _TSB(_zp()); }
917  break;
918  case 0x05: /* ORA Zero_Page */
919 #ifdef MEGA65
920  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ORQ $nn
921  CPU65.op_cycles = 8 - 2 + mega65_fastclock_1_penalty;
922  SET_NZ32(AXYZ_SET(AXYZ_GET() | readQuad(_zp())));
923  break;
924  }
925 #endif
926  SET_NZ(A_OP(|,readByte(_zp())));
927  break;
928  case 0x06: /* ASL Zero_Page */
929 #ifdef MEGA65
930  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ASLQ $nn
931  _ASLQ_RMW(_zp());
932  break;
933  }
934 #endif
935  _ASL(_zp());
936  break;
937  case 0x07: /* RMB Zero_Page */
938  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
939  int a = _zp();
940  writeByte(a, readByte(a) & 254);
941  }
942  break;
943  case 0x08: /* PHP Implied */
945  break;
946  case 0x09: /* ORA Immediate */
947  SET_NZ(A_OP(|,readByte(_imm())));
948  break;
949  case 0x0A: /* ASL Accumulator */
950 #ifdef MEGA65
951  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ASLQ (Q)
952  CPU65.op_cycles = 3 - 2;
953  _ASLQ_Q();
954  break;
955  }
956 #endif
957  _ASL(-1);
958  break;
959  case 0x0B: /* 65C02: NOP (nonstd loc, implied), 65CE02: TSY */
960  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
961 #ifdef CPU_65CE02
962  OPC_65CE02("TSY");
963  SET_NZ(CPU65.y = (CPU65.sphi >> 8)); // TSY
964 #endif
965  }
966  break;
967  case 0x0C: /* TSB Absolute */
968  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
969  _TSB(_abs());
970  }
971  break;
972  case 0x0D: /* ORA Absolute */
973 #ifdef MEGA65
974  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ORQ $nnnn
975  CPU65.op_cycles = 9 - 2 + mega65_fastclock_1_penalty;
976  SET_NZ32(AXYZ_SET(AXYZ_GET() | readQuad(_abs())));
977  break;
978  }
979 #endif
980  SET_NZ(A_OP(|,readByte(_abs())));
981  break;
982  case 0x0E: /* ASL Absolute */
983 #ifdef MEGA65
984  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ASLQ $nnnn
985  _ASLQ_RMW(_abs());
986  break;
987  }
988 #endif
989  _ASL(_abs());
990  break;
991  case 0x0F: /* BBR Relative */
992  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
993  _BRA(!(readByte(_zp()) & 1));
994  }
995  break;
996  case 0x10: /* BPL Relative */
997 #ifdef CPU65_DISCRETE_PF_NZ
998  _BRA(! CPU65.pf_n);
999 #else
1000  _BRA(!(CPU65.pf_nz & CPU65_PF_N));
1001 #endif
1002  break;
1003  case 0x11: /* ORA (Zero_Page),Y */
1004  SET_NZ(A_OP(|,readByte(_zpiy())));
1005  break;
1006  case 0x12: /* ORA (Zero_Page) or (ZP),Z on 65CE02 */
1007  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1008 #ifdef MEGA65
1009  if (XEMU_UNLIKELY(CPU65.prefix != PREFIX_NOTHING)) {
1010  if (IS_NOP_OP()) { // MEGA65-BOP: ORA [$nn],Z
1011  CPU65.op_cycles = 7 - 1 + mega65_fastclock_2_penalty;
1012  SET_NZ(A_OP(|,readFlatAddressedByte()));
1013  break;
1014  }
1015  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ORQ ($nn)
1016  CPU65.op_cycles = 10 - 2 + mega65_fastclock_1_penalty;
1017  SET_NZ32(AXYZ_SET(AXYZ_GET() | readQuad(_zpi_noz())));
1018  break;
1019  }
1020  if (IS_NEG_NEG_NOP_OP()) { // MEGA65-QOP: ORQ [$nn]
1021  CPU65.op_cycles = 13 - 3 + mega65_fastclock_1_penalty;
1022  SET_NZ32(AXYZ_SET(AXYZ_GET() | readFlatAddressedQuadWithoutZ()));
1023  break;
1024  }
1025  // do not break here, some quasi-state may apply, we need to continue then!
1026  }
1027 #endif
1028  SET_NZ(A_OP(|,readByte(_zpi())));
1029  }
1030  break;
1031  case 0x13: /* 65C02: NOP (nonstd loc, implied), 65CE02: BPL 16 bit relative */
1032  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1033 #ifdef CPU_65CE02
1034  OPC_65CE02("BPL16");
1035 #ifdef CPU65_DISCRETE_PF_NZ
1036  _BRA16(!CPU65.pf_n);
1037 #else
1038  _BRA16(!(CPU65.pf_nz & CPU65_PF_N));
1039 #endif
1040 #endif
1041  }
1042  break;
1043  case 0x14: /* TRB Zero_Page */
1044  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1045  _TRB(_zp());
1046  }
1047  break;
1048  case 0x15: /* ORA Zero_Page,X */
1049  SET_NZ(A_OP(|,readByte(_zpx())));
1050  break;
1051  case 0x16: /* ASL Zero_Page,X */
1052 #ifdef MEGA65
1053  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ASLQ $nn,X
1054  _ASLQ_RMW(_zpx());
1055  break;
1056  }
1057 #endif
1058  _ASL(_zpx());
1059  break;
1060  case 0x17: /* RMB Zero_Page */
1061  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1062  int a = _zp(); writeByte(a, readByte(a) & 253);
1063  }
1064  break;
1065  case 0x18: /* CLC Implied */
1066  CPU65.pf_c = 0;
1067  break;
1068  case 0x19: /* ORA Absolute,Y */
1069  SET_NZ(A_OP(|,readByte(_absy())));
1070  break;
1071  case 0x1A: /* INA Accumulator */
1072  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1073 #ifdef MEGA65
1074  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: INQ (Q)
1075  CPU65.op_cycles = 3 - 2;
1076  _INQ_Q();
1077  break;
1078  }
1079 #endif
1080  SET_NZ(++CPU65.a);
1081  }
1082  break;
1083  case 0x1B: /* 65C02: NOP (nonstd loc, implied), 65CE02: INZ */
1084  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1085 #ifdef CPU_65CE02
1086  OPC_65CE02("INZ");
1087  SET_NZ(++CPU65.z);
1088 #endif
1089  }
1090  break;
1091  case 0x1C: /* TRB Absolute */
1092  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1093  _TRB(_abs());
1094  }
1095  break;
1096  case 0x1D: /* ORA Absolute,X */
1097  SET_NZ(A_OP(|,readByte(_absx())));
1098  break;
1099  case 0x1E: /* ASL Absolute,X */
1100 #ifdef MEGA65
1101  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ASLQ $nnnn,X
1102  _ASLQ_RMW(_absx());
1103  break;
1104  }
1105 #endif
1106  _ASL(_absx());
1107  break;
1108  case 0x1F: /* BBR Relative */
1109  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1110  _BRA(!(readByte(_zp()) & 2));
1111  }
1112  break;
1113  case 0x20: /* JSR Absolute */
1114  pushWord(CPU65.pc + 1);
1115  CPU65.pc = _abs();
1116  break;
1117  case 0x21: /* AND (Zero_Page,X) */
1118  SET_NZ(A_OP(&,readByte(_zpxi())));
1119  break;
1120  case 0x22: /* 65C02 NOP imm (non-std NOP with addr mode), 65CE02: JSR (nnnn) */
1121  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1122 #ifdef CPU_65CE02
1123  OPC_65CE02("JSR (nnnn)");
1124  // 65CE02 JSR ($nnnn)
1125  pushWord(CPU65.pc + 1);
1126  CPU65.pc = _absi();
1127 #else
1128  CPU65.pc++;
1129 #endif
1130  }
1131  break;
1132  case 0x23: /* 65C02 NOP (nonstd loc, implied), 65CE02: JSR (nnnn,X) */
1133  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1134 #ifdef CPU_65CE02
1135  OPC_65CE02("JSR (nnnn,X)");
1136  pushWord(CPU65.pc + 1);
1137  CPU65.pc = _absxi();
1138 #endif
1139  }
1140  break;
1141  case 0x24: /* BIT Zero_Page */
1142 #ifdef MEGA65
1143  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: BITQ $nn
1144  CPU65.op_cycles = 8 - 2 + mega65_fastclock_1_penalty;
1145  _BITQ(readQuad(_zp()));
1146  break;
1147  }
1148 #endif
1149  _BIT(readByte(_zp()));
1150  break;
1151  case 0x25: /* AND Zero_Page */
1152 #ifdef MEGA65
1153  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ANDQ $nn
1154  CPU65.op_cycles = 8 - 2 + mega65_fastclock_1_penalty;
1155  SET_NZ32(AXYZ_SET(AXYZ_GET() & readQuad(_zp())));
1156  break;
1157  }
1158 #endif
1159  SET_NZ(A_OP(&,readByte(_zp())));
1160  break;
1161  case 0x26: /* ROL Zero_Page */
1162 #ifdef MEGA65
1163  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ROLQ $nn
1164  _ROLQ_RMW(_zp());
1165  break;
1166  }
1167 #endif
1168  _ROL(_zp());
1169  break;
1170  case 0x27: /* RMB Zero_Page */
1171  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1172  int a = _zp();
1173  writeByte(a, readByte(a) & 251);
1174  }
1175  break;
1176  case 0x28: /* PLP Implied */
1177  cpu65_set_pf(pop());
1178  break;
1179  case 0x29: /* AND Immediate */
1180  SET_NZ(A_OP(&,readByte(_imm())));
1181  break;
1182  case 0x2A: /* ROL Accumulator */
1183 #ifdef MEGA65
1184  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ROLQ (Q)
1185  CPU65.op_cycles = 3 - 2;
1186  _ROLQ_Q();
1187  break;
1188  }
1189 #endif
1190  _ROL(-1);
1191  break;
1192  case 0x2B: /* 65C02: NOP (nonstd loc, implied), 65CE02: TYS */
1193  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1194 #ifdef CPU_65CE02
1195  OPC_65CE02("TYS");
1196  CPU65.sphi = CPU65.y << 8; // 65CE02 TYS
1197 #ifdef DEBUG_CPU
1198  if (CPU65.sphi != 0x100)
1199  DEBUG("CPU: WARN: stack page is set non-0x100: $%04X" NL, CPU65.sphi);
1200 #endif
1201 #endif
1202  }
1203  break;
1204  case 0x2C: /* BIT Absolute */
1205 #ifdef MEGA65
1206  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: BITQ $nnnn
1207  CPU65.op_cycles = 9 - 2 + mega65_fastclock_1_penalty;
1208  _BITQ(readQuad(_abs()));
1209  break;
1210  }
1211 #endif
1212  _BIT(readByte(_abs()));
1213  break;
1214  case 0x2D: /* AND Absolute */
1215 #ifdef MEGA65
1216  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ANDQ $nnnn
1217  CPU65.op_cycles = 9 - 2 + mega65_fastclock_1_penalty;
1218  SET_NZ32(AXYZ_SET(AXYZ_GET() & readQuad(_abs())));
1219  break;
1220  }
1221 #endif
1222  SET_NZ(A_OP(&,readByte(_abs())));
1223  break;
1224  case 0x2E: /* ROL Absolute */
1225 #ifdef MEGA65
1226  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ROLQ $nnnn
1227  _ROLQ_RMW(_abs());
1228  break;
1229  }
1230 #endif
1231  _ROL(_abs());
1232  break;
1233  case 0x2F: /* BBR Relative */
1234  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1235  _BRA(!(readByte(_zp()) & 4));
1236  }
1237  break;
1238  case 0x30: /* BMI Relative */
1239 #ifdef CPU65_DISCRETE_PF_NZ
1240  _BRA(CPU65.pf_n);
1241 #else
1242  _BRA(CPU65.pf_nz & CPU65_PF_N);
1243 #endif
1244  break;
1245  case 0x31: /* AND (Zero_Page),Y */
1246  SET_NZ(A_OP(&,readByte(_zpiy())));
1247  break;
1248  case 0x32: /* 65C02: AND (Zero_Page), 65CE02: AND (ZP),Z */
1249  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1250 #ifdef MEGA65
1251  if (XEMU_UNLIKELY(CPU65.prefix != PREFIX_NOTHING)) {
1252  if (IS_NOP_OP()) { // MEGA65-BOP: AND [$nn],Z
1253  CPU65.op_cycles = 7 - 1 + mega65_fastclock_2_penalty;
1254  SET_NZ(A_OP(&,readFlatAddressedByte()));
1255  break;
1256  }
1257  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ANDQ ($nn)
1258  CPU65.op_cycles = 10 - 2 + mega65_fastclock_2_penalty;
1259  SET_NZ32(AXYZ_SET(AXYZ_GET() & readQuad(_zpi_noz())));
1260  break;
1261  }
1262  if (IS_NEG_NEG_NOP_OP()) { // MEGA65-QOP: ANDQ [$nn]
1263  CPU65.op_cycles = 13 - 3 + mega65_fastclock_2_penalty;
1264  SET_NZ32(AXYZ_SET(AXYZ_GET() & readFlatAddressedQuadWithoutZ()));
1265  break;
1266  }
1267  // do not break here, some quasi-state may apply, we need to continue then!
1268  }
1269 #endif
1270  SET_NZ(A_OP(&,readByte(_zpi())));
1271  }
1272  break;
1273  case 0x33: /* 65C02: NOP (nonstd loc, implied), 65CE02: BMI 16-bit relative */
1274  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1275 #ifdef CPU_65CE02
1276  OPC_65CE02("BMI16");
1277 #ifdef CPU65_DISCRETE_PF_NZ
1278  _BRA16(CPU65.pf_n);
1279 #else
1280  _BRA16(CPU65.pf_nz & CPU65_PF_N);
1281 #endif
1282 #endif
1283  }
1284  break;
1285  case 0x34: /* BIT Zero_Page,X */
1286  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1287  _BIT(readByte(_zpx()));
1288  }
1289  break;
1290  case 0x35: /* AND Zero_Page,X */
1291  SET_NZ(A_OP(&,readByte(_zpx())));
1292  break;
1293  case 0x36: /* ROL Zero_Page,X */
1294 #ifdef MEGA65
1295  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ROLQ $nn,X
1296  _ROLQ_RMW(_zpx());
1297  break;
1298  }
1299 #endif
1300  _ROL(_zpx());
1301  break;
1302  case 0x37: /* RMB Zero_Page */
1303  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1304  int a = _zp();
1305  writeByte(a, readByte(a) & 247);
1306  }
1307  break;
1308  case 0x38: /* SEC Implied */
1309  CPU65.pf_c = 1;
1310  break;
1311  case 0x39: /* AND Absolute,Y */
1312  SET_NZ(A_OP(&,readByte(_absy())));
1313  break;
1314  case 0x3A: /* DEA Accumulator */
1315  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1316 #ifdef MEGA65
1317  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: DEQ (Q)
1318  CPU65.op_cycles = 3 - 2;
1319  _DEQ_Q();
1320  break;
1321  }
1322 #endif
1323  SET_NZ(--CPU65.a);
1324  }
1325  break;
1326  case 0x3B: /* 65C02: NOP (nonstd loc, implied), 65CE02: DEZ */
1327  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1328 #ifdef CPU_65CE02
1329  OPC_65CE02("DEZ");
1330  SET_NZ(--CPU65.z);
1331 #endif
1332  }
1333  break;
1334  case 0x3C: /* BIT Absolute,X */
1335  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1336  _BIT(readByte(_absx()));
1337  }
1338  break;
1339  case 0x3D: /* AND Absolute,X */
1340  SET_NZ(A_OP(&,readByte(_absx())));
1341  break;
1342  case 0x3E: /* ROL Absolute,X */
1343 #ifdef MEGA65
1344  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ROLQ $nnnn,X
1345  _ROLQ_RMW(_absx());
1346  break;
1347  }
1348 #endif
1349  _ROL(_absx());
1350  break;
1351  case 0x3F: /* BBR Relative */
1352  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1353  _BRA(!(readByte(_zp()) & 8));
1354  }
1355  break;
1356  case 0x40: /* RTI Implied */
1357  cpu65_set_pf(pop());
1358  CPU65.pc = popWord();
1359  break;
1360  case 0x41: /* EOR (Zero_Page,X) */
1361  SET_NZ(A_OP(^,readByte(_zpxi())));
1362  break;
1363  case 0x42: /* 65C02: NOP imm (non-std NOP with addr mode), 65CE02: NEG */
1364  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1365 #ifdef CPU_65CE02
1366  /* NEG on 65CE02/4510 and MEGA65 as well, of course */
1367 #ifdef MEGA65
1369  if (CPU65.prefix == PREFIX_NEG || CPU65.prefix == PREFIX_NEG_NEG) {
1370  OPC_65CE02("NEG-NEG");
1371  CPU65.prefix = PREFIX_NEG_NEG;
1372  } else {
1373  CPU65.prefix = PREFIX_NEG;
1374  }
1375  // 65GS02 extension for "32 bit opcodes" (not to be confused with 32 bit addressing ...)
1376  // we continue with NEG execution though, since it restores the original A then also the NZ
1377  // flags, so no need to remember what was the NZ flags and A values before the first NEG :)
1378  // But we still need to execute the NEG as well, even if it's a "prefix"!
1379  SET_NZ(CPU65.a = -CPU65.a);
1380  goto do_not_clear_prefix;
1381  }
1382 #endif
1383  OPC_65CE02("NEG");
1384  SET_NZ(CPU65.a = -CPU65.a); // 65CE02: NEG FIXME: flags etc are correct?
1385 #else
1386  CPU65.pc++; /* 0x42 NOP imm (non-std NOP with addr mode) */
1387 #endif
1388  }
1389  break;
1390  case 0x43: /* 65C02: NOP (nonstd loc, implied), 65CE02: ASR A */
1391  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1392 #ifdef MEGA65
1393  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ASRQ (Q)
1394  CPU65.op_cycles = 3 - 2;
1395  _ASRQ_Q();
1396  break;
1397  }
1398 #endif
1399 #ifdef CPU_65CE02
1400  OPC_65CE02("ASR A");
1401  _ASR(-1);
1402  //CPU65.pf_c = CPU65.a & 1;
1403  //CPU65.a = (CPU65.a >> 1) | (CPU65.a & 0x80);
1404  //SET_NZ(CPU65.a);
1405 #endif
1406  }
1407  break;
1408  case 0x44: /* 65C02: NOP zp (non-std NOP with addr mode), 65CE02: ASR $nn */
1409  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1410 #ifdef MEGA65
1411  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ASRQ $nn
1412  _ASRQ_RMW(_zp());
1413  break;
1414  }
1415 #endif
1416 #ifdef CPU_65CE02
1417  OPC_65CE02("ASR nn");
1418  _ASR(_zp()); // 65CE02: ASR $nn
1419 #else
1420  CPU65.pc++; // 0x44 NOP zp (non-std NOP with addr mode)
1421 #endif
1422  }
1423  break;
1424  case 0x45: /* EOR Zero_Page */
1425 #ifdef MEGA65
1426  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: EORQ $nn
1427  CPU65.op_cycles = 8 - 2 + mega65_fastclock_1_penalty;
1428  SET_NZ32(AXYZ_SET(AXYZ_GET() ^ readQuad(_zp())));
1429  break;
1430  }
1431 #endif
1432  SET_NZ(A_OP(^,readByte(_zp())));
1433  break;
1434  case 0x46: /* LSR Zero_Page */
1435 #ifdef MEGA65
1436  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: LSRQ $nn
1437  _LSRQ_RMW(_zp());
1438  break;
1439  }
1440 #endif
1441  _LSR(_zp());
1442  break;
1443  case 0x47: /* RMB Zero_Page */
1444  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1445  int a = _zp();
1446  writeByte(a, readByte(a) & 239);
1447  }
1448  break;
1449  case 0x48: /* PHA Implied */
1450  push(CPU65.a);
1451  break;
1452  case 0x49: /* EOR Immediate */
1453  SET_NZ(A_OP(^,readByte(_imm())));
1454  break;
1455  case 0x4A: /* LSR Accumulator */
1456 #ifdef MEGA65
1457  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: LSRQ (Q)
1458  CPU65.op_cycles = 3 - 2;
1459  _LSRQ_Q();
1460  break;
1461  }
1462 #endif
1463  _LSR(-1);
1464  break;
1465  case 0x4B: /* 65C02: NOP (nonstd loc, implied), 65CE02: TAZ */
1466  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1467 #ifdef CPU_65CE02
1468  OPC_65CE02("TAZ");
1469  SET_NZ(CPU65.z = CPU65.a); // 65CE02: TAZ
1470 #endif
1471  }
1472  break;
1473  case 0x4C: /* JMP Absolute */
1474  CPU65.pc = _abs();
1475  break;
1476  case 0x4D: /* EOR Absolute */
1477 #ifdef MEGA65
1478  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: EORQ $nnnn
1479  CPU65.op_cycles = 9 - 2 + mega65_fastclock_1_penalty;
1480  SET_NZ32(AXYZ_SET(AXYZ_GET() ^ readQuad(_abs())));
1481  break;
1482  }
1483 #endif
1484  SET_NZ(A_OP(^,readByte(_abs())));
1485  break;
1486  case 0x4E: /* LSR Absolute */
1487 #ifdef MEGA65
1488  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: LSRQ $nnnn
1489  _LSRQ_RMW(_abs());
1490  break;
1491  }
1492 #endif
1493  _LSR(_abs());
1494  break;
1495  case 0x4F: /* BBR Relative */
1496  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1497  _BRA(!(readByte(_zp()) & 16));
1498  }
1499  break;
1500  case 0x50: /* BVC Relative */
1501  _BRA(!CPU65.pf_v);
1502  break;
1503  case 0x51: /* EOR (Zero_Page),Y */
1504  SET_NZ(A_OP(^,readByte(_zpiy())));
1505  break;
1506  case 0x52: /* EOR (Zero_Page) or (ZP),Z on 65CE02 */
1507  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1508 #ifdef MEGA65
1509  if (XEMU_UNLIKELY(CPU65.prefix != PREFIX_NOTHING)) {
1510  if (IS_NOP_OP()) { // MEGA65-BOP: EOR [$nn],Z
1511  CPU65.op_cycles = 7 - 1 + mega65_fastclock_2_penalty;
1512  SET_NZ(A_OP(^,readFlatAddressedByte()));
1513  break;
1514  }
1515  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: EORQ ($nn)
1516  CPU65.op_cycles = 10 - 2 + mega65_fastclock_2_penalty;
1517  SET_NZ32(AXYZ_SET(AXYZ_GET() ^ readQuad(_zpi_noz())));
1518  break;
1519  }
1520  if (IS_NEG_NEG_NOP_OP()) { // MEGA65-QOP: EORQ [$nn]
1521  CPU65.op_cycles = 13 - 3 + mega65_fastclock_2_penalty;
1522  SET_NZ32(AXYZ_SET(AXYZ_GET() ^ readFlatAddressedQuadWithoutZ()));
1523  break;
1524  }
1525  // do not break here, some quasi-state may apply, we need to continue then!
1526  }
1527 #endif
1528  SET_NZ(A_OP(^,readByte(_zpi())));
1529  }
1530  break;
1531  case 0x53: /* 65C02: NOP (nonstd loc, implied), 65CE02: BVC 16-bit-relative */
1532  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1533 #ifdef CPU_65CE02
1534  OPC_65CE02("BVC16");
1535  _BRA16(!CPU65.pf_v);
1536 #endif
1537  }
1538  break;
1539  case 0x54: /* 65C02: NOP zpx (non-std NOP with addr mode), 65CE02: ASR $nn,X */
1540  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1541 #ifdef MEGA65
1542  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ASRQ $nn,X
1543  _ASRQ_RMW(_zpx());
1544  break;
1545  }
1546 #endif
1547 #ifdef CPU_65CE02
1548  OPC_65CE02("ASR nn,X");
1549  _ASR(_zpx());
1550 #else
1551  CPU65.pc++;
1552 #endif
1553  }
1554  break;
1555  case 0x55: /* EOR Zero_Page,X */
1556  SET_NZ(A_OP(^,readByte(_zpx())));
1557  break;
1558  case 0x56: /* LSR Zero_Page,X */
1559 #ifdef MEGA65
1560  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: LSRQ $nn,X
1561  _LSRQ_RMW(_zpx());
1562  break;
1563  }
1564 #endif
1565  _LSR(_zpx());
1566  break;
1567  case 0x57: /* RMB Zero_Page */
1568  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1569  int a = _zp();
1570  writeByte(a, readByte(a) & 223);
1571  }
1572  break;
1573  case 0x58: /* CLI Implied */
1574  CPU65.pf_i = 0;
1575  break;
1576  case 0x59: /* EOR Absolute,Y */
1577  SET_NZ(A_OP(^,readByte(_absy())));
1578  break;
1579  case 0x5A: /* PHY Implied */
1580  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1581  push(CPU65.y);
1582  }
1583  break;
1584  case 0x5B: /* 65C02: NOP (nonstd loc, implied), 65CE02: TAB */
1585  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1586 #ifdef CPU_65CE02
1587  OPC_65CE02("TAB");
1588  CPU65.bphi = CPU65.a << 8;
1589 #ifdef DEBUG_CPU
1590  if (CPU65.bphi)
1591  DEBUG("CPU: WARN base page is non-zero now with value of $%04X" NL, CPU65.bphi);
1592 #endif
1593 #endif
1594  }
1595  break;
1596  case 0x5C: /* 65C02: NOP (nonstd loc, implied FIXME or absolute?!), 65CE02: AUG/MAP */
1597  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1598 #ifdef CPU_65CE02
1599  OPC_65CE02("MAP");
1600  cpu65_do_aug_callback(); /* $5C on 65CE02: this is the "AUG" opcode. It must be handled by the emulator, on 4510 (C65) it's redefined as MAP for MMU functionality */
1601 #else
1602  CPU65.pc += 2;
1603 #endif
1604  }
1605  break;
1606  case 0x5D: /* EOR Absolute,X */
1607  SET_NZ(A_OP(^,readByte(_absx())));
1608  break;
1609  case 0x5E: /* LSR Absolute,X */
1610 #ifdef MEGA65
1611  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: LSRQ $nnnn,X
1612  _LSRQ_RMW(_absx());
1613  break;
1614  }
1615 #endif
1616  _LSR(_absx());
1617  break;
1618  case 0x5F: /* BBR Relative */
1619  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1620  _BRA(!(readByte(_zp()) & 32));
1621  }
1622  break;
1623  case 0x60: /* RTS Implied */
1624  CPU65.pc = popWord() + 1;
1625  break;
1626  case 0x61: /* ADC (Zero_Page,X) */
1627  _ADC(readByte(_zpxi()));
1628  break;
1629  case 0x62: /* 65C02: NOP imm (non-std NOP with addr mode), 65CE02: RTS #$nn */
1630  /* 65CE02 FIXME TODO : what this opcode does _exactly_? Guess: correcting stack pointer with a given value? Also some docs says it's RTN ... */
1631  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1632 #ifdef CPU_65CE02
1633  OPC_65CE02("RTS #nn");
1634  { // 65CE02 RTS #$nn TODO: what this opcode does _exactly_? Guess: correcting stack pointer with a given value? Also some docs says it's RTN ...
1635  int temp = readByte(CPU65.pc);
1636  CPU65.pc = popWord() + 1;
1637  if (CPU65.s + temp > 0xFF && (!CPU65.pf_e))
1638  CPU65.sphi += 0x100;
1639  CPU65.s += temp; // SP was already incremented by two by popWord, we need only the extra stuff here
1640  }
1641 #else
1642  CPU65.pc++; // NOP imm (non-std NOP with addr mode)
1643 #endif
1644  }
1645  break;
1646  case 0x63: /* 65C02: NOP (nonstd loc, implied), 65CE02: BSR16 */
1647  /* FIXME TODO: BSR $nnnn Interesting 65C02-only? does this opcode exist before 65CE02 as well?! */
1648  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1649 #ifdef CPU_65CE02
1650  OPC_65CE02("BSR16");
1651  // 65C02 ?! BSR $nnnn Interesting 65C02-only? FIXME TODO: does this opcode exist before 65CE02 as well?!
1652  pushWord(CPU65.pc + 1);
1653  _BRA16(1);
1654 #endif
1655  }
1656  break;
1657  case 0x64: /* STZ Zero_Page */
1658  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1659  writeByte(_zp(), ZERO_REG);
1660  }
1661  break;
1662  case 0x65: /* ADC Zero_Page */
1663 #ifdef MEGA65
1664  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ADCQ $nn
1665  CPU65.op_cycles = 8 - 2 - mega65_fastclock_1_penalty;
1666  _ADCQ(readQuad(_zp()));
1667  break;
1668  }
1669 #endif
1670  _ADC(readByte(_zp()));
1671  break;
1672  case 0x66: /* ROR Zero_Page */
1673 #ifdef MEGA65
1674  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: RORQ $nn
1675  _RORQ_RMW(_zp());
1676  break;
1677  }
1678 #endif
1679  _ROR(_zp());
1680  break;
1681  case 0x67: /* RMB Zero_Page */
1682  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1683  int a = _zp();
1684  writeByte(a, readByte(a) & 191);
1685  }
1686  break;
1687  case 0x68: /* PLA Implied */
1688  SET_NZ(CPU65.a = pop());
1689  break;
1690  case 0x69: /* ADC Immediate */
1691  _ADC(readByte(_imm()));
1692  break;
1693  case 0x6A: /* ROR Accumulator */
1694 #ifdef MEGA65
1695  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: RORQ (Q)
1696  CPU65.op_cycles = 3 - 2;
1697  _RORQ_Q();
1698  break;
1699  }
1700 #endif
1701  _ROR(-1);
1702  break;
1703  case 0x6B: /* 65C02: NOP (nonstd loc, implied), 65CE02: TZA */
1704  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1705 #ifdef CPU_65CE02
1706  OPC_65CE02("TZA");
1707  SET_NZ(CPU65.a = CPU65.z); // 65CE02 TZA
1708 #endif
1709  }
1710  break;
1711  case 0x6C: /* JMP (Absolute) */
1713  int t = _abs();
1714  CPU65.pc = readByte(t) | (readByte((t & 0xFF00) | ((t + 1) & 0xFF)) << 8);
1715  } else
1716  CPU65.pc = _absi();
1717  break;
1718  case 0x6D: /* ADC Absolute */
1719 #ifdef MEGA65
1720  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ADCQ $nnnn
1721  CPU65.op_cycles = 9 - 2 + mega65_fastclock_2_penalty;
1722  _ADCQ(readQuad(_abs()));
1723  break;
1724  }
1725 #endif
1726  _ADC(readByte(_abs()));
1727  break;
1728  case 0x6E: /* ROR Absolute */
1729 #ifdef MEGA65
1730  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: RORQ $nnnn
1731  _RORQ_RMW(_abs());
1732  break;
1733  }
1734 #endif
1735  _ROR(_abs());
1736  break;
1737  case 0x6F: /* BBR Relative */
1738  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1739  _BRA(!(readByte(_zp()) & 64));
1740  }
1741  break;
1742  case 0x70: /* BVS Relative */
1743  _BRA(CPU65.pf_v);
1744  break;
1745  case 0x71: /* ADC (Zero_Page),Y */
1746  _ADC(readByte(_zpiy()));
1747  break;
1748  case 0x72: /* 0x72 ADC (Zero_Page) or (ZP),Z on 65CE02 */
1749  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1750 #ifdef MEGA65
1751  if (XEMU_UNLIKELY(CPU65.prefix != PREFIX_NOTHING)) {
1752  if (IS_NOP_OP()) { // MEGA65-BOP: ADC [$nn],Z
1753  CPU65.op_cycles = 7 - 1 + mega65_fastclock_2_penalty;
1754  _ADC(readFlatAddressedByte());
1755  break;
1756  }
1757  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: ADCQ ($nn)
1758  CPU65.op_cycles = 10 - 2 + mega65_fastclock_2_penalty;
1759  _ADCQ(readQuad(_zpi_noz()));
1760  break;
1761  }
1762  if (IS_NEG_NEG_NOP_OP()) { // MEGA65-QOP: ADCQ [$nn]
1763  CPU65.op_cycles = 13 - 3 + mega65_fastclock_2_penalty;
1765  break;
1766  }
1767  // do not break here, some quasi-state may apply, we need to continue then!
1768  }
1769 #endif
1770  _ADC(readByte(_zpi()));
1771  }
1772  break;
1773  case 0x73: /* 65C02: NOP (nonstd loc, implied), 65CE02: BVS 16 bit relative */
1774  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1775 #ifdef CPU_65CE02
1776  OPC_65CE02("BVS16");
1777  _BRA16(CPU65.pf_v);
1778 #endif
1779  }
1780  break;
1781  case 0x74: /* STZ Zero_Page,X */
1782  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1783  writeByte(_zpx(), ZERO_REG);
1784  }
1785  break;
1786  case 0x75: /* ADC Zero_Page,X */
1787  _ADC(readByte(_zpx()));
1788  break;
1789  case 0x76: /* ROR Zero_Page,X */
1790 #ifdef MEGA65
1791  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: RORQ $nn,X
1792  _RORQ_RMW(_zpx());
1793  break;
1794  }
1795 #endif
1796  _ROR(_zpx());
1797  break;
1798  case 0x77: /* RMB Zero_Page */
1799  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1800  int a = _zp();
1801  writeByte(a, readByte(a) & 127);
1802  }
1803  break;
1804  case 0x78: /* SEI Implied */
1805  CPU65.pf_i = 1;
1806  break;
1807  case 0x79: /* ADC Absolute,Y */
1808  _ADC(readByte(_absy()));
1809  break;
1810  case 0x7A: /* PLY Implied */
1811  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1812  SET_NZ(CPU65.y = pop());
1813  }
1814  break;
1815  case 0x7B: /* 65C02: NOP (nonstd loc, implied), 65CE02: TBA */
1816  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1817 #ifdef CPU_65CE02
1818  OPC_65CE02("TBA");
1819  SET_NZ(CPU65.a = (CPU65.bphi >> 8)); // 65C02 TBA
1820 #endif
1821  }
1822  break;
1823  case 0x7C: /* JMP (Absolute,X) */
1824  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1825  CPU65.pc = _absxi();
1826  }
1827  break;
1828  case 0x7D: /* ADC Absolute,X */
1829  _ADC(readByte(_absx()));
1830  break;
1831  case 0x7E: /* ROR Absolute,X */
1832 #ifdef MEGA65
1833  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: RORQ $nnnn,X
1834  _RORQ_RMW(_absx());
1835  break;
1836  }
1837 #endif
1838  _ROR(_absx());
1839  break;
1840  case 0x7F: /* BBR Relative */
1841  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1842  _BRA(!(readByte(_zp()) & 128));
1843  }
1844  break;
1845  case 0x80: /* BRA Relative */
1846  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1847  _BRA(1);
1848  }
1849  break;
1850  case 0x81: /* STA (Zero_Page,X) */
1851  writeByte(_zpxi(), CPU65.a);
1852  break;
1853  case 0x82: /* 65C02: NOP imm (non-std NOP with addr mode), 65CE02: STA ($nn,SP),Y */
1854  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1855 #ifdef CPU_65CE02
1856  OPC_65CE02("STA (nn,S),Y");
1857  writeByte(_GET_SP_INDIRECT_ADDR(), CPU65.a); // 65CE02 STA ($nn,SP),Y
1858 #else
1859  CPU65.pc++; // NOP imm (non-std NOP with addr mode)
1860 #endif
1861  }
1862  break;
1863  case 0x83: /* 65C02: NOP (nonstd loc, implied), 65CE02: BRA $nnnn 16-bit-pc-rel? */
1864  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1865 #ifdef CPU_65CE02
1866  OPC_65CE02("BRA16");
1867  _BRA16(1); // 65CE02 BRA $nnnn 16-bit-pc-rel?
1868 #endif
1869  }
1870  break;
1871  case 0x84: /* STY Zero_Page */
1872  writeByte(_zp(), CPU65.y);
1873  break;
1874  case 0x85: /* STA Zero_Page */
1875 #ifdef MEGA65
1876  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: STQ $nn
1877  CPU65.op_cycles = 8 - 2;
1878  writeQuad(_zp(), AXYZ_GET());
1879  break;
1880  }
1881 #endif
1882  writeByte(_zp(), CPU65.a);
1883  break;
1884  case 0x86: /* STX Zero_Page */
1885  writeByte(_zp(), CPU65.x);
1886  break;
1887  case 0x87: /* SMB Zero_Page */
1888  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1889  int a = _zp();
1890  writeByte(a, readByte(a) | 1);
1891  }
1892  break;
1893  case 0x88: /* DEY Implied */
1894  SET_NZ(--CPU65.y);
1895  break;
1896  case 0x89: /* BIT+ Immediate */
1897  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1898 #ifdef CPU65_DISCRETE_PF_NZ
1899  CPU65.pf_z = (!(CPU65.a & readByte(_imm())));
1900 #else
1901  if (CPU65.a & readByte(_imm())) CPU65.pf_nz &= (~CPU65_PF_Z); else CPU65.pf_nz |= CPU65_PF_Z;
1902 #endif
1903  }
1904  break;
1905  case 0x8A: /* TXA Implied */
1906  SET_NZ(CPU65.a = CPU65.x);
1907  break;
1908  case 0x8B: /* 65C02: NOP (nonstd loc, implied), 65CE02: STY $nnnn,X */
1909  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1910 #ifdef CPU_65CE02
1911  OPC_65CE02("STY nnnn,X");
1912  writeByte(_absx(), CPU65.y); // 65CE02 STY $nnnn,X
1913 #endif
1914  }
1915  break;
1916  case 0x8C: /* STY Absolute */
1917  writeByte(_abs(), CPU65.y);
1918  break;
1919  case 0x8D: /* STA Absolute */
1920 #ifdef MEGA65
1921  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: STQ $nnnn
1922  CPU65.op_cycles = 9 - 2;
1923  writeQuad(_abs(), AXYZ_GET());
1924  break;
1925  }
1926 #endif
1927  writeByte(_abs(), CPU65.a);
1928  break;
1929  case 0x8E: /* STX Absolute */
1930  writeByte(_abs(), CPU65.x);
1931  break;
1932  case 0x8F: /* BBS Relative */
1933  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1934  _BRA( readByte(_zp()) & 1 );
1935  }
1936  break;
1937  case 0x90: /* BCC Relative */
1938  _BRA(!CPU65.pf_c);
1939  break;
1940  case 0x91: /* STA (Zero_Page),Y */
1941  writeByte(_zpiy(), CPU65.a);
1942  break;
1943  case 0x92: /* STA (Zero_Page) or (ZP),Z on 65CE02 */
1944  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1945 #ifdef MEGA65
1946  if (XEMU_UNLIKELY(CPU65.prefix != PREFIX_NOTHING)) {
1947  if (IS_NOP_OP()) { // MEGA65-BOP: STA [$nn],Z
1948  CPU65.op_cycles = 8 - 1 + mega65_fastclock_1_penalty;
1950  break;
1951  }
1952  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: STQ ($nn)
1953  CPU65.op_cycles = 10 - 2 + mega65_fastclock_1_penalty;
1954  writeQuad(_zpi_noz(), AXYZ_GET());
1955  break;
1956  }
1957  if (IS_NEG_NEG_NOP_OP()) { // MEGA65-QOP: STQ [$nn]
1958  CPU65.op_cycles = 13 - 3 + mega65_fastclock_1_penalty;
1959  writeFlatAddressedQuadWithoutZ(AXYZ_GET());
1960  break;
1961  }
1962  // do not break here, some quasi-state may apply, we need to continue then!
1963  }
1964 #endif
1965  writeByte(_zpi(), CPU65.a);
1966  }
1967  break;
1968  case 0x93: /* 65C02: NOP (nonstd loc, implied), 65CE02: BCC $nnnn */
1969  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1970 #ifdef CPU_65CE02
1971  OPC_65CE02("BCC16");
1972  _BRA16(!CPU65.pf_c); // 65CE02 BCC $nnnn
1973 #endif
1974  }
1975  break;
1976  case 0x94: /* STY Zero_Page,X */
1977  writeByte(_zpx(), CPU65.y);
1978  break;
1979  case 0x95: /* STA Zero_Page,X */
1980  writeByte(_zpx(), CPU65.a);
1981  break;
1982  case 0x96: /* STX Zero_Page,Y */
1983  writeByte(_zpy(), CPU65.x);
1984  break;
1985  case 0x97: /* SMB Zero_Page */
1986  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
1987  int a = _zp();
1988  writeByte(a, readByte(a) | 2);
1989  }
1990  break;
1991  case 0x98: /* TYA Implied */
1992  SET_NZ(CPU65.a = CPU65.y);
1993  break;
1994  case 0x99: /* STA Absolute,Y */
1995  writeByte(_absy(), CPU65.a);
1996  break;
1997  case 0x9A: /* TXS Implied */
1998  CPU65.s = CPU65.x;
1999  break;
2000  case 0x9B: /* 65C02: NOP (nonstd loc, implied), 65CE02: STX $nnnn,Y */
2001  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2002 #ifdef CPU_65CE02
2003  OPC_65CE02("STX nnnn,Y");
2004  writeByte(_absy(), CPU65.x); // 65CE02 STX $nnnn,Y
2005 #endif
2006  }
2007  break;
2008  case 0x9C: /* STZ Absolute */
2009  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2010  writeByte(_abs(), ZERO_REG);
2011  }
2012  break;
2013  case 0x9D: /* STA Absolute,X */
2014  writeByte(_absx(), CPU65.a);
2015  break;
2016  case 0x9E: /* STZ Absolute,X */
2017  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2018  writeByte(_absx(), ZERO_REG);
2019  }
2020  break;
2021  case 0x9F: /* BBS Relative */
2022  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2023  _BRA( readByte(_zp()) & 2 );
2024  }
2025  break;
2026  case 0xA0: /* LDY Immediate */
2027  SET_NZ(CPU65.y = readByte(_imm()));
2028  break;
2029  case 0xA1: /* LDA (Zero_Page,X) */
2030  SET_NZ(CPU65.a = readByte(_zpxi()));
2031  break;
2032  case 0xA2: /* LDX Immediate */
2033  SET_NZ(CPU65.x = readByte(_imm()));
2034  break;
2035  case 0xA3: /* 65C02: NOP (nonstd loc, implied), 65CE02: LDZ #$nn */
2036  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2037 #ifdef CPU_65CE02
2038  OPC_65CE02("LDZ #nn");
2039  SET_NZ(CPU65.z = readByte(_imm()));
2040 #endif
2041  }
2042  break;
2043  case 0xA4: /* LDY Zero_Page */
2044  SET_NZ(CPU65.y = readByte(_zp()));
2045  break;
2046  case 0xA5: /* LDA Zero_Page */
2047 #ifdef MEGA65
2048  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: LDQ $nn
2049  CPU65.op_cycles = 8 - 2 + mega65_fastclock_1_penalty;
2050  SET_NZ32(AXYZ_SET(readQuad(_zp())));
2051  break;
2052  }
2053 #endif
2054  SET_NZ(CPU65.a = readByte(_zp()));
2055  break;
2056  case 0xA6: /* LDX Zero_Page */
2057  SET_NZ(CPU65.x = readByte(_zp()));
2058  break;
2059  case 0xA7: /* SMB Zero_Page */
2060  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2061  int a = _zp();
2062  writeByte(a, readByte(a) | 4);
2063  }
2064  break;
2065  case 0xA8: /* TAY Implied */
2066  SET_NZ(CPU65.y = CPU65.a);
2067  break;
2068  case 0xA9: /* LDA Immediate */
2069  SET_NZ(CPU65.a = readByte(_imm()));
2070  break;
2071  case 0xAA: /* TAX Implied */
2072  SET_NZ(CPU65.x = CPU65.a);
2073  break;
2074  case 0xAB: /* 65C02: NOP (nonstd loc, implied), 65CE02: LDZ $nnnn */
2075  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2076 #ifdef CPU_65CE02
2077  OPC_65CE02("LDZ nnnn");
2078  SET_NZ(CPU65.z = readByte(_abs()));
2079 #endif
2080  }
2081  break;
2082  case 0xAC: /* LDY Absolute */
2083  SET_NZ(CPU65.y = readByte(_abs()));
2084  break;
2085  case 0xAD: /* LDA Absolute */
2086 #ifdef MEGA65
2087  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: LDQ $nnnn
2088  CPU65.op_cycles = 9 - 2 + mega65_fastclock_1_penalty;
2089  SET_NZ32(AXYZ_SET(readQuad(_abs())));
2090  break;
2091  }
2092 #endif
2093  SET_NZ(CPU65.a = readByte(_abs()));
2094  break;
2095  case 0xAE: /* LDX Absolute */
2096  SET_NZ(CPU65.x = readByte(_abs()));
2097  break;
2098  case 0xAF: /* BSS Relative */
2099  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2100  _BRA( readByte(_zp()) & 4 );
2101  }
2102  break;
2103  case 0xB0: /* BCS Relative */
2104  _BRA(CPU65.pf_c);
2105  break;
2106  case 0xB1: /* LDA (Zero_Page),Y */
2107  SET_NZ(CPU65.a = readByte(_zpiy()));
2108  break;
2109  case 0xB2: /* LDA (Zero_Page) or (ZP),Z on 65CE02 */
2110  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2111 #ifdef MEGA65
2112  if (XEMU_UNLIKELY(CPU65.prefix != PREFIX_NOTHING)) {
2113  if (IS_NOP_OP()) { // MEGA65-BOP: LDA [$nn],Z
2114  CPU65.op_cycles = 7 - 1 + mega65_fastclock_2_penalty;
2115  SET_NZ(CPU65.a = readFlatAddressedByte());
2116  break;
2117  }
2118  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: LDQ ($nn),Z
2119  CPU65.op_cycles = 10 - 2 + mega65_fastclock_2_penalty;
2120  SET_NZ32(AXYZ_SET(readQuad(_zpi())));
2121  break;
2122  }
2123  if (IS_NEG_NEG_NOP_OP()) { // MEGA65-QOP: LDQ [$nn],Z
2124  CPU65.op_cycles = 13 - 3 + mega65_fastclock_2_penalty;
2125  SET_NZ32(AXYZ_SET(readFlatAddressedQuadWithZ()));
2126  break;
2127  }
2128  // do not break here, some quasi-state may apply, we need to continue then!
2129  }
2130 #endif
2131  SET_NZ(CPU65.a = readByte(_zpi()));
2132  }
2133  break;
2134  case 0xB3: /* 65C02: NOP (nonstd loc, implied), 65CE02: BCS $nnnn */
2135  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2136 #ifdef CPU_65CE02
2137  OPC_65CE02("BCS16");
2138  _BRA16(CPU65.pf_c);
2139 #endif
2140  }
2141  break;
2142  case 0xB4: /* LDY Zero_Page,X */
2143  SET_NZ(CPU65.y = readByte(_zpx()));
2144  break;
2145  case 0xB5: /* LDA Zero_Page,X */
2146  SET_NZ(CPU65.a = readByte(_zpx()));
2147  break;
2148  case 0xB6: /* LDX Zero_Page,Y */
2149  SET_NZ(CPU65.x = readByte(_zpy()));
2150  break;
2151  case 0xB7: /* SMB Zero_Page */
2152  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2153  int a = _zp();
2154  writeByte(a, readByte(a) | 8);
2155  }
2156  break;
2157  case 0xB8: /* CLV Implied */
2158  CPU65.pf_v = 0;
2159  break;
2160  case 0xB9: /* LDA Absolute,Y */
2161  SET_NZ(CPU65.a = readByte(_absy()));
2162  break;
2163  case 0xBA: /* TSX Implied */
2164  SET_NZ(CPU65.x = CPU65.s);
2165  break;
2166  case 0xBB: /* 65C02: NOP (nonstd loc, implied), 65CE02: LDZ $nnnn,X */
2167  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2168 #ifdef CPU_65CE02
2169  OPC_65CE02("LDZ nnnn,X");
2170  SET_NZ(CPU65.z = readByte(_absx()));
2171 #endif
2172  }
2173  break;
2174  case 0xBC: /* LDY Absolute,X */
2175  SET_NZ(CPU65.y = readByte(_absx()));
2176  break;
2177  case 0xBD: /* LDA Absolute,X */
2178  SET_NZ(CPU65.a = readByte(_absx()));
2179  break;
2180  case 0xBE: /* LDX Absolute,Y */
2181  SET_NZ(CPU65.x = readByte(_absy()));
2182  break;
2183  case 0xBF: /* BBS Relative */
2184  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2185  _BRA( readByte(_zp()) & 8 );
2186  }
2187  break;
2188  case 0xC0: /* CPY Immediate */
2189  _CMP(CPU65.y, readByte(_imm()));
2190  break;
2191  case 0xC1: /* CMP (Zero_Page,X) */
2192  _CMP(CPU65.a, readByte(_zpxi()));
2193  break;
2194  case 0xC2: /* 65C02: imm (non-std NOP with addr mode), 65CE02: CPZ #$nn */
2195  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2196 #ifdef CPU_65CE02
2197  OPC_65CE02("CPZ #nn");
2198  _CMP(CPU65.z, readByte(_imm()));
2199 #else
2200  CPU65.pc++; // imm (non-std NOP with addr mode)
2201 #endif
2202  }
2203  break;
2204  case 0xC3: /* 65C02: NOP (nonstd loc, implied), 65CE02: DEW $nn */
2205  /* DEW $nn 65CE02 C3 Decrement Word (maybe an error in 64NET.OPC ...) ANOTHER FIXME: this is zero (errr, base ...) page!!! */
2206  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2207 #ifdef CPU_65CE02
2208  OPC_65CE02("DEW nn");
2209  int alo = _zp();
2210  int ahi = (alo & 0xFF00) | ((alo + 1) & 0xFF);
2211  Uint16 data = (readByte(alo) | (readByte(ahi) << 8)) - 1;
2212  SET_NZ16(data);
2213  writeByte(alo, data & 0xFF);
2214  writeByte(ahi, data >> 8);
2215 #endif
2216  }
2217  break;
2218  case 0xC4: /* CPY Zero_Page */
2219  _CMP(CPU65.y, readByte(_zp()));
2220  break;
2221  case 0xC5: /* CMP Zero_Page */
2222 #ifdef MEGA65
2223  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: CPMQ $nn
2224  CPU65.op_cycles = 8 - 2 + mega65_fastclock_1_penalty;
2225  _CMPQ(readQuad(_zp()));
2226  break;
2227  }
2228 #endif
2229  _CMP(CPU65.a, readByte(_zp()));
2230  break;
2231  case 0xC6: /* DEC Zero_Page */
2232  {
2233 #ifdef MEGA65
2234  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: DEQ $nn
2235  _DEQ_RMW(_zp());
2236  break;
2237  }
2238 #endif
2239  int addr = _zp();
2240  Uint8 data = readByte(addr) - 1;
2241  SET_NZ(data);
2242  writeByte(addr, data);
2243  }
2244  break;
2245  case 0xC7: /* SMB Zero_Page */
2246  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2247  int a = _zp();
2248  writeByte(a, readByte(a) | 16);
2249  }
2250  break;
2251  case 0xC8: /* INY Implied */
2252  SET_NZ(++CPU65.y);
2253  break;
2254  case 0xC9: /* CMP Immediate */
2255  _CMP(CPU65.a, readByte(_imm()));
2256  break;
2257  case 0xCA: /* DEX Implied */
2258  SET_NZ(--CPU65.x);
2259  break;
2260  case 0xCB: /* 65C02: NOP (nonstd loc, implied), 65CE02: ASW $nnnn ("Arithmetic Shift Left Word") */
2261  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2262 #ifdef CPU_65CE02
2263  OPC_65CE02("ASW nnnn");
2264  int addr = _abs();
2265  Uint16 data = readByte(addr) | (readByte(addr + 1) << 8);
2266  CPU65.pf_c = data & 0x8000;
2267  data <<= 1;
2268  SET_NZ16(data);
2269  writeByte(addr, data & 0xFF);
2270  writeByte(addr + 1, data >> 8);
2271 #endif
2272  }
2273  break;
2274  case 0xCC: /* CPY Absolute */
2275  _CMP(CPU65.y, readByte(_abs()));
2276  break;
2277  case 0xCD: /* CMP Absolute */
2278 #ifdef MEGA65
2279  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: CPMQ $nnnn
2280  CPU65.op_cycles = 9 - 2 + mega65_fastclock_1_penalty;
2281  _CMPQ(readQuad(_abs()));
2282  break;
2283  }
2284 #endif
2285  _CMP(CPU65.a, readByte(_abs()));
2286  break;
2287  case 0xCE: /* DEC Absolute */
2288  {
2289 #ifdef MEGA65
2290  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: DEQ $nnnn
2291  _DEQ_RMW(_abs());
2292  break;
2293  }
2294 #endif
2295  const int addr = _abs();
2296  const Uint8 old_data = readByte(addr);
2297  const Uint8 new_data = old_data - 1;
2298  SET_NZ(new_data);
2299  writeByteTwice(addr, old_data, new_data);
2300  }
2301  break;
2302  case 0xCF: /* BBS Relative */
2303  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2304  _BRA( readByte(_zp()) & 16 );
2305  }
2306  break;
2307  case 0xD0: /* BNE Relative */
2308 #ifdef CPU65_DISCRETE_PF_NZ
2309  _BRA( !CPU65.pf_z);
2310 #else
2311  _BRA(!(CPU65.pf_nz & CPU65_PF_Z));
2312 #endif
2313  break;
2314  case 0xD1: /* CMP (Zero_Page),Y */
2315  _CMP(CPU65.a, readByte(_zpiy()));
2316  break;
2317  case 0xD2: /* CMP (Zero_Page) or (ZP),Z on 65CE02 */
2318  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2319 #ifdef MEGA65
2320  if (XEMU_UNLIKELY(CPU65.prefix != PREFIX_NOTHING)) {
2321  if (IS_NOP_OP()) { // MEGA65-BOP: CMP [$nn],Z -- NOTE: this was not mentioned in Paul's blog-post, but this op should have this property as well, IMHO!
2322  CPU65.op_cycles = 7 - 1 + mega65_fastclock_2_penalty;
2323  _CMP(CPU65.a, readFlatAddressedByte());
2324  break;
2325  }
2326  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: CMPQ ($nn)
2327  CPU65.op_cycles = 10 - 2 + mega65_fastclock_2_penalty;
2328  _CMPQ(readQuad(_zpi_noz()));
2329  break;
2330  }
2331  if (IS_NEG_NEG_NOP_OP()) { // MEGA65-QOP: CMPQ [$nn]
2332  CPU65.op_cycles = 13 - 3 + mega65_fastclock_2_penalty;
2334  break;
2335  }
2336  // do not break here, some quasi-state may apply, we need to continue then!
2337  }
2338 #endif
2339  _CMP(CPU65.a, readByte(_zpi()));
2340  }
2341  break;
2342  case 0xD3: /* 65C02: NOP (nonstd loc, implied), 65CE02: BNE16 */
2343  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2344 #ifdef CPU_65CE02
2345  OPC_65CE02("BNE16");
2346 #ifdef CPU65_DISCRETE_PF_NZ
2347  _BRA16( !CPU65.pf_z);
2348 #else
2349  _BRA16(!(CPU65.pf_nz & CPU65_PF_Z));
2350 #endif
2351 #endif
2352  }
2353  break;
2354  case 0xD4: /* 65C02: NOP zpx (non-std NOP with addr mode), 65CE02: CPZ $nn */
2355  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2356 #ifdef CPU_65CE02
2357  OPC_65CE02("CPZ nn");
2358  _CMP(CPU65.z, readByte(_zp()));
2359 #else
2360  CPU65.pc++; // NOP zpx (non-std NOP with addr mode)
2361 #endif
2362  }
2363  break;
2364  case 0xD5: /* CMP Zero_Page,X */
2365  _CMP(CPU65.a, readByte(_zpx()));
2366  break;
2367  case 0xD6: /* DEC Zero_Page,X */
2368  {
2369 #ifdef MEGA65
2370  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: DEQ $nn,X
2371  _DEQ_RMW(_zpx());
2372  break;
2373  }
2374 #endif
2375  int addr = _zpx();
2376  Uint8 data = readByte(addr) - 1;
2377  SET_NZ(data); writeByte(addr, data);
2378  }
2379  break;
2380  case 0xD7: /* SMB Zero_Page */
2381  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2382  int a = _zp();
2383  writeByte(a, readByte(a) | 32);
2384  }
2385  break;
2386  case 0xD8: /* CLD Implied */
2387  CPU65.pf_d = 0;
2388  break;
2389  case 0xD9: /* CMP Absolute,Y */
2390  _CMP(CPU65.a, readByte(_absy()));
2391  break;
2392  case 0xDA: /* PHX Implied */
2393  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2394  push(CPU65.x);
2395  }
2396  break;
2397  case 0xDB: /* 65C02: NOP (nonstd loc, implied), 65CE02: PHZ */
2398  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2399 #ifdef CPU_65CE02
2400  OPC_65CE02("PHZ");
2401  push(CPU65.z);
2402 #endif
2403  }
2404  break;
2405  case 0xDC: /* 65C02: NOP (nonstd loc, implied) FIXME: bugfix NOP absolute!, 65CE02: CPZ $nnnn */
2406  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2407 #ifdef CPU_65CE02
2408  OPC_65CE02("CPZ nnnn");
2409  _CMP(CPU65.z, readByte(_abs()));
2410 #else
2411  CPU65.pc += 2;
2412 #endif
2413  }
2414  break;
2415  case 0xDD: /* CMP Absolute,X */
2416  _CMP(CPU65.a, readByte(_absx()));
2417  break;
2418  case 0xDE: /* DEC Absolute,X */
2419  {
2420 #ifdef MEGA65
2421  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: DEQ $nnnn,X
2422  _DEQ_RMW(_absx());
2423  break;
2424  }
2425 #endif
2426  int addr = _absx();
2427  Uint8 data = readByte(addr) - 1;
2428  SET_NZ(data);
2429  writeByte(addr, data);
2430  }
2431  break;
2432  case 0xDF: /* BBS Relative */
2433  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2434  _BRA( readByte(_zp()) & 32 );
2435  }
2436  break;
2437  case 0xE0: /* CPX Immediate */
2438  _CMP(CPU65.x, readByte(_imm()));
2439  break;
2440  case 0xE1: /* SBC (Zero_Page,X) */
2441  _SBC(readByte(_zpxi()));
2442  break;
2443  case 0xE2: /* 65C02: NOP imm (non-std NOP with addr mode), 65CE02: LDA (nn,S),Y */
2444  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2445 #ifdef CPU_65CE02
2446  OPC_65CE02("LDA (nn,S),Y");
2447  // 65CE02 LDA ($nn,SP),Y
2448  // REALLY IMPORTANT: please read the comment at _GET_SP_INDIRECT_ADDR()!
2449  SET_NZ(CPU65.a = readByte(_GET_SP_INDIRECT_ADDR()));
2450  //DEBUG("CPU: LDA (nn,S),Y returned: A = $%02X, P before last IRQ was: $%02X" NL, CPU65.a, last_p);
2451 #else
2452  CPU65.pc++; // 0xe2 NOP imm (non-std NOP with addr mode)
2453 #endif
2454  }
2455  break;
2456  case 0xE3: /* 65C02: NOP (nonstd loc, implied), 65CE02: Increment Word (maybe an error in 64NET.OPC ...) ANOTHER FIXME: this is zero (errr, base ...) page!!! */
2457  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2458 #ifdef CPU_65CE02
2459  OPC_65CE02("INW nn");
2460  int alo = _zp();
2461  int ahi = (alo & 0xFF00) | ((alo + 1) & 0xFF);
2462  Uint16 data = (readByte(alo) | (readByte(ahi) << 8)) + 1;
2463  SET_NZ16(data);
2464  //cpu_pfz = (data == 0);
2465  writeByte(alo, data & 0xFF);
2466  writeByte(ahi, data >> 8);
2467 #endif
2468  }
2469  break;
2470  case 0xE4: /* CPX Zero_Page */
2471  _CMP(CPU65.x, readByte(_zp()));
2472  break;
2473  case 0xE5: /* SBC Zero_Page */
2474 #ifdef MEGA65
2475  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: SBCQ $nn
2476  CPU65.op_cycles = 8 - 2 + mega65_fastclock_1_penalty;
2477  _SBCQ(readQuad(_zp()));
2478  break;
2479  }
2480 #endif
2481  _SBC(readByte(_zp()));
2482  break;
2483  case 0xE6: /* INC Zero_Page */
2484  {
2485 #ifdef MEGA65
2486  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: INQ $nn
2487  _INQ_RMW(_zp());
2488  break;
2489  }
2490 #endif
2491  int addr = _zp();
2492  Uint8 data = readByte(addr) + 1;
2493  SET_NZ(data);
2494  writeByte(addr, data);
2495  }
2496  break;
2497  case 0xE7: /* SMB Zero_Page */
2498  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2499  int a = _zp();
2500  writeByte(a, readByte(a) | 64);
2501  }
2502  break;
2503  case 0xE8: /* INX Implied */
2504  SET_NZ(++CPU65.x);
2505  break;
2506  case 0xE9: /* SBC Immediate */
2507  _SBC(readByte(_imm()));
2508  break;
2509  case 0xEA: /* NOP, 65CE02: it's not special, but in C65 (4510) it is (EOM). It's up the emulator though (in the the second case) ... */
2510 #ifdef CPU_65CE02
2511 #ifdef MEGA65
2513  OPC_65CE02("EOM");
2514  cpu65_do_nop_callback(); // MEGA65 will execute the "EOM" as well !!! since it does not know it WILL be a prefix or no.
2515  if (CPU65.prefix == PREFIX_NEG_NEG) {
2516  OPC_65CE02("NEG-NEG-NOP");
2517  CPU65.prefix = PREFIX_NEG_NEG_NOP;
2518  } else {
2519  OPC_65CE02("NOP");
2520  CPU65.prefix = PREFIX_NOP;
2521  }
2522  goto do_not_clear_prefix;
2523  }
2524 #endif
2525  OPC_65CE02("EOM");
2527 #endif
2528  break;
2529  case 0xEB: /* 65C02: NOP (nonstd loc, implied), 65CE02: ROW $nnnn Rotate word LEFT?! [other documents says RIGHT!!! FIXME] */
2530  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2531 #ifdef CPU_65CE02
2532  OPC_65CE02("ROW nnnn");
2533  int addr = _abs();
2534  int data = ((readByte(addr) | (readByte(addr + 1) << 8)) << 1) | (CPU65.pf_c ? 1 : 0);
2535  CPU65.pf_c = data & 0x10000;
2536  data &= 0xFFFF;
2537  SET_NZ16(data);
2538  writeByte(addr, data & 0xFF);
2539  writeByte(addr + 1, data >> 8);
2540 #endif
2541  }
2542  break;
2543  case 0xEC: /* CPX Absolute */
2544  _CMP(CPU65.x, readByte(_abs()));
2545  break;
2546  case 0xED: /* SBC Absolute */
2547 #ifdef MEGA65
2548  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: SBCQ $nnnn
2549  CPU65.op_cycles = 9 - 2 + mega65_fastclock_1_penalty;
2550  _SBCQ(readQuad(_abs()));
2551  break;
2552  }
2553 #endif
2554  _SBC(readByte(_abs()));
2555  break;
2556  case 0xEE: /* INC Absolute */
2557  {
2558 #ifdef MEGA65
2559  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: INQ $nnnn
2560  _INQ_RMW(_abs());
2561  break;
2562  }
2563 #endif
2564  const int addr = _abs();
2565  const Uint8 old_data = readByte(addr);
2566  const Uint8 new_data = old_data + 1;
2567  SET_NZ(new_data);
2568  writeByteTwice(addr, old_data, new_data);
2569  }
2570  break;
2571  case 0xEF: /* BBS Relative */
2572  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2573  _BRA( readByte(_zp()) & 64 );
2574  }
2575  break;
2576  case 0xF0: /* BEQ Relative */
2577 #ifdef CPU65_DISCRETE_PF_NZ
2578  _BRA(CPU65.pf_z);
2579 #else
2580  _BRA(CPU65.pf_nz & CPU65_PF_Z);
2581 #endif
2582  break;
2583  case 0xF1: /* SBC (Zero_Page),Y */
2584  _SBC(readByte(_zpiy()));
2585  break;
2586  case 0xF2: /* SBC (Zero_Page) or (ZP),Z on 65CE02 */
2587  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2588 #ifdef MEGA65
2589  if (XEMU_UNLIKELY(CPU65.prefix != PREFIX_NOTHING)) {
2590  if (IS_NOP_OP()) { // MEGA65-BOP: SBC [$nn],Z
2591  CPU65.op_cycles = 8 - 1 + mega65_fastclock_1_penalty;
2592  _SBC(readFlatAddressedByte());
2593  break;
2594  }
2595  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: SBCQ ($nn)
2596  CPU65.op_cycles = 10 - 2 + mega65_fastclock_2_penalty;
2597  _SBCQ(readQuad(_zpi_noz()));
2598  break;
2599  }
2600  if (IS_NEG_NEG_NOP_OP()) { // MEGA65-QOP: SBCQ [$nn]
2601  CPU65.op_cycles = 13 - 3 + mega65_fastclock_2_penalty;
2603  break;
2604  }
2605  // do not break here, some quasi-state may apply, we need to continue then!
2606  }
2607 #endif
2608  _SBC(readByte(_zpi()));
2609  }
2610  break;
2611  case 0xF3: /* 65C02: NOP (nonstd loc, implied), 65CE02: BEQ16 */
2612  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2613 #ifdef CPU_65CE02
2614  OPC_65CE02("BEQ16");
2615 #ifdef CPU65_DISCRETE_PF_NZ
2616  _BRA16(CPU65.pf_z);
2617 #else
2618  _BRA16(CPU65.pf_nz & CPU65_PF_Z);
2619 #endif
2620 #endif
2621  }
2622  break;
2623  case 0xF4: /* 65C02: NOP zpx (non-std NOP with addr mode), 65CE02: PHW #$nnnn (push word) */
2624  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2625 #ifdef CPU_65CE02
2626  OPC_65CE02("PHW #nnnn");
2627  PUSH_FOR_PHW(readWord(CPU65.pc)); // 65CE02 PHW #$nnnn
2628  CPU65.pc += 2;
2629 #else
2630  CPU65.pc++; // 0xf4 NOP zpx (non-std NOP with addr mode)
2631 #endif
2632  }
2633  break;
2634  case 0xF5: /* SBC Zero_Page,X */
2635  _SBC(readByte(_zpx()));
2636  break;
2637  case 0xF6: /* INC Zero_Page,X */
2638  {
2639 #ifdef MEGA65
2640  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: INQ $nn,X
2641  _INQ_RMW(_zpx());
2642  break;
2643  }
2644 #endif
2645  int addr = _zpx();
2646  Uint8 data = readByte(addr) + 1;
2647  SET_NZ(data);
2648  writeByte(addr, data);
2649  }
2650  break;
2651  case 0xF7: /* SMB Zero_Page */
2652  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2653  int a = _zp();
2654  writeByte(a, readByte(a) | 128);
2655  }
2656  break;
2657  case 0xF8: /* SED Implied */
2658  CPU65.pf_d = 1;
2659  break;
2660  case 0xF9: /* SBC Absolute,Y */
2661  _SBC(readByte(_absy()));
2662  break;
2663  case 0xFA: /* PLX Implied */
2664  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2665  SET_NZ(CPU65.x = pop());
2666  }
2667  break;
2668  case 0xFB: /* 65C02: NOP (nonstd loc, implied), 65CE02: PLZ */
2669  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2670 #ifdef CPU_65CE02
2671  OPC_65CE02("PLZ");
2672  SET_NZ(CPU65.z = pop()); // PLZ
2673 #endif
2674  }
2675  break;
2676  case 0xFC: /* 65C02: NOP (nonstd loc, implied) FIXME: bugfix NOP absolute?
2677  65CE02: PHW $nnnn [? push word from an absolute address, maybe?] Note: C65 BASIC depends on this opcode to be correct! */
2678  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2679 #ifdef CPU_65CE02
2680  OPC_65CE02("PHW nnnn");
2681  PUSH_FOR_PHW(readWord(readWord(CPU65.pc)));
2682  CPU65.pc += 2;
2683 #else
2684  CPU65.pc += 2;
2685 #endif
2686  }
2687  break;
2688  case 0xFD: /* SBC Absolute,X */
2689  _SBC(readByte(_absx()));
2690  break;
2691  case 0xFE: /* INC Absolute,X */
2692  {
2693 #ifdef MEGA65
2694  if (IS_NEG_NEG_OP()) { // MEGA65-QOP: INQ $nnnn,X
2695  _INQ_RMW(_absx());
2696  break;
2697  }
2698 #endif
2699  int addr = _absx();
2700  Uint8 data = readByte(addr) + 1;
2701  SET_NZ(data);
2702  writeByte(addr, data);
2703  }
2704  break;
2705  case 0xFF: /* BBS Relative */
2706  if (IS_CPU_NMOS) { NMOS_JAM_OPCODE(); } else {
2707  _BRA( readByte(_zp()) & 128 );
2708  }
2709  break;
2710  default:
2711  XEMU_UNREACHABLE();
2712  break;
2713  }
2714 #ifdef MEGA65
2715  // this with the label too, must be after the opcode big switch/case stuff!!!!
2716  CPU65.prefix = PREFIX_NOTHING;
2717 do_not_clear_prefix:
2718 #endif
2719 #ifdef CPU_STEP_MULTI_OPS
2720  all_cycles += CPU65.op_cycles;
2723  return all_cycles;
2724  }
2725  } while (all_cycles < run_for_cycles);
2726  return all_cycles;
2727 #else
2728  return CPU65.op_cycles;
2729 #endif
2730 }
2731 
2732 
2733 /* ---- SNAPSHOT RELATED ---- */
2734 
2735 /* NOTE: cpu_linear_memory_addressing_is_enabled is not the CPU emulator handled data ...
2736  * FIXME: many things are missing for now from snapshot ... I should review all cpu65 struct things
2737  * if they're really stored, I can't remember, but at least things like neg_neg_prefix is not,
2738  * and maybe tons of others. Certainly it will cause problems on shapshot loading back, which is
2739  * not so much a frequent usage in Xemu now but there can be in the future!
2740 */
2741 
2742 
2743 #ifdef XEMU_SNAPSHOT_SUPPORT
2744 
2745 #include "xemu/emutools_snapshot.h"
2746 #include <string.h>
2747 
2748 #define SNAPSHOT_CPU65_BLOCK_VERSION 0
2749 #define SNAPSHOT_CPU65_BLOCK_SIZE 256
2750 
2751 #ifdef CPU_65CE02
2752 #define SNAPSHOT_CPU65_ID 2
2753 #else
2754 #define SNAPSHOT_CPU65_ID 1
2755 #endif
2756 
2757 int cpu65_snapshot_load_state ( const struct xemu_snapshot_definition_st *def, struct xemu_snapshot_block_st *block )
2758 {
2759  int ret;
2760  Uint8 buffer[SNAPSHOT_CPU65_BLOCK_SIZE];
2761  if (block->sub_counter || block->block_version != SNAPSHOT_CPU65_BLOCK_VERSION || block->sub_size != sizeof buffer)
2762  RETURN_XSNAPERR_USER("Bad CPU 65xx block syntax");
2763  ret = xemusnap_read_file(buffer, sizeof buffer);
2764  if (ret) return ret;
2765  if (buffer[0] != SNAPSHOT_CPU65_ID)
2766  RETURN_XSNAPERR_USER("CPU type mismatch");
2767  CPU65.pc = P_AS_BE16(buffer + 1);
2768  CPU65.a = buffer[3];
2769  CPU65.x = buffer[4];
2770  CPU65.y = buffer[5];
2771  CPU65.s = buffer[6];
2772  cpu65_set_pf(buffer[7]);
2773  CPU65.pf_e = buffer[7] & CPU65_PF_E; // must be set manually ....
2774  CPU65.irqLevel = (int)P_AS_BE32(buffer + 32);
2775  CPU65.nmiEdge = (int)P_AS_BE32(buffer + 36);
2776  CPU65.op_cycles = buffer[42];
2777  CPU65.op = buffer[43];
2778 #ifdef CPU_65CE02
2779  CPU65.z = buffer[64];
2780  CPU65.bphi = (Uint16)buffer[65] << 8;
2781  CPU65.sphi = (Uint16)buffer[66] << 8;
2782  CPU65.cpu_inhibit_interrupts = (int)P_AS_BE32(buffer + 96);
2783 #endif
2784  return 0;
2785 }
2786 
2787 
2788 int cpu65_snapshot_save_state ( const struct xemu_snapshot_definition_st *def )
2789 {
2790  Uint8 buffer[SNAPSHOT_CPU65_BLOCK_SIZE];
2791  int ret = xemusnap_write_block_header(def->idstr, SNAPSHOT_CPU65_BLOCK_VERSION);
2792  if (ret) return ret;
2793  memset(buffer, 0xFF, sizeof buffer);
2794  buffer[0] = SNAPSHOT_CPU65_ID;
2795  U16_AS_BE(buffer + 1, CPU65.pc);
2796  buffer[3] = CPU65.a;
2797  buffer[4] = CPU65.x;
2798  buffer[5] = CPU65.y;
2799  buffer[6] = CPU65.s;
2800  buffer[7] = cpu65_get_pf();
2801  U32_AS_BE(buffer + 32, (Uint32)CPU65.irqLevel);
2802  U32_AS_BE(buffer + 36, (Uint32)CPU65.nmiEdge);
2803  buffer[42] = CPU65.op_cycles;
2804  buffer[43] = CPU65.op;
2805 #ifdef CPU_65CE02
2806  buffer[64] = CPU65.z;
2807  buffer[65] = CPU65.bphi >> 8;
2808  buffer[66] = CPU65.sphi >> 8;
2809  U32_AS_BE(buffer + 96, (Uint32)CPU65.cpu_inhibit_interrupts);
2810 #endif
2811  return xemusnap_write_sub_block(buffer, sizeof buffer);
2812 }
2813 #endif
CPU65_PF_E
#define CPU65_PF_E
Definition: cpu65.h:25
TIMINGS_65C02
#define TIMINGS_65C02
Definition: cpu65.c:120
cpu65_st::multi_step_stop_trigger
int multi_step_stop_trigger
Definition: cpu65.h:72
_zpy
#define _zpy()
Definition: cpu65.c:448
cpu65_st::x
Uint8 x
Definition: cpu65.h:52
CPU_TYPE
#define CPU_TYPE
Definition: cpu65.c:74
cpu65_st::pf_nz
Uint8 pf_nz
Definition: cpu65.h:68
ZP_HI
#define ZP_HI
Definition: cpu65.c:70
NMOS_JAM_OPCODE
#define NMOS_JAM_OPCODE()
Definition: cpu65.c:237
CPU65_PF_Z
#define CPU65_PF_Z
Definition: cpu65.h:29
cpu_mega65_opcodes
int cpu_mega65_opcodes
Definition: io_mapper.c:41
cpu65_st::irqLevel
int irqLevel
Definition: cpu65.h:73
_absxi
#define _absxi()
Definition: cpu65.c:422
CPU65_PF_D
#define CPU65_PF_D
Definition: cpu65.h:27
IS_CPU_NMOS
#define IS_CPU_NMOS
Definition: cpu65.c:236
cpu65_st::s
Uint8 s
Definition: cpu65.h:53
_absy
#define _absy()
Definition: cpu65.c:420
addr
int addr
Definition: dma65.c:81
VALUE_TO_PF_ZERO
#define VALUE_TO_PF_ZERO(a)
Definition: cpu65.c:181
ASSIGN_PF_N_BY_COND
#define ASSIGN_PF_N_BY_COND(a)
Definition: cpu65.c:189
cpu65_st::y
Uint8 y
Definition: cpu65.h:52
MEGA65
#define MEGA65
Definition: xemu-target.h:4
XEMU_INLINE
#define XEMU_INLINE
Definition: emutools_basicdefs.h:126
m65-memcontent-generator.data
data
Definition: m65-memcontent-generator.py:119
Uint32
uint32_t Uint32
Definition: fat32.c:49
readByte
#define readByte(a)
Definition: cpu65.c:206
memory_cpurd2linear_xlat
int memory_cpurd2linear_xlat(Uint16 cpu_addr)
Definition: memory_mapper.c:966
Uint8
uint8_t Uint8
Definition: fat32.c:51
_absi
#define _absi()
Definition: cpu65.c:421
cpu65_st::pf_i
int pf_i
Definition: cpu65.h:70
HAS_NMOS_BUG_BCD
#define HAS_NMOS_BUG_BCD
Definition: cpu65.c:240
CPU65_PF_C
#define CPU65_PF_C
Definition: cpu65.h:30
TIMINGS_65CE02
#define TIMINGS_65CE02
Definition: cpu65.c:117
cpu65_st::pf_c
int pf_c
Definition: cpu65.h:70
block
Uint32 block
Definition: fat32.c:156
cpu65_do_nop_callback
void cpu65_do_nop_callback(void)
Definition: commodore_65.c:434
emutools_basicdefs.h
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
cpu65_trap_callback
int cpu65_trap_callback(const Uint8 opcode)
Definition: commodore_geos.c:677
cpu65_st::nmiEdge
int nmiEdge
Definition: cpu65.h:73
XEMU_LIKELY
#define XEMU_LIKELY(__x__)
Definition: emutools_basicdefs.h:124
mode
int mode
Definition: vera.c:61
cpu65_st::op_cycles
int op_cycles
Definition: cpu65.h:74
NL
#define NL
Definition: fat32.c:37
CPU65_PF_V
#define CPU65_PF_V
Definition: cpu65.h:24
CPU65_PF_I
#define CPU65_PF_I
Definition: cpu65.h:28
hypervisor.h
cpu65_st::pf_d
int pf_d
Definition: cpu65.h:70
ZERO_REG
#define ZERO_REG
Definition: cpu65.c:76
cpu65ce02_disasm_tables.c
_zp
#define _zp()
Definition: cpu65.c:423
cpu65.h
writeByte
#define writeByte(a, d)
Definition: cpu65.c:205
CPU_STEP_MULTI_OPS
#define CPU_STEP_MULTI_OPS
Definition: xemu-target.h:6
cpu65_st::old_pc
Uint16 old_pc
Definition: cpu65.h:71
readFlatAddressedByte
#define readFlatAddressedByte()
Definition: cpu65.c:194
writeFlatAddressedQuadWithoutZ
#define writeFlatAddressedQuadWithoutZ(d)
Definition: cpu65.c:198
cpu65_st::a
Uint8 a
Definition: cpu65.h:52
_zpx
#define _zpx()
Definition: cpu65.c:447
_absx
#define _absx()
Definition: cpu65.c:419
TIMINGS_6502C65
#define TIMINGS_6502C65
Definition: cpu65.c:118
cpu65_reset
void cpu65_reset(void)
Definition: cpu65.c:353
ASSIGN_PF_Z_BY_COND
#define ASSIGN_PF_Z_BY_COND(a)
Definition: cpu65.c:188
_imm
#define _imm()
Definition: cpu65.c:414
emutools_snapshot.h
CPU65_PF_B
#define CPU65_PF_B
Definition: cpu65.h:26
cpu65_get_pf
Uint8 cpu65_get_pf(void)
Definition: cpu65.c:331
writeFlatAddressedByte
#define writeFlatAddressedByte(d)
Definition: cpu65.c:193
in_hypervisor
int in_hypervisor
Definition: hypervisor.c:40
cpu65_st::pc
Uint16 pc
Definition: cpu65.h:71
CPU65_TRAP_OPCODE
#define CPU65_TRAP_OPCODE
Definition: xemu-target.h:3
CPU65
struct cpu65_st CPU65
Definition: cpu65.c:60
Uint16
uint16_t Uint16
Definition: fat32.c:50
TIMINGS_6502MOS
#define TIMINGS_6502MOS
Definition: cpu65.c:119
cpu65_do_aug_callback
void cpu65_do_aug_callback(void)
Definition: commodore_65.c:418
writeByteTwice
#define writeByteTwice(a, od, nd)
Definition: cpu65.c:203
cpu65_st
Definition: cpu65.h:51
A_OP
#define A_OP(op, dat)
Definition: cpu65.c:79
HAS_NMOS_BUG_JMP_INDIRECT
#define HAS_NMOS_BUG_JMP_INDIRECT
Definition: cpu65.c:238
push
#define push(data)
Definition: cpu65.c:297
readFlatAddressedQuadWithoutZ
#define readFlatAddressedQuadWithoutZ()
Definition: cpu65.c:199
CPU_65CE02
#define CPU_65CE02
Definition: xemu-target.h:3
XEMU_UNREACHABLE
#define XEMU_UNREACHABLE()
Definition: emutools_basicdefs.h:127
DEBUG
#define DEBUG(...)
Definition: emutools_basicdefs.h:167
cpu65_st::op
Uint8 op
Definition: cpu65.h:54
cpu65_step
int cpu65_step(void)
Definition: cpu65.c:796
CPU65_PF_N
#define CPU65_PF_N
Definition: cpu65.h:23
cpu65_set_pf
void cpu65_set_pf(const Uint8 st)
Definition: cpu65.c:313
cpu65_st::pf_v
int pf_v
Definition: cpu65.h:70
XEMU_UNLIKELY
#define XEMU_UNLIKELY(__x__)
Definition: emutools_basicdefs.h:125
readFlatAddressedQuadWithZ
#define readFlatAddressedQuadWithZ()
Definition: cpu65.c:197
pop
#define pop()
Definition: cpu65.c:298
st
struct stat st
Definition: cpmfs.c:43