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