Mercurial > audlegacy-plugins
comparison src/console/Gb_Cpu.cxx @ 12:3da1b8942b8b trunk
[svn] - remove src/Input src/Output src/Effect src/General src/Visualization src/Container
author | nenolod |
---|---|
date | Mon, 18 Sep 2006 03:14:20 -0700 |
parents | src/Input/console/Gb_Cpu.cxx@13389e613d67 |
children | fb513e10174e |
comparison
equal
deleted
inserted
replaced
11:cff1d04026ae | 12:3da1b8942b8b |
---|---|
1 | |
2 // Game_Music_Emu 0.3.0. http://www.slack.net/~ant/ | |
3 | |
4 #include "Gb_Cpu.h" | |
5 | |
6 #include <string.h> | |
7 #include <limits.h> | |
8 | |
9 #include "blargg_endian.h" | |
10 | |
11 /* Copyright (C) 2003-2006 Shay Green. This module is free software; you | |
12 can redistribute it and/or modify it under the terms of the GNU Lesser | |
13 General Public License as published by the Free Software Foundation; either | |
14 version 2.1 of the License, or (at your option) any later version. This | |
15 module is distributed in the hope that it will be useful, but WITHOUT ANY | |
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for | |
18 more details. You should have received a copy of the GNU Lesser General | |
19 Public License along with this module; if not, write to the Free Software | |
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | |
21 | |
22 #include BLARGG_SOURCE_BEGIN | |
23 | |
24 // Common instructions: | |
25 // | |
26 // 365880 FA LD A,IND16 | |
27 // 355863 20 JR NZ | |
28 // 313655 21 LD HL,IMM | |
29 // 274580 28 JR Z | |
30 // 252878 FE CMP IMM | |
31 // 230541 7E LD A,(HL) | |
32 // 226209 2A LD A,(HL+) | |
33 // 217467 CD CALL | |
34 // 212034 C9 RET | |
35 // 208376 CB CB prefix | |
36 // | |
37 // 27486 CB 7E BIT 7,(HL) | |
38 // 15925 CB 76 BIT 6,(HL) | |
39 // 13035 CB 19 RR C | |
40 // 11557 CB 7F BIT 7,A | |
41 // 10898 CB 37 SWAP A | |
42 // 10208 CB 66 BIT 4,(HL) | |
43 | |
44 #if BLARGG_NONPORTABLE | |
45 #define PAGE_OFFSET( addr ) (addr) | |
46 #else | |
47 #define PAGE_OFFSET( addr ) ((addr) & (page_size - 1)) | |
48 #endif | |
49 | |
50 Gb_Cpu::Gb_Cpu( Gbs_Emu* gbs_emu ) | |
51 { | |
52 callback_data = gbs_emu; | |
53 rst_base = 0; | |
54 reset(); | |
55 } | |
56 | |
57 inline void Gb_Cpu::set_code_page( int i, uint8_t const* p ) | |
58 { | |
59 code_map [i] = p - PAGE_OFFSET( i * page_size ); | |
60 } | |
61 | |
62 void Gb_Cpu::reset( const void* unmapped_code_page, reader_t read, writer_t write ) | |
63 { | |
64 interrupts_enabled = false; | |
65 remain_ = 0; | |
66 | |
67 r.pc = 0; | |
68 r.sp = 0; | |
69 r.flags = 0; | |
70 r.a = 0; | |
71 r.b = 0; | |
72 r.c = 0; | |
73 r.d = 0; | |
74 r.e = 0; | |
75 r.h = 0; | |
76 r.l = 0; | |
77 | |
78 for ( int i = 0; i < page_count + 1; i++ ) | |
79 { | |
80 set_code_page( i, (uint8_t*) unmapped_code_page ); | |
81 data_reader [i] = read; | |
82 data_writer [i] = write; | |
83 } | |
84 } | |
85 | |
86 void Gb_Cpu::map_code( gb_addr_t start, unsigned long size, const void* data ) | |
87 { | |
88 // address range must begin and end on page boundaries | |
89 require( start % page_size == 0 ); | |
90 require( size % page_size == 0 ); | |
91 | |
92 unsigned first_page = start / page_size; | |
93 for ( unsigned i = size / page_size; i--; ) | |
94 set_code_page( first_page + i, (uint8_t*) data + i * page_size ); | |
95 } | |
96 | |
97 void Gb_Cpu::map_memory( gb_addr_t start, unsigned long size, reader_t read, writer_t write ) | |
98 { | |
99 // address range must begin and end on page boundaries | |
100 require( start % page_size == 0 ); | |
101 require( size % page_size == 0 ); | |
102 | |
103 unsigned first_page = start / page_size; | |
104 for ( unsigned i = size / page_size; i--; ) | |
105 { | |
106 data_reader [first_page + i] = read; | |
107 data_writer [first_page + i] = write; | |
108 } | |
109 } | |
110 | |
111 // Note: 'addr' is evaulated more than once in the following macros, so it | |
112 // must not contain side-effects. | |
113 | |
114 #define READ( addr ) (data_reader [(addr) >> page_bits]( callback_data, addr )) | |
115 #define WRITE( addr, data ) (data_writer [(addr) >> page_bits]( callback_data, addr, data )) | |
116 | |
117 #define READ_PROG( addr ) (code_map [(addr) >> page_bits] [PAGE_OFFSET( addr )]) | |
118 #define READ_PROG16( addr ) GET_LE16( &READ_PROG( addr ) ) | |
119 | |
120 int Gb_Cpu::read( gb_addr_t addr ) | |
121 { | |
122 return READ( addr ); | |
123 } | |
124 | |
125 void Gb_Cpu::write( gb_addr_t addr, int data ) | |
126 { | |
127 WRITE( addr, data ); | |
128 } | |
129 | |
130 BOOST::uint8_t* Gb_Cpu::get_code( gb_addr_t addr ) | |
131 { | |
132 return (uint8_t*) &READ_PROG( addr ); | |
133 } | |
134 | |
135 #ifndef GB_CPU_GLUE_ONLY | |
136 | |
137 const unsigned z_flag = 0x80; | |
138 const unsigned n_flag = 0x40; | |
139 const unsigned h_flag = 0x20; | |
140 const unsigned c_flag = 0x10; | |
141 | |
142 #include BLARGG_ENABLE_OPTIMIZER | |
143 | |
144 Gb_Cpu::result_t Gb_Cpu::run( long cycle_count ) | |
145 { | |
146 const int cycles_per_instruction = 4; | |
147 | |
148 // to do: use cycle table | |
149 remain_ = cycle_count + cycles_per_instruction; | |
150 | |
151 Gb_Cpu::result_t result = result_cycles; | |
152 | |
153 #if BLARGG_CPU_POWERPC | |
154 const reader_t* data_reader = this->data_reader; // cache | |
155 const writer_t* data_writer = this->data_writer; // cache | |
156 #endif | |
157 | |
158 union { | |
159 struct { | |
160 #if BLARGG_BIG_ENDIAN | |
161 uint8_t b, c, d, e, h, l, unused, a; | |
162 # define R8( n ) (r8_ [n]) | |
163 #elif BLARGG_LITTLE_ENDIAN | |
164 uint8_t c, b, e, d, l, h, a, unused; | |
165 # define R8( n ) (r8_ [(n) ^ 1]) | |
166 #else | |
167 # error "Byte order of CPU must be known" | |
168 #endif | |
169 } rg; // registers | |
170 | |
171 struct { | |
172 BOOST::uint16_t bc, de, hl, unused; // pairs | |
173 } rp; | |
174 | |
175 uint8_t r8_ [8]; // indexed registers (use R8 macro due to endian dependence) | |
176 BOOST::uint16_t r16 [4]; // indexed pairs | |
177 }; | |
178 BOOST_STATIC_ASSERT( sizeof rg == 8 && sizeof rp == 8 ); | |
179 | |
180 rg.a = r.a; | |
181 rg.b = r.b; | |
182 rg.c = r.c; | |
183 rg.d = r.d; | |
184 rg.e = r.e; | |
185 rg.h = r.h; | |
186 rg.l = r.l; | |
187 unsigned pc = r.pc; | |
188 unsigned sp = r.sp; | |
189 unsigned flags = r.flags; | |
190 | |
191 loop: | |
192 | |
193 int new_remain = remain_ - cycles_per_instruction; | |
194 | |
195 check( (unsigned) pc < 0x10000 ); | |
196 check( (unsigned) sp < 0x10000 ); | |
197 check( (flags & ~0xf0) == 0 ); | |
198 | |
199 uint8_t const* page = code_map [pc >> page_bits]; | |
200 unsigned op = page [PAGE_OFFSET( pc )]; | |
201 unsigned data = page [PAGE_OFFSET( pc ) + 1]; | |
202 check( op == 0xC9 || &READ_PROG( pc + 1 ) == &page [PAGE_OFFSET( pc ) + 1] ); | |
203 | |
204 pc++; | |
205 | |
206 remain_ = new_remain; | |
207 if ( new_remain <= 0 ) | |
208 goto stop; | |
209 | |
210 switch ( op ) | |
211 { | |
212 | |
213 #define BRANCH( cond ) \ | |
214 { \ | |
215 pc++; \ | |
216 int offset = (BOOST::int8_t) data; \ | |
217 if ( !(cond) ) goto loop; \ | |
218 pc += offset; \ | |
219 goto loop; \ | |
220 } | |
221 | |
222 // Most Common | |
223 | |
224 case 0x20: // JR NZ | |
225 BRANCH( !(flags & z_flag) ) | |
226 | |
227 case 0x21: // LD HL,IMM (common) | |
228 rp.hl = READ_PROG16( pc ); | |
229 pc += 2; | |
230 goto loop; | |
231 | |
232 case 0x28: // JR Z | |
233 BRANCH( flags & z_flag ) | |
234 | |
235 { | |
236 unsigned temp; | |
237 | |
238 case 0xF0: // LD A,(0xff00+imm) | |
239 temp = data + 0xff00; | |
240 pc++; | |
241 goto ld_a_ind_comm; | |
242 | |
243 case 0xF2: // LD A,(0xff00+C) | |
244 temp = rg.c + 0xff00; | |
245 goto ld_a_ind_comm; | |
246 | |
247 case 0x0A: // LD A,(BC) | |
248 temp = rp.bc; | |
249 goto ld_a_ind_comm; | |
250 | |
251 case 0x3A: // LD A,(HL-) | |
252 temp = rp.hl; | |
253 rp.hl = temp - 1; | |
254 goto ld_a_ind_comm; | |
255 | |
256 case 0x1A: // LD A,(DE) | |
257 temp = rp.de; | |
258 goto ld_a_ind_comm; | |
259 | |
260 case 0x2A: // LD A,(HL+) (common) | |
261 temp = rp.hl; | |
262 rp.hl = temp + 1; | |
263 goto ld_a_ind_comm; | |
264 | |
265 case 0xFA: // LD A,IND16 (common) | |
266 temp = READ_PROG16( pc ); | |
267 pc += 2; | |
268 ld_a_ind_comm: | |
269 rg.a = READ( temp ); | |
270 goto loop; | |
271 } | |
272 | |
273 case 0xBE: // CMP (HL) | |
274 data = READ( rp.hl ); | |
275 goto cmp_comm; | |
276 | |
277 case 0xB8: // CMP B | |
278 case 0xB9: // CMP C | |
279 case 0xBA: // CMP D | |
280 case 0xBB: // CMP E | |
281 case 0xBC: // CMP H | |
282 case 0xBD: // CMP L | |
283 data = R8( op & 7 ); | |
284 goto cmp_comm; | |
285 | |
286 case 0xFE: // CMP IMM | |
287 pc++; | |
288 cmp_comm: | |
289 op = rg.a; | |
290 data = op - data; | |
291 sub_set_flags: | |
292 flags = ((op & 15) - (data & 15)) & h_flag; | |
293 flags |= (data >> 4) & c_flag; | |
294 flags |= n_flag; | |
295 if ( data & 0xff ) | |
296 goto loop; | |
297 flags |= z_flag; | |
298 goto loop; | |
299 | |
300 case 0x46: // LD B,(HL) | |
301 case 0x4E: // LD C,(HL) | |
302 case 0x56: // LD D,(HL) | |
303 case 0x5E: // LD E,(HL) | |
304 case 0x66: // LD H,(HL) | |
305 case 0x6E: // LD L,(HL) | |
306 case 0x7E: // LD A,(HL) | |
307 R8( (op >> 3) & 7 ) = READ( rp.hl ); | |
308 goto loop; | |
309 | |
310 case 0xC4: // CNZ (next-most-common) | |
311 pc += 2; | |
312 if ( flags & z_flag ) | |
313 goto loop; | |
314 call: | |
315 pc -= 2; | |
316 case 0xCD: // CALL (most-common) | |
317 data = pc + 2; | |
318 pc = READ_PROG16( pc ); | |
319 push: | |
320 sp = (sp - 1) & 0xFFFF; | |
321 WRITE( sp, data >> 8 ); | |
322 sp = (sp - 1) & 0xFFFF; | |
323 WRITE( sp, data & 0xff ); | |
324 goto loop; | |
325 | |
326 case 0xC8: // RNZ (next-most-common) | |
327 if ( !(flags & z_flag) ) | |
328 goto loop; | |
329 case 0xC9: // RET (most common) | |
330 ret: | |
331 pc = READ( sp ); | |
332 pc += 0x100 * READ( (sp + 1) & 0xFFFF ); | |
333 sp = (sp + 2) & 0xFFFF; | |
334 goto loop; | |
335 | |
336 case 0x00: // NOP | |
337 case 0x40: // LD B,B | |
338 case 0x49: // LD C,C | |
339 case 0x52: // LD D,D | |
340 case 0x5B: // LD E,E | |
341 case 0x64: // LD H,H | |
342 case 0x6D: // LD L,L | |
343 case 0x7F: // LD A,A | |
344 goto loop; | |
345 | |
346 // CB Instructions | |
347 | |
348 case 0xCB: | |
349 pc++; | |
350 // now data is the opcode | |
351 switch ( data ) { | |
352 | |
353 { | |
354 int temp; | |
355 | |
356 case 0x46: // BIT b,(HL) | |
357 case 0x4E: | |
358 case 0x56: | |
359 case 0x5E: | |
360 case 0x66: | |
361 case 0x6E: | |
362 case 0x76: | |
363 case 0x7E: | |
364 temp = READ( rp.hl ); | |
365 goto bit_comm; | |
366 | |
367 case 0x40: case 0x41: case 0x42: case 0x43: // BIT b,r | |
368 case 0x44: case 0x45: case 0x47: case 0x48: | |
369 case 0x49: case 0x4A: case 0x4B: case 0x4C: | |
370 case 0x4D: case 0x4F: case 0x50: case 0x51: | |
371 case 0x52: case 0x53: case 0x54: case 0x55: | |
372 case 0x57: case 0x58: case 0x59: case 0x5A: | |
373 case 0x5B: case 0x5C: case 0x5D: case 0x5F: | |
374 case 0x60: case 0x61: case 0x62: case 0x63: | |
375 case 0x64: case 0x65: case 0x67: case 0x68: | |
376 case 0x69: case 0x6A: case 0x6B: case 0x6C: | |
377 case 0x6D: case 0x6F: case 0x70: case 0x71: | |
378 case 0x72: case 0x73: case 0x74: case 0x75: | |
379 case 0x77: case 0x78: case 0x79: case 0x7A: | |
380 case 0x7B: case 0x7C: case 0x7D: case 0x7F: | |
381 temp = R8( data & 7 ); | |
382 bit_comm: | |
383 int bit = (~data >> 3) & 7; | |
384 flags &= ~n_flag; | |
385 flags |= h_flag | z_flag; | |
386 flags ^= (temp << bit) & z_flag; | |
387 goto loop; | |
388 } | |
389 | |
390 case 0x86: // RES b,(HL) | |
391 case 0x8E: | |
392 case 0x96: | |
393 case 0x9E: | |
394 case 0xA6: | |
395 case 0xAE: | |
396 case 0xB6: | |
397 case 0xBE: | |
398 case 0xC6: // SET b,(HL) | |
399 case 0xCE: | |
400 case 0xD6: | |
401 case 0xDE: | |
402 case 0xE6: | |
403 case 0xEE: | |
404 case 0xF6: | |
405 case 0xFE: { | |
406 int temp = READ( rp.hl ); | |
407 int bit = 1 << ((data >> 3) & 7); | |
408 temp &= ~bit; | |
409 if ( !(data & 0x40) ) | |
410 bit = 0; | |
411 WRITE( rp.hl, temp | bit ); | |
412 goto loop; | |
413 } | |
414 | |
415 case 0xC0: case 0xC1: case 0xC2: case 0xC3: // SET b,r | |
416 case 0xC4: case 0xC5: case 0xC7: case 0xC8: | |
417 case 0xC9: case 0xCA: case 0xCB: case 0xCC: | |
418 case 0xCD: case 0xCF: case 0xD0: case 0xD1: | |
419 case 0xD2: case 0xD3: case 0xD4: case 0xD5: | |
420 case 0xD7: case 0xD8: case 0xD9: case 0xDA: | |
421 case 0xDB: case 0xDC: case 0xDD: case 0xDF: | |
422 case 0xE0: case 0xE1: case 0xE2: case 0xE3: | |
423 case 0xE4: case 0xE5: case 0xE7: case 0xE8: | |
424 case 0xE9: case 0xEA: case 0xEB: case 0xEC: | |
425 case 0xED: case 0xEF: case 0xF0: case 0xF1: | |
426 case 0xF2: case 0xF3: case 0xF4: case 0xF5: | |
427 case 0xF7: case 0xF8: case 0xF9: case 0xFA: | |
428 case 0xFB: case 0xFC: case 0xFD: case 0xFF: | |
429 R8( data & 7 ) |= 1 << ((data >> 3) & 7); | |
430 goto loop; | |
431 | |
432 case 0x80: case 0x81: case 0x82: case 0x83: // RES b,r | |
433 case 0x84: case 0x85: case 0x87: case 0x88: | |
434 case 0x89: case 0x8A: case 0x8B: case 0x8C: | |
435 case 0x8D: case 0x8F: case 0x90: case 0x91: | |
436 case 0x92: case 0x93: case 0x94: case 0x95: | |
437 case 0x97: case 0x98: case 0x99: case 0x9A: | |
438 case 0x9B: case 0x9C: case 0x9D: case 0x9F: | |
439 case 0xA0: case 0xA1: case 0xA2: case 0xA3: | |
440 case 0xA4: case 0xA5: case 0xA7: case 0xA8: | |
441 case 0xA9: case 0xAA: case 0xAB: case 0xAC: | |
442 case 0xAD: case 0xAF: case 0xB0: case 0xB1: | |
443 case 0xB2: case 0xB3: case 0xB4: case 0xB5: | |
444 case 0xB7: case 0xB8: case 0xB9: case 0xBA: | |
445 case 0xBB: case 0xBC: case 0xBD: case 0xBF: | |
446 R8( data & 7 ) &= ~(1 << ((data >> 3) & 7)); | |
447 goto loop; | |
448 | |
449 { | |
450 int temp; | |
451 case 0x36: // SWAP (HL) | |
452 temp = READ( rp.hl ); | |
453 goto swap_comm; | |
454 | |
455 case 0x30: // SWAP B | |
456 case 0x31: // SWAP C | |
457 case 0x32: // SWAP D | |
458 case 0x33: // SWAP E | |
459 case 0x34: // SWAP H | |
460 case 0x35: // SWAP L | |
461 case 0x37: // SWAP A | |
462 temp = R8( data & 7 ); | |
463 swap_comm: | |
464 op = (temp >> 4) | (temp << 4); | |
465 flags = 0; | |
466 goto shift_comm; | |
467 } | |
468 | |
469 // Shift/Rotate | |
470 | |
471 case 0x06: // RLC (HL) | |
472 case 0x16: // RL (HL) | |
473 case 0x26: // SLA (HL) | |
474 op = READ( rp.hl ); | |
475 goto rl_comm; | |
476 | |
477 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x27: // SLA A | |
478 case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x07: // RLC A | |
479 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x17: // RL A | |
480 op = R8( data & 7 ); | |
481 goto rl_comm; | |
482 | |
483 case 0x3E: // SRL (HL) | |
484 data += 0x10; // bump up to 0x4n to avoid preserving sign bit | |
485 case 0x1E: // RR (HL) | |
486 case 0x0E: // RRC (HL) | |
487 case 0x2E: // SRA (HL) | |
488 op = READ( rp.hl ); | |
489 goto rr_comm; | |
490 | |
491 case 0x38: case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D: case 0x3F: // SRL A | |
492 data += 0x10; // bump up to 0x4n | |
493 case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1F: // RR A | |
494 case 0x08: case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0F: // RRC A | |
495 case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2F: // SRA A | |
496 op = R8( data & 7 ); | |
497 goto rr_comm; | |
498 | |
499 } // CB op | |
500 assert( false ); // unhandled CB op | |
501 | |
502 case 0x07: // RLCA | |
503 case 0x17: // RLA | |
504 data = op; | |
505 op = rg.a; | |
506 rl_comm: | |
507 op <<= 1; | |
508 op |= ((data & flags) >> 4) & 1; // RL and carry is set | |
509 flags = (op >> 4) & c_flag; // C = bit shifted out | |
510 if ( data < 0x10 ) // RLC | |
511 op |= op >> 8; | |
512 // SLA doesn't fill lower bit | |
513 goto shift_comm; | |
514 | |
515 case 0x0F: // RRCA | |
516 case 0x1F: // RRA | |
517 data = op; | |
518 op = rg.a; | |
519 rr_comm: | |
520 op |= (data & flags) << 4; // RR and carry is set | |
521 flags = (op << 4) & c_flag; // C = bit shifted out | |
522 if ( data < 0x10 ) // RRC | |
523 op |= op << 8; | |
524 op >>= 1; | |
525 if ( data & 0x20 ) // SRA propagates sign bit | |
526 op |= (op << 1) & 0x80; | |
527 shift_comm: | |
528 data &= 7; | |
529 if ( !(op & 0xff) ) | |
530 flags |= z_flag; | |
531 if ( data == 6 ) | |
532 goto write_hl_op_ff; | |
533 R8( data ) = op; | |
534 goto loop; | |
535 | |
536 // Load | |
537 | |
538 case 0x70: // LD (HL),B | |
539 case 0x71: // LD (HL),C | |
540 case 0x72: // LD (HL),D | |
541 case 0x73: // LD (HL),E | |
542 case 0x74: // LD (HL),H | |
543 case 0x75: // LD (HL),L | |
544 case 0x77: // LD (HL),A | |
545 op = R8( op & 7 ); | |
546 write_hl_op_ff: | |
547 WRITE( rp.hl, op & 0xff ); | |
548 goto loop; | |
549 | |
550 case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x47: // LD r,r | |
551 case 0x48: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4F: | |
552 case 0x50: case 0x51: case 0x53: case 0x54: case 0x55: case 0x57: | |
553 case 0x58: case 0x59: case 0x5A: case 0x5C: case 0x5D: case 0x5F: | |
554 case 0x60: case 0x61: case 0x62: case 0x63: case 0x65: case 0x67: | |
555 case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6F: | |
556 case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: | |
557 R8( (op >> 3) & 7 ) = R8( op & 7 ); | |
558 goto loop; | |
559 | |
560 case 0x08: // LD IND16,SP | |
561 data = READ_PROG16( pc ); | |
562 pc += 2; | |
563 WRITE( data, sp&0xff ); | |
564 data++; | |
565 WRITE( data, sp >> 8 ); | |
566 goto loop; | |
567 | |
568 case 0xF9: // LD SP,HL | |
569 sp = rp.hl; | |
570 goto loop; | |
571 | |
572 case 0x31: // LD SP,IMM | |
573 sp = READ_PROG16( pc ); | |
574 pc += 2; | |
575 goto loop; | |
576 | |
577 case 0x01: // LD BC,IMM | |
578 case 0x11: // LD DE,IMM | |
579 r16 [op >> 4] = READ_PROG16( pc ); | |
580 pc += 2; | |
581 goto loop; | |
582 | |
583 { | |
584 unsigned temp; | |
585 case 0xE0: // LD (0xff00+imm),A | |
586 temp = data + 0xff00; | |
587 pc++; | |
588 goto write_data_rg_a; | |
589 | |
590 case 0xE2: // LD (0xff00+C),A | |
591 temp = rg.c + 0xff00; | |
592 goto write_data_rg_a; | |
593 | |
594 case 0x32: // LD (HL-),A | |
595 temp = rp.hl; | |
596 rp.hl = temp - 1; | |
597 goto write_data_rg_a; | |
598 | |
599 case 0x02: // LD (BC),A | |
600 temp = rp.bc; | |
601 goto write_data_rg_a; | |
602 | |
603 case 0x12: // LD (DE),A | |
604 temp = rp.de; | |
605 goto write_data_rg_a; | |
606 | |
607 case 0x22: // LD (HL+),A | |
608 temp = rp.hl; | |
609 rp.hl = temp + 1; | |
610 goto write_data_rg_a; | |
611 | |
612 case 0xEA: // LD IND16,A (common) | |
613 temp = READ_PROG16( pc ); | |
614 pc += 2; | |
615 write_data_rg_a: | |
616 WRITE( temp, rg.a ); | |
617 goto loop; | |
618 } | |
619 | |
620 case 0x06: // LD B,IMM | |
621 rg.b = data; | |
622 pc++; | |
623 goto loop; | |
624 | |
625 case 0x0E: // LD C,IMM | |
626 rg.c = data; | |
627 pc++; | |
628 goto loop; | |
629 | |
630 case 0x16: // LD D,IMM | |
631 rg.d = data; | |
632 pc++; | |
633 goto loop; | |
634 | |
635 case 0x1E: // LD E,IMM | |
636 rg.e = data; | |
637 pc++; | |
638 goto loop; | |
639 | |
640 case 0x26: // LD H,IMM | |
641 rg.h = data; | |
642 pc++; | |
643 goto loop; | |
644 | |
645 case 0x2E: // LD L,IMM | |
646 rg.l = data; | |
647 pc++; | |
648 goto loop; | |
649 | |
650 case 0x36: // LD (HL),IMM | |
651 WRITE( rp.hl, data ); | |
652 pc++; | |
653 goto loop; | |
654 | |
655 case 0x3E: // LD A,IMM | |
656 rg.a = data; | |
657 pc++; | |
658 goto loop; | |
659 | |
660 // Increment/Decrement | |
661 | |
662 case 0x03: // INC BC | |
663 case 0x13: // INC DE | |
664 case 0x23: // INC HL | |
665 r16 [op >> 4]++; | |
666 goto loop; | |
667 | |
668 case 0x33: // INC SP | |
669 sp = (sp + 1) & 0xFFFF; | |
670 goto loop; | |
671 | |
672 case 0x0B: // DEC BC | |
673 case 0x1B: // DEC DE | |
674 case 0x2B: // DEC HL | |
675 r16 [op >> 4]--; | |
676 goto loop; | |
677 | |
678 case 0x3B: // DEC SP | |
679 sp = (sp - 1) & 0xFFFF; | |
680 goto loop; | |
681 | |
682 case 0x34: // INC (HL) | |
683 op = rp.hl; | |
684 data = READ( op ); | |
685 data++; | |
686 WRITE( op, data & 0xff ); | |
687 goto inc_comm; | |
688 | |
689 case 0x04: // INC B | |
690 case 0x0C: // INC C (common) | |
691 case 0x14: // INC D | |
692 case 0x1C: // INC E | |
693 case 0x24: // INC H | |
694 case 0x2C: // INC L | |
695 case 0x3C: // INC A | |
696 op = (op >> 3) & 7; | |
697 R8( op ) = data = R8( op ) + 1; | |
698 inc_comm: | |
699 flags = (flags & c_flag) | (((data & 15) - 1) & h_flag) | ((data >> 1) & z_flag); | |
700 goto loop; | |
701 | |
702 case 0x35: // DEC (HL) | |
703 op = rp.hl; | |
704 data = READ( op ); | |
705 data--; | |
706 WRITE( op, data & 0xff ); | |
707 goto dec_comm; | |
708 | |
709 case 0x05: // DEC B | |
710 case 0x0D: // DEC C | |
711 case 0x15: // DEC D | |
712 case 0x1D: // DEC E | |
713 case 0x25: // DEC H | |
714 case 0x2D: // DEC L | |
715 case 0x3D: // DEC A | |
716 op = (op >> 3) & 7; | |
717 data = R8( op ) - 1; | |
718 R8( op ) = data; | |
719 dec_comm: | |
720 flags = (flags & c_flag) | n_flag | (((data & 15) + 0x31) & h_flag); | |
721 if ( data & 0xff ) | |
722 goto loop; | |
723 flags |= z_flag; | |
724 goto loop; | |
725 | |
726 // Add 16-bit | |
727 | |
728 { | |
729 unsigned long temp; // need more than 16 bits for carry | |
730 unsigned prev; | |
731 | |
732 case 0xF8: // LD HL,SP+imm | |
733 temp = BOOST::int8_t (data); // sign-extend to 16 bits | |
734 pc++; | |
735 flags = 0; | |
736 temp += sp; | |
737 prev = sp; | |
738 goto add_16_hl; | |
739 | |
740 case 0xE8: // ADD SP,IMM | |
741 temp = BOOST::int8_t (data); // sign-extend to 16 bits | |
742 pc++; | |
743 flags = 0; | |
744 temp += sp; | |
745 prev = sp; | |
746 sp = temp & 0xffff; | |
747 goto add_16_comm; | |
748 | |
749 case 0x39: // ADD HL,SP | |
750 temp = sp; | |
751 goto add_hl_comm; | |
752 | |
753 case 0x09: // ADD HL,BC | |
754 case 0x19: // ADD HL,DE | |
755 case 0x29: // ADD HL,HL | |
756 temp = r16 [op >> 4]; | |
757 add_hl_comm: | |
758 prev = rp.hl; | |
759 temp += prev; | |
760 flags &= z_flag; | |
761 add_16_hl: | |
762 rp.hl = temp; | |
763 add_16_comm: | |
764 flags |= (temp >> 12) & c_flag; | |
765 flags |= (((temp & 0x0fff) - (prev & 0x0fff)) >> 7) & h_flag; | |
766 goto loop; | |
767 } | |
768 | |
769 case 0x86: // ADD (HL) | |
770 data = READ( rp.hl ); | |
771 goto add_comm; | |
772 | |
773 case 0x80: // ADD B | |
774 case 0x81: // ADD C | |
775 case 0x82: // ADD D | |
776 case 0x83: // ADD E | |
777 case 0x84: // ADD H | |
778 case 0x85: // ADD L | |
779 case 0x87: // ADD A | |
780 data = R8( op & 7 ); | |
781 goto add_comm; | |
782 | |
783 case 0xC6: // ADD IMM | |
784 pc++; | |
785 add_comm: | |
786 flags = rg.a; | |
787 data += flags; | |
788 flags = ((data & 15) - (flags & 15)) & h_flag; | |
789 flags |= (data >> 4) & c_flag; | |
790 rg.a = data; | |
791 if ( data & 0xff ) | |
792 goto loop; | |
793 flags |= z_flag; | |
794 goto loop; | |
795 | |
796 // Add/Subtract | |
797 | |
798 case 0x8E: // ADC (HL) | |
799 data = READ( rp.hl ); | |
800 goto adc_comm; | |
801 | |
802 case 0x88: // ADC B | |
803 case 0x89: // ADC C | |
804 case 0x8A: // ADC D | |
805 case 0x8B: // ADC E | |
806 case 0x8C: // ADC H | |
807 case 0x8D: // ADC L | |
808 case 0x8F: // ADC A | |
809 data = R8( op & 7 ); | |
810 goto adc_comm; | |
811 | |
812 case 0xCE: // ADC IMM | |
813 pc++; | |
814 adc_comm: | |
815 data += (flags >> 4) & 1; | |
816 data &= 0xff; // to do: does carry get set when sum + carry = 0x100? | |
817 goto add_comm; | |
818 | |
819 case 0x96: // SUB (HL) | |
820 data = READ( rp.hl ); | |
821 goto sub_comm; | |
822 | |
823 case 0x90: // SUB B | |
824 case 0x91: // SUB C | |
825 case 0x92: // SUB D | |
826 case 0x93: // SUB E | |
827 case 0x94: // SUB H | |
828 case 0x95: // SUB L | |
829 case 0x97: // SUB A | |
830 data = R8( op & 7 ); | |
831 goto sub_comm; | |
832 | |
833 case 0xD6: // SUB IMM | |
834 pc++; | |
835 sub_comm: | |
836 op = rg.a; | |
837 data = op - data; | |
838 rg.a = data; | |
839 goto sub_set_flags; | |
840 | |
841 case 0x9E: // SBC (HL) | |
842 data = READ( rp.hl ); | |
843 goto sbc_comm; | |
844 | |
845 case 0x98: // SBC B | |
846 case 0x99: // SBC C | |
847 case 0x9A: // SBC D | |
848 case 0x9B: // SBC E | |
849 case 0x9C: // SBC H | |
850 case 0x9D: // SBC L | |
851 case 0x9F: // SBC A | |
852 data = R8( op & 7 ); | |
853 goto sbc_comm; | |
854 | |
855 case 0xDE: // SBC IMM | |
856 pc++; | |
857 sbc_comm: | |
858 data += (flags >> 4) & 1; | |
859 data &= 0xff; // to do: does carry get set when sum + carry = 0x100? | |
860 goto sub_comm; | |
861 | |
862 // Logical | |
863 | |
864 case 0xA0: // AND B | |
865 case 0xA1: // AND C | |
866 case 0xA2: // AND D | |
867 case 0xA3: // AND E | |
868 case 0xA4: // AND H | |
869 case 0xA5: // AND L | |
870 data = R8( op & 7 ); | |
871 goto and_comm; | |
872 | |
873 case 0xA6: // AND (HL) | |
874 data = READ( rp.hl ); | |
875 pc--; | |
876 case 0xE6: // AND IMM | |
877 pc++; | |
878 and_comm: | |
879 rg.a &= data; | |
880 case 0xA7: // AND A | |
881 flags = h_flag | (((rg.a - 1) >> 1) & z_flag); | |
882 goto loop; | |
883 | |
884 case 0xB0: // OR B | |
885 case 0xB1: // OR C | |
886 case 0xB2: // OR D | |
887 case 0xB3: // OR E | |
888 case 0xB4: // OR H | |
889 case 0xB5: // OR L | |
890 data = R8( op & 7 ); | |
891 goto or_comm; | |
892 | |
893 case 0xB6: // OR (HL) | |
894 data = READ( rp.hl ); | |
895 pc--; | |
896 case 0xF6: // OR IMM | |
897 pc++; | |
898 or_comm: | |
899 rg.a |= data; | |
900 case 0xB7: // OR A | |
901 flags = ((rg.a - 1) >> 1) & z_flag; | |
902 goto loop; | |
903 | |
904 case 0xA8: // XOR B | |
905 case 0xA9: // XOR C | |
906 case 0xAA: // XOR D | |
907 case 0xAB: // XOR E | |
908 case 0xAC: // XOR H | |
909 case 0xAD: // XOR L | |
910 data = R8( op & 7 ); | |
911 goto xor_comm; | |
912 | |
913 case 0xAE: // XOR (HL) | |
914 data = READ( rp.hl ); | |
915 pc--; | |
916 case 0xEE: // XOR IMM | |
917 pc++; | |
918 xor_comm: | |
919 data ^= rg.a; | |
920 rg.a = data; | |
921 data--; | |
922 flags = (data >> 1) & z_flag; | |
923 goto loop; | |
924 | |
925 case 0xAF: // XOR A | |
926 rg.a = 0; | |
927 flags = z_flag; | |
928 goto loop; | |
929 | |
930 // Stack | |
931 | |
932 case 0xC1: // POP BC | |
933 case 0xD1: // POP DE | |
934 case 0xE1:{// POP HL (common) | |
935 int temp = READ( sp ); | |
936 r16 [(op >> 4) & 3] = temp + 0x100 * READ( (sp + 1) & 0xFFFF ); | |
937 sp = (sp + 2) & 0xFFFF; | |
938 goto loop; | |
939 } | |
940 | |
941 case 0xF1: // POP FA | |
942 rg.a = READ( sp ); | |
943 flags = READ( (sp + 1) & 0xFFFF ) & 0xf0; | |
944 sp = (sp + 2) & 0xFFFF; | |
945 goto loop; | |
946 | |
947 case 0xC5: // PUSH BC | |
948 data = rp.bc; | |
949 goto push; | |
950 | |
951 case 0xD5: // PUSH DE | |
952 data = rp.de; | |
953 goto push; | |
954 | |
955 case 0xE5: // PUSH HL | |
956 data = rp.hl; | |
957 goto push; | |
958 | |
959 case 0xF5: // PUSH FA | |
960 data = (flags << 8) | rg.a; | |
961 goto push; | |
962 | |
963 // Flow control | |
964 | |
965 case 0xC7: case 0xCF: case 0xD7: case 0xDF: // RST | |
966 case 0xE7: case 0xEF: case 0xF7: case 0xFF: | |
967 data = pc; | |
968 pc = (op & 0x38) + rst_base; | |
969 goto push; | |
970 | |
971 case 0xCC: // CZ | |
972 pc += 2; | |
973 if ( flags & z_flag ) | |
974 goto call; | |
975 goto loop; | |
976 | |
977 case 0xD4: // CNC | |
978 pc += 2; | |
979 if ( !(flags & c_flag) ) | |
980 goto call; | |
981 goto loop; | |
982 | |
983 case 0xDC: // CC | |
984 pc += 2; | |
985 if ( flags & c_flag ) | |
986 goto call; | |
987 goto loop; | |
988 | |
989 case 0xD9: // RETI | |
990 Gb_Cpu::interrupts_enabled = 1; | |
991 goto ret; | |
992 | |
993 case 0xC0: // RZ | |
994 if ( !(flags & z_flag) ) | |
995 goto ret; | |
996 goto loop; | |
997 | |
998 case 0xD0: // RNC | |
999 if ( !(flags & c_flag) ) | |
1000 goto ret; | |
1001 goto loop; | |
1002 | |
1003 case 0xD8: // RC | |
1004 if ( flags & c_flag ) | |
1005 goto ret; | |
1006 goto loop; | |
1007 | |
1008 case 0x18: // JR | |
1009 BRANCH( true ) | |
1010 | |
1011 case 0x30: // JR NC | |
1012 BRANCH( !(flags & c_flag) ) | |
1013 | |
1014 case 0x38: // JR C | |
1015 BRANCH( flags & c_flag ) | |
1016 | |
1017 case 0xE9: // JP_HL | |
1018 pc = rp.hl; | |
1019 goto loop; | |
1020 | |
1021 case 0xC3: // JP (next-most-common) | |
1022 pc = READ_PROG16( pc ); | |
1023 goto loop; | |
1024 | |
1025 case 0xC2: // JP NZ | |
1026 pc += 2; | |
1027 if ( !(flags & z_flag) ) | |
1028 goto jp_taken; | |
1029 goto loop; | |
1030 | |
1031 case 0xCA: // JP Z (most common) | |
1032 pc += 2; | |
1033 if ( !(flags & z_flag) ) | |
1034 goto loop; | |
1035 jp_taken: | |
1036 pc -= 2; | |
1037 pc = READ_PROG16( pc ); | |
1038 goto loop; | |
1039 | |
1040 case 0xD2: // JP NC | |
1041 pc += 2; | |
1042 if ( !(flags & c_flag) ) | |
1043 goto jp_taken; | |
1044 goto loop; | |
1045 | |
1046 case 0xDA: // JP C | |
1047 pc += 2; | |
1048 if ( flags & c_flag ) | |
1049 goto jp_taken; | |
1050 goto loop; | |
1051 | |
1052 // Flags | |
1053 | |
1054 case 0x2F: // CPL | |
1055 rg.a = ~rg.a; | |
1056 flags |= n_flag | h_flag; | |
1057 goto loop; | |
1058 | |
1059 case 0x3F: // CCF | |
1060 flags = (flags ^ c_flag) & ~(n_flag | h_flag); | |
1061 goto loop; | |
1062 | |
1063 case 0x37: // SCF | |
1064 flags = (flags | c_flag) & ~(n_flag | h_flag); | |
1065 goto loop; | |
1066 | |
1067 case 0xF3: // DI | |
1068 interrupts_enabled = 0; | |
1069 goto loop; | |
1070 | |
1071 case 0xFB: // EI | |
1072 interrupts_enabled = 1; | |
1073 goto loop; | |
1074 | |
1075 // Special | |
1076 | |
1077 case 0xDD: case 0xD3: case 0xDB: case 0xE3: case 0xE4: // ? | |
1078 case 0xEB: case 0xEC: case 0xF4: case 0xFD: case 0xFC: | |
1079 case 0x10: // STOP | |
1080 case 0x27: // DAA (I'll have to implement this eventually...) | |
1081 case 0xBF: | |
1082 case 0xED: // Z80 prefix | |
1083 result = Gb_Cpu::result_badop; | |
1084 goto stop; | |
1085 | |
1086 case 0x76: // HALT | |
1087 result = Gb_Cpu::result_halt; | |
1088 goto stop; | |
1089 } | |
1090 | |
1091 // If this fails then the case above is missing an opcode | |
1092 assert( false ); | |
1093 | |
1094 stop: | |
1095 pc--; | |
1096 | |
1097 // copy state back | |
1098 r.pc = pc; | |
1099 r.sp = sp; | |
1100 r.flags = flags; | |
1101 r.a = rg.a; | |
1102 r.b = rg.b; | |
1103 r.c = rg.c; | |
1104 r.d = rg.d; | |
1105 r.e = rg.e; | |
1106 r.h = rg.h; | |
1107 r.l = rg.l; | |
1108 | |
1109 return result; | |
1110 } | |
1111 | |
1112 #endif | |
1113 |