/src/vlc/contrib/contrib-build/game-music-emu/gme/Nes_Cpu.cpp
Line | Count | Source |
1 | | // Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ |
2 | | |
3 | | #include "Nes_Cpu.h" |
4 | | |
5 | | #include "blargg_endian.h" |
6 | | #include <limits.h> |
7 | | |
8 | | #define BLARGG_CPU_X86 1 |
9 | | |
10 | | /* Copyright (C) 2003-2006 Shay Green. This module is free software; you |
11 | | can redistribute it and/or modify it under the terms of the GNU Lesser |
12 | | General Public License as published by the Free Software Foundation; either |
13 | | version 2.1 of the License, or (at your option) any later version. This |
14 | | module is distributed in the hope that it will be useful, but WITHOUT ANY |
15 | | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
16 | | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
17 | | details. You should have received a copy of the GNU Lesser General Public |
18 | | License along with this module; if not, write to the Free Software Foundation, |
19 | | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ |
20 | | |
21 | | #ifdef BLARGG_ENABLE_OPTIMIZER |
22 | | #include BLARGG_ENABLE_OPTIMIZER |
23 | | #endif |
24 | | |
25 | 158M | #define FLUSH_TIME() (void) (s.time = s_time) |
26 | 158M | #define CACHE_TIME() (void) (s_time = s.time) |
27 | | |
28 | | #include "nes_cpu_io.h" |
29 | | |
30 | | #include "blargg_source.h" |
31 | | |
32 | | #ifndef CPU_DONE |
33 | 16.2M | #define CPU_DONE( cpu, time, result_out ) { result_out = -1; } |
34 | | #endif |
35 | | |
36 | | #ifndef CPU_READ_PPU |
37 | | #define CPU_READ_PPU( cpu, addr, out, time )\ |
38 | 2.39M | {\ |
39 | 2.39M | FLUSH_TIME();\ |
40 | 2.39M | out = CPU_READ( cpu, addr, time );\ |
41 | 2.39M | CACHE_TIME();\ |
42 | 2.39M | } |
43 | | #endif |
44 | | |
45 | | #if BLARGG_NONPORTABLE |
46 | | #define PAGE_OFFSET( addr ) (addr) |
47 | | #else |
48 | 2.84G | #define PAGE_OFFSET( addr ) ((addr) & (page_size - 1)) |
49 | | #endif |
50 | | |
51 | | inline void Nes_Cpu::set_code_page( int i, void const* p ) |
52 | 282k | { |
53 | 282k | state->code_map [i] = (uint8_t const*) p - PAGE_OFFSET( i * page_size ); |
54 | 282k | } |
55 | | |
56 | | enum { |
57 | | st_n = 0x80, |
58 | | st_v = 0x40, |
59 | | st_r = 0x20, |
60 | | st_b = 0x10, |
61 | | st_d = 0x08, |
62 | | st_i = 0x04, |
63 | | st_z = 0x02, |
64 | | st_c = 0x01 |
65 | | }; |
66 | | |
67 | | void Nes_Cpu::reset( void const* unmapped_page ) |
68 | 5.32k | { |
69 | 5.32k | check( state == &state_ ); |
70 | 5.32k | state = &state_; |
71 | 5.32k | r.status = st_i; |
72 | 5.32k | r.sp = 0xFF; |
73 | 5.32k | r.pc = 0; |
74 | 5.32k | r.a = 0; |
75 | 5.32k | r.x = 0; |
76 | 5.32k | r.y = 0; |
77 | 5.32k | state_.time = 0; |
78 | 5.32k | state_.base = 0; |
79 | 5.32k | irq_time_ = future_nes_time; |
80 | 5.32k | end_time_ = future_nes_time; |
81 | 5.32k | error_count_ = 0; |
82 | | |
83 | 5.32k | blaarg_static_assert( page_size == 0x800, "NES set to use unhandled page size" ); // assumes this |
84 | 5.32k | set_code_page( page_count, unmapped_page ); |
85 | 5.32k | map_code( 0x2000, 0xE000, unmapped_page, true ); |
86 | 5.32k | map_code( 0x0000, 0x2000, low_mem, true ); |
87 | | |
88 | 5.32k | blargg_verify_byte_order(); |
89 | 5.32k | } |
90 | | |
91 | | void Nes_Cpu::map_code( nes_addr_t start, unsigned size, void const* data, bool mirror ) |
92 | 58.5k | { |
93 | | // address range must begin and end on page boundaries |
94 | 58.5k | require( start % page_size == 0 ); |
95 | 58.5k | require( size % page_size == 0 ); |
96 | 58.5k | require( start + size <= 0x10000 ); |
97 | | |
98 | 58.5k | unsigned page = start / page_size; |
99 | 335k | for ( unsigned n = size / page_size; n; --n ) |
100 | 276k | { |
101 | 276k | set_code_page( page++, data ); |
102 | 276k | if ( !mirror ) |
103 | 106k | data = (char const*) data + page_size; |
104 | 276k | } |
105 | 58.5k | } |
106 | | |
107 | 5.94M | #define TIME (s_time + s.base) |
108 | 2.39M | #define READ_LIKELY_PPU( addr, out ) {CPU_READ_PPU( this, (addr), out, TIME );} |
109 | 62.6M | #define READ( addr ) CPU_READ( this, (addr), TIME ) |
110 | 84.9M | #define WRITE( addr, data ) {CPU_WRITE( this, (addr), (data), TIME );} |
111 | 6.99G | #define READ_LOW( addr ) (low_mem [int (addr)]) |
112 | 6.81G | #define WRITE_LOW( addr, data ) (void) (READ_LOW( addr ) = (data)) |
113 | 229k | #define READ_PROG( addr ) (s.code_map [(addr) >> page_bits] [PAGE_OFFSET( addr )]) |
114 | | |
115 | 152M | #define SET_SP( v ) (sp = ((v) + 1) | 0x100) |
116 | 152M | #define GET_SP() ((sp - 1) & 0xFF) |
117 | 6.89M | #define PUSH( v ) ((sp = (sp - 1) | 0x100), WRITE_LOW( sp, v )) |
118 | | |
119 | | bool Nes_Cpu::run( nes_time_t end_time ) |
120 | 152M | { |
121 | 152M | set_end_time( end_time ); |
122 | 152M | state_t s = this->state_; |
123 | 152M | this->state = &s; |
124 | | // even on x86, using s.time in place of s_time was slower |
125 | 152M | int16_t s_time = s.time; |
126 | | |
127 | | // registers |
128 | 152M | uint16_t pc = r.pc; |
129 | 152M | uint8_t a = r.a; |
130 | 152M | uint8_t x = r.x; |
131 | 152M | uint8_t y = r.y; |
132 | 152M | uint16_t sp; |
133 | 152M | SET_SP( r.sp ); |
134 | | |
135 | | // status flags |
136 | 152M | #define IS_NEG (nz & 0x8080) |
137 | | |
138 | 2.41G | #define CALC_STATUS( out ) do {\ |
139 | 2.41G | out = status & (st_v | st_d | st_i);\ |
140 | 2.41G | out |= ((nz >> 8) | nz) & st_n;\ |
141 | 2.41G | out |= c >> 8 & st_c;\ |
142 | 2.41G | if ( !(nz & 0xFF) ) out |= st_z;\ |
143 | 2.41G | } while ( 0 ) |
144 | | |
145 | 154M | #define SET_STATUS( in ) do {\ |
146 | 154M | status = in & (st_v | st_d | st_i);\ |
147 | 154M | nz = in << 8;\ |
148 | 154M | c = nz;\ |
149 | 154M | nz |= ~in & st_z;\ |
150 | 154M | } while ( 0 ) |
151 | | |
152 | 152M | uint8_t status; |
153 | 152M | uint16_t c; // carry set if (c & 0x100) != 0 |
154 | 152M | uint16_t nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 |
155 | 152M | { |
156 | 152M | uint8_t temp = r.status; |
157 | 152M | SET_STATUS( temp ); |
158 | 152M | } |
159 | | |
160 | 152M | goto loop; |
161 | 1.63M | dec_clock_loop: |
162 | 1.63M | s_time--; |
163 | 2.84G | loop: |
164 | | |
165 | 2.84G | check( (unsigned) GET_SP() < 0x100 ); |
166 | 2.84G | check( (unsigned) pc < 0x10000 ); |
167 | 2.84G | check( (unsigned) a < 0x100 ); |
168 | 2.84G | check( (unsigned) x < 0x100 ); |
169 | 2.84G | check( (unsigned) y < 0x100 ); |
170 | 2.84G | check( -32768 <= s_time && s_time < 32767 ); |
171 | | |
172 | 2.84G | uint8_t const* instr = s.code_map [pc >> page_bits]; |
173 | 2.84G | uint8_t opcode; |
174 | | |
175 | | // TODO: eliminate this special case |
176 | | #if BLARGG_NONPORTABLE |
177 | | opcode = instr [pc]; |
178 | | pc++; |
179 | | instr += pc; |
180 | | #else |
181 | 2.84G | instr += PAGE_OFFSET( pc ); |
182 | 2.84G | opcode = *instr++; |
183 | 2.84G | pc++; |
184 | 2.84G | #endif |
185 | | |
186 | 2.84G | static uint8_t const clock_table [256] = |
187 | 2.84G | {// 0 1 2 3 4 5 6 7 8 9 A B C D E F |
188 | 2.84G | 0,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,// 0 |
189 | 2.84G | 3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 1 |
190 | 2.84G | 6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6,// 2 |
191 | 2.84G | 3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 3 |
192 | 2.84G | 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,// 4 |
193 | 2.84G | 3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 5 |
194 | 2.84G | 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,// 6 |
195 | 2.84G | 3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 7 |
196 | 2.84G | 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// 8 |
197 | 2.84G | 3,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,// 9 |
198 | 2.84G | 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// A |
199 | 2.84G | 3,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,// B |
200 | 2.84G | 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// C |
201 | 2.84G | 3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// D |
202 | 2.84G | 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// E |
203 | 2.84G | 3,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7 // F |
204 | 2.84G | }; // 0x00 was 7 and 0xF2 was 2 |
205 | | |
206 | 2.84G | uint16_t data; |
207 | | |
208 | | #if !BLARGG_CPU_X86 |
209 | | if ( s_time >= 0 ) |
210 | | goto out_of_time; |
211 | | s_time += clock_table [opcode]; |
212 | | |
213 | | data = *instr; |
214 | | |
215 | | switch ( opcode ) |
216 | | { |
217 | | #else |
218 | | |
219 | 2.84G | data = clock_table [opcode]; |
220 | 2.84G | if ( (s_time += data) >= 0 ) |
221 | 20.1M | goto possibly_out_of_time; |
222 | 2.82G | almost_out_of_time: |
223 | | |
224 | 2.82G | data = *instr; |
225 | | |
226 | 2.82G | switch ( opcode ) |
227 | 2.82G | { |
228 | 20.1M | possibly_out_of_time: |
229 | 20.1M | if ( s_time < (int) data ) |
230 | 3.90M | goto almost_out_of_time; |
231 | 16.2M | s_time -= data; |
232 | 16.2M | goto out_of_time; |
233 | 0 | #endif |
234 | | |
235 | | // Macros |
236 | | |
237 | 30.5M | #define GET_MSB() (instr [1]) |
238 | 29.8M | #define ADD_PAGE() (pc++, data += 0x100 * GET_MSB()) |
239 | 100M | #define GET_ADDR() GET_LE16( instr ) |
240 | | |
241 | 0 | #define NO_PAGE_CROSSING( lsb ) |
242 | 729k | #define HANDLE_PAGE_CROSSING( lsb ) s_time += (lsb) >> 8; |
243 | | |
244 | 138k | #define INC_DEC_XY( reg, n ) reg = uint8_t (nz = reg + n); goto loop; |
245 | | |
246 | 6.34M | #define IND_Y( cross, out ) {\ |
247 | 6.34M | uint16_t temp = READ_LOW( data ) + y;\ |
248 | 6.34M | out = temp + 0x100 * READ_LOW( uint8_t (data + 1) );\ |
249 | 6.34M | cross( temp );\ |
250 | 6.34M | } |
251 | | |
252 | 22.7M | #define IND_X( out ) {\ |
253 | 22.7M | uint16_t temp = data + x;\ |
254 | 22.7M | out = 0x100 * READ_LOW( uint8_t (temp + 1) ) + READ_LOW( uint8_t (temp) );\ |
255 | 22.7M | } |
256 | | |
257 | 22.6M | #define ARITH_ADDR_MODES( op )\ |
258 | 22.6M | case op - 0x04: /* (ind,x) */\ |
259 | 22.6M | IND_X( data )\ |
260 | 22.6M | goto ptr##op;\ |
261 | 6.31M | case op + 0x0C: /* (ind),y */\ |
262 | 6.31M | IND_Y( HANDLE_PAGE_CROSSING, data )\ |
263 | 6.60M | goto ptr##op;\ |
264 | 6.60M | case op + 0x10: /* zp,X */\ |
265 | 91.2M | data = uint8_t (data + x);/* FALLTHRU */\ |
266 | 91.2M | case op + 0x00: /* zp */\ |
267 | 91.2M | data = READ_LOW( data );\ |
268 | 91.2M | goto imm##op;\ |
269 | 5.04M | case op + 0x14: /* abs,Y */\ |
270 | 5.04M | data += y;\ |
271 | 10.6M | goto ind##op;\ |
272 | 10.6M | case op + 0x18: /* abs,X */\ |
273 | 15.7M | data += x;\ |
274 | 15.7M | ind##op:\ |
275 | 24.9M | HANDLE_PAGE_CROSSING( data );/* FALLTHRU */\ |
276 | 24.9M | case op + 0x08: /* abs */\ |
277 | 53.8M | ADD_PAGE();\ |
278 | 53.8M | ptr##op:\ |
279 | 53.8M | FLUSH_TIME();\ |
280 | 53.8M | data = READ( data );\ |
281 | 64.6M | CACHE_TIME();/*FALLTHRU*/\ |
282 | 155M | case op + 0x04: /* imm */\ |
283 | 155M | imm##op: |
284 | | |
285 | | // TODO: more efficient way to handle negative branch that wraps PC around |
286 | 8.51M | #define BRANCH( cond )\ |
287 | 8.51M | {\ |
288 | 8.51M | int16_t offset = (int8_t) data;\ |
289 | 8.51M | uint16_t extra_clock = (++pc & 0xFF) + offset;\ |
290 | 10.1M | if ( !(cond) ) goto dec_clock_loop;\ |
291 | 8.51M | pc = uint16_t (pc + offset);\ |
292 | 8.51M | s_time += extra_clock >> 8 & 1;\ |
293 | 8.51M | goto loop;\ |
294 | 8.51M | } |
295 | | |
296 | | // Often-Used |
297 | | |
298 | 581 | case 0xB5: // LDA zp,x |
299 | 581 | a = nz = READ_LOW( uint8_t (data + x) ); |
300 | 581 | pc++; |
301 | 581 | goto loop; |
302 | | |
303 | 225 | case 0xA5: // LDA zp |
304 | 225 | a = nz = READ_LOW( data ); |
305 | 225 | pc++; |
306 | 225 | goto loop; |
307 | | |
308 | 2.92M | case 0xD0: // BNE |
309 | 2.92M | BRANCH( (uint8_t) nz ); |
310 | |
|
311 | 15.4M | case 0x20: { // JSR |
312 | 15.4M | uint16_t temp = pc + 1; |
313 | 15.4M | pc = GET_ADDR(); |
314 | 15.4M | WRITE_LOW( 0x100 | (sp - 1), temp >> 8 ); |
315 | 15.4M | sp = (sp - 2) | 0x100; |
316 | 15.4M | WRITE_LOW( sp, temp ); |
317 | 15.4M | goto loop; |
318 | 0 | } |
319 | | |
320 | 80.5k | case 0x4C: // JMP abs |
321 | 80.5k | pc = GET_ADDR(); |
322 | 80.5k | goto loop; |
323 | | |
324 | 125k | case 0xE8: // INX |
325 | 125k | INC_DEC_XY( x, 1 ) |
326 | | |
327 | 7.09M | case 0x10: // BPL |
328 | 7.09M | BRANCH( !IS_NEG ) |
329 | | |
330 | 184k | ARITH_ADDR_MODES( 0xC5 ) // CMP |
331 | 184k | nz = a - data; |
332 | 184k | pc++; |
333 | 184k | c = ~nz; |
334 | 184k | nz &= 0xFF; |
335 | 184k | goto loop; |
336 | | |
337 | 64.4k | case 0x30: // BMI |
338 | 64.4k | BRANCH( IS_NEG ) |
339 | | |
340 | 1.34k | case 0xF0: // BEQ |
341 | 1.34k | BRANCH( !(uint8_t) nz ); |
342 | |
|
343 | 2.36k | case 0x95: // STA zp,x |
344 | 2.36k | data = uint8_t (data + x);/*FALLTHRU*/ |
345 | 10.6k | case 0x85: // STA zp |
346 | 10.6k | pc++; |
347 | 10.6k | WRITE_LOW( data, a ); |
348 | 10.6k | goto loop; |
349 | | |
350 | 3.16k | case 0xC8: // INY |
351 | 3.16k | INC_DEC_XY( y, 1 ) |
352 | | |
353 | 225 | case 0xA8: // TAY |
354 | 225 | y = a; |
355 | 225 | nz = a; |
356 | 225 | goto loop; |
357 | | |
358 | 3.08k | case 0x98: // TYA |
359 | 3.08k | a = y; |
360 | 3.08k | nz = y; |
361 | 3.08k | goto loop; |
362 | | |
363 | 865 | case 0xAD:{// LDA abs |
364 | 865 | unsigned addr = GET_ADDR(); |
365 | 865 | pc += 2; |
366 | 865 | READ_LIKELY_PPU( addr, nz ); |
367 | 865 | a = nz; |
368 | 865 | goto loop; |
369 | 2.36k | } |
370 | | |
371 | 12.1M | case 0x60: // RTS |
372 | 12.1M | pc = 1 + READ_LOW( sp ); |
373 | 12.1M | pc += 0x100 * READ_LOW( 0x100 | (sp - 0xFF) ); |
374 | 12.1M | sp = (sp - 0xFE) | 0x100; |
375 | 12.1M | goto loop; |
376 | | |
377 | 0 | { |
378 | 0 | uint16_t addr; |
379 | |
|
380 | 136k | case 0x99: // STA abs,Y |
381 | 136k | addr = y + GET_ADDR(); |
382 | 136k | pc += 2; |
383 | 136k | if ( addr <= 0x7FF ) |
384 | 223 | { |
385 | 223 | WRITE_LOW( addr, a ); |
386 | 223 | goto loop; |
387 | 223 | } |
388 | 136k | goto sta_ptr; |
389 | | |
390 | 78.8M | case 0x8D: // STA abs |
391 | 78.8M | addr = GET_ADDR(); |
392 | 78.8M | pc += 2; |
393 | 78.8M | if ( addr <= 0x7FF ) |
394 | 2.28M | { |
395 | 2.28M | WRITE_LOW( addr, a ); |
396 | 2.28M | goto loop; |
397 | 2.28M | } |
398 | 76.6M | goto sta_ptr; |
399 | | |
400 | 76.6M | case 0x9D: // STA abs,X (slightly more common than STA abs) |
401 | 478 | addr = x + GET_ADDR(); |
402 | 478 | pc += 2; |
403 | 478 | if ( addr <= 0x7FF ) |
404 | 225 | { |
405 | 225 | WRITE_LOW( addr, a ); |
406 | 225 | goto loop; |
407 | 225 | } |
408 | 76.8M | sta_ptr: |
409 | 76.8M | FLUSH_TIME(); |
410 | 76.8M | WRITE( addr, a ); |
411 | 76.8M | CACHE_TIME(); |
412 | 76.8M | goto loop; |
413 | | |
414 | 33.1k | case 0x91: // STA (ind),Y |
415 | 33.1k | IND_Y( NO_PAGE_CROSSING, addr ) |
416 | 33.1k | pc++; |
417 | 33.1k | goto sta_ptr; |
418 | | |
419 | 127k | case 0x81: // STA (ind,X) |
420 | 127k | IND_X( addr ) |
421 | 127k | pc++; |
422 | 127k | goto sta_ptr; |
423 | | |
424 | 478 | } |
425 | | |
426 | 1.32M | case 0xA9: // LDA #imm |
427 | 1.32M | pc++; |
428 | 1.32M | a = data; |
429 | 1.32M | nz = data; |
430 | 1.32M | goto loop; |
431 | | |
432 | | // common read instructions |
433 | 0 | { |
434 | 0 | uint16_t addr; |
435 | |
|
436 | 3.37k | case 0xA1: // LDA (ind,X) |
437 | 3.37k | IND_X( addr ) |
438 | 3.37k | pc++; |
439 | 3.37k | goto a_nz_read_addr; |
440 | | |
441 | 223k | case 0xB1:// LDA (ind),Y |
442 | 223k | addr = READ_LOW( data ) + y; |
443 | 223k | HANDLE_PAGE_CROSSING( addr ); |
444 | 223k | addr += 0x100 * READ_LOW( (uint8_t) (data + 1) ); |
445 | 223k | pc++; |
446 | 223k | a = nz = READ_PROG( addr ); |
447 | 223k | if ( (addr ^ 0x8000) <= 0x9FFF ) |
448 | 223k | goto loop; |
449 | 0 | goto a_nz_read_addr; |
450 | | |
451 | 6.56k | case 0xB9: // LDA abs,Y |
452 | 6.56k | HANDLE_PAGE_CROSSING( data + y ); |
453 | 6.56k | addr = GET_ADDR() + y; |
454 | 6.56k | pc += 2; |
455 | 6.56k | a = nz = READ_PROG( addr ); |
456 | 6.56k | if ( (addr ^ 0x8000) <= 0x9FFF ) |
457 | 6.46k | goto loop; |
458 | 94 | goto a_nz_read_addr; |
459 | | |
460 | 228 | case 0xBD: // LDA abs,X |
461 | 228 | HANDLE_PAGE_CROSSING( data + x ); |
462 | 228 | addr = GET_ADDR() + x; |
463 | 228 | pc += 2; |
464 | 228 | a = nz = READ_PROG( addr ); |
465 | 228 | if ( (addr ^ 0x8000) <= 0x9FFF ) |
466 | 226 | goto loop; |
467 | 3.47k | a_nz_read_addr: |
468 | 3.47k | FLUSH_TIME(); |
469 | 3.47k | a = nz = READ( addr ); |
470 | 3.47k | CACHE_TIME(); |
471 | 3.47k | goto loop; |
472 | | |
473 | 228 | } |
474 | | |
475 | | // Branch |
476 | | |
477 | 32.1k | case 0x50: // BVC |
478 | 32.1k | BRANCH( !(status & st_v) ) |
479 | | |
480 | 38.2k | case 0x70: // BVS |
481 | 38.2k | BRANCH( status & st_v ) |
482 | | |
483 | 244 | case 0xB0: // BCS |
484 | 244 | BRANCH( c & 0x100 ) |
485 | | |
486 | 450 | case 0x90: // BCC |
487 | 450 | BRANCH( !(c & 0x100) ) |
488 | | |
489 | | // Load/store |
490 | | |
491 | 12.6k | case 0x94: // STY zp,x |
492 | 12.6k | data = uint8_t (data + x); // FALLTHRU |
493 | 225k | case 0x84: // STY zp |
494 | 225k | pc++; |
495 | 225k | WRITE_LOW( data, y ); |
496 | 225k | goto loop; |
497 | | |
498 | 1.58k | case 0x96: // STX zp,y |
499 | 1.58k | data = uint8_t (data + y); // FALLTHRU |
500 | 3.48k | case 0x86: // STX zp |
501 | 3.48k | pc++; |
502 | 3.48k | WRITE_LOW( data, x ); |
503 | 3.48k | goto loop; |
504 | | |
505 | 27.7k | case 0xB6: // LDX zp,y |
506 | 27.7k | data = uint8_t (data + y); // FALLTHRU |
507 | 34.5k | case 0xA6: // LDX zp |
508 | 34.5k | data = READ_LOW( data ); // FALLTHRU |
509 | 34.7k | case 0xA2: // LDX #imm |
510 | 34.7k | pc++; |
511 | 34.7k | x = data; |
512 | 34.7k | nz = data; |
513 | 34.7k | goto loop; |
514 | | |
515 | 449 | case 0xB4: // LDY zp,x |
516 | 449 | data = uint8_t (data + x); // FALLTHRU |
517 | 945 | case 0xA4: // LDY zp |
518 | 945 | data = READ_LOW( data ); // FALLTHRU |
519 | 125k | case 0xA0: // LDY #imm |
520 | 125k | pc++; |
521 | 125k | y = data; |
522 | 125k | nz = data; |
523 | 125k | goto loop; |
524 | | |
525 | 3.74k | case 0xBC: // LDY abs,X |
526 | 3.74k | data += x; |
527 | 3.74k | HANDLE_PAGE_CROSSING( data );/*FALLTHRU*/ |
528 | 3.97k | case 0xAC:{// LDY abs |
529 | 3.97k | unsigned addr = data + 0x100 * GET_MSB(); |
530 | 3.97k | pc += 2; |
531 | 3.97k | FLUSH_TIME(); |
532 | 3.97k | y = nz = READ( addr ); |
533 | 3.97k | CACHE_TIME(); |
534 | 3.97k | goto loop; |
535 | 3.74k | } |
536 | | |
537 | 225 | case 0xBE: // LDX abs,y |
538 | 225 | data += y; |
539 | 225 | HANDLE_PAGE_CROSSING( data );/*FALLTHRU*/ |
540 | 699k | case 0xAE:{// LDX abs |
541 | 699k | unsigned addr = data + 0x100 * GET_MSB(); |
542 | 699k | pc += 2; |
543 | 699k | FLUSH_TIME(); |
544 | 699k | x = nz = READ( addr ); |
545 | 699k | CACHE_TIME(); |
546 | 699k | goto loop; |
547 | 225 | } |
548 | | |
549 | 0 | { |
550 | 0 | uint8_t temp; |
551 | 6.68k | case 0x8C: // STY abs |
552 | 6.68k | temp = y; |
553 | 6.68k | goto store_abs; |
554 | | |
555 | 8.87k | case 0x8E: // STX abs |
556 | 8.87k | temp = x; |
557 | 15.5k | store_abs: |
558 | 15.5k | unsigned addr = GET_ADDR(); |
559 | 15.5k | pc += 2; |
560 | 15.5k | if ( addr <= 0x7FF ) |
561 | 223 | { |
562 | 223 | WRITE_LOW( addr, temp ); |
563 | 223 | goto loop; |
564 | 223 | } |
565 | 15.3k | FLUSH_TIME(); |
566 | 15.3k | WRITE( addr, temp ); |
567 | 15.3k | CACHE_TIME(); |
568 | 15.3k | goto loop; |
569 | 15.5k | } |
570 | | |
571 | | // Compare |
572 | | |
573 | 279 | case 0xEC:{// CPX abs |
574 | 279 | unsigned addr = GET_ADDR(); |
575 | 279 | pc++; |
576 | 279 | FLUSH_TIME(); |
577 | 279 | data = READ( addr ); |
578 | 279 | CACHE_TIME(); |
579 | 279 | goto cpx_data; |
580 | 15.5k | } |
581 | | |
582 | 300 | case 0xE4: // CPX zp |
583 | 300 | data = READ_LOW( data );/*FALLTHRU*/ |
584 | 124k | case 0xE0: // CPX #imm |
585 | 125k | cpx_data: |
586 | 125k | nz = x - data; |
587 | 125k | pc++; |
588 | 125k | c = ~nz; |
589 | 125k | nz &= 0xFF; |
590 | 125k | goto loop; |
591 | | |
592 | 250 | case 0xCC:{// CPY abs |
593 | 250 | unsigned addr = GET_ADDR(); |
594 | 250 | pc++; |
595 | 250 | FLUSH_TIME(); |
596 | 250 | data = READ( addr ); |
597 | 250 | CACHE_TIME(); |
598 | 250 | goto cpy_data; |
599 | 124k | } |
600 | | |
601 | 46 | case 0xC4: // CPY zp |
602 | 46 | data = READ_LOW( data );/*FALLTHRU*/ |
603 | 281 | case 0xC0: // CPY #imm |
604 | 531 | cpy_data: |
605 | 531 | nz = y - data; |
606 | 531 | pc++; |
607 | 531 | c = ~nz; |
608 | 531 | nz &= 0xFF; |
609 | 531 | goto loop; |
610 | | |
611 | | // Logical |
612 | | |
613 | 7.52M | ARITH_ADDR_MODES( 0x25 ) // AND |
614 | 7.52M | nz = (a &= data); |
615 | 7.52M | pc++; |
616 | 7.52M | goto loop; |
617 | | |
618 | 2.33M | ARITH_ADDR_MODES( 0x45 ) // EOR |
619 | 2.33M | nz = (a ^= data); |
620 | 2.33M | pc++; |
621 | 2.33M | goto loop; |
622 | | |
623 | 139M | ARITH_ADDR_MODES( 0x05 ) // ORA |
624 | 139M | nz = (a |= data); |
625 | 139M | pc++; |
626 | 139M | goto loop; |
627 | | |
628 | 2.39M | case 0x2C:{// BIT abs |
629 | 2.39M | unsigned addr = GET_ADDR(); |
630 | 2.39M | pc += 2; |
631 | 2.39M | status &= ~st_v; |
632 | 2.39M | READ_LIKELY_PPU( addr, nz ); |
633 | 2.39M | status |= nz & st_v; |
634 | 2.39M | if ( a & nz ) |
635 | 2.39M | goto loop; |
636 | 1.34k | nz <<= 8; // result must be zero, even if N bit is set |
637 | 1.34k | goto loop; |
638 | 2.39M | } |
639 | | |
640 | 2.72M | case 0x24: // BIT zp |
641 | 2.72M | nz = READ_LOW( data ); |
642 | 2.72M | pc++; |
643 | 2.72M | status &= ~st_v; |
644 | 2.72M | status |= nz & st_v; |
645 | 2.72M | if ( a & nz ) |
646 | 2.72M | goto loop; |
647 | 202 | nz <<= 8; // result must be zero, even if N bit is set |
648 | 202 | goto loop; |
649 | | |
650 | | // Add/subtract |
651 | | |
652 | 24.3M | ARITH_ADDR_MODES( 0xE5 ) // SBC |
653 | 24.3M | case 0xEB: // unofficial equivalent |
654 | 4.12M | data ^= 0xFF; |
655 | 4.12M | goto adc_imm; |
656 | | |
657 | 8.10M | ARITH_ADDR_MODES( 0x65 ) // ADC |
658 | 8.10M | adc_imm: { |
659 | 6.26M | int16_t carry = c >> 8 & 1; |
660 | 6.26M | int16_t ov = (a ^ 0x80) + carry + (int8_t) data; // sign-extend |
661 | 6.26M | status &= ~st_v; |
662 | 6.26M | status |= ov >> 2 & 0x40; |
663 | 6.26M | c = nz = a + data + carry; |
664 | 6.26M | pc++; |
665 | 6.26M | a = (uint8_t) nz; |
666 | 6.26M | goto loop; |
667 | 8.10M | } |
668 | | |
669 | | // Shift/rotate |
670 | | |
671 | 151k | case 0x4A: // LSR A |
672 | 151k | c = 0;/*FALLTHRU*/ |
673 | 658k | case 0x6A: // ROR A |
674 | 658k | nz = c >> 1 & 0x80; |
675 | 658k | c = a << 8; |
676 | 658k | nz |= a >> 1; |
677 | 658k | a = nz; |
678 | 658k | goto loop; |
679 | | |
680 | 3.19M | case 0x0A: // ASL A |
681 | 3.19M | nz = a << 1; |
682 | 3.19M | c = nz; |
683 | 3.19M | a = (uint8_t) nz; |
684 | 3.19M | goto loop; |
685 | | |
686 | 1.45M | case 0x2A: { // ROL A |
687 | 1.45M | nz = a << 1; |
688 | 1.45M | int16_t temp = c >> 8 & 1; |
689 | 1.45M | c = nz; |
690 | 1.45M | nz |= temp; |
691 | 1.45M | a = (uint8_t) nz; |
692 | 1.45M | goto loop; |
693 | 151k | } |
694 | | |
695 | 144k | case 0x5E: // LSR abs,X |
696 | 144k | data += x;/*FALLTHRU*/ |
697 | 153k | case 0x4E: // LSR abs |
698 | 153k | c = 0;/*FALLTHRU*/ |
699 | 1.76M | case 0x6E: // ROR abs |
700 | 1.89M | ror_abs: { |
701 | 1.89M | ADD_PAGE(); |
702 | 1.89M | FLUSH_TIME(); |
703 | 1.89M | int temp = READ( data ); |
704 | 1.89M | nz = (c >> 1 & 0x80) | (temp >> 1); |
705 | 1.89M | c = temp << 8; |
706 | 1.89M | goto rotate_common; |
707 | 1.76M | } |
708 | | |
709 | 1.06M | case 0x3E: // ROL abs,X |
710 | 1.06M | data += x; |
711 | 1.06M | goto rol_abs; |
712 | | |
713 | 1.92M | case 0x1E: // ASL abs,X |
714 | 1.92M | data += x;/*FALLTHRU*/ |
715 | 1.92M | case 0x0E: // ASL abs |
716 | 1.92M | c = 0;/*FALLTHRU*/ |
717 | 1.95M | case 0x2E: // ROL abs |
718 | 3.01M | rol_abs: |
719 | 3.01M | ADD_PAGE(); |
720 | 3.01M | nz = c >> 8 & 1; |
721 | 3.01M | FLUSH_TIME(); |
722 | 3.01M | nz |= (c = READ( data ) << 1); |
723 | 4.91M | rotate_common: |
724 | 4.91M | pc++; |
725 | 4.91M | WRITE( data, (uint8_t) nz ); |
726 | 4.91M | CACHE_TIME(); |
727 | 4.91M | goto loop; |
728 | | |
729 | 127k | case 0x7E: // ROR abs,X |
730 | 127k | data += x; |
731 | 127k | goto ror_abs; |
732 | | |
733 | 127k | case 0x76: // ROR zp,x |
734 | 127k | data = uint8_t (data + x); |
735 | 127k | goto ror_zp; |
736 | | |
737 | 155k | case 0x56: // LSR zp,x |
738 | 155k | data = uint8_t (data + x);/*FALLTHRU*/ |
739 | 1.58M | case 0x46: // LSR zp |
740 | 1.58M | c = 0;/*FALLTHRU*/ |
741 | 1.71M | case 0x66: // ROR zp |
742 | 1.84M | ror_zp: { |
743 | 1.84M | int temp = READ_LOW( data ); |
744 | 1.84M | nz = (c >> 1 & 0x80) | (temp >> 1); |
745 | 1.84M | c = temp << 8; |
746 | 1.84M | goto write_nz_zp; |
747 | 1.71M | } |
748 | | |
749 | 1.09M | case 0x36: // ROL zp,x |
750 | 1.09M | data = uint8_t (data + x); |
751 | 1.09M | goto rol_zp; |
752 | | |
753 | 3.08M | case 0x16: // ASL zp,x |
754 | 3.08M | data = uint8_t (data + x);/*FALLTHRU*/ |
755 | 3.08M | case 0x06: // ASL zp |
756 | 3.08M | c = 0;/*FALLTHRU*/ |
757 | 3.15M | case 0x26: // ROL zp |
758 | 4.25M | rol_zp: |
759 | 4.25M | nz = c >> 8 & 1; |
760 | 4.25M | nz |= (c = READ_LOW( data ) << 1); |
761 | 4.25M | goto write_nz_zp; |
762 | | |
763 | | // Increment/decrement |
764 | | |
765 | 6.49k | case 0xCA: // DEX |
766 | 6.49k | INC_DEC_XY( x, -1 ) |
767 | | |
768 | 3.08k | case 0x88: // DEY |
769 | 3.08k | INC_DEC_XY( y, -1 ) |
770 | | |
771 | 225 | case 0xF6: // INC zp,x |
772 | 225 | data = uint8_t (data + x);/*FALLTHRU*/ |
773 | 1.80M | case 0xE6: // INC zp |
774 | 1.80M | nz = 1; |
775 | 1.80M | goto add_nz_zp; |
776 | | |
777 | 223 | case 0xD6: // DEC zp,x |
778 | 223 | data = uint8_t (data + x);/*FALLTHRU*/ |
779 | 449 | case 0xC6: // DEC zp |
780 | 449 | nz = (uint16_t) -1; |
781 | 1.80M | add_nz_zp: |
782 | 1.80M | nz += READ_LOW( data ); |
783 | 7.90M | write_nz_zp: |
784 | 7.90M | pc++; |
785 | 7.90M | WRITE_LOW( data, nz ); |
786 | 7.90M | goto loop; |
787 | | |
788 | 3.11M | case 0xFE: // INC abs,x |
789 | 3.11M | data = x + GET_ADDR(); |
790 | 3.11M | goto inc_ptr; |
791 | | |
792 | 226 | case 0xEE: // INC abs |
793 | 226 | data = GET_ADDR(); |
794 | 3.11M | inc_ptr: |
795 | 3.11M | nz = 1; |
796 | 3.11M | goto inc_common; |
797 | | |
798 | 1.11k | case 0xDE: // DEC abs,x |
799 | 1.11k | data = x + GET_ADDR(); |
800 | 1.11k | goto dec_ptr; |
801 | | |
802 | 283 | case 0xCE: // DEC abs |
803 | 283 | data = GET_ADDR(); |
804 | 1.39k | dec_ptr: |
805 | 1.39k | nz = (uint16_t) -1; |
806 | 3.12M | inc_common: |
807 | 3.12M | FLUSH_TIME(); |
808 | 3.12M | nz += READ( data ); |
809 | 3.12M | pc += 2; |
810 | 3.12M | WRITE( data, (uint8_t) nz ); |
811 | 3.12M | CACHE_TIME(); |
812 | 3.12M | goto loop; |
813 | | |
814 | | // Transfer |
815 | | |
816 | 719 | case 0xAA: // TAX |
817 | 719 | x = a; |
818 | 719 | nz = a; |
819 | 719 | goto loop; |
820 | | |
821 | 3.08k | case 0x8A: // TXA |
822 | 3.08k | a = x; |
823 | 3.08k | nz = x; |
824 | 3.08k | goto loop; |
825 | | |
826 | 41 | case 0x9A: // TXS |
827 | 41 | SET_SP( x ); // verified (no flag change) |
828 | 41 | goto loop; |
829 | | |
830 | 9.25k | case 0xBA: // TSX |
831 | 9.25k | x = nz = GET_SP(); |
832 | 9.25k | goto loop; |
833 | | |
834 | | // Stack |
835 | | |
836 | 24.8k | case 0x48: // PHA |
837 | 24.8k | PUSH( a ); // verified |
838 | 24.8k | goto loop; |
839 | | |
840 | 282 | case 0x68: // PLA |
841 | 282 | a = nz = READ_LOW( sp ); |
842 | 282 | sp = (sp - 0xFF) | 0x100; |
843 | 282 | goto loop; |
844 | | |
845 | 3.93k | case 0x40:{// RTI |
846 | 3.93k | uint8_t temp = READ_LOW( sp ); |
847 | 3.93k | pc = READ_LOW( 0x100 | (sp - 0xFF) ); |
848 | 3.93k | pc |= READ_LOW( 0x100 | (sp - 0xFE) ) * 0x100; |
849 | 3.93k | sp = (sp - 0xFD) | 0x100; |
850 | 3.93k | data = status; |
851 | 3.93k | SET_STATUS( temp ); |
852 | 3.93k | if ( !((data ^ status) & st_i) ) goto loop; // I flag didn't change |
853 | 9 | this->r.status = status; // update externally-visible I flag |
854 | 9 | blargg_long delta = s.base - irq_time_; |
855 | 9 | if ( delta <= 0 ) goto loop; |
856 | 0 | if ( status & st_i ) goto loop; |
857 | 0 | s_time += delta; |
858 | 0 | s.base = irq_time_; |
859 | 0 | goto loop; |
860 | 0 | } |
861 | | |
862 | 2.38M | case 0x28:{// PLP |
863 | 2.38M | uint8_t temp = READ_LOW( sp ); |
864 | 2.38M | sp = (sp - 0xFF) | 0x100; |
865 | 2.38M | uint8_t changed = status ^ temp; |
866 | 2.38M | SET_STATUS( temp ); |
867 | 2.38M | if ( !(changed & st_i) ) |
868 | 2.38M | goto loop; // I flag didn't change |
869 | 116 | if ( status & st_i ) |
870 | 57 | goto handle_sei; |
871 | 59 | goto handle_cli; |
872 | 116 | } |
873 | | |
874 | 6.87M | case 0x08: { // PHP |
875 | 6.87M | uint8_t temp; |
876 | 6.87M | CALC_STATUS( temp ); |
877 | 6.87M | PUSH( temp | (st_b | st_r) ); |
878 | 6.87M | goto loop; |
879 | 116 | } |
880 | | |
881 | 19 | case 0x6C:{// JMP (ind) |
882 | 19 | data = GET_ADDR(); |
883 | 19 | check( unsigned (data - 0x2000) >= 0x4000 ); // ensure it's outside I/O space |
884 | 19 | uint8_t const* page = s.code_map [data >> page_bits]; |
885 | 19 | pc = page [PAGE_OFFSET( data )]; |
886 | 19 | data = (data & 0xFF00) | ((data + 1) & 0xFF); |
887 | 19 | pc |= page [PAGE_OFFSET( data )] << 8; |
888 | 19 | goto loop; |
889 | 116 | } |
890 | | |
891 | 2.25G | case 0x00: // BRK |
892 | 2.25G | goto handle_brk; |
893 | | |
894 | | // Flags |
895 | | |
896 | 1.46M | case 0x38: // SEC |
897 | 1.46M | c = (uint16_t) ~0; |
898 | 1.46M | goto loop; |
899 | | |
900 | 3.00M | case 0x18: // CLC |
901 | 3.00M | c = 0; |
902 | 3.00M | goto loop; |
903 | | |
904 | 364 | case 0xB8: // CLV |
905 | 364 | status &= ~st_v; |
906 | 364 | goto loop; |
907 | | |
908 | 225 | case 0xD8: // CLD |
909 | 225 | status &= ~st_d; |
910 | 225 | goto loop; |
911 | | |
912 | 72.0k | case 0xF8: // SED |
913 | 72.0k | status |= st_d; |
914 | 72.0k | goto loop; |
915 | | |
916 | 6.17M | case 0x58: // CLI |
917 | 6.17M | if ( !(status & st_i) ) |
918 | 229k | goto loop; |
919 | 5.94M | status &= ~st_i; |
920 | 5.94M | handle_cli: { |
921 | | //debug_printf( "CLI at %d\n", TIME ); |
922 | 5.94M | this->r.status = status; // update externally-visible I flag |
923 | 5.94M | blargg_long delta = s.base - irq_time_; |
924 | 5.94M | if ( delta <= 0 ) |
925 | 5.94M | { |
926 | 5.94M | if ( TIME < irq_time_ ) |
927 | 5.94M | goto loop; |
928 | 0 | goto delayed_cli; |
929 | 5.94M | } |
930 | 0 | s.base = irq_time_; |
931 | 0 | s_time += delta; |
932 | 0 | if ( s_time < 0 ) |
933 | 0 | goto loop; |
934 | | |
935 | 0 | if ( delta >= s_time + 1 ) |
936 | 0 | { |
937 | 0 | s.base += s_time + 1; |
938 | 0 | s_time = -1; |
939 | 0 | goto loop; |
940 | 0 | } |
941 | | |
942 | | // TODO: implement |
943 | 0 | delayed_cli: |
944 | 0 | debug_printf( "Delayed CLI not emulated\n" ); |
945 | 0 | goto loop; |
946 | 0 | } |
947 | | |
948 | 28.8k | case 0x78: // SEI |
949 | 28.8k | if ( status & st_i ) |
950 | 28.8k | goto loop; |
951 | 0 | status |= st_i; |
952 | 57 | handle_sei: { |
953 | 57 | this->r.status = status; // update externally-visible I flag |
954 | 57 | blargg_long delta = s.base - end_time_; |
955 | 57 | s.base = end_time_; |
956 | 57 | s_time += delta; |
957 | 57 | if ( s_time < 0 ) |
958 | 57 | goto loop; |
959 | | |
960 | 0 | debug_printf( "Delayed SEI not emulated\n" ); |
961 | 0 | goto loop; |
962 | 57 | } |
963 | | |
964 | | // Unofficial |
965 | | |
966 | | // SKW - Skip word |
967 | 11.6M | case 0x1C: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC: |
968 | 11.6M | HANDLE_PAGE_CROSSING( data + x );/*FALLTHRU*/ |
969 | 27.8M | case 0x0C: |
970 | 27.8M | pc++;/*FALLTHRU*/ |
971 | | // SKB - Skip byte |
972 | 46.8M | case 0x74: case 0x04: case 0x14: case 0x34: case 0x44: case 0x54: case 0x64: |
973 | 47.0M | case 0x80: case 0x82: case 0x89: case 0xC2: case 0xD4: case 0xE2: case 0xF4: |
974 | 47.0M | pc++; |
975 | 47.0M | goto loop; |
976 | | |
977 | | // NOP |
978 | 9.44M | case 0xEA: case 0x1A: case 0x3A: case 0x5A: case 0x7A: case 0xDA: case 0xFA: |
979 | 9.44M | goto loop; |
980 | | |
981 | 110M | case bad_opcode: // HLT |
982 | 110M | pc--; |
983 | 135M | case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52: |
984 | 135M | case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: |
985 | 135M | goto stop; |
986 | | |
987 | | // Unimplemented |
988 | | |
989 | 4.17M | case 0xFF: // force 256-entry jump table for optimization purposes |
990 | 4.17M | c |= 1;/*FALLTHRU*/ |
991 | 56.6M | default: |
992 | 56.6M | check( (unsigned) opcode <= 0xFF ); |
993 | | // skip over proper number of bytes |
994 | 56.6M | static unsigned char const illop_lens [8] = { |
995 | 56.6M | 0x40, 0x40, 0x40, 0x80, 0x40, 0x40, 0x80, 0xA0 |
996 | 56.6M | }; |
997 | 56.6M | uint8_t opcode = instr [-1]; |
998 | 56.6M | int16_t len = illop_lens [opcode >> 2 & 7] >> (opcode << 1 & 6) & 3; |
999 | 56.6M | if ( opcode == 0x9C ) |
1000 | 1.77k | len = 2; |
1001 | 56.6M | pc += len; |
1002 | 56.6M | error_count_++; |
1003 | | |
1004 | 56.6M | if ( (opcode >> 4) == 0x0B ) |
1005 | 730k | { |
1006 | 730k | if ( opcode == 0xB3 ) |
1007 | 225 | data = READ_LOW( data ); |
1008 | 730k | if ( opcode != 0xB7 ) |
1009 | 729k | HANDLE_PAGE_CROSSING( data + y ); |
1010 | 730k | } |
1011 | 56.6M | goto loop; |
1012 | 2.82G | } |
1013 | 2.82G | assert( false ); |
1014 | |
|
1015 | 0 | int result_; |
1016 | 2.25G | handle_brk: |
1017 | 2.25G | pc++; |
1018 | 2.25G | result_ = 4; |
1019 | | |
1020 | 2.25G | interrupt: |
1021 | 2.25G | { |
1022 | 2.25G | s_time += 7; |
1023 | | |
1024 | 2.25G | WRITE_LOW( 0x100 | (sp - 1), pc >> 8 ); |
1025 | 2.25G | WRITE_LOW( 0x100 | (sp - 2), pc ); |
1026 | 2.25G | pc = GET_LE16( &READ_PROG( 0xFFFA ) + result_ ); |
1027 | | |
1028 | 2.25G | sp = (sp - 3) | 0x100; |
1029 | 2.25G | uint8_t temp; |
1030 | 2.25G | CALC_STATUS( temp ); |
1031 | 2.25G | temp |= st_r; |
1032 | 2.25G | if ( result_ ) |
1033 | 2.25G | temp |= st_b; // TODO: incorrectly sets B flag for IRQ |
1034 | 2.25G | WRITE_LOW( sp, temp ); |
1035 | | |
1036 | 2.25G | this->r.status = status |= st_i; |
1037 | 2.25G | blargg_long delta = s.base - end_time_; |
1038 | 2.25G | if ( delta >= 0 ) goto loop; |
1039 | 0 | s_time += delta; |
1040 | 0 | s.base = end_time_; |
1041 | 0 | goto loop; |
1042 | 2.25G | } |
1043 | | |
1044 | 16.2M | out_of_time: |
1045 | 16.2M | pc--; |
1046 | 16.2M | FLUSH_TIME(); |
1047 | 16.2M | CPU_DONE( this, TIME, result_ ); |
1048 | 16.2M | CACHE_TIME(); |
1049 | 16.2M | if ( result_ >= 0 ) |
1050 | 0 | goto interrupt; |
1051 | 16.2M | if ( s_time < 0 ) |
1052 | 0 | goto loop; |
1053 | | |
1054 | 152M | stop: |
1055 | | |
1056 | 152M | s.time = s_time; |
1057 | | |
1058 | 152M | r.pc = pc; |
1059 | 152M | r.sp = GET_SP(); |
1060 | 152M | r.a = a; |
1061 | 152M | r.x = x; |
1062 | 152M | r.y = y; |
1063 | | |
1064 | 152M | { |
1065 | 152M | uint8_t temp; |
1066 | 152M | CALC_STATUS( temp ); |
1067 | 152M | r.status = temp; |
1068 | 152M | } |
1069 | | |
1070 | 152M | this->state_ = s; |
1071 | 152M | this->state = &this->state_; |
1072 | | |
1073 | 152M | return s_time < 0; |
1074 | 16.2M | } |
1075 | | |