summaryrefslogtreecommitdiff
path: root/apps/codecs/libgme/nes_cpu_run.h
diff options
context:
space:
mode:
authorTorne Wuff <torne@wolfpuppy.org.uk>2011-11-06 22:44:25 +0000
committerTorne Wuff <torne@wolfpuppy.org.uk>2011-11-06 22:44:25 +0000
commit569285794b9112f0134ddad4bb886308ea4a7be6 (patch)
treece702cb07829820261a682c471133c76d11c610e /apps/codecs/libgme/nes_cpu_run.h
parentd9b7d58fa6c9ceb136bea429adf6746cc7138208 (diff)
downloadrockbox-569285794b9112f0134ddad4bb886308ea4a7be6.tar.gz
rockbox-569285794b9112f0134ddad4bb886308ea4a7be6.zip
Bulk convert all DOS line endings to UNIX.
For the git migration we want a nice clean repository with UNIX line endings. git does not use svn:eol-style, we just need the file contents to be sane. Sorry everybody. I know this messes up blame. Scumbag *NIX developer says migrating to git will make line ending issues go away; commits giant change to svn which changes line endings anyway. :) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30924 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/libgme/nes_cpu_run.h')
-rw-r--r--apps/codecs/libgme/nes_cpu_run.h2244
1 files changed, 1122 insertions, 1122 deletions
diff --git a/apps/codecs/libgme/nes_cpu_run.h b/apps/codecs/libgme/nes_cpu_run.h
index 5b964d5070..fd1fea9659 100644
--- a/apps/codecs/libgme/nes_cpu_run.h
+++ b/apps/codecs/libgme/nes_cpu_run.h
@@ -1,1122 +1,1122 @@
1// NES 6502 cpu emulator run function 1// NES 6502 cpu emulator run function
2 2
3#if 0 3#if 0
4/* Define these macros in the source file before #including this file. 4/* Define these macros in the source file before #including this file.
5- Parameters might be expressions, so they are best evaluated only once, 5- Parameters might be expressions, so they are best evaluated only once,
6though they NEVER have side-effects, so multiple evaluation is OK. 6though they NEVER have side-effects, so multiple evaluation is OK.
7- Output parameters might be a multiple-assignment expression like "a=x", 7- Output parameters might be a multiple-assignment expression like "a=x",
8so they must NOT be parenthesized. 8so they must NOT be parenthesized.
9- Except where noted, time() and related functions will NOT work 9- Except where noted, time() and related functions will NOT work
10correctly inside a macro. TIME() is always correct, and FLUSH_TIME() and 10correctly inside a macro. TIME() is always correct, and FLUSH_TIME() and
11CACHE_TIME() allow the time changing functions to work. 11CACHE_TIME() allow the time changing functions to work.
12- Macros "returning" void may use a {} statement block. */ 12- Macros "returning" void may use a {} statement block. */
13 13
14 // 0 <= addr <= 0xFFFF + page_size 14 // 0 <= addr <= 0xFFFF + page_size
15 // time functions can be used 15 // time functions can be used
16 int READ_MEM( addr_t ); 16 int READ_MEM( addr_t );
17 void WRITE_MEM( addr_t, int data ); 17 void WRITE_MEM( addr_t, int data );
18 // 0 <= READ_MEM() <= 0xFF 18 // 0 <= READ_MEM() <= 0xFF
19 19
20 // 0 <= addr <= 0x1FF 20 // 0 <= addr <= 0x1FF
21 int READ_LOW( addr_t ); 21 int READ_LOW( addr_t );
22 void WRITE_LOW( addr_t, int data ); 22 void WRITE_LOW( addr_t, int data );
23 // 0 <= READ_LOW() <= 0xFF 23 // 0 <= READ_LOW() <= 0xFF
24 24
25 // Often-used instructions attempt these before using a normal memory access. 25 // Often-used instructions attempt these before using a normal memory access.
26 // Optional; defaults to READ_MEM() and WRITE_MEM() 26 // Optional; defaults to READ_MEM() and WRITE_MEM()
27 bool CAN_READ_FAST( addr_t ); // if true, uses result of READ_FAST 27 bool CAN_READ_FAST( addr_t ); // if true, uses result of READ_FAST
28 void READ_FAST( addr_t, int& out ); // ALWAYS called BEFORE CAN_READ_FAST 28 void READ_FAST( addr_t, int& out ); // ALWAYS called BEFORE CAN_READ_FAST
29 bool CAN_WRITE_FAST( addr_t ); // if true, uses WRITE_FAST instead of WRITE_MEM 29 bool CAN_WRITE_FAST( addr_t ); // if true, uses WRITE_FAST instead of WRITE_MEM
30 void WRITE_FAST( addr_t, int data ); 30 void WRITE_FAST( addr_t, int data );
31 31
32 // Used by instructions most often used to access the NES PPU (LDA abs and BIT abs). 32 // Used by instructions most often used to access the NES PPU (LDA abs and BIT abs).
33 // Optional; defaults to READ_MEM. 33 // Optional; defaults to READ_MEM.
34 void READ_PPU( addr_t, int& out ); 34 void READ_PPU( addr_t, int& out );
35 // 0 <= out <= 0xFF 35 // 0 <= out <= 0xFF
36 36
37// The following can be used within macros: 37// The following can be used within macros:
38 38
39 // Current time 39 // Current time
40 time_t TIME(); 40 time_t TIME();
41 41
42 // Allows use of time functions 42 // Allows use of time functions
43 void FLUSH_TIME(); 43 void FLUSH_TIME();
44 44
45 // Must be used before end of macro if FLUSH_TIME() was used earlier 45 // Must be used before end of macro if FLUSH_TIME() was used earlier
46 void CACHE_TIME(); 46 void CACHE_TIME();
47 47
48// Configuration (optional; commented behavior if defined) 48// Configuration (optional; commented behavior if defined)
49 49
50 // Emulates dummy reads for indexed instructions 50 // Emulates dummy reads for indexed instructions
51 #define NES_CPU_DUMMY_READS 1 51 #define NES_CPU_DUMMY_READS 1
52 52
53 // Optimizes as if map_code( 0, 0x10000 + cpu_padding, FLAT_MEM ) is always in effect 53 // Optimizes as if map_code( 0, 0x10000 + cpu_padding, FLAT_MEM ) is always in effect
54 #define FLAT_MEM my_mem_array 54 #define FLAT_MEM my_mem_array
55 55
56 // Expanded just before beginning of code, to help debugger 56 // Expanded just before beginning of code, to help debugger
57 #define CPU_BEGIN void my_run_cpu() { 57 #define CPU_BEGIN void my_run_cpu() {
58 58
59#endif 59#endif
60 60
61/* Copyright (C) 2003-2008 Shay Green. This module is free software; you 61/* Copyright (C) 2003-2008 Shay Green. This module is free software; you
62can redistribute it and/or modify it under the terms of the GNU Lesser 62can redistribute it and/or modify it under the terms of the GNU Lesser
63General Public License as published by the Free Software Foundation; either 63General Public License as published by the Free Software Foundation; either
64version 2.1 of the License, or (at your option) any later version. This 64version 2.1 of the License, or (at your option) any later version. This
65module is distributed in the hope that it will be useful, but WITHOUT ANY 65module is distributed in the hope that it will be useful, but WITHOUT ANY
66WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 66WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
67FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 67FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
68details. You should have received a copy of the GNU Lesser General Public 68details. You should have received a copy of the GNU Lesser General Public
69License along with this module; if not, write to the Free Software Foundation, 69License along with this module; if not, write to the Free Software Foundation,
70Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 70Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
71 71
72// Allows MWCW debugger to step through code properly 72// Allows MWCW debugger to step through code properly
73#ifdef CPU_BEGIN 73#ifdef CPU_BEGIN
74 CPU_BEGIN 74 CPU_BEGIN
75#endif 75#endif
76 76
77// Time 77// Time
78#define TIME() (s_time + s.base) 78#define TIME() (s_time + s.base)
79#define FLUSH_TIME() {s.time = s_time - time_offset;} 79#define FLUSH_TIME() {s.time = s_time - time_offset;}
80#define CACHE_TIME() {s_time = s.time + time_offset;} 80#define CACHE_TIME() {s_time = s.time + time_offset;}
81 81
82// Defaults 82// Defaults
83#ifndef CAN_WRITE_FAST 83#ifndef CAN_WRITE_FAST
84 #define CAN_WRITE_FAST( addr ) 0 84 #define CAN_WRITE_FAST( addr ) 0
85 #define WRITE_FAST( addr, data ) 85 #define WRITE_FAST( addr, data )
86#endif 86#endif
87 87
88#ifndef CAN_READ_FAST 88#ifndef CAN_READ_FAST
89 #define CAN_READ_FAST( addr ) 0 89 #define CAN_READ_FAST( addr ) 0
90 #define READ_FAST( addr, out ) 90 #define READ_FAST( addr, out )
91#endif 91#endif
92 92
93#ifndef READ_PPU 93#ifndef READ_PPU
94 #define READ_PPU( addr, out )\ 94 #define READ_PPU( addr, out )\
95 {\ 95 {\
96 FLUSH_TIME();\ 96 FLUSH_TIME();\
97 out = READ_MEM( addr );\ 97 out = READ_MEM( addr );\
98 CACHE_TIME();\ 98 CACHE_TIME();\
99 } 99 }
100#endif 100#endif
101 101
102#define READ_STACK READ_LOW 102#define READ_STACK READ_LOW
103#define WRITE_STACK WRITE_LOW 103#define WRITE_STACK WRITE_LOW
104 104
105// Dummy reads 105// Dummy reads
106#ifdef NES_CPU_DUMMY_READS 106#ifdef NES_CPU_DUMMY_READS
107 // TODO: optimize time handling 107 // TODO: optimize time handling
108 #define DUMMY_READ( addr, idx ) \ 108 #define DUMMY_READ( addr, idx ) \
109 if ( (addr & 0xFF) < idx )\ 109 if ( (addr & 0xFF) < idx )\
110 {\ 110 {\
111 int const time_offset = 1;\ 111 int const time_offset = 1;\
112 FLUSH_TIME();\ 112 FLUSH_TIME();\
113 READ_MEM( (addr - 0x100) );\ 113 READ_MEM( (addr - 0x100) );\
114 CACHE_TIME();\ 114 CACHE_TIME();\
115 } 115 }
116#else 116#else
117 #define DUMMY_READ( addr, idx ) 117 #define DUMMY_READ( addr, idx )
118#endif 118#endif
119 119
120// Code 120// Code
121#ifdef FLAT_MEM 121#ifdef FLAT_MEM
122 #define CODE_PAGE( addr ) (FLAT_MEM) 122 #define CODE_PAGE( addr ) (FLAT_MEM)
123 #define CODE_OFFSET( addr ) (addr) 123 #define CODE_OFFSET( addr ) (addr)
124#else 124#else
125 #define CODE_PAGE( addr ) (s.code_map [NES_CPU_PAGE( addr )]) 125 #define CODE_PAGE( addr ) (s.code_map [NES_CPU_PAGE( addr )])
126 #define CODE_OFFSET( addr ) NES_CPU_OFFSET( addr ) 126 #define CODE_OFFSET( addr ) NES_CPU_OFFSET( addr )
127#endif 127#endif
128#define READ_CODE( addr ) (CODE_PAGE( addr ) [CODE_OFFSET( addr )]) 128#define READ_CODE( addr ) (CODE_PAGE( addr ) [CODE_OFFSET( addr )])
129 129
130// Stack 130// Stack
131#define SET_SP( v ) (sp = ((v) + 1) | 0x100) 131#define SET_SP( v ) (sp = ((v) + 1) | 0x100)
132#define GET_SP() ((sp - 1) & 0xFF) 132#define GET_SP() ((sp - 1) & 0xFF)
133#define SP( o ) ((sp + (o - (o>0)*0x100)) | 0x100) 133#define SP( o ) ((sp + (o - (o>0)*0x100)) | 0x100)
134 134
135// Truncation 135// Truncation
136#define BYTE( n ) ((uint8_t ) (n)) /* (unsigned) n & 0xFF */ 136#define BYTE( n ) ((uint8_t ) (n)) /* (unsigned) n & 0xFF */
137#define SBYTE( n ) ((int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */ 137#define SBYTE( n ) ((int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */
138#define WORD( n ) ((uint16_t) (n)) /* (unsigned) n & 0xFFFF */ 138#define WORD( n ) ((uint16_t) (n)) /* (unsigned) n & 0xFFFF */
139 139
140// Flags with hex value for clarity when used as mask. 140// Flags with hex value for clarity when used as mask.
141// Stored in indicated variable during emulation. 141// Stored in indicated variable during emulation.
142int const n80 = 0x80; // nz 142int const n80 = 0x80; // nz
143int const v40 = 0x40; // flags 143int const v40 = 0x40; // flags
144int const r20 = 0x20; 144int const r20 = 0x20;
145int const b10 = 0x10; 145int const b10 = 0x10;
146int const d08 = 0x08; // flags 146int const d08 = 0x08; // flags
147int const i04 = 0x04; // flags 147int const i04 = 0x04; // flags
148int const z02 = 0x02; // nz 148int const z02 = 0x02; // nz
149int const c01 = 0x01; // c 149int const c01 = 0x01; // c
150 150
151#define IS_NEG (nz & 0x8080) 151#define IS_NEG (nz & 0x8080)
152 152
153#define GET_FLAGS( out ) \ 153#define GET_FLAGS( out ) \
154{\ 154{\
155 out = flags & (v40 | d08 | i04);\ 155 out = flags & (v40 | d08 | i04);\
156 out += ((nz >> 8) | nz) & n80;\ 156 out += ((nz >> 8) | nz) & n80;\
157 out += c >> 8 & c01;\ 157 out += c >> 8 & c01;\
158 if ( !BYTE( nz ) )\ 158 if ( !BYTE( nz ) )\
159 out += z02;\ 159 out += z02;\
160} 160}
161 161
162#define SET_FLAGS( in ) \ 162#define SET_FLAGS( in ) \
163{\ 163{\
164 flags = in & (v40 | d08 | i04);\ 164 flags = in & (v40 | d08 | i04);\
165 c = nz = in << 8;\ 165 c = nz = in << 8;\
166 nz += ~in & z02;\ 166 nz += ~in & z02;\
167} 167}
168 168
169{ 169{
170 int const time_offset = 0; 170 int const time_offset = 0;
171 171
172 // Local state 172 // Local state
173 struct cpu_state_t s; 173 struct cpu_state_t s;
174 #ifdef FLAT_MEM 174 #ifdef FLAT_MEM
175 s.base = cpu->cpu_state_.base; 175 s.base = cpu->cpu_state_.base;
176 #else 176 #else
177 s = cpu->cpu_state_; 177 s = cpu->cpu_state_;
178 #endif 178 #endif
179 cpu->cpu_state = &s; 179 cpu->cpu_state = &s;
180 int s_time = cpu->cpu_state_.time; // helps even on x86 180 int s_time = cpu->cpu_state_.time; // helps even on x86
181 181
182 // Registers 182 // Registers
183 int pc = cpu->r.pc; 183 int pc = cpu->r.pc;
184 int a = cpu->r.a; 184 int a = cpu->r.a;
185 int x = cpu->r.x; 185 int x = cpu->r.x;
186 int y = cpu->r.y; 186 int y = cpu->r.y;
187 int sp; 187 int sp;
188 SET_SP( cpu->r.sp ); 188 SET_SP( cpu->r.sp );
189 189
190 // Flags 190 // Flags
191 int flags; 191 int flags;
192 int c; // carry set if (c & 0x100) != 0 192 int c; // carry set if (c & 0x100) != 0
193 int nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 193 int nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0
194 { 194 {
195 int temp = cpu->r.flags; 195 int temp = cpu->r.flags;
196 SET_FLAGS( temp ); 196 SET_FLAGS( temp );
197 } 197 }
198 198
199loop: 199loop:
200 200
201 // Check all values 201 // Check all values
202 check( (unsigned) sp - 0x100 < 0x100 ); 202 check( (unsigned) sp - 0x100 < 0x100 );
203 check( (unsigned) pc < 0x10000 ); 203 check( (unsigned) pc < 0x10000 );
204 check( (unsigned) a < 0x100 ); 204 check( (unsigned) a < 0x100 );
205 check( (unsigned) x < 0x100 ); 205 check( (unsigned) x < 0x100 );
206 check( (unsigned) y < 0x100 ); 206 check( (unsigned) y < 0x100 );
207 207
208 // Read instruction 208 // Read instruction
209 byte const* instr = CODE_PAGE( pc ); 209 byte const* instr = CODE_PAGE( pc );
210 int opcode; 210 int opcode;
211 211
212 if ( CODE_OFFSET(~0) == ~0 ) 212 if ( CODE_OFFSET(~0) == ~0 )
213 { 213 {
214 opcode = instr [pc]; 214 opcode = instr [pc];
215 pc++; 215 pc++;
216 instr += pc; 216 instr += pc;
217 } 217 }
218 else 218 else
219 { 219 {
220 instr += CODE_OFFSET( pc ); 220 instr += CODE_OFFSET( pc );
221 opcode = *instr++; 221 opcode = *instr++;
222 pc++; 222 pc++;
223 } 223 }
224 224
225 // local to function in case it helps optimizer 225 // local to function in case it helps optimizer
226 static byte const clock_table [256] = 226 static byte const clock_table [256] =
227 {// 0 1 2 3 4 5 6 7 8 9 A B C D E F 227 {// 0 1 2 3 4 5 6 7 8 9 A B C D E F
228 0,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,// 0 228 0,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,// 0
229 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 1 229 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 1
230 6,6,0,8,3,3,5,5,4,2,2,2,4,4,6,6,// 2 230 6,6,0,8,3,3,5,5,4,2,2,2,4,4,6,6,// 2
231 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 3 231 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 3
232 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,// 4 232 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,// 4
233 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 5 233 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 5
234 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,// 6 234 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,// 6
235 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 7 235 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 7
236 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// 8 236 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// 8
237 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,// 9 237 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,// 9
238 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// A 238 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// A
239 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,// B 239 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,// B
240 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// C 240 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// C
241 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// D 241 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// D
242 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// E 242 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// E
243 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7 // F 243 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7 // F
244 }; // 0x00 was 7 and 0x22 was 2 244 }; // 0x00 was 7 and 0x22 was 2
245 245
246 // Update time 246 // Update time
247 if ( s_time >= 0 ) 247 if ( s_time >= 0 )
248 goto out_of_time; 248 goto out_of_time;
249 249
250 #ifdef CPU_INSTR_HOOK 250 #ifdef CPU_INSTR_HOOK
251 { CPU_INSTR_HOOK( (pc-1), (&instr [-1]), a, x, y, GET_SP(), TIME() ); } 251 { CPU_INSTR_HOOK( (pc-1), (&instr [-1]), a, x, y, GET_SP(), TIME() ); }
252 #endif 252 #endif
253 253
254 s_time += clock_table [opcode]; 254 s_time += clock_table [opcode];
255 255
256 int data; 256 int data;
257 data = *instr; 257 data = *instr;
258 258
259 switch ( opcode ) 259 switch ( opcode )
260 { 260 {
261 261
262// Macros 262// Macros
263 263
264#define GET_MSB() (instr [1]) 264#define GET_MSB() (instr [1])
265#define ADD_PAGE( out ) (pc++, out = data + 0x100 * GET_MSB()) 265#define ADD_PAGE( out ) (pc++, out = data + 0x100 * GET_MSB())
266#define GET_ADDR() GET_LE16( instr ) 266#define GET_ADDR() GET_LE16( instr )
267 267
268#define PAGE_PENALTY( lsb ) s_time += (lsb) >> 8; 268#define PAGE_PENALTY( lsb ) s_time += (lsb) >> 8;
269 269
270#define INC_DEC( reg, n ) reg = BYTE( nz = reg + n ); goto loop; 270#define INC_DEC( reg, n ) reg = BYTE( nz = reg + n ); goto loop;
271 271
272#define IND_Y( cross, out ) {\ 272#define IND_Y( cross, out ) {\
273 int temp = READ_LOW( data ) + y;\ 273 int temp = READ_LOW( data ) + y;\
274 out = temp + 0x100 * READ_LOW( BYTE( data + 1 ) );\ 274 out = temp + 0x100 * READ_LOW( BYTE( data + 1 ) );\
275 cross( temp );\ 275 cross( temp );\
276 } 276 }
277 277
278#define IND_X( out ) {\ 278#define IND_X( out ) {\
279 int temp = data + x;\ 279 int temp = data + x;\
280 out = 0x100 * READ_LOW( BYTE( temp + 1 ) ) + READ_LOW( BYTE( temp ) );\ 280 out = 0x100 * READ_LOW( BYTE( temp + 1 ) ) + READ_LOW( BYTE( temp ) );\
281 } 281 }
282 282
283#define ARITH_ADDR_MODES( op )\ 283#define ARITH_ADDR_MODES( op )\
284case op - 0x04: /* (ind,x) */\ 284case op - 0x04: /* (ind,x) */\
285 IND_X( data )\ 285 IND_X( data )\
286 goto ptr##op;\ 286 goto ptr##op;\
287case op + 0x0C: /* (ind),y */\ 287case op + 0x0C: /* (ind),y */\
288 IND_Y( PAGE_PENALTY, data )\ 288 IND_Y( PAGE_PENALTY, data )\
289 goto ptr##op;\ 289 goto ptr##op;\
290case op + 0x10: /* zp,X */\ 290case op + 0x10: /* zp,X */\
291 data = BYTE( data + x );\ 291 data = BYTE( data + x );\
292case op + 0x00: /* zp */\ 292case op + 0x00: /* zp */\
293 data = READ_LOW( data );\ 293 data = READ_LOW( data );\
294 goto imm##op;\ 294 goto imm##op;\
295case op + 0x14: /* abs,Y */\ 295case op + 0x14: /* abs,Y */\
296 data += y;\ 296 data += y;\
297 goto ind##op;\ 297 goto ind##op;\
298case op + 0x18: /* abs,X */\ 298case op + 0x18: /* abs,X */\
299 data += x;\ 299 data += x;\
300ind##op:\ 300ind##op:\
301 PAGE_PENALTY( data );\ 301 PAGE_PENALTY( data );\
302case op + 0x08: /* abs */\ 302case op + 0x08: /* abs */\
303 ADD_PAGE( data );\ 303 ADD_PAGE( data );\
304ptr##op:\ 304ptr##op:\
305 FLUSH_TIME();\ 305 FLUSH_TIME();\
306 data = READ_MEM( data );\ 306 data = READ_MEM( data );\
307 CACHE_TIME();\ 307 CACHE_TIME();\
308case op + 0x04: /* imm */\ 308case op + 0x04: /* imm */\
309imm##op: 309imm##op:
310 310
311// TODO: more efficient way to handle negative branch that wraps PC around 311// TODO: more efficient way to handle negative branch that wraps PC around
312#define BRANCH( cond )\ 312#define BRANCH( cond )\
313{\ 313{\
314 ++pc;\ 314 ++pc;\
315 if ( !(cond) ) goto loop;\ 315 if ( !(cond) ) goto loop;\
316 s_time++;\ 316 s_time++;\
317 int offset = SBYTE( data );\ 317 int offset = SBYTE( data );\
318 s_time += (BYTE(pc) + offset) >> 8 & 1;\ 318 s_time += (BYTE(pc) + offset) >> 8 & 1;\
319 pc = WORD( pc + offset );\ 319 pc = WORD( pc + offset );\
320 goto loop;\ 320 goto loop;\
321} 321}
322 322
323// Often-Used 323// Often-Used
324 324
325 case 0xB5: // LDA zp,x 325 case 0xB5: // LDA zp,x
326 a = nz = READ_LOW( BYTE( data + x ) ); 326 a = nz = READ_LOW( BYTE( data + x ) );
327 pc++; 327 pc++;
328 goto loop; 328 goto loop;
329 329
330 case 0xA5: // LDA zp 330 case 0xA5: // LDA zp
331 a = nz = READ_LOW( data ); 331 a = nz = READ_LOW( data );
332 pc++; 332 pc++;
333 goto loop; 333 goto loop;
334 334
335 case 0xD0: // BNE 335 case 0xD0: // BNE
336 BRANCH( BYTE( nz ) ); 336 BRANCH( BYTE( nz ) );
337 337
338 case 0x20: { // JSR 338 case 0x20: { // JSR
339 int temp = pc + 1; 339 int temp = pc + 1;
340 pc = GET_ADDR(); 340 pc = GET_ADDR();
341 WRITE_STACK( SP( -1 ), temp >> 8 ); 341 WRITE_STACK( SP( -1 ), temp >> 8 );
342 sp = SP( -2 ); 342 sp = SP( -2 );
343 WRITE_STACK( sp, temp ); 343 WRITE_STACK( sp, temp );
344 goto loop; 344 goto loop;
345 } 345 }
346 346
347 case 0x4C: // JMP abs 347 case 0x4C: // JMP abs
348 pc = GET_ADDR(); 348 pc = GET_ADDR();
349 goto loop; 349 goto loop;
350 350
351 case 0xE8: // INX 351 case 0xE8: // INX
352 INC_DEC( x, 1 ) 352 INC_DEC( x, 1 )
353 353
354 case 0x10: // BPL 354 case 0x10: // BPL
355 BRANCH( !IS_NEG ) 355 BRANCH( !IS_NEG )
356 356
357 ARITH_ADDR_MODES( 0xC5 ) // CMP 357 ARITH_ADDR_MODES( 0xC5 ) // CMP
358 nz = a - data; 358 nz = a - data;
359 pc++; 359 pc++;
360 c = ~nz; 360 c = ~nz;
361 nz &= 0xFF; 361 nz &= 0xFF;
362 goto loop; 362 goto loop;
363 363
364 case 0x30: // BMI 364 case 0x30: // BMI
365 BRANCH( IS_NEG ) 365 BRANCH( IS_NEG )
366 366
367 case 0xF0: // BEQ 367 case 0xF0: // BEQ
368 BRANCH( !BYTE( nz ) ); 368 BRANCH( !BYTE( nz ) );
369 369
370 case 0x95: // STA zp,x 370 case 0x95: // STA zp,x
371 data = BYTE( data + x ); 371 data = BYTE( data + x );
372 case 0x85: // STA zp 372 case 0x85: // STA zp
373 pc++; 373 pc++;
374 WRITE_LOW( data, a ); 374 WRITE_LOW( data, a );
375 goto loop; 375 goto loop;
376 376
377 case 0xC8: // INY 377 case 0xC8: // INY
378 INC_DEC( y, 1 ) 378 INC_DEC( y, 1 )
379 379
380 case 0xA8: // TAY 380 case 0xA8: // TAY
381 y = a; 381 y = a;
382 nz = a; 382 nz = a;
383 goto loop; 383 goto loop;
384 384
385 case 0x98: // TYA 385 case 0x98: // TYA
386 a = y; 386 a = y;
387 nz = y; 387 nz = y;
388 goto loop; 388 goto loop;
389 389
390 case 0xAD:{// LDA abs 390 case 0xAD:{// LDA abs
391 int addr = GET_ADDR(); 391 int addr = GET_ADDR();
392 pc += 2; 392 pc += 2;
393 READ_PPU( addr, a = nz ); 393 READ_PPU( addr, a = nz );
394 goto loop; 394 goto loop;
395 } 395 }
396 396
397 case 0x60: // RTS 397 case 0x60: // RTS
398 pc = 1 + READ_STACK( sp ); 398 pc = 1 + READ_STACK( sp );
399 pc += 0x100 * READ_STACK( SP( 1 ) ); 399 pc += 0x100 * READ_STACK( SP( 1 ) );
400 sp = SP( 2 ); 400 sp = SP( 2 );
401 goto loop; 401 goto loop;
402 402
403 { 403 {
404 int addr; 404 int addr;
405 405
406 case 0x8D: // STA abs 406 case 0x8D: // STA abs
407 addr = GET_ADDR(); 407 addr = GET_ADDR();
408 pc += 2; 408 pc += 2;
409 if ( CAN_WRITE_FAST( addr ) ) 409 if ( CAN_WRITE_FAST( addr ) )
410 { 410 {
411 WRITE_FAST( addr, a ); 411 WRITE_FAST( addr, a );
412 goto loop; 412 goto loop;
413 } 413 }
414 sta_ptr: 414 sta_ptr:
415 FLUSH_TIME(); 415 FLUSH_TIME();
416 WRITE_MEM( addr, a ); 416 WRITE_MEM( addr, a );
417 CACHE_TIME(); 417 CACHE_TIME();
418 goto loop; 418 goto loop;
419 419
420 case 0x99: // STA abs,Y 420 case 0x99: // STA abs,Y
421 addr = y + GET_ADDR(); 421 addr = y + GET_ADDR();
422 pc += 2; 422 pc += 2;
423 if ( CAN_WRITE_FAST( addr ) ) 423 if ( CAN_WRITE_FAST( addr ) )
424 { 424 {
425 WRITE_FAST( addr, a ); 425 WRITE_FAST( addr, a );
426 goto loop; 426 goto loop;
427 } 427 }
428 goto sta_abs_x; 428 goto sta_abs_x;
429 429
430 case 0x9D: // STA abs,X (slightly more common than STA abs) 430 case 0x9D: // STA abs,X (slightly more common than STA abs)
431 addr = x + GET_ADDR(); 431 addr = x + GET_ADDR();
432 pc += 2; 432 pc += 2;
433 if ( CAN_WRITE_FAST( addr ) ) 433 if ( CAN_WRITE_FAST( addr ) )
434 { 434 {
435 WRITE_FAST( addr, a ); 435 WRITE_FAST( addr, a );
436 goto loop; 436 goto loop;
437 } 437 }
438 DUMMY_READ( addr, x ); 438 DUMMY_READ( addr, x );
439 sta_abs_x: 439 sta_abs_x:
440 FLUSH_TIME(); 440 FLUSH_TIME();
441 WRITE_MEM( addr, a ); 441 WRITE_MEM( addr, a );
442 CACHE_TIME(); 442 CACHE_TIME();
443 goto loop; 443 goto loop;
444 444
445 case 0x91: // STA (ind),Y 445 case 0x91: // STA (ind),Y
446 #define NO_PAGE_PENALTY( lsb ) 446 #define NO_PAGE_PENALTY( lsb )
447 IND_Y( NO_PAGE_PENALTY, addr ) 447 IND_Y( NO_PAGE_PENALTY, addr )
448 pc++; 448 pc++;
449 DUMMY_READ( addr, y ); 449 DUMMY_READ( addr, y );
450 goto sta_ptr; 450 goto sta_ptr;
451 451
452 case 0x81: // STA (ind,X) 452 case 0x81: // STA (ind,X)
453 IND_X( addr ) 453 IND_X( addr )
454 pc++; 454 pc++;
455 goto sta_ptr; 455 goto sta_ptr;
456 456
457 } 457 }
458 458
459 case 0xA9: // LDA #imm 459 case 0xA9: // LDA #imm
460 pc++; 460 pc++;
461 a = data; 461 a = data;
462 nz = data; 462 nz = data;
463 goto loop; 463 goto loop;
464 464
465 // common read instructions 465 // common read instructions
466 { 466 {
467 int addr; 467 int addr;
468 468
469 case 0xA1: // LDA (ind,X) 469 case 0xA1: // LDA (ind,X)
470 IND_X( addr ) 470 IND_X( addr )
471 pc++; 471 pc++;
472 goto a_nz_read_addr; 472 goto a_nz_read_addr;
473 473
474 case 0xB1:// LDA (ind),Y 474 case 0xB1:// LDA (ind),Y
475 addr = READ_LOW( data ) + y; 475 addr = READ_LOW( data ) + y;
476 PAGE_PENALTY( addr ); 476 PAGE_PENALTY( addr );
477 addr += 0x100 * READ_LOW( BYTE( data + 1 ) ); 477 addr += 0x100 * READ_LOW( BYTE( data + 1 ) );
478 pc++; 478 pc++;
479 READ_FAST( addr, a = nz ); 479 READ_FAST( addr, a = nz );
480 if ( CAN_READ_FAST( addr ) ) 480 if ( CAN_READ_FAST( addr ) )
481 goto loop; 481 goto loop;
482 DUMMY_READ( addr, y ); 482 DUMMY_READ( addr, y );
483 goto a_nz_read_addr; 483 goto a_nz_read_addr;
484 484
485 case 0xB9: // LDA abs,Y 485 case 0xB9: // LDA abs,Y
486 PAGE_PENALTY( data + y ); 486 PAGE_PENALTY( data + y );
487 addr = GET_ADDR() + y; 487 addr = GET_ADDR() + y;
488 pc += 2; 488 pc += 2;
489 READ_FAST( addr, a = nz ); 489 READ_FAST( addr, a = nz );
490 if ( CAN_READ_FAST( addr ) ) 490 if ( CAN_READ_FAST( addr ) )
491 goto loop; 491 goto loop;
492 goto a_nz_read_addr; 492 goto a_nz_read_addr;
493 493
494 case 0xBD: // LDA abs,X 494 case 0xBD: // LDA abs,X
495 PAGE_PENALTY( data + x ); 495 PAGE_PENALTY( data + x );
496 addr = GET_ADDR() + x; 496 addr = GET_ADDR() + x;
497 pc += 2; 497 pc += 2;
498 READ_FAST( addr, a = nz ); 498 READ_FAST( addr, a = nz );
499 if ( CAN_READ_FAST( addr ) ) 499 if ( CAN_READ_FAST( addr ) )
500 goto loop; 500 goto loop;
501 DUMMY_READ( addr, x ); 501 DUMMY_READ( addr, x );
502 a_nz_read_addr: 502 a_nz_read_addr:
503 FLUSH_TIME(); 503 FLUSH_TIME();
504 a = nz = READ_MEM( addr ); 504 a = nz = READ_MEM( addr );
505 CACHE_TIME(); 505 CACHE_TIME();
506 goto loop; 506 goto loop;
507 507
508 } 508 }
509 509
510// Branch 510// Branch
511 511
512 case 0x50: // BVC 512 case 0x50: // BVC
513 BRANCH( !(flags & v40) ) 513 BRANCH( !(flags & v40) )
514 514
515 case 0x70: // BVS 515 case 0x70: // BVS
516 BRANCH( flags & v40 ) 516 BRANCH( flags & v40 )
517 517
518 case 0xB0: // BCS 518 case 0xB0: // BCS
519 BRANCH( c & 0x100 ) 519 BRANCH( c & 0x100 )
520 520
521 case 0x90: // BCC 521 case 0x90: // BCC
522 BRANCH( !(c & 0x100) ) 522 BRANCH( !(c & 0x100) )
523 523
524// Load/store 524// Load/store
525 525
526 case 0x94: // STY zp,x 526 case 0x94: // STY zp,x
527 data = BYTE( data + x ); 527 data = BYTE( data + x );
528 case 0x84: // STY zp 528 case 0x84: // STY zp
529 pc++; 529 pc++;
530 WRITE_LOW( data, y ); 530 WRITE_LOW( data, y );
531 goto loop; 531 goto loop;
532 532
533 case 0x96: // STX zp,y 533 case 0x96: // STX zp,y
534 data = BYTE( data + y ); 534 data = BYTE( data + y );
535 case 0x86: // STX zp 535 case 0x86: // STX zp
536 pc++; 536 pc++;
537 WRITE_LOW( data, x ); 537 WRITE_LOW( data, x );
538 goto loop; 538 goto loop;
539 539
540 case 0xB6: // LDX zp,y 540 case 0xB6: // LDX zp,y
541 data = BYTE( data + y ); 541 data = BYTE( data + y );
542 case 0xA6: // LDX zp 542 case 0xA6: // LDX zp
543 data = READ_LOW( data ); 543 data = READ_LOW( data );
544 case 0xA2: // LDX #imm 544 case 0xA2: // LDX #imm
545 pc++; 545 pc++;
546 x = data; 546 x = data;
547 nz = data; 547 nz = data;
548 goto loop; 548 goto loop;
549 549
550 case 0xB4: // LDY zp,x 550 case 0xB4: // LDY zp,x
551 data = BYTE( data + x ); 551 data = BYTE( data + x );
552 case 0xA4: // LDY zp 552 case 0xA4: // LDY zp
553 data = READ_LOW( data ); 553 data = READ_LOW( data );
554 case 0xA0: // LDY #imm 554 case 0xA0: // LDY #imm
555 pc++; 555 pc++;
556 y = data; 556 y = data;
557 nz = data; 557 nz = data;
558 goto loop; 558 goto loop;
559 559
560 case 0xBC: // LDY abs,X 560 case 0xBC: // LDY abs,X
561 data += x; 561 data += x;
562 PAGE_PENALTY( data ); 562 PAGE_PENALTY( data );
563 case 0xAC:{// LDY abs 563 case 0xAC:{// LDY abs
564 int addr = data + 0x100 * GET_MSB(); 564 int addr = data + 0x100 * GET_MSB();
565 pc += 2; 565 pc += 2;
566 FLUSH_TIME(); 566 FLUSH_TIME();
567 y = nz = READ_MEM( addr ); 567 y = nz = READ_MEM( addr );
568 CACHE_TIME(); 568 CACHE_TIME();
569 goto loop; 569 goto loop;
570 } 570 }
571 571
572 case 0xBE: // LDX abs,y 572 case 0xBE: // LDX abs,y
573 data += y; 573 data += y;
574 PAGE_PENALTY( data ); 574 PAGE_PENALTY( data );
575 case 0xAE:{// LDX abs 575 case 0xAE:{// LDX abs
576 int addr = data + 0x100 * GET_MSB(); 576 int addr = data + 0x100 * GET_MSB();
577 pc += 2; 577 pc += 2;
578 FLUSH_TIME(); 578 FLUSH_TIME();
579 x = nz = READ_MEM( addr ); 579 x = nz = READ_MEM( addr );
580 CACHE_TIME(); 580 CACHE_TIME();
581 goto loop; 581 goto loop;
582 } 582 }
583 583
584 { 584 {
585 int temp; 585 int temp;
586 case 0x8C: // STY abs 586 case 0x8C: // STY abs
587 temp = y; 587 temp = y;
588 goto store_abs; 588 goto store_abs;
589 589
590 case 0x8E: // STX abs 590 case 0x8E: // STX abs
591 temp = x; 591 temp = x;
592 store_abs: 592 store_abs:
593 { 593 {
594 int addr = GET_ADDR(); 594 int addr = GET_ADDR();
595 pc += 2; 595 pc += 2;
596 if ( CAN_WRITE_FAST( addr ) ) 596 if ( CAN_WRITE_FAST( addr ) )
597 { 597 {
598 WRITE_FAST( addr, temp ); 598 WRITE_FAST( addr, temp );
599 goto loop; 599 goto loop;
600 } 600 }
601 FLUSH_TIME(); 601 FLUSH_TIME();
602 WRITE_MEM( addr, temp ); 602 WRITE_MEM( addr, temp );
603 CACHE_TIME(); 603 CACHE_TIME();
604 goto loop; 604 goto loop;
605 } 605 }
606 } 606 }
607 607
608// Compare 608// Compare
609 609
610 case 0xEC: {// CPX abs 610 case 0xEC: {// CPX abs
611 int addr = GET_ADDR(); 611 int addr = GET_ADDR();
612 pc++; 612 pc++;
613 FLUSH_TIME(); 613 FLUSH_TIME();
614 data = READ_MEM( addr ); 614 data = READ_MEM( addr );
615 CACHE_TIME(); 615 CACHE_TIME();
616 goto cpx_data; 616 goto cpx_data;
617 } 617 }
618 618
619 case 0xE4: // CPX zp 619 case 0xE4: // CPX zp
620 data = READ_LOW( data ); 620 data = READ_LOW( data );
621 case 0xE0: // CPX #imm 621 case 0xE0: // CPX #imm
622 cpx_data: 622 cpx_data:
623 nz = x - data; 623 nz = x - data;
624 pc++; 624 pc++;
625 c = ~nz; 625 c = ~nz;
626 nz &= 0xFF; 626 nz &= 0xFF;
627 goto loop; 627 goto loop;
628 628
629 case 0xCC:{// CPY abs 629 case 0xCC:{// CPY abs
630 int addr = GET_ADDR(); 630 int addr = GET_ADDR();
631 pc++; 631 pc++;
632 FLUSH_TIME(); 632 FLUSH_TIME();
633 data = READ_MEM( addr ); 633 data = READ_MEM( addr );
634 CACHE_TIME(); 634 CACHE_TIME();
635 goto cpy_data; 635 goto cpy_data;
636 } 636 }
637 637
638 case 0xC4: // CPY zp 638 case 0xC4: // CPY zp
639 data = READ_LOW( data ); 639 data = READ_LOW( data );
640 case 0xC0: // CPY #imm 640 case 0xC0: // CPY #imm
641 cpy_data: 641 cpy_data:
642 nz = y - data; 642 nz = y - data;
643 pc++; 643 pc++;
644 c = ~nz; 644 c = ~nz;
645 nz &= 0xFF; 645 nz &= 0xFF;
646 goto loop; 646 goto loop;
647 647
648// Logical 648// Logical
649 649
650 ARITH_ADDR_MODES( 0x25 ) // AND 650 ARITH_ADDR_MODES( 0x25 ) // AND
651 nz = (a &= data); 651 nz = (a &= data);
652 pc++; 652 pc++;
653 goto loop; 653 goto loop;
654 654
655 ARITH_ADDR_MODES( 0x45 ) // EOR 655 ARITH_ADDR_MODES( 0x45 ) // EOR
656 nz = (a ^= data); 656 nz = (a ^= data);
657 pc++; 657 pc++;
658 goto loop; 658 goto loop;
659 659
660 ARITH_ADDR_MODES( 0x05 ) // ORA 660 ARITH_ADDR_MODES( 0x05 ) // ORA
661 nz = (a |= data); 661 nz = (a |= data);
662 pc++; 662 pc++;
663 goto loop; 663 goto loop;
664 664
665 case 0x2C:{// BIT abs 665 case 0x2C:{// BIT abs
666 int addr = GET_ADDR(); 666 int addr = GET_ADDR();
667 pc += 2; 667 pc += 2;
668 READ_PPU( addr, nz ); 668 READ_PPU( addr, nz );
669 flags = (flags & ~v40) + (nz & v40); 669 flags = (flags & ~v40) + (nz & v40);
670 if ( a & nz ) 670 if ( a & nz )
671 goto loop; 671 goto loop;
672 nz <<= 8; // result must be zero, even if N bit is set 672 nz <<= 8; // result must be zero, even if N bit is set
673 goto loop; 673 goto loop;
674 } 674 }
675 675
676 case 0x24: // BIT zp 676 case 0x24: // BIT zp
677 nz = READ_LOW( data ); 677 nz = READ_LOW( data );
678 pc++; 678 pc++;
679 flags = (flags & ~v40) + (nz & v40); 679 flags = (flags & ~v40) + (nz & v40);
680 if ( a & nz ) 680 if ( a & nz )
681 goto loop; // Z should be clear, and nz must be non-zero if nz & a is 681 goto loop; // Z should be clear, and nz must be non-zero if nz & a is
682 nz <<= 8; // set Z flag without affecting N flag 682 nz <<= 8; // set Z flag without affecting N flag
683 goto loop; 683 goto loop;
684 684
685// Add/subtract 685// Add/subtract
686 686
687 ARITH_ADDR_MODES( 0xE5 ) // SBC 687 ARITH_ADDR_MODES( 0xE5 ) // SBC
688 case 0xEB: // unofficial equivalent 688 case 0xEB: // unofficial equivalent
689 data ^= 0xFF; 689 data ^= 0xFF;
690 goto adc_imm; 690 goto adc_imm;
691 691
692 ARITH_ADDR_MODES( 0x65 ) // ADC 692 ARITH_ADDR_MODES( 0x65 ) // ADC
693 adc_imm: { 693 adc_imm: {
694 int carry = c >> 8 & 1; 694 int carry = c >> 8 & 1;
695 int ov = (a ^ 0x80) + carry + SBYTE( data ); 695 int ov = (a ^ 0x80) + carry + SBYTE( data );
696 flags = (flags & ~v40) + (ov >> 2 & v40); 696 flags = (flags & ~v40) + (ov >> 2 & v40);
697 c = nz = a + data + carry; 697 c = nz = a + data + carry;
698 pc++; 698 pc++;
699 a = BYTE( nz ); 699 a = BYTE( nz );
700 goto loop; 700 goto loop;
701 } 701 }
702 702
703// Shift/rotate 703// Shift/rotate
704 704
705 case 0x4A: // LSR A 705 case 0x4A: // LSR A
706 c = 0; 706 c = 0;
707 case 0x6A: // ROR A 707 case 0x6A: // ROR A
708 nz = c >> 1 & 0x80; 708 nz = c >> 1 & 0x80;
709 c = a << 8; 709 c = a << 8;
710 nz += a >> 1; 710 nz += a >> 1;
711 a = nz; 711 a = nz;
712 goto loop; 712 goto loop;
713 713
714 case 0x0A: // ASL A 714 case 0x0A: // ASL A
715 nz = a << 1; 715 nz = a << 1;
716 c = nz; 716 c = nz;
717 a = BYTE( nz ); 717 a = BYTE( nz );
718 goto loop; 718 goto loop;
719 719
720 case 0x2A: { // ROL A 720 case 0x2A: { // ROL A
721 nz = a << 1; 721 nz = a << 1;
722 int temp = c >> 8 & 1; 722 int temp = c >> 8 & 1;
723 c = nz; 723 c = nz;
724 nz += temp; 724 nz += temp;
725 a = BYTE( nz ); 725 a = BYTE( nz );
726 goto loop; 726 goto loop;
727 } 727 }
728 728
729 case 0x5E: // LSR abs,X 729 case 0x5E: // LSR abs,X
730 data += x; 730 data += x;
731 case 0x4E: // LSR abs 731 case 0x4E: // LSR abs
732 c = 0; 732 c = 0;
733 case 0x6E: // ROR abs 733 case 0x6E: // ROR abs
734 ror_abs: { 734 ror_abs: {
735 ADD_PAGE( data ); 735 ADD_PAGE( data );
736 FLUSH_TIME(); 736 FLUSH_TIME();
737 int temp = READ_MEM( data ); 737 int temp = READ_MEM( data );
738 nz = (c >> 1 & 0x80) + (temp >> 1); 738 nz = (c >> 1 & 0x80) + (temp >> 1);
739 c = temp << 8; 739 c = temp << 8;
740 goto rotate_common; 740 goto rotate_common;
741 } 741 }
742 742
743 case 0x3E: // ROL abs,X 743 case 0x3E: // ROL abs,X
744 data += x; 744 data += x;
745 goto rol_abs; 745 goto rol_abs;
746 746
747 case 0x1E: // ASL abs,X 747 case 0x1E: // ASL abs,X
748 data += x; 748 data += x;
749 case 0x0E: // ASL abs 749 case 0x0E: // ASL abs
750 c = 0; 750 c = 0;
751 case 0x2E: // ROL abs 751 case 0x2E: // ROL abs
752 rol_abs: 752 rol_abs:
753 ADD_PAGE( data ); 753 ADD_PAGE( data );
754 nz = c >> 8 & 1; 754 nz = c >> 8 & 1;
755 FLUSH_TIME(); 755 FLUSH_TIME();
756 nz += (c = READ_MEM( data ) << 1); 756 nz += (c = READ_MEM( data ) << 1);
757 rotate_common: 757 rotate_common:
758 pc++; 758 pc++;
759 WRITE_MEM( data, BYTE( nz ) ); 759 WRITE_MEM( data, BYTE( nz ) );
760 CACHE_TIME(); 760 CACHE_TIME();
761 goto loop; 761 goto loop;
762 762
763 case 0x7E: // ROR abs,X 763 case 0x7E: // ROR abs,X
764 data += x; 764 data += x;
765 goto ror_abs; 765 goto ror_abs;
766 766
767 case 0x76: // ROR zp,x 767 case 0x76: // ROR zp,x
768 data = BYTE( data + x ); 768 data = BYTE( data + x );
769 goto ror_zp; 769 goto ror_zp;
770 770
771 case 0x56: // LSR zp,x 771 case 0x56: // LSR zp,x
772 data = BYTE( data + x ); 772 data = BYTE( data + x );
773 case 0x46: // LSR zp 773 case 0x46: // LSR zp
774 c = 0; 774 c = 0;
775 case 0x66: // ROR zp 775 case 0x66: // ROR zp
776 ror_zp: { 776 ror_zp: {
777 int temp = READ_LOW( data ); 777 int temp = READ_LOW( data );
778 nz = (c >> 1 & 0x80) + (temp >> 1); 778 nz = (c >> 1 & 0x80) + (temp >> 1);
779 c = temp << 8; 779 c = temp << 8;
780 goto write_nz_zp; 780 goto write_nz_zp;
781 } 781 }
782 782
783 case 0x36: // ROL zp,x 783 case 0x36: // ROL zp,x
784 data = BYTE( data + x ); 784 data = BYTE( data + x );
785 goto rol_zp; 785 goto rol_zp;
786 786
787 case 0x16: // ASL zp,x 787 case 0x16: // ASL zp,x
788 data = BYTE( data + x ); 788 data = BYTE( data + x );
789 case 0x06: // ASL zp 789 case 0x06: // ASL zp
790 c = 0; 790 c = 0;
791 case 0x26: // ROL zp 791 case 0x26: // ROL zp
792 rol_zp: 792 rol_zp:
793 nz = c >> 8 & 1; 793 nz = c >> 8 & 1;
794 nz += (c = READ_LOW( data ) << 1); 794 nz += (c = READ_LOW( data ) << 1);
795 goto write_nz_zp; 795 goto write_nz_zp;
796 796
797// Increment/decrement 797// Increment/decrement
798 798
799 case 0xCA: // DEX 799 case 0xCA: // DEX
800 INC_DEC( x, -1 ) 800 INC_DEC( x, -1 )
801 801
802 case 0x88: // DEY 802 case 0x88: // DEY
803 INC_DEC( y, -1 ) 803 INC_DEC( y, -1 )
804 804
805 case 0xF6: // INC zp,x 805 case 0xF6: // INC zp,x
806 data = BYTE( data + x ); 806 data = BYTE( data + x );
807 case 0xE6: // INC zp 807 case 0xE6: // INC zp
808 nz = 1; 808 nz = 1;
809 goto add_nz_zp; 809 goto add_nz_zp;
810 810
811 case 0xD6: // DEC zp,x 811 case 0xD6: // DEC zp,x
812 data = BYTE( data + x ); 812 data = BYTE( data + x );
813 case 0xC6: // DEC zp 813 case 0xC6: // DEC zp
814 nz = -1; 814 nz = -1;
815 add_nz_zp: 815 add_nz_zp:
816 nz += READ_LOW( data ); 816 nz += READ_LOW( data );
817 write_nz_zp: 817 write_nz_zp:
818 pc++; 818 pc++;
819 WRITE_LOW( data, nz ); 819 WRITE_LOW( data, nz );
820 goto loop; 820 goto loop;
821 821
822 case 0xFE: // INC abs,x 822 case 0xFE: // INC abs,x
823 data = x + GET_ADDR(); 823 data = x + GET_ADDR();
824 goto inc_ptr; 824 goto inc_ptr;
825 825
826 case 0xEE: // INC abs 826 case 0xEE: // INC abs
827 data = GET_ADDR(); 827 data = GET_ADDR();
828 inc_ptr: 828 inc_ptr:
829 nz = 1; 829 nz = 1;
830 goto inc_common; 830 goto inc_common;
831 831
832 case 0xDE: // DEC abs,x 832 case 0xDE: // DEC abs,x
833 data = x + GET_ADDR(); 833 data = x + GET_ADDR();
834 goto dec_ptr; 834 goto dec_ptr;
835 835
836 case 0xCE: // DEC abs 836 case 0xCE: // DEC abs
837 data = GET_ADDR(); 837 data = GET_ADDR();
838 dec_ptr: 838 dec_ptr:
839 nz = -1; 839 nz = -1;
840 inc_common: 840 inc_common:
841 FLUSH_TIME(); 841 FLUSH_TIME();
842 pc += 2; 842 pc += 2;
843 nz += READ_MEM( data ); 843 nz += READ_MEM( data );
844 WRITE_MEM( data, BYTE( nz ) ); 844 WRITE_MEM( data, BYTE( nz ) );
845 CACHE_TIME(); 845 CACHE_TIME();
846 goto loop; 846 goto loop;
847 847
848// Transfer 848// Transfer
849 849
850 case 0xAA: // TAX 850 case 0xAA: // TAX
851 x = nz = a; 851 x = nz = a;
852 goto loop; 852 goto loop;
853 853
854 case 0x8A: // TXA 854 case 0x8A: // TXA
855 a = nz = x; 855 a = nz = x;
856 goto loop; 856 goto loop;
857 857
858 case 0x9A: // TXS 858 case 0x9A: // TXS
859 SET_SP( x ); // verified (no flag change) 859 SET_SP( x ); // verified (no flag change)
860 goto loop; 860 goto loop;
861 861
862 case 0xBA: // TSX 862 case 0xBA: // TSX
863 x = nz = GET_SP(); 863 x = nz = GET_SP();
864 goto loop; 864 goto loop;
865 865
866// Stack 866// Stack
867 867
868 case 0x48: // PHA 868 case 0x48: // PHA
869 sp = SP( -1 ); 869 sp = SP( -1 );
870 WRITE_STACK( sp, a ); 870 WRITE_STACK( sp, a );
871 goto loop; 871 goto loop;
872 872
873 case 0x68: // PLA 873 case 0x68: // PLA
874 a = nz = READ_STACK( sp ); 874 a = nz = READ_STACK( sp );
875 sp = SP( 1 ); 875 sp = SP( 1 );
876 goto loop; 876 goto loop;
877 877
878 case 0x40:{// RTI 878 case 0x40:{// RTI
879 pc = READ_STACK( SP( 1 ) ); 879 pc = READ_STACK( SP( 1 ) );
880 pc += READ_STACK( SP( 2 ) ) * 0x100; 880 pc += READ_STACK( SP( 2 ) ) * 0x100;
881 int temp = READ_STACK( sp ); 881 int temp = READ_STACK( sp );
882 sp = SP( 3 ); 882 sp = SP( 3 );
883 data = flags; 883 data = flags;
884 SET_FLAGS( temp ); 884 SET_FLAGS( temp );
885 cpu->r.flags = flags; // update externally-visible I flag 885 cpu->r.flags = flags; // update externally-visible I flag
886 int delta = s.base - cpu->irq_time; 886 int delta = s.base - cpu->irq_time;
887 if ( delta <= 0 ) goto loop; // end_time < irq_time 887 if ( delta <= 0 ) goto loop; // end_time < irq_time
888 if ( flags & i04 ) goto loop; 888 if ( flags & i04 ) goto loop;
889 s_time += delta; 889 s_time += delta;
890 s.base = cpu->irq_time; 890 s.base = cpu->irq_time;
891 goto loop; 891 goto loop;
892 } 892 }
893 893
894 case 0x28:{// PLP 894 case 0x28:{// PLP
895 int temp = READ_STACK( sp ); 895 int temp = READ_STACK( sp );
896 sp = SP( 1 ); 896 sp = SP( 1 );
897 int changed = flags ^ temp; 897 int changed = flags ^ temp;
898 SET_FLAGS( temp ); 898 SET_FLAGS( temp );
899 if ( !(changed & i04) ) 899 if ( !(changed & i04) )
900 goto loop; // I flag didn't change 900 goto loop; // I flag didn't change
901 if ( flags & i04 ) 901 if ( flags & i04 )
902 goto handle_sei; 902 goto handle_sei;
903 goto handle_cli; 903 goto handle_cli;
904 } 904 }
905 905
906 case 0x08:{// PHP 906 case 0x08:{// PHP
907 int temp; 907 int temp;
908 GET_FLAGS( temp ); 908 GET_FLAGS( temp );
909 sp = SP( -1 ); 909 sp = SP( -1 );
910 WRITE_STACK( sp, temp | (b10 | r20) ); 910 WRITE_STACK( sp, temp | (b10 | r20) );
911 goto loop; 911 goto loop;
912 } 912 }
913 913
914 case 0x6C:{// JMP (ind) 914 case 0x6C:{// JMP (ind)
915 data = GET_ADDR(); 915 data = GET_ADDR();
916 byte const* page = CODE_PAGE( data ); 916 byte const* page = CODE_PAGE( data );
917 pc = page [CODE_OFFSET( data )]; 917 pc = page [CODE_OFFSET( data )];
918 data = (data & 0xFF00) + ((data + 1) & 0xFF); 918 data = (data & 0xFF00) + ((data + 1) & 0xFF);
919 pc += page [CODE_OFFSET( data )] * 0x100; 919 pc += page [CODE_OFFSET( data )] * 0x100;
920 goto loop; 920 goto loop;
921 } 921 }
922 922
923 case 0x00: // BRK 923 case 0x00: // BRK
924 goto handle_brk; 924 goto handle_brk;
925 925
926// Flags 926// Flags
927 927
928 case 0x38: // SEC 928 case 0x38: // SEC
929 c = 0x100; 929 c = 0x100;
930 goto loop; 930 goto loop;
931 931
932 case 0x18: // CLC 932 case 0x18: // CLC
933 c = 0; 933 c = 0;
934 goto loop; 934 goto loop;
935 935
936 case 0xB8: // CLV 936 case 0xB8: // CLV
937 flags &= ~v40; 937 flags &= ~v40;
938 goto loop; 938 goto loop;
939 939
940 case 0xD8: // CLD 940 case 0xD8: // CLD
941 flags &= ~d08; 941 flags &= ~d08;
942 goto loop; 942 goto loop;
943 943
944 case 0xF8: // SED 944 case 0xF8: // SED
945 flags |= d08; 945 flags |= d08;
946 goto loop; 946 goto loop;
947 947
948 case 0x58: // CLI 948 case 0x58: // CLI
949 if ( !(flags & i04) ) 949 if ( !(flags & i04) )
950 goto loop; 950 goto loop;
951 flags &= ~i04; 951 flags &= ~i04;
952 handle_cli: { 952 handle_cli: {
953 //dprintf( "CLI at %d\n", TIME ); 953 //dprintf( "CLI at %d\n", TIME );
954 cpu->r.flags = flags; // update externally-visible I flag 954 cpu->r.flags = flags; // update externally-visible I flag
955 int delta = s.base - cpu->irq_time; 955 int delta = s.base - cpu->irq_time;
956 if ( delta <= 0 ) 956 if ( delta <= 0 )
957 { 957 {
958 if ( TIME() < cpu->irq_time ) 958 if ( TIME() < cpu->irq_time )
959 goto loop; 959 goto loop;
960 goto delayed_cli; 960 goto delayed_cli;
961 } 961 }
962 s.base = cpu->irq_time; 962 s.base = cpu->irq_time;
963 s_time += delta; 963 s_time += delta;
964 if ( s_time < 0 ) 964 if ( s_time < 0 )
965 goto loop; 965 goto loop;
966 966
967 if ( delta >= s_time + 1 ) 967 if ( delta >= s_time + 1 )
968 { 968 {
969 // delayed irq until after next instruction 969 // delayed irq until after next instruction
970 s.base += s_time + 1; 970 s.base += s_time + 1;
971 s_time = -1; 971 s_time = -1;
972 goto loop; 972 goto loop;
973 } 973 }
974 974
975 // TODO: implement 975 // TODO: implement
976 delayed_cli: 976 delayed_cli:
977 dprintf( "Delayed CLI not emulated\n" ); 977 dprintf( "Delayed CLI not emulated\n" );
978 goto loop; 978 goto loop;
979 } 979 }
980 980
981 case 0x78: // SEI 981 case 0x78: // SEI
982 if ( flags & i04 ) 982 if ( flags & i04 )
983 goto loop; 983 goto loop;
984 flags |= i04; 984 flags |= i04;
985 handle_sei: { 985 handle_sei: {
986 cpu->r.flags = flags; // update externally-visible I flag 986 cpu->r.flags = flags; // update externally-visible I flag
987 int delta = s.base - cpu->end_time; 987 int delta = s.base - cpu->end_time;
988 s.base = cpu->end_time; 988 s.base = cpu->end_time;
989 s_time += delta; 989 s_time += delta;
990 if ( s_time < 0 ) 990 if ( s_time < 0 )
991 goto loop; 991 goto loop;
992 992
993 dprintf( "Delayed SEI not emulated\n" ); 993 dprintf( "Delayed SEI not emulated\n" );
994 goto loop; 994 goto loop;
995 } 995 }
996 996
997// Unofficial 997// Unofficial
998 998
999 // SKW - skip word 999 // SKW - skip word
1000 case 0x1C: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC: 1000 case 0x1C: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC:
1001 PAGE_PENALTY( data + x ); 1001 PAGE_PENALTY( data + x );
1002 case 0x0C: 1002 case 0x0C:
1003 pc++; 1003 pc++;
1004 // SKB - skip byte 1004 // SKB - skip byte
1005 case 0x74: case 0x04: case 0x14: case 0x34: case 0x44: case 0x54: case 0x64: 1005 case 0x74: case 0x04: case 0x14: case 0x34: case 0x44: case 0x54: case 0x64:
1006 case 0x80: case 0x82: case 0x89: case 0xC2: case 0xD4: case 0xE2: case 0xF4: 1006 case 0x80: case 0x82: case 0x89: case 0xC2: case 0xD4: case 0xE2: case 0xF4:
1007 pc++; 1007 pc++;
1008 goto loop; 1008 goto loop;
1009 1009
1010 // NOP 1010 // NOP
1011 case 0xEA: case 0x1A: case 0x3A: case 0x5A: case 0x7A: case 0xDA: case 0xFA: 1011 case 0xEA: case 0x1A: case 0x3A: case 0x5A: case 0x7A: case 0xDA: case 0xFA:
1012 goto loop; 1012 goto loop;
1013 1013
1014 case halt_opcode: // HLT - halt processor 1014 case halt_opcode: // HLT - halt processor
1015 if ( pc-- > 0x10000 ) 1015 if ( pc-- > 0x10000 )
1016 { 1016 {
1017 // handle wrap-around (assumes caller has put page of HLT at 0x10000) 1017 // handle wrap-around (assumes caller has put page of HLT at 0x10000)
1018 pc = WORD( pc ); 1018 pc = WORD( pc );
1019 goto loop; 1019 goto loop;
1020 } 1020 }
1021 case 0x02: case 0x12: case 0x32: case 0x42: case 0x52: 1021 case 0x02: case 0x12: case 0x32: case 0x42: case 0x52:
1022 case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2: 1022 case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2:
1023 goto stop; 1023 goto stop;
1024 1024
1025// Unimplemented 1025// Unimplemented
1026 1026
1027 case 0xFF: // force 256-entry jump table for optimization purposes 1027 case 0xFF: // force 256-entry jump table for optimization purposes
1028 c |= 1; // compiler doesn't know that this won't affect anything 1028 c |= 1; // compiler doesn't know that this won't affect anything
1029 default: 1029 default:
1030 check( (unsigned) opcode < 0x100 ); 1030 check( (unsigned) opcode < 0x100 );
1031 1031
1032 #ifdef UNIMPL_INSTR 1032 #ifdef UNIMPL_INSTR
1033 UNIMPL_INSTR(); 1033 UNIMPL_INSTR();
1034 #endif 1034 #endif
1035 1035
1036 // At least skip over proper number of bytes instruction uses 1036 // At least skip over proper number of bytes instruction uses
1037 static unsigned char const illop_lens [8] = { 1037 static unsigned char const illop_lens [8] = {
1038 0x40, 0x40, 0x40, 0x80, 0x40, 0x40, 0x80, 0xA0 1038 0x40, 0x40, 0x40, 0x80, 0x40, 0x40, 0x80, 0xA0
1039 }; 1039 };
1040 int opcode = instr [-1]; 1040 int opcode = instr [-1];
1041 int len = illop_lens [opcode >> 2 & 7] >> (opcode << 1 & 6) & 3; 1041 int len = illop_lens [opcode >> 2 & 7] >> (opcode << 1 & 6) & 3;
1042 if ( opcode == 0x9C ) 1042 if ( opcode == 0x9C )
1043 len = 2; 1043 len = 2;
1044 pc += len; 1044 pc += len;
1045 1045
1046 // Account for extra clock 1046 // Account for extra clock
1047 if ( (opcode >> 4) == 0x0B ) 1047 if ( (opcode >> 4) == 0x0B )
1048 { 1048 {
1049 if ( opcode == 0xB3 ) 1049 if ( opcode == 0xB3 )
1050 data = READ_LOW( data ); 1050 data = READ_LOW( data );
1051 if ( opcode != 0xB7 ) 1051 if ( opcode != 0xB7 )
1052 PAGE_PENALTY( data + y ); 1052 PAGE_PENALTY( data + y );
1053 } 1053 }
1054 goto loop; 1054 goto loop;
1055 } 1055 }
1056 assert( false ); // catch missing 'goto loop' or accidental 'break' 1056 assert( false ); // catch missing 'goto loop' or accidental 'break'
1057 1057
1058 int result_; 1058 int result_;
1059handle_brk: 1059handle_brk:
1060 pc++; 1060 pc++;
1061 result_ = b10 | 4; 1061 result_ = b10 | 4;
1062 1062
1063#ifdef CPU_DONE 1063#ifdef CPU_DONE
1064interrupt: 1064interrupt:
1065#endif 1065#endif
1066 { 1066 {
1067 s_time += 7; 1067 s_time += 7;
1068 1068
1069 // Save PC and read vector 1069 // Save PC and read vector
1070 WRITE_STACK( SP( -1 ), pc >> 8 ); 1070 WRITE_STACK( SP( -1 ), pc >> 8 );
1071 WRITE_STACK( SP( -2 ), pc ); 1071 WRITE_STACK( SP( -2 ), pc );
1072 pc = GET_LE16( &READ_CODE( 0xFFFA ) + (result_ & 4) ); 1072 pc = GET_LE16( &READ_CODE( 0xFFFA ) + (result_ & 4) );
1073 1073
1074 // Save flags 1074 // Save flags
1075 int temp; 1075 int temp;
1076 GET_FLAGS( temp ); 1076 GET_FLAGS( temp );
1077 temp |= r20 + (result_ & b10); // B flag set for BRK 1077 temp |= r20 + (result_ & b10); // B flag set for BRK
1078 sp = SP( -3 ); 1078 sp = SP( -3 );
1079 WRITE_STACK( sp, temp ); 1079 WRITE_STACK( sp, temp );
1080 1080
1081 // Update I flag in externally-visible flags 1081 // Update I flag in externally-visible flags
1082 cpu->r.flags = (flags |= i04); 1082 cpu->r.flags = (flags |= i04);
1083 1083
1084 // Update time 1084 // Update time
1085 int delta = s.base - cpu->end_time; 1085 int delta = s.base - cpu->end_time;
1086 if ( delta >= 0 ) 1086 if ( delta >= 0 )
1087 goto loop; 1087 goto loop;
1088 s_time += delta; 1088 s_time += delta;
1089 s.base = cpu->end_time; 1089 s.base = cpu->end_time;
1090 goto loop; 1090 goto loop;
1091 } 1091 }
1092 1092
1093out_of_time: 1093out_of_time:
1094 pc--; 1094 pc--;
1095 1095
1096 // Optional action that triggers interrupt or changes irq/end time 1096 // Optional action that triggers interrupt or changes irq/end time
1097 #ifdef CPU_DONE 1097 #ifdef CPU_DONE
1098 { 1098 {
1099 CPU_DONE( result_ ); 1099 CPU_DONE( result_ );
1100 if ( result_ >= 0 ) 1100 if ( result_ >= 0 )
1101 goto interrupt; 1101 goto interrupt;
1102 if ( s_time < 0 ) 1102 if ( s_time < 0 )
1103 goto loop; 1103 goto loop;
1104 } 1104 }
1105 #endif 1105 #endif
1106stop: 1106stop:
1107 1107
1108 // Flush cached state 1108 // Flush cached state
1109 cpu->r.pc = pc; 1109 cpu->r.pc = pc;
1110 cpu->r.sp = GET_SP(); 1110 cpu->r.sp = GET_SP();
1111 cpu->r.a = a; 1111 cpu->r.a = a;
1112 cpu->r.x = x; 1112 cpu->r.x = x;
1113 cpu->r.y = y; 1113 cpu->r.y = y;
1114 1114
1115 int temp; 1115 int temp;
1116 GET_FLAGS( temp ); 1116 GET_FLAGS( temp );
1117 cpu->r.flags = temp; 1117 cpu->r.flags = temp;
1118 1118
1119 cpu->cpu_state_.base = s.base; 1119 cpu->cpu_state_.base = s.base;
1120 cpu->cpu_state_.time = s_time; 1120 cpu->cpu_state_.time = s_time;
1121 cpu->cpu_state = &cpu->cpu_state_; 1121 cpu->cpu_state = &cpu->cpu_state_;
1122} 1122}