comparison src/console/Ay_Cpu.cxx @ 316:fb513e10174e trunk

[svn] - merge libconsole-blargg into mainline libconsole: + obsoletes plugins-ugly:sapplug
author nenolod
date Thu, 30 Nov 2006 19:54:33 -0800
parents
children 986f098da058
comparison
equal deleted inserted replaced
315:2294f3a6f136 316:fb513e10174e
1 // Game_Music_Emu 0.5.1. http://www.slack.net/~ant/
2
3 // Last validated with zexall 2006.11.21 5:26 PM
4 // Doesn't implement interrupts or the R register, though both would be
5 // easy to support.
6
7 #include "Ay_Cpu.h"
8
9 #include "blargg_endian.h"
10 #include <string.h>
11
12 //#include "z80_cpu_log.h"
13
14 /* Copyright (C) 2006 Shay Green. This module is free software; you
15 can redistribute it and/or modify it under the terms of the GNU Lesser
16 General Public License as published by the Free Software Foundation; either
17 version 2.1 of the License, or (at your option) any later version. This
18 module is distributed in the hope that it will be useful, but WITHOUT ANY
19 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
21 details. You should have received a copy of the GNU Lesser General Public
22 License along with this module; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
24
25 #define SYNC_TIME() (void) (s.time = s_time)
26 #define RELOAD_TIME() (void) (s_time = s.time)
27
28 // Callbacks to emulator
29
30 #define CPU_OUT( cpu, addr, data, TIME ) \
31 ay_cpu_out( cpu, TIME, addr, data )
32
33 #define CPU_IN( cpu, addr, TIME ) \
34 ay_cpu_in( cpu, addr )
35
36 #include "blargg_source.h"
37
38 // flags, named with hex value for clarity
39 int const S80 = 0x80;
40 int const Z40 = 0x40;
41 int const F20 = 0x20;
42 int const H10 = 0x10;
43 int const F08 = 0x08;
44 int const V04 = 0x04;
45 int const P04 = 0x04;
46 int const N02 = 0x02;
47 int const C01 = 0x01;
48
49 #define SZ28P( n ) szpc [n]
50 #define SZ28PC( n ) szpc [n]
51 #define SZ28C( n ) (szpc [n] & ~P04)
52 #define SZ28( n ) SZ28C( n )
53
54 #define SET_R( n ) (void) (r.r = n)
55 #define GET_R() (r.r)
56
57 Ay_Cpu::Ay_Cpu()
58 {
59 state = &state_;
60 for ( int i = 0x100; --i >= 0; )
61 {
62 int even = 1;
63 for ( int p = i; p; p >>= 1 )
64 even ^= p;
65 int n = (i & (S80 | F20 | F08)) | ((even & 1) * P04);
66 szpc [i] = n;
67 szpc [i + 0x100] = n | C01;
68 }
69 szpc [0x000] |= Z40;
70 szpc [0x100] |= Z40;
71 }
72
73 void Ay_Cpu::reset( void* m )
74 {
75 mem = (uint8_t*) m;
76
77 check( state == &state_ );
78 state = &state_;
79 state_.time = 0;
80 state_.base = 0;
81 end_time_ = 0;
82
83 memset( &r, 0, sizeof r );
84 }
85
86 #define TIME (s_time + s.base)
87 #define READ_PROG( addr ) (mem [addr])
88 #define INSTR( offset ) READ_PROG( pc + (offset) )
89 #define GET_ADDR() GET_LE16( &READ_PROG( pc ) )
90 #define READ( addr ) READ_PROG( addr )
91 #define WRITE( addr, data ) (void) (READ_PROG( addr ) = data)
92 #define READ_WORD( addr ) GET_LE16( &READ_PROG( addr ) )
93 #define WRITE_WORD( addr, data ) SET_LE16( &READ_PROG( addr ), data )
94 #define IN( addr ) CPU_IN( this, addr, TIME )
95 #define OUT( addr, data ) CPU_OUT( this, addr, data, TIME )
96
97 #if BLARGG_BIG_ENDIAN
98 #define R8( n, offset ) ((r8_ - offset) [n])
99 #elif BLARGG_LITTLE_ENDIAN
100 #define R8( n, offset ) ((r8_ - offset) [(n) ^ 1])
101 #else
102 #error "Byte order of CPU must be known"
103 #endif
104
105 //#define R16( n, shift, offset ) (r16_ [((n) >> shift) - (offset >> shift)])
106
107 // help compiler see that it can just adjust stack offset, saving an extra instruction
108 #define R16( n, shift, offset ) \
109 (*(uint16_t*) ((char*) r16_ - (offset >> (shift - 1)) + ((n) >> (shift - 1))))
110
111 #define CASE5( a, b, c, d, e ) case 0x##a:case 0x##b:case 0x##c:case 0x##d:case 0x##e
112 #define CASE6( a, b, c, d, e, f ) CASE5( a, b, c, d, e ): case 0x##f
113 #define CASE7( a, b, c, d, e, f, g ) CASE6( a, b, c, d, e, f ): case 0x##g
114 #define CASE8( a, b, c, d, e, f, g, h ) CASE7( a, b, c, d, e, f, g ): case 0x##h
115
116 // high four bits are $ED time - 8, low four bits are $DD/$FD time - 8
117 static byte const ed_dd_timing [0x100] = {
118 //0 1 2 3 4 5 6 7 8 9 A B C D E F
119 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
120 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
121 0x00,0x06,0x0C,0x02,0x00,0x00,0x03,0x00,0x00,0x07,0x0C,0x02,0x00,0x00,0x03,0x00,
122 0x00,0x00,0x00,0x00,0x0F,0x0F,0x0B,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
123 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,
124 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,
125 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0,
126 0x4B,0x4B,0x7B,0xCB,0x0B,0x6B,0x00,0x0B,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x00,
127 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,
128 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,
129 0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00,
130 0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00,0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00,
131 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,
132 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
133 0x00,0x06,0x00,0x0F,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
134 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,
135 };
136
137 // even on x86, using short and unsigned char was slower
138 typedef int fint16;
139 typedef unsigned fuint16;
140 typedef unsigned fuint8;
141
142 bool Ay_Cpu::run( cpu_time_t end_time )
143 {
144 set_end_time( end_time );
145 state_t s = this->state_;
146 this->state = &s;
147 bool warning = false;
148
149 typedef BOOST::int8_t int8_t;
150
151 union {
152 regs_t rg;
153 pairs_t rp;
154 uint8_t r8_ [8]; // indexed
155 uint16_t r16_ [4];
156 };
157 rg = this->r.b;
158
159 cpu_time_t s_time = s.time;
160 uint8_t* const mem = this->mem; // cache
161 fuint16 pc = r.pc;
162 fuint16 sp = r.sp;
163 fuint16 ix = r.ix; // TODO: keep in memory for direct access?
164 fuint16 iy = r.iy;
165 int flags = r.b.flags;
166
167 goto loop;
168 jr_not_taken:
169 s_time -= 5;
170 goto loop;
171 call_not_taken:
172 s_time -= 7;
173 jp_not_taken:
174 pc += 2;
175 loop:
176
177 check( (unsigned long) pc < 0x10000 );
178 check( (unsigned long) sp < 0x10000 );
179 check( (unsigned) flags < 0x100 );
180 check( (unsigned) ix < 0x10000 );
181 check( (unsigned) iy < 0x10000 );
182
183 fuint8 opcode;
184 opcode = READ_PROG( pc );
185 pc++;
186
187 static byte const base_timing [0x100] = {
188 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
189 4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4, // 0
190 13,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4, // 1
191 12,10,16, 6, 4, 4, 7, 4,12,11,16, 6, 4, 4, 7, 4, // 2
192 12,10,13, 6,11,11,10, 4,12,11,13, 6, 4, 4, 7, 4, // 3
193 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 4
194 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 5
195 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 6
196 7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4, // 7
197 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 8
198 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 9
199 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // A
200 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // B
201 11,10,10,10,17,11, 7,11,11,10,10, 8,17,17, 7,11, // C
202 11,10,10,11,17,11, 7,11,11, 4,10,11,17, 8, 7,11, // D
203 11,10,10,19,17,11, 7,11,11, 4,10, 4,17, 8, 7,11, // E
204 11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F
205 };
206
207 fuint16 data;
208 data = base_timing [opcode];
209 if ( (s_time += data) >= 0 )
210 goto possibly_out_of_time;
211 almost_out_of_time:
212
213 data = READ_PROG( pc );
214
215 #ifdef Z80_CPU_LOG_H
216 //log_opcode( opcode, READ_PROG( pc ) );
217 z80_log_regs( rg.a, rp.bc, rp.de, rp.hl, sp, ix, iy );
218 z80_cpu_log( "new", pc - 1, opcode, READ_PROG( pc ),
219 READ_PROG( pc + 1 ), READ_PROG( pc + 2 ) );
220 #endif
221
222 switch ( opcode )
223 {
224 possibly_out_of_time:
225 if ( s_time < (int) data )
226 goto almost_out_of_time;
227 s_time -= data;
228 goto out_of_time;
229
230 // Common
231
232 case 0x00: // NOP
233 CASE7( 40, 49, 52, 5B, 64, 6D, 7F ): // LD B,B etc.
234 goto loop;
235
236 case 0x08:{// EX AF,AF'
237 int temp = r.alt.b.a;
238 r.alt.b.a = rg.a;
239 rg.a = temp;
240
241 temp = r.alt.b.flags;
242 r.alt.b.flags = flags;
243 flags = temp;
244 goto loop;
245 }
246
247 case 0xD3: // OUT (imm),A
248 pc++;
249 OUT( data + rg.a * 0x100, rg.a );
250 goto loop;
251
252 case 0x2E: // LD L,imm
253 pc++;
254 rg.l = data;
255 goto loop;
256
257 case 0x3E: // LD A,imm
258 pc++;
259 rg.a = data;
260 goto loop;
261
262 case 0x3A:{// LD A,(addr)
263 fuint16 addr = GET_ADDR();
264 pc += 2;
265 rg.a = READ( addr );
266 goto loop;
267 }
268
269 // Conditional
270
271 #define ZERO (flags & Z40)
272 #define CARRY (flags & C01)
273 #define EVEN (flags & P04)
274 #define MINUS (flags & S80)
275
276 // JR
277 #define JR( cond ) {\
278 int disp = (BOOST::int8_t) data;\
279 pc++;\
280 if ( !(cond) )\
281 goto jr_not_taken;\
282 pc += disp;\
283 goto loop;\
284 }
285
286 case 0x20: JR( !ZERO ) // JR NZ,disp
287 case 0x28: JR( ZERO ) // JR Z,disp
288 case 0x30: JR( !CARRY ) // JR NC,disp
289 case 0x38: JR( CARRY ) // JR C,disp
290 case 0x18: JR( true ) // JR disp
291
292 case 0x10:{// DJNZ disp
293 int temp = rg.b - 1;
294 rg.b = temp;
295 JR( temp )
296 }
297
298 // JP
299 #define JP( cond ) if ( !(cond) ) goto jp_not_taken; pc = GET_ADDR(); goto loop;
300
301 case 0xC2: JP( !ZERO ) // JP NZ,addr
302 case 0xCA: JP( ZERO ) // JP Z,addr
303 case 0xD2: JP( !CARRY ) // JP NC,addr
304 case 0xDA: JP( CARRY ) // JP C,addr
305 case 0xE2: JP( !EVEN ) // JP PO,addr
306 case 0xEA: JP( EVEN ) // JP PE,addr
307 case 0xF2: JP( !MINUS ) // JP P,addr
308 case 0xFA: JP( MINUS ) // JP M,addr
309
310 case 0xC3: // JP addr
311 pc = GET_ADDR();
312 goto loop;
313
314 case 0xE9: // JP HL
315 pc = rp.hl;
316 goto loop;
317
318 // RET
319 #define RET( cond ) if ( cond ) goto ret_taken; s_time -= 6; goto loop;
320
321 case 0xC0: RET( !ZERO ) // RET NZ
322 case 0xC8: RET( ZERO ) // RET Z
323 case 0xD0: RET( !CARRY ) // RET NC
324 case 0xD8: RET( CARRY ) // RET C
325 case 0xE0: RET( !EVEN ) // RET PO
326 case 0xE8: RET( EVEN ) // RET PE
327 case 0xF0: RET( !MINUS ) // RET P
328 case 0xF8: RET( MINUS ) // RET M
329
330 case 0xC9: // RET
331 ret_taken:
332 pc = READ_WORD( sp );
333 sp = uint16_t (sp + 2);
334 goto loop;
335
336 // CALL
337 #define CALL( cond ) if ( cond ) goto call_taken; goto call_not_taken;
338
339 case 0xC4: CALL( !ZERO ) // CALL NZ,addr
340 case 0xCC: CALL( ZERO ) // CALL Z,addr
341 case 0xD4: CALL( !CARRY ) // CALL NC,addr
342 case 0xDC: CALL( CARRY ) // CALL C,addr
343 case 0xE4: CALL( !EVEN ) // CALL PO,addr
344 case 0xEC: CALL( EVEN ) // CALL PE,addr
345 case 0xF4: CALL( !MINUS ) // CALL P,addr
346 case 0xFC: CALL( MINUS ) // CALL M,addr
347
348 case 0xCD:{// CALL addr
349 call_taken:
350 fuint16 addr = pc + 2;
351 pc = GET_ADDR();
352 sp = uint16_t (sp - 2);
353 WRITE_WORD( sp, addr );
354 goto loop;
355 }
356
357 CASE8( C7, CF, D7, DF, E7, EF, F7, FF ): // RST
358 data = pc;
359 pc = opcode & 0x38;
360 goto push_data;
361
362 // PUSH/POP
363 case 0xF5: // PUSH AF
364 data = rg.a * 0x100u + flags;
365 goto push_data;
366
367 case 0xC5: // PUSH BC
368 case 0xD5: // PUSH DE
369 case 0xE5: // PUSH HL
370 data = R16( opcode, 4, 0xC5 );
371 push_data:
372 sp = uint16_t (sp - 2);
373 WRITE_WORD( sp, data );
374 goto loop;
375
376 case 0xF1: // POP AF
377 flags = READ( sp );
378 rg.a = READ( sp + 1 );
379 sp = uint16_t (sp + 2);
380 goto loop;
381
382 case 0xC1: // POP BC
383 case 0xD1: // POP DE
384 case 0xE1: // POP HL
385 R16( opcode, 4, 0xC1 ) = READ_WORD( sp );
386 sp = uint16_t (sp + 2);
387 goto loop;
388
389 // ADC/ADD/SBC/SUB
390 case 0x96: // SUB (HL)
391 case 0x86: // ADD (HL)
392 flags &= ~C01;
393 case 0x9E: // SBC (HL)
394 case 0x8E: // ADC (HL)
395 data = READ( rp.hl );
396 goto adc_data;
397
398 case 0xD6: // SUB A,imm
399 case 0xC6: // ADD imm
400 flags &= ~C01;
401 case 0xDE: // SBC A,imm
402 case 0xCE: // ADC imm
403 pc++;
404 goto adc_data;
405
406 CASE7( 90, 91, 92, 93, 94, 95, 97 ): // SUB r
407 CASE7( 80, 81, 82, 83, 84, 85, 87 ): // ADD r
408 flags &= ~C01;
409 CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // SBC r
410 CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // ADC r
411 data = R8( opcode & 7, 0 );
412 adc_data: {
413 int result = data + (flags & C01);
414 data ^= rg.a;
415 flags = opcode >> 3 & N02; // bit 4 is set in subtract opcodes
416 if ( flags )
417 result = -result;
418 result += rg.a;
419 data ^= result;
420 flags |=(data & H10) |
421 ((data - -0x80) >> 6 & V04) |
422 SZ28C( result & 0x1FF );
423 rg.a = result;
424 goto loop;
425 }
426
427 // CP
428 case 0xBE: // CP (HL)
429 data = READ( rp.hl );
430 goto cp_data;
431
432 case 0xFE: // CP imm
433 pc++;
434 goto cp_data;
435
436 CASE7( B8, B9, BA, BB, BC, BD, BF ): // CP r
437 data = R8( opcode, 0xB8 );
438 cp_data: {
439 int result = rg.a - data;
440 flags = N02 | (data & (F20 | F08)) | (result >> 8 & C01);
441 data ^= rg.a;
442 flags |=(((result ^ rg.a) & data) >> 5 & V04) |
443 (((data & H10) ^ result) & (S80 | H10));
444 if ( (uint8_t) result )
445 goto loop;
446 flags |= Z40;
447 goto loop;
448 }
449
450 // ADD HL,rp
451
452 case 0x39: // ADD HL,SP
453 data = sp;
454 goto add_hl_data;
455
456 case 0x09: // ADD HL,BC
457 case 0x19: // ADD HL,DE
458 case 0x29: // ADD HL,HL
459 data = R16( opcode, 4, 0x09 );
460 add_hl_data: {
461 blargg_ulong sum = rp.hl + data;
462 data ^= rp.hl;
463 rp.hl = sum;
464 flags = (flags & (S80 | Z40 | V04)) |
465 (sum >> 16) |
466 (sum >> 8 & (F20 | F08)) |
467 ((data ^ sum) >> 8 & H10);
468 goto loop;
469 }
470
471 case 0x27:{// DAA
472 int a = rg.a;
473 if ( a > 0x99 )
474 flags |= C01;
475
476 int adjust = 0x60 & -(flags & C01);
477
478 if ( flags & H10 || (a & 0x0F) > 9 )
479 adjust |= 0x06;
480
481 if ( flags & N02 )
482 adjust = -adjust;
483 a += adjust;
484
485 flags = (flags & (C01 | N02)) |
486 ((rg.a ^ a) & H10) |
487 SZ28P( (uint8_t) a );
488 rg.a = a;
489 goto loop;
490 }
491 /*
492 case 0x27:{// DAA
493 // more optimized, but probably not worth the obscurity
494 int f = (rg.a + (0xFF - 0x99)) >> 8 | flags; // (a > 0x99 ? C01 : 0) | flags
495 int adjust = 0x60 & -(f & C01); // f & C01 ? 0x60 : 0
496
497 if ( (((rg.a + (0x0F - 9)) ^ rg.a) | f) & H10 ) // flags & H10 || (rg.a & 0x0F) > 9
498 adjust |= 0x06;
499
500 if ( f & N02 )
501 adjust = -adjust;
502 int a = rg.a + adjust;
503
504 flags = (f & (N02 | C01)) | ((rg.a ^ a) & H10) | SZ28P( (uint8_t) a );
505 rg.a = a;
506 goto loop;
507 }
508 */
509
510 // INC/DEC
511 case 0x34: // INC (HL)
512 data = READ( rp.hl ) + 1;
513 WRITE( rp.hl, data );
514 goto inc_set_flags;
515
516 CASE7( 04, 0C, 14, 1C, 24, 2C, 3C ): // INC r
517 data = ++R8( opcode >> 3, 0 );
518 inc_set_flags:
519 flags = (flags & C01) |
520 (((data & 0x0F) - 1) & H10) |
521 SZ28( (uint8_t) data );
522 if ( data != 0x80 )
523 goto loop;
524 flags |= V04;
525 goto loop;
526
527 case 0x35: // DEC (HL)
528 data = READ( rp.hl ) - 1;
529 WRITE( rp.hl, data );
530 goto dec_set_flags;
531
532 CASE7( 05, 0D, 15, 1D, 25, 2D, 3D ): // DEC r
533 data = --R8( opcode >> 3, 0 );
534 dec_set_flags:
535 flags = (flags & C01) | N02 |
536 (((data & 0x0F) + 1) & H10) |
537 SZ28( (uint8_t) data );
538 if ( data != 0x7F )
539 goto loop;
540 flags |= V04;
541 goto loop;
542
543 case 0x03: // INC BC
544 case 0x13: // INC DE
545 case 0x23: // INC HL
546 R16( opcode, 4, 0x03 )++;
547 goto loop;
548
549 case 0x33: // INC SP
550 sp = uint16_t (sp + 1);
551 goto loop;
552
553 case 0x0B: // DEC BC
554 case 0x1B: // DEC DE
555 case 0x2B: // DEC HL
556 R16( opcode, 4, 0x0B )--;
557 goto loop;
558
559 case 0x3B: // DEC SP
560 sp = uint16_t (sp - 1);
561 goto loop;
562
563 // AND
564 case 0xA6: // AND (HL)
565 data = READ( rp.hl );
566 goto and_data;
567
568 case 0xE6: // AND imm
569 pc++;
570 goto and_data;
571
572 CASE7( A0, A1, A2, A3, A4, A5, A7 ): // AND r
573 data = R8( opcode, 0xA0 );
574 and_data:
575 rg.a &= data;
576 flags = SZ28P( rg.a ) | H10;
577 goto loop;
578
579 // OR
580 case 0xB6: // OR (HL)
581 data = READ( rp.hl );
582 goto or_data;
583
584 case 0xF6: // OR imm
585 pc++;
586 goto or_data;
587
588 CASE7( B0, B1, B2, B3, B4, B5, B7 ): // OR r
589 data = R8( opcode, 0xB0 );
590 or_data:
591 rg.a |= data;
592 flags = SZ28P( rg.a );
593 goto loop;
594
595 // XOR
596 case 0xAE: // XOR (HL)
597 data = READ( rp.hl );
598 goto xor_data;
599
600 case 0xEE: // XOR imm
601 pc++;
602 goto xor_data;
603
604 CASE7( A8, A9, AA, AB, AC, AD, AF ): // XOR r
605 data = R8( opcode, 0xA8 );
606 xor_data:
607 rg.a ^= data;
608 flags = SZ28P( rg.a );
609 goto loop;
610
611 // LD
612 CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (HL),r
613 WRITE( rp.hl, R8( opcode, 0x70 ) );
614 goto loop;
615
616 CASE6( 41, 42, 43, 44, 45, 47 ): // LD B,r
617 CASE6( 48, 4A, 4B, 4C, 4D, 4F ): // LD C,r
618 CASE6( 50, 51, 53, 54, 55, 57 ): // LD D,r
619 CASE6( 58, 59, 5A, 5C, 5D, 5F ): // LD E,r
620 CASE6( 60, 61, 62, 63, 65, 67 ): // LD H,r
621 CASE6( 68, 69, 6A, 6B, 6C, 6F ): // LD L,r
622 CASE6( 78, 79, 7A, 7B, 7C, 7D ): // LD A,r
623 R8( opcode >> 3 & 7, 0 ) = R8( opcode & 7, 0 );
624 goto loop;
625
626 CASE5( 06, 0E, 16, 1E, 26 ): // LD r,imm
627 R8( opcode >> 3, 0 ) = data;
628 pc++;
629 goto loop;
630
631 case 0x36: // LD (HL),imm
632 pc++;
633 WRITE( rp.hl, data );
634 goto loop;
635
636 CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(HL)
637 R8( opcode >> 3, 8 ) = READ( rp.hl );
638 goto loop;
639
640 case 0x01: // LD rp,imm
641 case 0x11:
642 case 0x21:
643 R16( opcode, 4, 0x01 ) = GET_ADDR();
644 pc += 2;
645 goto loop;
646
647 case 0x31: // LD sp,imm
648 sp = GET_ADDR();
649 pc += 2;
650 goto loop;
651
652 case 0x2A:{// LD HL,(addr)
653 fuint16 addr = GET_ADDR();
654 pc += 2;
655 rp.hl = READ_WORD( addr );
656 goto loop;
657 }
658
659 case 0x32:{// LD (addr),A
660 fuint16 addr = GET_ADDR();
661 pc += 2;
662 WRITE( addr, rg.a );
663 goto loop;
664 }
665
666 case 0x22:{// LD (addr),HL
667 fuint16 addr = GET_ADDR();
668 pc += 2;
669 WRITE_WORD( addr, rp.hl );
670 goto loop;
671 }
672
673 case 0x02: // LD (BC),A
674 case 0x12: // LD (DE),A
675 WRITE( R16( opcode, 4, 0x02 ), rg.a );
676 goto loop;
677
678 case 0x0A: // LD A,(BC)
679 case 0x1A: // LD A,(DE)
680 rg.a = READ( R16( opcode, 4, 0x0A ) );
681 goto loop;
682
683 case 0xF9: // LD SP,HL
684 sp = rp.hl;
685 goto loop;
686
687 // Rotate
688
689 case 0x07:{// RLCA
690 fuint16 temp = rg.a;
691 temp = (temp << 1) | (temp >> 7);
692 flags = (flags & (S80 | Z40 | P04)) |
693 (temp & (F20 | F08 | C01));
694 rg.a = temp;
695 goto loop;
696 }
697
698 case 0x0F:{// RRCA
699 fuint16 temp = rg.a;
700 flags = (flags & (S80 | Z40 | P04)) |
701 (temp & C01);
702 temp = (temp << 7) | (temp >> 1);
703 flags |= temp & (F20 | F08);
704 rg.a = temp;
705 goto loop;
706 }
707
708 case 0x17:{// RLA
709 blargg_ulong temp = (rg.a << 1) | (flags & C01);
710 flags = (flags & (S80 | Z40 | P04)) |
711 (temp & (F20 | F08)) |
712 (temp >> 8);
713 rg.a = temp;
714 goto loop;
715 }
716
717 case 0x1F:{// RRA
718 fuint16 temp = (flags << 7) | (rg.a >> 1);
719 flags = (flags & (S80 | Z40 | P04)) |
720 (temp & (F20 | F08)) |
721 (rg.a & C01);
722 rg.a = temp;
723 goto loop;
724 }
725
726 // Misc
727 case 0x2F:{// CPL
728 fuint16 temp = ~rg.a;
729 flags = (flags & (S80 | Z40 | P04 | C01)) |
730 (temp & (F20 | F08)) |
731 (H10 | N02);
732 rg.a = temp;
733 goto loop;
734 }
735
736 case 0x3F:{// CCF
737 flags = ((flags & (S80 | Z40 | P04 | C01)) ^ C01) |
738 (flags << 4 & H10) |
739 (rg.a & (F20 | F08));
740 goto loop;
741 }
742
743 case 0x37: // SCF
744 flags = (flags & (S80 | Z40 | P04)) | C01 |
745 (rg.a & (F20 | F08));
746 goto loop;
747
748 case 0xDB: // IN A,(imm)
749 pc++;
750 rg.a = IN( data + rg.a * 0x100 );
751 goto loop;
752
753 case 0xE3:{// EX (SP),HL
754 fuint16 temp = READ_WORD( sp );
755 WRITE_WORD( sp, rp.hl );
756 rp.hl = temp;
757 goto loop;
758 }
759
760 case 0xEB:{// EX DE,HL
761 fuint16 temp = rp.hl;
762 rp.hl = rp.de;
763 rp.de = temp;
764 goto loop;
765 }
766
767 case 0xD9:{// EXX DE,HL
768 fuint16 temp = r.alt.w.bc;
769 r.alt.w.bc = rp.bc;
770 rp.bc = temp;
771
772 temp = r.alt.w.de;
773 r.alt.w.de = rp.de;
774 rp.de = temp;
775
776 temp = r.alt.w.hl;
777 r.alt.w.hl = rp.hl;
778 rp.hl = temp;
779 goto loop;
780 }
781
782 case 0xF3: // DI
783 r.iff1 = 0;
784 r.iff2 = 0;
785 goto loop;
786
787 case 0xFB: // EI
788 r.iff1 = 1;
789 r.iff2 = 1;
790 // TODO: delayed effect
791 goto loop;
792
793 case 0x76: // HALT
794 goto halt;
795
796 //////////////////////////////////////// CB prefix
797 {
798 case 0xCB:
799 unsigned data2;
800 data2 = INSTR( 1 );
801 pc++;
802 switch ( data )
803 {
804
805 // Rotate left
806
807 #define RLC( read, write ) {\
808 fuint8 result = read;\
809 result = uint8_t (result << 1) | (result >> 7);\
810 flags = SZ28P( result ) | (result & C01);\
811 write;\
812 goto loop;\
813 }
814
815 case 0x06: // RLC (HL)
816 s_time += 7;
817 data = rp.hl;
818 rlc_data_addr:
819 RLC( READ( data ), WRITE( data, result ) )
820
821 CASE7( 00, 01, 02, 03, 04, 05, 07 ):{// RLC r
822 uint8_t& reg = R8( data, 0 );
823 RLC( reg, reg = result )
824 }
825
826 #define RL( read, write ) {\
827 fuint16 result = (read << 1) | (flags & C01);\
828 flags = SZ28PC( result );\
829 write;\
830 goto loop;\
831 }
832
833 case 0x16: // RL (HL)
834 s_time += 7;
835 data = rp.hl;
836 rl_data_addr:
837 RL( READ( data ), WRITE( data, result ) )
838
839 CASE7( 10, 11, 12, 13, 14, 15, 17 ):{// RL r
840 uint8_t& reg = R8( data, 0x10 );
841 RL( reg, reg = result )
842 }
843
844 #define SLA( read, add, write ) {\
845 fuint16 result = (read << 1) | add;\
846 flags = SZ28PC( result );\
847 write;\
848 goto loop;\
849 }
850
851 case 0x26: // SLA (HL)
852 s_time += 7;
853 data = rp.hl;
854 sla_data_addr:
855 SLA( READ( data ), 0, WRITE( data, result ) )
856
857 CASE7( 20, 21, 22, 23, 24, 25, 27 ):{// SLA r
858 uint8_t& reg = R8( data, 0x20 );
859 SLA( reg, 0, reg = result )
860 }
861
862 case 0x36: // SLL (HL)
863 s_time += 7;
864 data = rp.hl;
865 sll_data_addr:
866 SLA( READ( data ), 1, WRITE( data, result ) )
867
868 CASE7( 30, 31, 32, 33, 34, 35, 37 ):{// SLL r
869 uint8_t& reg = R8( data, 0x30 );
870 SLA( reg, 1, reg = result )
871 }
872
873 // Rotate right
874
875 #define RRC( read, write ) {\
876 fuint8 result = read;\
877 flags = result & C01;\
878 result = uint8_t (result << 7) | (result >> 1);\
879 flags |= SZ28P( result );\
880 write;\
881 goto loop;\
882 }
883
884 case 0x0E: // RRC (HL)
885 s_time += 7;
886 data = rp.hl;
887 rrc_data_addr:
888 RRC( READ( data ), WRITE( data, result ) )
889
890 CASE7( 08, 09, 0A, 0B, 0C, 0D, 0F ):{// RRC r
891 uint8_t& reg = R8( data, 0x08 );
892 RRC( reg, reg = result )
893 }
894
895 #define RR( read, write ) {\
896 fuint8 result = read;\
897 fuint8 temp = result & C01;\
898 result = uint8_t (flags << 7) | (result >> 1);\
899 flags = SZ28P( result ) | temp;\
900 write;\
901 goto loop;\
902 }
903
904 case 0x1E: // RR (HL)
905 s_time += 7;
906 data = rp.hl;
907 rr_data_addr:
908 RR( READ( data ), WRITE( data, result ) )
909
910 CASE7( 18, 19, 1A, 1B, 1C, 1D, 1F ):{// RR r
911 uint8_t& reg = R8( data, 0x18 );
912 RR( reg, reg = result )
913 }
914
915 #define SRA( read, write ) {\
916 fuint8 result = read;\
917 flags = result & C01;\
918 result = (result & 0x80) | (result >> 1);\
919 flags |= SZ28P( result );\
920 write;\
921 goto loop;\
922 }
923
924 case 0x2E: // SRA (HL)
925 data = rp.hl;
926 s_time += 7;
927 sra_data_addr:
928 SRA( READ( data ), WRITE( data, result ) )
929
930 CASE7( 28, 29, 2A, 2B, 2C, 2D, 2F ):{// SRA r
931 uint8_t& reg = R8( data, 0x28 );
932 SRA( reg, reg = result )
933 }
934
935 #define SRL( read, write ) {\
936 fuint8 result = read;\
937 flags = result & C01;\
938 result >>= 1;\
939 flags |= SZ28P( result );\
940 write;\
941 goto loop;\
942 }
943
944 case 0x3E: // SRL (HL)
945 s_time += 7;
946 data = rp.hl;
947 srl_data_addr:
948 SRL( READ( data ), WRITE( data, result ) )
949
950 CASE7( 38, 39, 3A, 3B, 3C, 3D, 3F ):{// SRL r
951 uint8_t& reg = R8( data, 0x38 );
952 SRL( reg, reg = result )
953 }
954
955 // BIT
956 {
957 unsigned temp;
958 CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ): // BIT b,(HL)
959 s_time += 4;
960 temp = READ( rp.hl );
961 flags &= C01;
962 goto bit_temp;
963 CASE7( 40, 41, 42, 43, 44, 45, 47 ): // BIT 0,r
964 CASE7( 48, 49, 4A, 4B, 4C, 4D, 4F ): // BIT 1,r
965 CASE7( 50, 51, 52, 53, 54, 55, 57 ): // BIT 2,r
966 CASE7( 58, 59, 5A, 5B, 5C, 5D, 5F ): // BIT 3,r
967 CASE7( 60, 61, 62, 63, 64, 65, 67 ): // BIT 4,r
968 CASE7( 68, 69, 6A, 6B, 6C, 6D, 6F ): // BIT 5,r
969 CASE7( 70, 71, 72, 73, 74, 75, 77 ): // BIT 6,r
970 CASE7( 78, 79, 7A, 7B, 7C, 7D, 7F ): // BIT 7,r
971 temp = R8( data & 7, 0 );
972 flags = (flags & C01) | (temp & (F20 | F08));
973 bit_temp:
974 int masked = temp & 1 << (data >> 3 & 7);
975 flags |=(masked & S80) | H10 |
976 ((masked - 1) >> 8 & (Z40 | P04));
977 goto loop;
978 }
979
980 // SET/RES
981 CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(HL)
982 CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(HL)
983 s_time += 7;
984 int temp = READ( rp.hl );
985 int bit = 1 << (data >> 3 & 7);
986 temp |= bit; // SET
987 if ( !(data & 0x40) )
988 temp ^= bit; // RES
989 WRITE( rp.hl, temp );
990 goto loop;
991 }
992
993 CASE7( C0, C1, C2, C3, C4, C5, C7 ): // SET 0,r
994 CASE7( C8, C9, CA, CB, CC, CD, CF ): // SET 1,r
995 CASE7( D0, D1, D2, D3, D4, D5, D7 ): // SET 2,r
996 CASE7( D8, D9, DA, DB, DC, DD, DF ): // SET 3,r
997 CASE7( E0, E1, E2, E3, E4, E5, E7 ): // SET 4,r
998 CASE7( E8, E9, EA, EB, EC, ED, EF ): // SET 5,r
999 CASE7( F0, F1, F2, F3, F4, F5, F7 ): // SET 6,r
1000 CASE7( F8, F9, FA, FB, FC, FD, FF ): // SET 7,r
1001 R8( data & 7, 0 ) |= 1 << (data >> 3 & 7);
1002 goto loop;
1003
1004 CASE7( 80, 81, 82, 83, 84, 85, 87 ): // RES 0,r
1005 CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // RES 1,r
1006 CASE7( 90, 91, 92, 93, 94, 95, 97 ): // RES 2,r
1007 CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // RES 3,r
1008 CASE7( A0, A1, A2, A3, A4, A5, A7 ): // RES 4,r
1009 CASE7( A8, A9, AA, AB, AC, AD, AF ): // RES 5,r
1010 CASE7( B0, B1, B2, B3, B4, B5, B7 ): // RES 6,r
1011 CASE7( B8, B9, BA, BB, BC, BD, BF ): // RES 7,r
1012 R8( data & 7, 0 ) &= ~(1 << (data >> 3 & 7));
1013 goto loop;
1014 }
1015 assert( false );
1016 }
1017
1018 //////////////////////////////////////// ED prefix
1019 {
1020 case 0xED:
1021 pc++;
1022 s_time += ed_dd_timing [data] >> 4;
1023 switch ( data )
1024 {
1025 {
1026 blargg_ulong temp;
1027 case 0x72: // SBC HL,SP
1028 case 0x7A: // ADC HL,SP
1029 temp = sp;
1030 if ( 0 )
1031 case 0x42: // SBC HL,BC
1032 case 0x52: // SBC HL,DE
1033 case 0x62: // SBC HL,HL
1034 case 0x4A: // ADC HL,BC
1035 case 0x5A: // ADC HL,DE
1036 case 0x6A: // ADC HL,HL
1037 temp = R16( data >> 3 & 6, 1, 0 );
1038 blargg_ulong sum = temp + (flags & C01);
1039 flags = ~data >> 2 & N02;
1040 if ( flags )
1041 sum = -sum;
1042 sum += rp.hl;
1043 temp ^= rp.hl;
1044 temp ^= sum;
1045 flags |=(sum >> 16 & C01) |
1046 (temp >> 8 & H10) |
1047 (sum >> 8 & (S80 | F20 | F08)) |
1048 ((temp - -0x8000) >> 14 & V04);
1049 rp.hl = sum;
1050 if ( (uint16_t) sum )
1051 goto loop;
1052 flags |= Z40;
1053 goto loop;
1054 }
1055
1056 CASE8( 40, 48, 50, 58, 60, 68, 70, 78 ):{// IN r,(C)
1057 int temp = IN( rp.bc );
1058 R8( data >> 3, 8 ) = temp;
1059 flags = (flags & C01) | SZ28P( temp );
1060 goto loop;
1061 }
1062
1063 case 0x71: // OUT (C),0
1064 rg.flags = 0;
1065 CASE7( 41, 49, 51, 59, 61, 69, 79 ): // OUT (C),r
1066 OUT( rp.bc, R8( data >> 3, 8 ) );
1067 goto loop;
1068
1069 {
1070 unsigned temp;
1071 case 0x73: // LD (ADDR),SP
1072 temp = sp;
1073 if ( 0 )
1074 case 0x43: // LD (ADDR),BC
1075 case 0x53: // LD (ADDR),DE
1076 temp = R16( data, 4, 0x43 );
1077 fuint16 addr = GET_ADDR();
1078 pc += 2;
1079 WRITE_WORD( addr, temp );
1080 goto loop;
1081 }
1082
1083 case 0x4B: // LD BC,(ADDR)
1084 case 0x5B:{// LD DE,(ADDR)
1085 fuint16 addr = GET_ADDR();
1086 pc += 2;
1087 R16( data, 4, 0x4B ) = READ_WORD( addr );
1088 goto loop;
1089 }
1090
1091 case 0x7B:{// LD SP,(ADDR)
1092 fuint16 addr = GET_ADDR();
1093 pc += 2;
1094 sp = READ_WORD( addr );
1095 goto loop;
1096 }
1097
1098 case 0x67:{// RRD
1099 fuint8 temp = READ( rp.hl );
1100 WRITE( rp.hl, (rg.a << 4) | (temp >> 4) );
1101 temp = (rg.a & 0xF0) | (temp & 0x0F);
1102 flags = (flags & C01) | SZ28P( temp );
1103 rg.a = temp;
1104 goto loop;
1105 }
1106
1107 case 0x6F:{// RLD
1108 fuint8 temp = READ( rp.hl );
1109 WRITE( rp.hl, (temp << 4) | (rg.a & 0x0F) );
1110 temp = (rg.a & 0xF0) | (temp >> 4);
1111 flags = (flags & C01) | SZ28P( temp );
1112 rg.a = temp;
1113 goto loop;
1114 }
1115
1116 CASE8( 44, 4C, 54, 5C, 64, 6C, 74, 7C ): // NEG
1117 opcode = 0x10; // flag to do SBC instead of ADC
1118 flags &= ~C01;
1119 data = rg.a;
1120 rg.a = 0;
1121 goto adc_data;
1122
1123 {
1124 int inc;
1125 case 0xA9: // CPD
1126 case 0xB9: // CPDR
1127 inc = -1;
1128 if ( 0 )
1129 case 0xA1: // CPI
1130 case 0xB1: // CPIR
1131 inc = +1;
1132 fuint16 addr = rp.hl;
1133 rp.hl = addr + inc;
1134 int temp = READ( addr );
1135
1136 int result = rg.a - temp;
1137 flags = (flags & C01) | N02 |
1138 ((((temp ^ rg.a) & H10) ^ result) & (S80 | H10));
1139
1140 if ( !(uint8_t) result ) flags |= Z40;
1141 result -= (flags & H10) >> 4;
1142 flags |= result & F08;
1143 flags |= result << 4 & F20;
1144 if ( !--rp.bc )
1145 goto loop;
1146
1147 flags |= V04;
1148 if ( flags & Z40 || data < 0xB0 )
1149 goto loop;
1150
1151 pc -= 2;
1152 s_time += 5;
1153 goto loop;
1154 }
1155
1156 {
1157 int inc;
1158 case 0xA8: // LDD
1159 case 0xB8: // LDDR
1160 inc = -1;
1161 if ( 0 )
1162 case 0xA0: // LDI
1163 case 0xB0: // LDIR
1164 inc = +1;
1165 fuint16 addr = rp.hl;
1166 rp.hl = addr + inc;
1167 int temp = READ( addr );
1168
1169 addr = rp.de;
1170 rp.de = addr + inc;
1171 WRITE( addr, temp );
1172
1173 temp += rg.a;
1174 flags = (flags & (S80 | Z40 | C01)) |
1175 (temp & F08) | (temp << 4 & F20);
1176 if ( !--rp.bc )
1177 goto loop;
1178
1179 flags |= V04;
1180 if ( data < 0xB0 )
1181 goto loop;
1182
1183 pc -= 2;
1184 s_time += 5;
1185 goto loop;
1186 }
1187
1188 {
1189 int inc;
1190 case 0xAB: // OUTD
1191 case 0xBB: // OTDR
1192 inc = -1;
1193 if ( 0 )
1194 case 0xA3: // OUTI
1195 case 0xB3: // OTIR
1196 inc = +1;
1197 fuint16 addr = rp.hl;
1198 rp.hl = addr + inc;
1199 int temp = READ( addr );
1200
1201 int b = --rg.b;
1202 flags = (temp >> 6 & N02) | SZ28( b );
1203 if ( b && data >= 0xB0 )
1204 {
1205 pc -= 2;
1206 s_time += 5;
1207 }
1208
1209 OUT( rp.bc, temp );
1210 goto loop;
1211 }
1212
1213 {
1214 int inc;
1215 case 0xAA: // IND
1216 case 0xBA: // INDR
1217 inc = -1;
1218 if ( 0 )
1219 case 0xA2: // INI
1220 case 0xB2: // INIR
1221 inc = +1;
1222
1223 fuint16 addr = rp.hl;
1224 rp.hl = addr + inc;
1225
1226 int temp = IN( rp.bc );
1227
1228 int b = --rg.b;
1229 flags = (temp >> 6 & N02) | SZ28( b );
1230 if ( b && data >= 0xB0 )
1231 {
1232 pc -= 2;
1233 s_time += 5;
1234 }
1235
1236 WRITE( addr, temp );
1237 goto loop;
1238 }
1239
1240 case 0x47: // LD I,A
1241 r.i = rg.a;
1242 goto loop;
1243
1244 case 0x4F: // LD R,A
1245 SET_R( rg.a );
1246 dprintf( "LD R,A not supported\n" );
1247 warning = true;
1248 goto loop;
1249
1250 case 0x57: // LD A,I
1251 rg.a = r.i;
1252 goto ld_ai_common;
1253
1254 case 0x5F: // LD A,R
1255 rg.a = GET_R();
1256 dprintf( "LD A,R not supported\n" );
1257 warning = true;
1258 ld_ai_common:
1259 flags = (flags & C01) | SZ28( rg.a ) | (r.iff2 << 2 & V04);
1260 goto loop;
1261
1262 CASE8( 45, 4D, 55, 5D, 65, 6D, 75, 7D ): // RETI/RETN
1263 r.iff1 = r.iff2;
1264 goto ret_taken;
1265
1266 case 0x46: case 0x4E: case 0x66: case 0x6E: // IM 0
1267 r.im = 0;
1268 goto loop;
1269
1270 case 0x56: case 0x76: // IM 1
1271 r.im = 1;
1272 goto loop;
1273
1274 case 0x5E: case 0x7E: // IM 2
1275 r.im = 2;
1276 goto loop;
1277
1278 default:
1279 dprintf( "Opcode $ED $%02X not supported\n", data );
1280 warning = true;
1281 goto loop;
1282 }
1283 assert( false );
1284 }
1285
1286 //////////////////////////////////////// DD/FD prefix
1287 {
1288 fuint16 ixy;
1289 case 0xDD:
1290 ixy = ix;
1291 goto ix_prefix;
1292 case 0xFD:
1293 ixy = iy;
1294 ix_prefix:
1295 pc++;
1296 unsigned data2 = READ_PROG( pc );
1297 s_time += ed_dd_timing [data] & 0x0F;
1298 switch ( data )
1299 {
1300 #define SET_IXY( in ) if ( opcode == 0xDD ) ix = in; else iy = in;
1301
1302 // ADD/ADC/SUB/SBC
1303
1304 case 0x96: // SUB (IXY+disp)
1305 case 0x86: // ADD (IXY+disp)
1306 flags &= ~C01;
1307 case 0x9E: // SBC (IXY+disp)
1308 case 0x8E: // ADC (IXY+disp)
1309 pc++;
1310 opcode = data;
1311 data = READ( ixy + (int8_t) data2 );
1312 goto adc_data;
1313
1314 case 0x94: // SUB HXY
1315 case 0x84: // ADD HXY
1316 flags &= ~C01;
1317 case 0x9C: // SBC HXY
1318 case 0x8C: // ADC HXY
1319 opcode = data;
1320 data = ixy >> 8;
1321 goto adc_data;
1322
1323 case 0x95: // SUB LXY
1324 case 0x85: // ADD LXY
1325 flags &= ~C01;
1326 case 0x9D: // SBC LXY
1327 case 0x8D: // ADC LXY
1328 opcode = data;
1329 data = (uint8_t) ixy;
1330 goto adc_data;
1331
1332 {
1333 unsigned data2;
1334 case 0x39: // ADD IXY,SP
1335 data2 = sp;
1336 goto add_ixy_data;
1337
1338 case 0x29: // ADD IXY,HL
1339 data2 = ixy;
1340 goto add_ixy_data;
1341
1342 case 0x09: // ADD IXY,BC
1343 case 0x19: // ADD IXY,DE
1344 data2 = R16( data, 4, 0x09 );
1345 add_ixy_data: {
1346 blargg_ulong sum = ixy + data2;
1347 data2 ^= ixy;
1348 ixy = sum;
1349 flags = (flags & (S80 | Z40 | V04)) |
1350 (sum >> 16) |
1351 (sum >> 8 & (F20 | F08)) |
1352 ((data2 ^ sum) >> 8 & H10);
1353 goto set_ixy;
1354 }
1355 }
1356
1357 // AND
1358 case 0xA6: // AND (IXY+disp)
1359 pc++;
1360 data = READ( ixy + (int8_t) data2 );
1361 goto and_data;
1362
1363 case 0xA4: // AND HXY
1364 data = ixy >> 8;
1365 goto and_data;
1366
1367 case 0xA5: // AND LXY
1368 data = (uint8_t) ixy;
1369 goto and_data;
1370
1371 // OR
1372 case 0xB6: // OR (IXY+disp)
1373 pc++;
1374 data = READ( ixy + (int8_t) data2 );
1375 goto or_data;
1376
1377 case 0xB4: // OR HXY
1378 data = ixy >> 8;
1379 goto or_data;
1380
1381 case 0xB5: // OR LXY
1382 data = (uint8_t) ixy;
1383 goto or_data;
1384
1385 // XOR
1386 case 0xAE: // XOR (IXY+disp)
1387 pc++;
1388 data = READ( ixy + (int8_t) data2 );
1389 goto xor_data;
1390
1391 case 0xAC: // XOR HXY
1392 data = ixy >> 8;
1393 goto xor_data;
1394
1395 case 0xAD: // XOR LXY
1396 data = (uint8_t) ixy;
1397 goto xor_data;
1398
1399 // CP
1400 case 0xBE: // CP (IXY+disp)
1401 pc++;
1402 data = READ( ixy + (int8_t) data2 );
1403 goto cp_data;
1404
1405 case 0xBC: // CP HXY
1406 data = ixy >> 8;
1407 goto cp_data;
1408
1409 case 0xBD: // CP LXY
1410 data = (uint8_t) ixy;
1411 goto cp_data;
1412
1413 // LD
1414 CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (IXY+disp),r
1415 data = R8( data, 0x70 );
1416 if ( 0 )
1417 case 0x36: // LD (IXY+disp),imm
1418 pc++, data = READ_PROG( pc );
1419 pc++;
1420 WRITE( ixy + (int8_t) data2, data );
1421 goto loop;
1422
1423 CASE5( 44, 4C, 54, 5C, 7C ): // LD r,HXY
1424 R8( data >> 3, 8 ) = ixy >> 8;
1425 goto loop;
1426
1427 case 0x64: // LD HXY,HXY
1428 case 0x6D: // LD LXY,LXY
1429 goto loop;
1430
1431 CASE5( 45, 4D, 55, 5D, 7D ): // LD r,LXY
1432 R8( data >> 3, 8 ) = ixy;
1433 goto loop;
1434
1435 CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(IXY+disp)
1436 pc++;
1437 R8( data >> 3, 8 ) = READ( ixy + (int8_t) data2 );
1438 goto loop;
1439
1440 case 0x26: // LD HXY,imm
1441 pc++;
1442 goto ld_hxy_data;
1443
1444 case 0x65: // LD HXY,LXY
1445 data2 = (uint8_t) ixy;
1446 goto ld_hxy_data;
1447
1448 CASE5( 60, 61, 62, 63, 67 ): // LD HXY,r
1449 data2 = R8( data, 0x60 );
1450 ld_hxy_data:
1451 ixy = (uint8_t) ixy | (data2 << 8);
1452 goto set_ixy;
1453
1454 case 0x2E: // LD LXY,imm
1455 pc++;
1456 goto ld_lxy_data;
1457
1458 case 0x6C: // LD LXY,HXY
1459 data2 = ixy >> 8;
1460 goto ld_lxy_data;
1461
1462 CASE5( 68, 69, 6A, 6B, 6F ): // LD LXY,r
1463 data2 = R8( data, 0x68 );
1464 ld_lxy_data:
1465 ixy = (ixy & 0xFF00) | data2;
1466 set_ixy:
1467 if ( opcode == 0xDD )
1468 {
1469 ix = ixy;
1470 goto loop;
1471 }
1472 iy = ixy;
1473 goto loop;
1474
1475 case 0xF9: // LD SP,IXY
1476 sp = ixy;
1477 goto loop;
1478
1479 case 0x22:{// LD (ADDR),IXY
1480 fuint16 addr = GET_ADDR();
1481 pc += 2;
1482 WRITE_WORD( addr, ixy );
1483 goto loop;
1484 }
1485
1486 case 0x21: // LD IXY,imm
1487 ixy = GET_ADDR();
1488 pc += 2;
1489 goto set_ixy;
1490
1491 case 0x2A:{// LD IXY,(addr)
1492 fuint16 addr = GET_ADDR();
1493 ixy = READ_WORD( addr );
1494 pc += 2;
1495 goto set_ixy;
1496 }
1497
1498 // DD/FD CB prefix
1499 case 0xCB: {
1500 data = ixy + (int8_t) data2;
1501 pc++;
1502 data2 = READ_PROG( pc );
1503 pc++;
1504 switch ( data2 )
1505 {
1506 case 0x06: goto rlc_data_addr; // RLC (IXY)
1507 case 0x16: goto rl_data_addr; // RL (IXY)
1508 case 0x26: goto sla_data_addr; // SLA (IXY)
1509 case 0x36: goto sll_data_addr; // SLL (IXY)
1510 case 0x0E: goto rrc_data_addr; // RRC (IXY)
1511 case 0x1E: goto rr_data_addr; // RR (IXY)
1512 case 0x2E: goto sra_data_addr; // SRA (IXY)
1513 case 0x3E: goto srl_data_addr; // SRL (IXY)
1514
1515 CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp)
1516 fuint8 temp = READ( data );
1517 int masked = temp & 1 << (data2 >> 3 & 7);
1518 flags = (flags & C01) | H10 |
1519 (masked & S80) |
1520 ((masked - 1) >> 8 & (Z40 | P04));
1521 goto loop;
1522 }
1523
1524 CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(IXY+disp)
1525 CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(IXY+disp)
1526 int temp = READ( data );
1527 int bit = 1 << (data2 >> 3 & 7);
1528 temp |= bit; // SET
1529 if ( !(data2 & 0x40) )
1530 temp ^= bit; // RES
1531 WRITE( data, temp );
1532 goto loop;
1533 }
1534
1535 default:
1536 dprintf( "Opcode $%02X $CB $%02X not supported\n", opcode, data2 );
1537 warning = true;
1538 goto loop;
1539 }
1540 assert( false );
1541 }
1542
1543 // INC/DEC
1544 case 0x23: // INC IXY
1545 ixy = uint16_t (ixy + 1);
1546 goto set_ixy;
1547
1548 case 0x2B: // DEC IXY
1549 ixy = uint16_t (ixy - 1);
1550 goto set_ixy;
1551
1552 case 0x34: // INC (IXY+disp)
1553 ixy += (int8_t) data2;
1554 pc++;
1555 data = READ( ixy ) + 1;
1556 WRITE( ixy, data );
1557 goto inc_set_flags;
1558
1559 case 0x35: // DEC (IXY+disp)
1560 ixy += (int8_t) data2;
1561 pc++;
1562 data = READ( ixy ) - 1;
1563 WRITE( ixy, data );
1564 goto dec_set_flags;
1565
1566 case 0x24: // INC HXY
1567 ixy = uint16_t (ixy + 0x100);
1568 data = ixy >> 8;
1569 goto inc_xy_common;
1570
1571 case 0x2C: // INC LXY
1572 data = uint8_t (ixy + 1);
1573 ixy = (ixy & 0xFF00) | data;
1574 inc_xy_common:
1575 if ( opcode == 0xDD )
1576 {
1577 ix = ixy;
1578 goto inc_set_flags;
1579 }
1580 iy = ixy;
1581 goto inc_set_flags;
1582
1583 case 0x25: // DEC HXY
1584 ixy = uint16_t (ixy - 0x100);
1585 data = ixy >> 8;
1586 goto dec_xy_common;
1587
1588 case 0x2D: // DEC LXY
1589 data = uint8_t (ixy - 1);
1590 ixy = (ixy & 0xFF00) | data;
1591 dec_xy_common:
1592 if ( opcode == 0xDD )
1593 {
1594 ix = ixy;
1595 goto dec_set_flags;
1596 }
1597 iy = ixy;
1598 goto dec_set_flags;
1599
1600 // PUSH/POP
1601 case 0xE5: // PUSH IXY
1602 data = ixy;
1603 goto push_data;
1604
1605 case 0xE1:{// POP IXY
1606 ixy = READ_WORD( sp );
1607 sp = uint16_t (sp + 2);
1608 goto set_ixy;
1609 }
1610
1611 // Misc
1612
1613 case 0xE9: // JP (IXY)
1614 pc = ixy;
1615 goto loop;
1616
1617 case 0xE3:{// EX (SP),IXY
1618 fuint16 temp = READ_WORD( sp );
1619 WRITE_WORD( sp, ixy );
1620 ixy = temp;
1621 goto set_ixy;
1622 }
1623
1624 default:
1625 dprintf( "Unnecessary DD/FD prefix encountered\n" );
1626 warning = true;
1627 pc--;
1628 goto loop;
1629 }
1630 assert( false );
1631 }
1632
1633 }
1634 dprintf( "Unhandled main opcode: $%02X\n", opcode );
1635 assert( false );
1636
1637 halt:
1638 s_time &= 3; // increment by multiple of 4
1639 out_of_time:
1640 pc--;
1641
1642 s.time = s_time;
1643 rg.flags = flags;
1644 r.ix = ix;
1645 r.iy = iy;
1646 r.sp = sp;
1647 r.pc = pc;
1648 this->r.b = rg;
1649 this->state_ = s;
1650 this->state = &this->state_;
1651
1652 return warning;
1653 }