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