diff options
author | Sean Bartell <wingedtachikoma@gmail.com> | 2011-06-25 21:32:25 -0400 |
---|---|---|
committer | Nils Wallménius <nils@rockbox.org> | 2012-04-25 22:13:20 +0200 |
commit | f40bfc9267b13b54e6379dfe7539447662879d24 (patch) | |
tree | 9b20069d5e62809ff434061ad730096836f916f2 /lib/rbcodec/codecs/libgme/hes_cpu_run.h | |
parent | a0009907de7a0107d49040d8a180f140e2eff299 (diff) | |
download | rockbox-f40bfc9267b13b54e6379dfe7539447662879d24.tar.gz rockbox-f40bfc9267b13b54e6379dfe7539447662879d24.zip |
Add codecs to librbcodec.
Change-Id: Id7f4717d51ed02d67cb9f9cb3c0ada4a81843f97
Reviewed-on: http://gerrit.rockbox.org/137
Reviewed-by: Nils Wallménius <nils@rockbox.org>
Tested-by: Nils Wallménius <nils@rockbox.org>
Diffstat (limited to 'lib/rbcodec/codecs/libgme/hes_cpu_run.h')
-rw-r--r-- | lib/rbcodec/codecs/libgme/hes_cpu_run.h | 1344 |
1 files changed, 1344 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libgme/hes_cpu_run.h b/lib/rbcodec/codecs/libgme/hes_cpu_run.h new file mode 100644 index 0000000000..bfba2b6109 --- /dev/null +++ b/lib/rbcodec/codecs/libgme/hes_cpu_run.h | |||
@@ -0,0 +1,1344 @@ | |||
1 | // Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ | ||
2 | |||
3 | #if 0 | ||
4 | /* Define these macros in the source file before #including this file. | ||
5 | - Parameters might be expressions, so they are best evaluated only once, | ||
6 | though they NEVER have side-effects, so multiple evaluation is OK. | ||
7 | - Output parameters might be a multiple-assignment expression like "a=x", | ||
8 | so they must NOT be parenthesized. | ||
9 | - Except where noted, time() and related functions will NOT work | ||
10 | correctly inside a macro. TIME() is always correct, and FLUSH_TIME() and | ||
11 | CACHE_TIME() allow the time changing functions to work. | ||
12 | - Macros "returning" void may use a {} statement block. */ | ||
13 | |||
14 | // 0 <= addr <= 0xFFFF + page_size | ||
15 | // time functions can be used | ||
16 | int READ_MEM( addr_t ); | ||
17 | void WRITE_MEM( addr_t, int data ); | ||
18 | |||
19 | // 0 <= addr <= 0x1FF | ||
20 | int READ_LOW( addr_t ); | ||
21 | void WRITE_LOW( addr_t, int data ); | ||
22 | |||
23 | // 0 <= addr <= 0xFFFF + page_size | ||
24 | // Used by common instructions. | ||
25 | int READ_FAST( addr_t, int& out ); | ||
26 | void WRITE_FAST( addr_t, int data ); | ||
27 | |||
28 | // 0 <= addr <= 2 | ||
29 | // ST0, ST1, ST2 instructions | ||
30 | void WRITE_VDP( int addr, int data ); | ||
31 | |||
32 | // The following can be used within macros: | ||
33 | |||
34 | // Current time | ||
35 | hes_time_t TIME(); | ||
36 | |||
37 | // Allows use of time functions | ||
38 | void FLUSH_TIME(); | ||
39 | |||
40 | // Must be used before end of macro if FLUSH_TIME() was used earlier | ||
41 | void CACHE_TIME(); | ||
42 | |||
43 | // Configuration (optional; commented behavior if defined) | ||
44 | |||
45 | // Expanded just before beginning of code, to help debugger | ||
46 | #define CPU_BEGIN void my_run_cpu() { | ||
47 | #endif | ||
48 | |||
49 | /* Copyright (C) 2003-2008 Shay Green. This module is free software; you | ||
50 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
51 | General Public License as published by the Free Software Foundation; either | ||
52 | version 2.1 of the License, or (at your option) any later version. This | ||
53 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
54 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
55 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
56 | details. You should have received a copy of the GNU Lesser General Public | ||
57 | License along with this module; if not, write to the Free Software Foundation, | ||
58 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
59 | |||
60 | // TODO: support T flag, including clearing it at appropriate times? | ||
61 | |||
62 | // all zero-page should really use whatever is at page 1, but that would | ||
63 | // reduce efficiency quite a bit | ||
64 | int const ram_addr = 0x2000; | ||
65 | |||
66 | void Cpu_reset( struct Hes_Cpu* this ) | ||
67 | { | ||
68 | check( this->cpu_state == &this->cpu_state_ ); | ||
69 | this->cpu_state = &this->cpu_state_; | ||
70 | |||
71 | this->cpu_state_.time = 0; | ||
72 | this->cpu_state_.base = 0; | ||
73 | this->irq_time_ = future_time; | ||
74 | this->end_time_ = future_time; | ||
75 | |||
76 | this->r.flags = 0x04; | ||
77 | this->r.sp = 0; | ||
78 | this->r.pc = 0; | ||
79 | this->r.a = 0; | ||
80 | this->r.x = 0; | ||
81 | this->r.y = 0; | ||
82 | |||
83 | // Be sure "blargg_endian.h" has been #included | ||
84 | blargg_verify_byte_order(); | ||
85 | } | ||
86 | |||
87 | // Allows MWCW debugger to step through code properly | ||
88 | #ifdef CPU_BEGIN | ||
89 | CPU_BEGIN | ||
90 | #endif | ||
91 | |||
92 | // Time | ||
93 | #define TIME() (s_time + s.base) | ||
94 | #define FLUSH_TIME() {s.time = s_time;} | ||
95 | #define CACHE_TIME() {s_time = s.time;} | ||
96 | |||
97 | // Memory | ||
98 | #define READ_STACK READ_LOW | ||
99 | #define WRITE_STACK WRITE_LOW | ||
100 | |||
101 | #define CODE_PAGE( addr ) s.code_map [HES_CPU_PAGE( addr )] | ||
102 | #define CODE_OFFSET( addr ) HES_CPU_OFFSET( addr ) | ||
103 | #define READ_CODE( addr ) CODE_PAGE( addr ) [CODE_OFFSET( addr )] | ||
104 | |||
105 | // Stack | ||
106 | #define SET_SP( v ) (sp = ((v) + 1) | 0x100) | ||
107 | #define GET_SP() ((sp - 1) & 0xFF) | ||
108 | #define SP( o ) ((sp + (o - (o>0)*0x100)) | 0x100) | ||
109 | |||
110 | // Truncation | ||
111 | #define BYTE( n ) ((uint8_t ) (n)) /* (unsigned) n & 0xFF */ | ||
112 | #define SBYTE( n ) ((int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */ | ||
113 | #define WORD( n ) ((uint16_t) (n)) /* (unsigned) n & 0xFFFF */ | ||
114 | |||
115 | // Flags with hex value for clarity when used as mask. | ||
116 | // Stored in indicated variable during emulation. | ||
117 | int const n80 = 0x80; // nz | ||
118 | int const v40 = 0x40; // flags | ||
119 | //int const t20 = 0x20; | ||
120 | int const b10 = 0x10; | ||
121 | int const d08 = 0x08; // flags | ||
122 | int const i04 = 0x04; // flags | ||
123 | int const z02 = 0x02; // nz | ||
124 | int const c01 = 0x01; // c | ||
125 | |||
126 | #define IS_NEG (nz & 0x8080) | ||
127 | |||
128 | #define GET_FLAGS( out ) \ | ||
129 | {\ | ||
130 | out = flags & (v40 | d08 | i04);\ | ||
131 | out += ((nz >> 8) | nz) & n80;\ | ||
132 | out += c >> 8 & c01;\ | ||
133 | if ( !BYTE( nz ) )\ | ||
134 | out += z02;\ | ||
135 | } | ||
136 | |||
137 | #define SET_FLAGS( in ) \ | ||
138 | {\ | ||
139 | flags = in & (v40 | d08 | i04);\ | ||
140 | c = nz = in << 8;\ | ||
141 | nz += ~in & z02;\ | ||
142 | } | ||
143 | |||
144 | bool illegal_encountered = false; | ||
145 | { | ||
146 | struct cpu_state_t s = cpu->cpu_state_; | ||
147 | cpu->cpu_state = &s; | ||
148 | // even on x86, using s.time in place of s_time was slower | ||
149 | int s_time = s.time; | ||
150 | |||
151 | // registers | ||
152 | int pc = cpu->r.pc; | ||
153 | int a = cpu->r.a; | ||
154 | int x = cpu->r.x; | ||
155 | int y = cpu->r.y; | ||
156 | int sp; | ||
157 | SET_SP( cpu->r.sp ); | ||
158 | |||
159 | // Flags | ||
160 | int flags; | ||
161 | int c; // carry set if (c & 0x100) != 0 | ||
162 | int nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 | ||
163 | { | ||
164 | int temp = cpu->r.flags; | ||
165 | SET_FLAGS( temp ); | ||
166 | } | ||
167 | |||
168 | loop: | ||
169 | |||
170 | #ifndef NDEBUG | ||
171 | { | ||
172 | hes_time_t correct = cpu->end_time_; | ||
173 | if ( !(flags & i04) && correct > cpu->irq_time_ ) | ||
174 | correct = cpu->irq_time_; | ||
175 | check( s.base == correct ); | ||
176 | /* | ||
177 | static int count; | ||
178 | if ( count == 1844 ) Debugger(); | ||
179 | if ( s.base != correct ) dprintf( "%ld\n", count ); | ||
180 | count++; | ||
181 | */ | ||
182 | } | ||
183 | #endif | ||
184 | |||
185 | // Check all values | ||
186 | check( (unsigned) sp - 0x100 < 0x100 ); | ||
187 | check( (unsigned) pc < 0x10000 + 0x100 ); // +0x100 so emulator can catch wrap-around | ||
188 | check( (unsigned) a < 0x100 ); | ||
189 | check( (unsigned) x < 0x100 ); | ||
190 | check( (unsigned) y < 0x100 ); | ||
191 | |||
192 | // Read instruction | ||
193 | byte const* instr = CODE_PAGE( pc ); | ||
194 | int opcode; | ||
195 | |||
196 | if ( CODE_OFFSET(~0) == ~0 ) | ||
197 | { | ||
198 | opcode = instr [pc]; | ||
199 | pc++; | ||
200 | instr += pc; | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | instr += CODE_OFFSET( pc ); | ||
205 | opcode = *instr++; | ||
206 | pc++; | ||
207 | } | ||
208 | |||
209 | // TODO: each reference lists slightly different timing values, ugh | ||
210 | static byte const clock_table [256] = | ||
211 | {// 0 1 2 3 4 5 6 7 8 9 A B C D E F | ||
212 | 1,7,3, 4,6,4,6,7,3,2,2,2,7,5,7,4,// 0 | ||
213 | 2,7,7, 4,6,4,6,7,2,5,2,2,7,5,7,4,// 1 | ||
214 | 7,7,3, 4,4,4,6,7,4,2,2,2,5,5,7,4,// 2 | ||
215 | 2,7,7, 2,4,4,6,7,2,5,2,2,5,5,7,4,// 3 | ||
216 | 7,7,3, 4,8,4,6,7,3,2,2,2,4,5,7,4,// 4 | ||
217 | 2,7,7, 5,2,4,6,7,2,5,3,2,2,5,7,4,// 5 | ||
218 | 7,7,2, 2,4,4,6,7,4,2,2,2,7,5,7,4,// 6 | ||
219 | 2,7,7,17,4,4,6,7,2,5,4,2,7,5,7,4,// 7 | ||
220 | 4,7,2, 7,4,4,4,7,2,2,2,2,5,5,5,4,// 8 | ||
221 | 2,7,7, 8,4,4,4,7,2,5,2,2,5,5,5,4,// 9 | ||
222 | 2,7,2, 7,4,4,4,7,2,2,2,2,5,5,5,4,// A | ||
223 | 2,7,7, 8,4,4,4,7,2,5,2,2,5,5,5,4,// B | ||
224 | 2,7,2,17,4,4,6,7,2,2,2,2,5,5,7,4,// C | ||
225 | 2,7,7,17,2,4,6,7,2,5,3,2,2,5,7,4,// D | ||
226 | 2,7,2,17,4,4,6,7,2,2,2,2,5,5,7,4,// E | ||
227 | 2,7,7,17,2,4,6,7,2,5,4,2,2,5,7,4 // F | ||
228 | }; // 0x00 was 8 | ||
229 | |||
230 | // Update time | ||
231 | if ( s_time >= 0 ) | ||
232 | goto out_of_time; | ||
233 | |||
234 | #ifdef HES_CPU_LOG_H | ||
235 | log_cpu( "new", pc - 1, opcode, instr [0], instr [1], instr [2], | ||
236 | instr [3], instr [4], instr [5], a, x, y ); | ||
237 | //log_opcode( opcode ); | ||
238 | #endif | ||
239 | |||
240 | s_time += clock_table [opcode]; | ||
241 | |||
242 | int data; | ||
243 | data = *instr; | ||
244 | |||
245 | switch ( opcode ) | ||
246 | { | ||
247 | // Macros | ||
248 | |||
249 | #define GET_MSB() (instr [1]) | ||
250 | #define ADD_PAGE( out ) (pc++, out = data + 0x100 * GET_MSB()); | ||
251 | #define GET_ADDR() GET_LE16( instr ) | ||
252 | |||
253 | // TODO: is the penalty really always added? the original 6502 was much better | ||
254 | //#define PAGE_PENALTY( lsb ) (void) (s_time += (lsb) >> 8) | ||
255 | #define PAGE_PENALTY( lsb ) | ||
256 | |||
257 | // Branch | ||
258 | |||
259 | // TODO: more efficient way to handle negative branch that wraps PC around | ||
260 | #define BRANCH_( cond, adj )\ | ||
261 | {\ | ||
262 | pc++;\ | ||
263 | if ( !(cond) ) goto loop;\ | ||
264 | pc = (uint16_t) (pc + SBYTE( data ));\ | ||
265 | s_time += adj;\ | ||
266 | goto loop;\ | ||
267 | } | ||
268 | |||
269 | #define BRANCH( cond ) BRANCH_( cond, 2 ) | ||
270 | |||
271 | case 0xF0: // BEQ | ||
272 | BRANCH( !BYTE( nz ) ); | ||
273 | |||
274 | case 0xD0: // BNE | ||
275 | BRANCH( BYTE( nz ) ); | ||
276 | |||
277 | case 0x10: // BPL | ||
278 | BRANCH( !IS_NEG ); | ||
279 | |||
280 | case 0x90: // BCC | ||
281 | BRANCH( !(c & 0x100) ) | ||
282 | |||
283 | case 0x30: // BMI | ||
284 | BRANCH( IS_NEG ) | ||
285 | |||
286 | case 0x50: // BVC | ||
287 | BRANCH( !(flags & v40) ) | ||
288 | |||
289 | case 0x70: // BVS | ||
290 | BRANCH( flags & v40 ) | ||
291 | |||
292 | case 0xB0: // BCS | ||
293 | BRANCH( c & 0x100 ) | ||
294 | |||
295 | case 0x80: // BRA | ||
296 | branch_taken: | ||
297 | BRANCH_( true, 0 ); | ||
298 | |||
299 | case 0xFF: | ||
300 | #ifdef IDLE_ADDR | ||
301 | if ( pc == IDLE_ADDR + 1 ) | ||
302 | goto idle_done; | ||
303 | #endif | ||
304 | |||
305 | pc = (uint16_t) pc; | ||
306 | |||
307 | case 0x0F: // BBRn | ||
308 | case 0x1F: | ||
309 | case 0x2F: | ||
310 | case 0x3F: | ||
311 | case 0x4F: | ||
312 | case 0x5F: | ||
313 | case 0x6F: | ||
314 | case 0x7F: | ||
315 | case 0x8F: // BBSn | ||
316 | case 0x9F: | ||
317 | case 0xAF: | ||
318 | case 0xBF: | ||
319 | case 0xCF: | ||
320 | case 0xDF: | ||
321 | case 0xEF: { | ||
322 | // Make two copies of bits, one negated | ||
323 | int t = 0x101 * READ_LOW( data ); | ||
324 | t ^= 0xFF; | ||
325 | pc++; | ||
326 | data = GET_MSB(); | ||
327 | BRANCH( t & (1 << (opcode >> 4)) ) | ||
328 | } | ||
329 | |||
330 | case 0x4C: // JMP abs | ||
331 | pc = GET_ADDR(); | ||
332 | goto loop; | ||
333 | |||
334 | case 0x7C: // JMP (ind+X) | ||
335 | data += x; | ||
336 | case 0x6C:{// JMP (ind) | ||
337 | data += 0x100 * GET_MSB(); | ||
338 | pc = GET_LE16( &READ_CODE( data ) ); | ||
339 | goto loop; | ||
340 | } | ||
341 | |||
342 | // Subroutine | ||
343 | |||
344 | case 0x44: // BSR | ||
345 | WRITE_STACK( SP( -1 ), pc >> 8 ); | ||
346 | sp = SP( -2 ); | ||
347 | WRITE_STACK( sp, pc ); | ||
348 | goto branch_taken; | ||
349 | |||
350 | case 0x20: { // JSR | ||
351 | int temp = pc + 1; | ||
352 | pc = GET_ADDR(); | ||
353 | WRITE_STACK( SP( -1 ), temp >> 8 ); | ||
354 | sp = SP( -2 ); | ||
355 | WRITE_STACK( sp, temp ); | ||
356 | goto loop; | ||
357 | } | ||
358 | |||
359 | case 0x60: // RTS | ||
360 | pc = 1 + READ_STACK( sp ); | ||
361 | pc += 0x100 * READ_STACK( SP( 1 ) ); | ||
362 | sp = SP( 2 ); | ||
363 | goto loop; | ||
364 | |||
365 | case 0x00: // BRK | ||
366 | goto handle_brk; | ||
367 | |||
368 | // Common | ||
369 | |||
370 | case 0xBD:{// LDA abs,X | ||
371 | PAGE_PENALTY( data + x ); | ||
372 | int addr = GET_ADDR() + x; | ||
373 | pc += 2; | ||
374 | READ_FAST( addr, nz ); | ||
375 | a = nz; | ||
376 | goto loop; | ||
377 | } | ||
378 | |||
379 | case 0x9D:{// STA abs,X | ||
380 | int addr = GET_ADDR() + x; | ||
381 | pc += 2; | ||
382 | WRITE_FAST( addr, a ); | ||
383 | goto loop; | ||
384 | } | ||
385 | |||
386 | case 0x95: // STA zp,x | ||
387 | data = BYTE( data + x ); | ||
388 | case 0x85: // STA zp | ||
389 | pc++; | ||
390 | WRITE_LOW( data, a ); | ||
391 | goto loop; | ||
392 | |||
393 | case 0xAE:{// LDX abs | ||
394 | int addr = GET_ADDR(); | ||
395 | pc += 2; | ||
396 | READ_FAST( addr, nz ); | ||
397 | x = nz; | ||
398 | goto loop; | ||
399 | } | ||
400 | |||
401 | case 0xA5: // LDA zp | ||
402 | a = nz = READ_LOW( data ); | ||
403 | pc++; | ||
404 | goto loop; | ||
405 | |||
406 | // Load/store | ||
407 | |||
408 | { | ||
409 | int addr; | ||
410 | case 0x91: // STA (ind),Y | ||
411 | addr = 0x100 * READ_LOW( BYTE( data + 1 ) ); | ||
412 | addr += READ_LOW( data ) + y; | ||
413 | pc++; | ||
414 | goto sta_ptr; | ||
415 | |||
416 | case 0x81: // STA (ind,X) | ||
417 | data = BYTE( data + x ); | ||
418 | case 0x92: // STA (ind) | ||
419 | addr = 0x100 * READ_LOW( BYTE( data + 1 ) ); | ||
420 | addr += READ_LOW( data ); | ||
421 | pc++; | ||
422 | goto sta_ptr; | ||
423 | |||
424 | case 0x99: // STA abs,Y | ||
425 | data += y; | ||
426 | case 0x8D: // STA abs | ||
427 | addr = data + 0x100 * GET_MSB(); | ||
428 | pc += 2; | ||
429 | sta_ptr: | ||
430 | WRITE_FAST( addr, a ); | ||
431 | goto loop; | ||
432 | } | ||
433 | |||
434 | { | ||
435 | int addr; | ||
436 | case 0xA1: // LDA (ind,X) | ||
437 | data = BYTE( data + x ); | ||
438 | case 0xB2: // LDA (ind) | ||
439 | addr = 0x100 * READ_LOW( BYTE( data + 1 ) ); | ||
440 | addr += READ_LOW( data ); | ||
441 | pc++; | ||
442 | goto a_nz_read_addr; | ||
443 | |||
444 | case 0xB1:// LDA (ind),Y | ||
445 | addr = READ_LOW( data ) + y; | ||
446 | PAGE_PENALTY( addr ); | ||
447 | addr += 0x100 * READ_LOW( BYTE( data + 1 ) ); | ||
448 | pc++; | ||
449 | goto a_nz_read_addr; | ||
450 | |||
451 | case 0xB9: // LDA abs,Y | ||
452 | data += y; | ||
453 | PAGE_PENALTY( data ); | ||
454 | case 0xAD: // LDA abs | ||
455 | addr = data + 0x100 * GET_MSB(); | ||
456 | pc += 2; | ||
457 | a_nz_read_addr: | ||
458 | READ_FAST( addr, nz ); | ||
459 | a = nz; | ||
460 | goto loop; | ||
461 | } | ||
462 | |||
463 | case 0xBE:{// LDX abs,y | ||
464 | PAGE_PENALTY( data + y ); | ||
465 | int addr = GET_ADDR() + y; | ||
466 | pc += 2; | ||
467 | FLUSH_TIME(); | ||
468 | x = nz = READ_MEM( addr ); | ||
469 | CACHE_TIME(); | ||
470 | goto loop; | ||
471 | } | ||
472 | |||
473 | case 0xB5: // LDA zp,x | ||
474 | a = nz = READ_LOW( BYTE( data + x ) ); | ||
475 | pc++; | ||
476 | goto loop; | ||
477 | |||
478 | case 0xA9: // LDA #imm | ||
479 | pc++; | ||
480 | a = data; | ||
481 | nz = data; | ||
482 | goto loop; | ||
483 | |||
484 | // Bit operations | ||
485 | |||
486 | case 0x3C: // BIT abs,x | ||
487 | data += x; | ||
488 | case 0x2C:{// BIT abs | ||
489 | int addr; | ||
490 | ADD_PAGE( addr ); | ||
491 | FLUSH_TIME(); | ||
492 | nz = READ_MEM( addr ); | ||
493 | CACHE_TIME(); | ||
494 | goto bit_common; | ||
495 | } | ||
496 | case 0x34: // BIT zp,x | ||
497 | data = BYTE( data + x ); | ||
498 | case 0x24: // BIT zp | ||
499 | data = READ_LOW( data ); | ||
500 | case 0x89: // BIT imm | ||
501 | nz = data; | ||
502 | bit_common: | ||
503 | pc++; | ||
504 | flags = (flags & ~v40) + (nz & v40); | ||
505 | if ( nz & a ) | ||
506 | goto loop; // Z should be clear, and nz must be non-zero if nz & a is | ||
507 | nz <<= 8; // set Z flag without affecting N flag | ||
508 | goto loop; | ||
509 | |||
510 | { | ||
511 | int addr; | ||
512 | |||
513 | case 0xB3: // TST abs,x | ||
514 | addr = GET_MSB() + x; | ||
515 | goto tst_abs; | ||
516 | |||
517 | case 0x93: // TST abs | ||
518 | addr = GET_MSB(); | ||
519 | tst_abs: | ||
520 | addr += 0x100 * instr [2]; | ||
521 | pc++; | ||
522 | FLUSH_TIME(); | ||
523 | nz = READ_MEM( addr ); | ||
524 | CACHE_TIME(); | ||
525 | goto tst_common; | ||
526 | } | ||
527 | |||
528 | case 0xA3: // TST zp,x | ||
529 | nz = READ_LOW( BYTE( GET_MSB() + x ) ); | ||
530 | goto tst_common; | ||
531 | |||
532 | case 0x83: // TST zp | ||
533 | nz = READ_LOW( GET_MSB() ); | ||
534 | tst_common: | ||
535 | pc += 2; | ||
536 | flags = (flags & ~v40) + (nz & v40); | ||
537 | if ( nz & data ) | ||
538 | goto loop; // Z should be clear, and nz must be non-zero if nz & data is | ||
539 | nz <<= 8; // set Z flag without affecting N flag | ||
540 | goto loop; | ||
541 | |||
542 | { | ||
543 | int addr; | ||
544 | case 0x0C: // TSB abs | ||
545 | case 0x1C: // TRB abs | ||
546 | addr = GET_ADDR(); | ||
547 | pc++; | ||
548 | goto txb_addr; | ||
549 | |||
550 | // TODO: everyone lists different behaviors for the flags flags, ugh | ||
551 | case 0x04: // TSB zp | ||
552 | case 0x14: // TRB zp | ||
553 | addr = data + ram_addr; | ||
554 | txb_addr: | ||
555 | FLUSH_TIME(); | ||
556 | nz = a | READ_MEM( addr ); | ||
557 | if ( opcode & 0x10 ) | ||
558 | nz ^= a; // bits from a will already be set, so this clears them | ||
559 | flags = (flags & ~v40) + (nz & v40); | ||
560 | pc++; | ||
561 | WRITE_MEM( addr, nz ); | ||
562 | CACHE_TIME(); | ||
563 | goto loop; | ||
564 | } | ||
565 | |||
566 | case 0x07: // RMBn | ||
567 | case 0x17: | ||
568 | case 0x27: | ||
569 | case 0x37: | ||
570 | case 0x47: | ||
571 | case 0x57: | ||
572 | case 0x67: | ||
573 | case 0x77: | ||
574 | pc++; | ||
575 | READ_LOW( data ) &= ~(1 << (opcode >> 4)); | ||
576 | goto loop; | ||
577 | |||
578 | case 0x87: // SMBn | ||
579 | case 0x97: | ||
580 | case 0xA7: | ||
581 | case 0xB7: | ||
582 | case 0xC7: | ||
583 | case 0xD7: | ||
584 | case 0xE7: | ||
585 | case 0xF7: | ||
586 | pc++; | ||
587 | READ_LOW( data ) |= 1 << ((opcode >> 4) - 8); | ||
588 | goto loop; | ||
589 | |||
590 | // Load/store | ||
591 | |||
592 | case 0x9E: // STZ abs,x | ||
593 | data += x; | ||
594 | case 0x9C: // STZ abs | ||
595 | ADD_PAGE( data ); | ||
596 | pc++; | ||
597 | FLUSH_TIME(); | ||
598 | WRITE_MEM( data, 0 ); | ||
599 | CACHE_TIME(); | ||
600 | goto loop; | ||
601 | |||
602 | case 0x74: // STZ zp,x | ||
603 | data = BYTE( data + x ); | ||
604 | case 0x64: // STZ zp | ||
605 | pc++; | ||
606 | WRITE_LOW( data, 0 ); | ||
607 | goto loop; | ||
608 | |||
609 | case 0x94: // STY zp,x | ||
610 | data = BYTE( data + x ); | ||
611 | case 0x84: // STY zp | ||
612 | pc++; | ||
613 | WRITE_LOW( data, y ); | ||
614 | goto loop; | ||
615 | |||
616 | case 0x96: // STX zp,y | ||
617 | data = BYTE( data + y ); | ||
618 | case 0x86: // STX zp | ||
619 | pc++; | ||
620 | WRITE_LOW( data, x ); | ||
621 | goto loop; | ||
622 | |||
623 | case 0xB6: // LDX zp,y | ||
624 | data = BYTE( data + y ); | ||
625 | case 0xA6: // LDX zp | ||
626 | data = READ_LOW( data ); | ||
627 | case 0xA2: // LDX #imm | ||
628 | pc++; | ||
629 | x = data; | ||
630 | nz = data; | ||
631 | goto loop; | ||
632 | |||
633 | case 0xB4: // LDY zp,x | ||
634 | data = BYTE( data + x ); | ||
635 | case 0xA4: // LDY zp | ||
636 | data = READ_LOW( data ); | ||
637 | case 0xA0: // LDY #imm | ||
638 | pc++; | ||
639 | y = data; | ||
640 | nz = data; | ||
641 | goto loop; | ||
642 | |||
643 | case 0xBC: // LDY abs,X | ||
644 | data += x; | ||
645 | PAGE_PENALTY( data ); | ||
646 | case 0xAC:{// LDY abs | ||
647 | int addr = data + 0x100 * GET_MSB(); | ||
648 | pc += 2; | ||
649 | FLUSH_TIME(); | ||
650 | y = nz = READ_MEM( addr ); | ||
651 | CACHE_TIME(); | ||
652 | goto loop; | ||
653 | } | ||
654 | |||
655 | { | ||
656 | int temp; | ||
657 | case 0x8C: // STY abs | ||
658 | temp = y; | ||
659 | if ( 0 ) | ||
660 | case 0x8E: // STX abs | ||
661 | temp = x; | ||
662 | int addr = GET_ADDR(); | ||
663 | pc += 2; | ||
664 | FLUSH_TIME(); | ||
665 | WRITE_MEM( addr, temp ); | ||
666 | CACHE_TIME(); | ||
667 | goto loop; | ||
668 | } | ||
669 | |||
670 | // Compare | ||
671 | |||
672 | case 0xEC:{// CPX abs | ||
673 | int addr = GET_ADDR(); | ||
674 | pc++; | ||
675 | FLUSH_TIME(); | ||
676 | data = READ_MEM( addr ); | ||
677 | CACHE_TIME(); | ||
678 | goto cpx_data; | ||
679 | } | ||
680 | |||
681 | case 0xE4: // CPX zp | ||
682 | data = READ_LOW( data ); | ||
683 | case 0xE0: // CPX #imm | ||
684 | cpx_data: | ||
685 | nz = x - data; | ||
686 | pc++; | ||
687 | c = ~nz; | ||
688 | nz = BYTE( nz ); | ||
689 | goto loop; | ||
690 | |||
691 | case 0xCC:{// CPY abs | ||
692 | int addr = GET_ADDR(); | ||
693 | pc++; | ||
694 | FLUSH_TIME(); | ||
695 | data = READ_MEM( addr ); | ||
696 | CACHE_TIME(); | ||
697 | goto cpy_data; | ||
698 | } | ||
699 | |||
700 | case 0xC4: // CPY zp | ||
701 | data = READ_LOW( data ); | ||
702 | case 0xC0: // CPY #imm | ||
703 | cpy_data: | ||
704 | nz = y - data; | ||
705 | pc++; | ||
706 | c = ~nz; | ||
707 | nz = BYTE( nz ); | ||
708 | goto loop; | ||
709 | |||
710 | // Logical | ||
711 | |||
712 | #define ARITH_ADDR_MODES( op )\ | ||
713 | case op - 0x04: /* (ind,x) */\ | ||
714 | data = BYTE( data + x );\ | ||
715 | case op + 0x0D: /* (ind) */\ | ||
716 | data = 0x100 * READ_LOW( BYTE( data + 1 ) ) + READ_LOW( data );\ | ||
717 | goto ptr##op;\ | ||
718 | case op + 0x0C:{/* (ind),y */\ | ||
719 | int temp = READ_LOW( data ) + y;\ | ||
720 | PAGE_PENALTY( temp );\ | ||
721 | data = temp + 0x100 * READ_LOW( BYTE( data + 1 ) );\ | ||
722 | goto ptr##op;\ | ||
723 | }\ | ||
724 | case op + 0x10: /* zp,X */\ | ||
725 | data = BYTE( data + x );\ | ||
726 | case op + 0x00: /* zp */\ | ||
727 | data = READ_LOW( data );\ | ||
728 | goto imm##op;\ | ||
729 | case op + 0x14: /* abs,Y */\ | ||
730 | data += y;\ | ||
731 | goto ind##op;\ | ||
732 | case op + 0x18: /* abs,X */\ | ||
733 | data += x;\ | ||
734 | ind##op:\ | ||
735 | PAGE_PENALTY( data );\ | ||
736 | case op + 0x08: /* abs */\ | ||
737 | ADD_PAGE( data );\ | ||
738 | ptr##op:\ | ||
739 | FLUSH_TIME();\ | ||
740 | data = READ_MEM( data );\ | ||
741 | CACHE_TIME();\ | ||
742 | case op + 0x04: /* imm */\ | ||
743 | imm##op: | ||
744 | |||
745 | ARITH_ADDR_MODES( 0xC5 ) // CMP | ||
746 | nz = a - data; | ||
747 | pc++; | ||
748 | c = ~nz; | ||
749 | nz = BYTE( nz ); | ||
750 | goto loop; | ||
751 | |||
752 | ARITH_ADDR_MODES( 0x25 ) // AND | ||
753 | nz = (a &= data); | ||
754 | pc++; | ||
755 | goto loop; | ||
756 | |||
757 | ARITH_ADDR_MODES( 0x45 ) // EOR | ||
758 | nz = (a ^= data); | ||
759 | pc++; | ||
760 | goto loop; | ||
761 | |||
762 | ARITH_ADDR_MODES( 0x05 ) // ORA | ||
763 | nz = (a |= data); | ||
764 | pc++; | ||
765 | goto loop; | ||
766 | |||
767 | // Add/subtract | ||
768 | |||
769 | ARITH_ADDR_MODES( 0xE5 ) // SBC | ||
770 | data ^= 0xFF; | ||
771 | goto adc_imm; | ||
772 | |||
773 | ARITH_ADDR_MODES( 0x65 ) // ADC | ||
774 | adc_imm: { | ||
775 | /* if ( flags & d08 ) | ||
776 | dprintf( "Decimal mode not supported\n" ); */ | ||
777 | int carry = c >> 8 & 1; | ||
778 | int ov = (a ^ 0x80) + carry + SBYTE( data ); | ||
779 | flags = (flags & ~v40) + (ov >> 2 & v40); | ||
780 | c = nz = a + data + carry; | ||
781 | pc++; | ||
782 | a = BYTE( nz ); | ||
783 | goto loop; | ||
784 | } | ||
785 | |||
786 | // Shift/rotate | ||
787 | |||
788 | case 0x4A: // LSR A | ||
789 | c = 0; | ||
790 | case 0x6A: // ROR A | ||
791 | nz = c >> 1 & 0x80; | ||
792 | c = a << 8; | ||
793 | nz += a >> 1; | ||
794 | a = nz; | ||
795 | goto loop; | ||
796 | |||
797 | case 0x0A: // ASL A | ||
798 | nz = a << 1; | ||
799 | c = nz; | ||
800 | a = BYTE( nz ); | ||
801 | goto loop; | ||
802 | |||
803 | case 0x2A: { // ROL A | ||
804 | nz = a << 1; | ||
805 | int temp = c >> 8 & 1; | ||
806 | c = nz; | ||
807 | nz += temp; | ||
808 | a = BYTE( nz ); | ||
809 | goto loop; | ||
810 | } | ||
811 | |||
812 | case 0x5E: // LSR abs,X | ||
813 | data += x; | ||
814 | case 0x4E: // LSR abs | ||
815 | c = 0; | ||
816 | case 0x6E: // ROR abs | ||
817 | ror_abs: { | ||
818 | ADD_PAGE( data ); | ||
819 | FLUSH_TIME(); | ||
820 | int temp = READ_MEM( data ); | ||
821 | nz = (c >> 1 & 0x80) + (temp >> 1); | ||
822 | c = temp << 8; | ||
823 | goto rotate_common; | ||
824 | } | ||
825 | |||
826 | case 0x3E: // ROL abs,X | ||
827 | data += x; | ||
828 | goto rol_abs; | ||
829 | |||
830 | case 0x1E: // ASL abs,X | ||
831 | data += x; | ||
832 | case 0x0E: // ASL abs | ||
833 | c = 0; | ||
834 | case 0x2E: // ROL abs | ||
835 | rol_abs: | ||
836 | ADD_PAGE( data ); | ||
837 | nz = c >> 8 & 1; | ||
838 | FLUSH_TIME(); | ||
839 | nz += (c = READ_MEM( data ) << 1); | ||
840 | rotate_common: | ||
841 | pc++; | ||
842 | WRITE_MEM( data, BYTE( nz ) ); | ||
843 | CACHE_TIME(); | ||
844 | goto loop; | ||
845 | |||
846 | case 0x7E: // ROR abs,X | ||
847 | data += x; | ||
848 | goto ror_abs; | ||
849 | |||
850 | case 0x76: // ROR zp,x | ||
851 | data = BYTE( data + x ); | ||
852 | goto ror_zp; | ||
853 | |||
854 | case 0x56: // LSR zp,x | ||
855 | data = BYTE( data + x ); | ||
856 | case 0x46: // LSR zp | ||
857 | c = 0; | ||
858 | case 0x66: // ROR zp | ||
859 | ror_zp: { | ||
860 | int temp = READ_LOW( data ); | ||
861 | nz = (c >> 1 & 0x80) + (temp >> 1); | ||
862 | c = temp << 8; | ||
863 | goto write_nz_zp; | ||
864 | } | ||
865 | |||
866 | case 0x36: // ROL zp,x | ||
867 | data = BYTE( data + x ); | ||
868 | goto rol_zp; | ||
869 | |||
870 | case 0x16: // ASL zp,x | ||
871 | data = BYTE( data + x ); | ||
872 | case 0x06: // ASL zp | ||
873 | c = 0; | ||
874 | case 0x26: // ROL zp | ||
875 | rol_zp: | ||
876 | nz = c >> 8 & 1; | ||
877 | nz += (c = READ_LOW( data ) << 1); | ||
878 | goto write_nz_zp; | ||
879 | |||
880 | // Increment/decrement | ||
881 | |||
882 | #define INC_DEC( reg, n ) reg = BYTE( nz = reg + n ); goto loop; | ||
883 | |||
884 | case 0x1A: // INA | ||
885 | INC_DEC( a, +1 ) | ||
886 | |||
887 | case 0xE8: // INX | ||
888 | INC_DEC( x, +1 ) | ||
889 | |||
890 | case 0xC8: // INY | ||
891 | INC_DEC( y, +1 ) | ||
892 | |||
893 | case 0x3A: // DEA | ||
894 | INC_DEC( a, -1 ) | ||
895 | |||
896 | case 0xCA: // DEX | ||
897 | INC_DEC( x, -1 ) | ||
898 | |||
899 | case 0x88: // DEY | ||
900 | INC_DEC( y, -1 ) | ||
901 | |||
902 | case 0xF6: // INC zp,x | ||
903 | data = BYTE( data + x ); | ||
904 | case 0xE6: // INC zp | ||
905 | nz = 1; | ||
906 | goto add_nz_zp; | ||
907 | |||
908 | case 0xD6: // DEC zp,x | ||
909 | data = BYTE( data + x ); | ||
910 | case 0xC6: // DEC zp | ||
911 | nz = -1; | ||
912 | add_nz_zp: | ||
913 | nz += READ_LOW( data ); | ||
914 | write_nz_zp: | ||
915 | pc++; | ||
916 | WRITE_LOW( data, nz ); | ||
917 | goto loop; | ||
918 | |||
919 | case 0xFE: // INC abs,x | ||
920 | data = x + GET_ADDR(); | ||
921 | goto inc_ptr; | ||
922 | |||
923 | case 0xEE: // INC abs | ||
924 | data = GET_ADDR(); | ||
925 | inc_ptr: | ||
926 | nz = 1; | ||
927 | goto inc_common; | ||
928 | |||
929 | case 0xDE: // DEC abs,x | ||
930 | data = x + GET_ADDR(); | ||
931 | goto dec_ptr; | ||
932 | |||
933 | case 0xCE: // DEC abs | ||
934 | data = GET_ADDR(); | ||
935 | dec_ptr: | ||
936 | nz = -1; | ||
937 | inc_common: | ||
938 | FLUSH_TIME(); | ||
939 | pc += 2; | ||
940 | nz += READ_MEM( data ); | ||
941 | WRITE_MEM( data, BYTE( nz ) ); | ||
942 | CACHE_TIME(); | ||
943 | goto loop; | ||
944 | |||
945 | // Transfer | ||
946 | |||
947 | case 0xA8: // TAY | ||
948 | y = nz = a; | ||
949 | goto loop; | ||
950 | |||
951 | case 0x98: // TYA | ||
952 | a = nz = y; | ||
953 | goto loop; | ||
954 | |||
955 | case 0xAA: // TAX | ||
956 | x = nz = a; | ||
957 | goto loop; | ||
958 | |||
959 | case 0x8A: // TXA | ||
960 | a = nz = x; | ||
961 | goto loop; | ||
962 | |||
963 | case 0x9A: // TXS | ||
964 | SET_SP( x ); // verified (no flag change) | ||
965 | goto loop; | ||
966 | |||
967 | case 0xBA: // TSX | ||
968 | x = nz = GET_SP(); | ||
969 | goto loop; | ||
970 | |||
971 | #define SWAP_REGS( r1, r2 ) {\ | ||
972 | int t = r1;\ | ||
973 | r1 = r2;\ | ||
974 | r2 = t;\ | ||
975 | goto loop;\ | ||
976 | } | ||
977 | |||
978 | case 0x02: // SXY | ||
979 | SWAP_REGS( x, y ); | ||
980 | |||
981 | case 0x22: // SAX | ||
982 | SWAP_REGS( a, x ); | ||
983 | |||
984 | case 0x42: // SAY | ||
985 | SWAP_REGS( a, y ); | ||
986 | |||
987 | case 0x62: // CLA | ||
988 | a = 0; | ||
989 | goto loop; | ||
990 | |||
991 | case 0x82: // CLX | ||
992 | x = 0; | ||
993 | goto loop; | ||
994 | |||
995 | case 0xC2: // CLY | ||
996 | y = 0; | ||
997 | goto loop; | ||
998 | |||
999 | // Stack | ||
1000 | |||
1001 | case 0x48: // PHA | ||
1002 | sp = SP( -1 ); | ||
1003 | WRITE_STACK( sp, a ); | ||
1004 | goto loop; | ||
1005 | |||
1006 | case 0x68: // PLA | ||
1007 | a = nz = READ_STACK( sp ); | ||
1008 | sp = SP( 1 ); | ||
1009 | goto loop; | ||
1010 | |||
1011 | case 0xDA: // PHX | ||
1012 | sp = SP( -1 ); | ||
1013 | WRITE_STACK( sp, x ); | ||
1014 | goto loop; | ||
1015 | |||
1016 | case 0x5A: // PHY | ||
1017 | sp = SP( -1 ); | ||
1018 | WRITE_STACK( sp, y ); | ||
1019 | goto loop; | ||
1020 | |||
1021 | case 0x40:{// RTI | ||
1022 | pc = READ_STACK( SP( 1 ) ); | ||
1023 | pc += READ_STACK( SP( 2 ) ) * 0x100; | ||
1024 | int temp = READ_STACK( sp ); | ||
1025 | sp = SP( 3 ); | ||
1026 | data = flags; | ||
1027 | SET_FLAGS( temp ); | ||
1028 | cpu->r.flags = flags; // update externally-visible I flag | ||
1029 | if ( (data ^ flags) & i04 ) | ||
1030 | { | ||
1031 | hes_time_t new_time = cpu->end_time_; | ||
1032 | if ( !(flags & i04) && new_time > cpu->irq_time_ ) | ||
1033 | new_time = cpu->irq_time_; | ||
1034 | int delta = s.base - new_time; | ||
1035 | s.base = new_time; | ||
1036 | s_time += delta; | ||
1037 | } | ||
1038 | goto loop; | ||
1039 | } | ||
1040 | |||
1041 | case 0xFA: // PLX | ||
1042 | x = nz = READ_STACK( sp ); | ||
1043 | sp = SP( 1 ); | ||
1044 | goto loop; | ||
1045 | |||
1046 | case 0x7A: // PLY | ||
1047 | y = nz = READ_STACK( sp ); | ||
1048 | sp = SP( 1 ); | ||
1049 | goto loop; | ||
1050 | |||
1051 | case 0x28:{// PLP | ||
1052 | int temp = READ_STACK( sp ); | ||
1053 | sp = SP( 1 ); | ||
1054 | int changed = flags ^ temp; | ||
1055 | SET_FLAGS( temp ); | ||
1056 | if ( !(changed & i04) ) | ||
1057 | goto loop; // I flag didn't change | ||
1058 | if ( flags & i04 ) | ||
1059 | goto handle_sei; | ||
1060 | goto handle_cli; | ||
1061 | } | ||
1062 | |||
1063 | case 0x08:{// PHP | ||
1064 | int temp; | ||
1065 | GET_FLAGS( temp ); | ||
1066 | sp = SP( -1 ); | ||
1067 | WRITE_STACK( sp, temp | b10 ); | ||
1068 | goto loop; | ||
1069 | } | ||
1070 | |||
1071 | // Flags | ||
1072 | |||
1073 | case 0x38: // SEC | ||
1074 | c = 0x100; | ||
1075 | goto loop; | ||
1076 | |||
1077 | case 0x18: // CLC | ||
1078 | c = 0; | ||
1079 | goto loop; | ||
1080 | |||
1081 | case 0xB8: // CLV | ||
1082 | flags &= ~v40; | ||
1083 | goto loop; | ||
1084 | |||
1085 | case 0xD8: // CLD | ||
1086 | flags &= ~d08; | ||
1087 | goto loop; | ||
1088 | |||
1089 | case 0xF8: // SED | ||
1090 | flags |= d08; | ||
1091 | goto loop; | ||
1092 | |||
1093 | case 0x58: // CLI | ||
1094 | if ( !(flags & i04) ) | ||
1095 | goto loop; | ||
1096 | flags &= ~i04; | ||
1097 | handle_cli: { | ||
1098 | //dprintf( "CLI at %d\n", TIME ); | ||
1099 | cpu->r.flags = flags; // update externally-visible I flag | ||
1100 | int delta = s.base - cpu->irq_time_; | ||
1101 | if ( delta <= 0 ) | ||
1102 | { | ||
1103 | if ( TIME() < cpu->irq_time_ ) | ||
1104 | goto loop; | ||
1105 | goto delayed_cli; | ||
1106 | } | ||
1107 | s.base = cpu->irq_time_; | ||
1108 | s_time += delta; | ||
1109 | if ( s_time < 0 ) | ||
1110 | goto loop; | ||
1111 | |||
1112 | if ( delta >= s_time + 1 ) | ||
1113 | { | ||
1114 | // delayed irq until after next instruction | ||
1115 | s.base += s_time + 1; | ||
1116 | s_time = -1; | ||
1117 | cpu->irq_time_ = s.base; // TODO: remove, as only to satisfy debug check in loop | ||
1118 | goto loop; | ||
1119 | } | ||
1120 | |||
1121 | // TODO: implement | ||
1122 | delayed_cli: | ||
1123 | dprintf( "Delayed CLI not supported\n" ); | ||
1124 | goto loop; | ||
1125 | } | ||
1126 | |||
1127 | case 0x78: // SEI | ||
1128 | if ( flags & i04 ) | ||
1129 | goto loop; | ||
1130 | flags |= i04; | ||
1131 | handle_sei: { | ||
1132 | cpu->r.flags = flags; // update externally-visible I flag | ||
1133 | int delta = s.base - cpu->end_time_; | ||
1134 | s.base = cpu->end_time_; | ||
1135 | s_time += delta; | ||
1136 | if ( s_time < 0 ) | ||
1137 | goto loop; | ||
1138 | |||
1139 | dprintf( "Delayed SEI not supported\n" ); | ||
1140 | goto loop; | ||
1141 | } | ||
1142 | |||
1143 | // Special | ||
1144 | |||
1145 | case 0x53:{// TAM | ||
1146 | int bits = data; // avoid using data across function call | ||
1147 | pc++; | ||
1148 | for ( int i = 0; i < 8; i++ ) | ||
1149 | if ( bits & (1 << i) ) | ||
1150 | SET_MMR( i, a ); | ||
1151 | goto loop; | ||
1152 | } | ||
1153 | |||
1154 | case 0x43:{// TMA | ||
1155 | pc++; | ||
1156 | byte const* in = cpu->mmr; | ||
1157 | do | ||
1158 | { | ||
1159 | if ( data & 1 ) | ||
1160 | a = *in; | ||
1161 | in++; | ||
1162 | } | ||
1163 | while ( (data >>= 1) != 0 ); | ||
1164 | goto loop; | ||
1165 | } | ||
1166 | |||
1167 | case 0x03: // ST0 | ||
1168 | case 0x13: // ST1 | ||
1169 | case 0x23:{// ST2 | ||
1170 | int addr = opcode >> 4; | ||
1171 | if ( addr ) | ||
1172 | addr++; | ||
1173 | pc++; | ||
1174 | FLUSH_TIME(); | ||
1175 | WRITE_VDP( addr, data ); | ||
1176 | CACHE_TIME(); | ||
1177 | goto loop; | ||
1178 | } | ||
1179 | |||
1180 | case 0xEA: // NOP | ||
1181 | goto loop; | ||
1182 | |||
1183 | case 0x54: // CSL | ||
1184 | dprintf( "CSL not supported\n" ); | ||
1185 | illegal_encountered = true; | ||
1186 | goto loop; | ||
1187 | |||
1188 | case 0xD4: // CSH | ||
1189 | goto loop; | ||
1190 | |||
1191 | case 0xF4: { // SET | ||
1192 | //int operand = GET_MSB(); | ||
1193 | dprintf( "SET not handled\n" ); | ||
1194 | //switch ( data ) | ||
1195 | //{ | ||
1196 | //} | ||
1197 | illegal_encountered = true; | ||
1198 | goto loop; | ||
1199 | } | ||
1200 | |||
1201 | // Block transfer | ||
1202 | |||
1203 | { | ||
1204 | int in_alt; | ||
1205 | int in_inc; | ||
1206 | int out_alt; | ||
1207 | int out_inc; | ||
1208 | |||
1209 | case 0xE3: // TIA | ||
1210 | in_alt = 0; | ||
1211 | goto bxfer_alt; | ||
1212 | |||
1213 | case 0xF3: // TAI | ||
1214 | in_alt = 1; | ||
1215 | bxfer_alt: | ||
1216 | in_inc = in_alt ^ 1; | ||
1217 | out_alt = in_inc; | ||
1218 | out_inc = in_alt; | ||
1219 | goto bxfer; | ||
1220 | |||
1221 | case 0xD3: // TIN | ||
1222 | in_inc = 1; | ||
1223 | out_inc = 0; | ||
1224 | goto bxfer_no_alt; | ||
1225 | |||
1226 | case 0xC3: // TDD | ||
1227 | in_inc = -1; | ||
1228 | out_inc = -1; | ||
1229 | goto bxfer_no_alt; | ||
1230 | |||
1231 | case 0x73: // TII | ||
1232 | in_inc = 1; | ||
1233 | out_inc = 1; | ||
1234 | bxfer_no_alt: | ||
1235 | in_alt = 0; | ||
1236 | out_alt = 0; | ||
1237 | bxfer: | ||
1238 | { | ||
1239 | int in = GET_LE16( instr + 0 ); | ||
1240 | int out = GET_LE16( instr + 2 ); | ||
1241 | int count = GET_LE16( instr + 4 ); | ||
1242 | if ( !count ) | ||
1243 | count = 0x10000; | ||
1244 | pc += 6; | ||
1245 | WRITE_STACK( SP( -1 ), y ); | ||
1246 | WRITE_STACK( SP( -2 ), a ); | ||
1247 | WRITE_STACK( SP( -3 ), x ); | ||
1248 | FLUSH_TIME(); | ||
1249 | do | ||
1250 | { | ||
1251 | // TODO: reads from $0800-$1400 in I/O page should do I/O | ||
1252 | int t = READ_MEM( in ); | ||
1253 | in = WORD( in + in_inc ); | ||
1254 | s.time += 6; | ||
1255 | if ( in_alt ) | ||
1256 | in_inc = -in_inc; | ||
1257 | WRITE_MEM( out, t ); | ||
1258 | out = WORD( out + out_inc ); | ||
1259 | if ( out_alt ) | ||
1260 | out_inc = -out_inc; | ||
1261 | } | ||
1262 | while ( --count ); | ||
1263 | CACHE_TIME(); | ||
1264 | goto loop; | ||
1265 | } | ||
1266 | } | ||
1267 | |||
1268 | // Illegal | ||
1269 | |||
1270 | default: | ||
1271 | check( (unsigned) opcode <= 0xFF ); | ||
1272 | dprintf( "Illegal opcode $%02X at $%04X\n", (int) opcode, (int) pc - 1 ); | ||
1273 | illegal_encountered = true; | ||
1274 | goto loop; | ||
1275 | } | ||
1276 | assert( false ); // catch missing 'goto loop' or accidental 'break' | ||
1277 | |||
1278 | int result_; | ||
1279 | handle_brk: | ||
1280 | pc++; | ||
1281 | result_ = 6; | ||
1282 | |||
1283 | interrupt: | ||
1284 | { | ||
1285 | s_time += 7; | ||
1286 | |||
1287 | // Save PC and read vector | ||
1288 | WRITE_STACK( SP( -1 ), pc >> 8 ); | ||
1289 | WRITE_STACK( SP( -2 ), pc ); | ||
1290 | pc = GET_LE16( &READ_CODE( 0xFFF0 ) + result_ ); | ||
1291 | |||
1292 | // Save flags | ||
1293 | int temp; | ||
1294 | GET_FLAGS( temp ); | ||
1295 | if ( result_ == 6 ) | ||
1296 | temp |= b10; // BRK sets B bit | ||
1297 | sp = SP( -3 ); | ||
1298 | WRITE_STACK( sp, temp ); | ||
1299 | |||
1300 | // Update I flag in externally-visible flags | ||
1301 | flags &= ~d08; | ||
1302 | cpu->r.flags = (flags |= i04); | ||
1303 | |||
1304 | // Update time | ||
1305 | int delta = s.base - cpu->end_time_; | ||
1306 | if ( delta >= 0 ) | ||
1307 | goto loop; | ||
1308 | s_time += delta; | ||
1309 | s.base = cpu->end_time_; | ||
1310 | goto loop; | ||
1311 | } | ||
1312 | |||
1313 | idle_done: | ||
1314 | s_time = 0; | ||
1315 | |||
1316 | out_of_time: | ||
1317 | pc--; | ||
1318 | |||
1319 | // Optional action that triggers interrupt or changes irq/end time | ||
1320 | #ifdef CPU_DONE | ||
1321 | { | ||
1322 | CPU_DONE( result_ ); | ||
1323 | if ( result_ >= 0 ) | ||
1324 | goto interrupt; | ||
1325 | if ( s_time < 0 ) | ||
1326 | goto loop; | ||
1327 | } | ||
1328 | #endif | ||
1329 | |||
1330 | // Flush cached state | ||
1331 | cpu->r.pc = pc; | ||
1332 | cpu->r.sp = GET_SP(); | ||
1333 | cpu->r.a = a; | ||
1334 | cpu->r.x = x; | ||
1335 | cpu->r.y = y; | ||
1336 | |||
1337 | int temp; | ||
1338 | GET_FLAGS( temp ); | ||
1339 | cpu->r.flags = temp; | ||
1340 | |||
1341 | cpu->cpu_state_.base = s.base; | ||
1342 | cpu->cpu_state_.time = s_time; | ||
1343 | cpu->cpu_state = &cpu->cpu_state_; | ||
1344 | } | ||