/gme/Kss_Cpu.cpp

http://game-music-emu.googlecode.com/ · C++ · 1706 lines · 1364 code · 257 blank · 85 comment · 59 complexity · ad5601bdcf9d714f1e05b1f88bb7e537 MD5 · raw file

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