An emulator, assembler, and disassembler for the Sega Game Gear
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

z80.c 6.9 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
  2. Released under the terms of the MIT License. See LICENSE for details. */
  3. #include "logging.h"
  4. #include "z80.h"
  5. #define REG_AF 0
  6. #define REG_BC 1
  7. #define REG_DE 2
  8. #define REG_HL 3
  9. #define FLAG_CARRY 0
  10. #define FLAG_SUBTRACT 1
  11. #define FLAG_PARITY 2
  12. #define FLAG_OVERFLOW 2
  13. #define FLAG_UNDOC_3 3
  14. #define FLAG_HALFCARRY 4
  15. #define FLAG_UNDOC_5 5
  16. #define FLAG_ZERO 6
  17. #define FLAG_SIGN 7
  18. #ifdef DEBUG_MODE
  19. #define BINARY_FMT "0b%u%u%u%u%u%u%u%u" // Used by z80_dump_registers()
  20. #define BINARY_VAL(data) \
  21. (data & (1 << 7) ? 1 : 0), \
  22. (data & (1 << 6) ? 1 : 0), \
  23. (data & (1 << 5) ? 1 : 0), \
  24. (data & (1 << 4) ? 1 : 0), \
  25. (data & (1 << 3) ? 1 : 0), \
  26. (data & (1 << 2) ? 1 : 0), \
  27. (data & (1 << 1) ? 1 : 0), \
  28. (data & (1 << 0) ? 1 : 0)
  29. #endif
  30. /*
  31. Initialize a Z80 object.
  32. Register values are invalid until z80_power() is called. No other Z80
  33. functions should be called before it.
  34. */
  35. void z80_init(Z80 *z80, MMU *mmu)
  36. {
  37. z80->mmu = mmu;
  38. z80->except = true;
  39. z80->exc_code = Z80_EXC_NOT_POWERED;
  40. z80->exc_data = 0;
  41. }
  42. /*
  43. Power on the Z80, setting registers to their default values.
  44. This also clears the exception flag, which is necessary before the Z80 can
  45. begin emulation.
  46. */
  47. void z80_power(Z80 *z80)
  48. {
  49. Z80RegFile *regfile = &z80->regfile;
  50. regfile->a = regfile->f = 0xFF;
  51. regfile->b = regfile->c = 0xFF;
  52. regfile->d = regfile->e = 0xFF;
  53. regfile->h = regfile->l = 0xFF;
  54. regfile->a_ = regfile->f_ = 0xFF;
  55. regfile->b_ = regfile->c_ = 0xFF;
  56. regfile->d_ = regfile->e_ = 0xFF;
  57. regfile->h_ = regfile->l_ = 0xFF;
  58. regfile->ix = 0xFFFF;
  59. regfile->iy = 0xFFFF;
  60. regfile->sp = 0xFFFF;
  61. regfile->pc = 0x0000;
  62. regfile->i = 0xFF;
  63. regfile->r = 0xFF;
  64. regfile->im_a = regfile->im_b = 0;
  65. regfile->iff1 = regfile->iff2 = 0;
  66. z80->except = false;
  67. z80->pending_cycles = 0;
  68. }
  69. /*
  70. Get the value of a register pair.
  71. */
  72. static inline uint16_t get_pair(Z80 *z80, uint8_t pair)
  73. {
  74. switch (pair) {
  75. case REG_AF: return (z80->regfile.a << 8) + z80->regfile.f;
  76. case REG_BC: return (z80->regfile.b << 8) + z80->regfile.c;
  77. case REG_DE: return (z80->regfile.d << 8) + z80->regfile.e;
  78. case REG_HL: return (z80->regfile.h << 8) + z80->regfile.l;
  79. default: FATAL("invalid call: get_pair(z80, %u)", pair)
  80. }
  81. }
  82. /*
  83. Set the value of a register pair.
  84. */
  85. static inline void set_pair(Z80 *z80, uint8_t pair, uint16_t value)
  86. {
  87. switch (pair) {
  88. case REG_AF: z80->regfile.a = value >> 8; z80->regfile.f = value; break;
  89. case REG_BC: z80->regfile.b = value >> 8; z80->regfile.c = value; break;
  90. case REG_DE: z80->regfile.d = value >> 8; z80->regfile.e = value; break;
  91. case REG_HL: z80->regfile.h = value >> 8; z80->regfile.l = value; break;
  92. default: FATAL("invalid call: set_pair(z80, %u, 0x%04X)", pair, value)
  93. }
  94. }
  95. /*
  96. Return whether a particular flag is set in the F register.
  97. */
  98. static inline bool get_flag(const Z80 *z80, uint8_t flag)
  99. {
  100. return z80->regfile.f & (1 << flag);
  101. }
  102. /*
  103. Return whether a particular flag is set in the F' register.
  104. */
  105. static inline bool get_shadow_flag(const Z80 *z80, uint8_t flag)
  106. {
  107. return z80->regfile.f_ & (1 << flag);
  108. }
  109. /*
  110. Update the F register flags according to the set bits in the mask.
  111. */
  112. static inline void update_flags(Z80 *z80, bool c, bool n, bool pv, bool f3,
  113. bool h, bool f5, bool z, bool s, uint8_t mask)
  114. {
  115. z80->regfile.f = (~mask & z80->regfile.f) | (mask & (
  116. c << FLAG_CARRY |
  117. n << FLAG_SUBTRACT |
  118. pv << FLAG_PARITY |
  119. f3 << FLAG_UNDOC_3 |
  120. h << FLAG_HALFCARRY |
  121. f5 << FLAG_UNDOC_5 |
  122. z << FLAG_ZERO |
  123. s << FLAG_SIGN));
  124. }
  125. /*
  126. Return the CPU's current interrupt mode.
  127. */
  128. static inline uint8_t get_interrupt_mode(const Z80 *z80)
  129. {
  130. if (!z80->regfile.im_a)
  131. return 0;
  132. if (!z80->regfile.im_b)
  133. return 1;
  134. return 2;
  135. }
  136. /*
  137. Increment the refresh counter register, R.
  138. */
  139. static inline void increment_refresh_counter(Z80 *z80)
  140. {
  141. z80->regfile.r = (z80->regfile.r & 0x80) | ((z80->regfile.r + 1) & 0x7F);
  142. }
  143. #include "z80_ops.inc.c"
  144. /*
  145. Emulate the given number of cycles of the Z80, or until an exception.
  146. The return value indicates whether the exception flag is set. If it is,
  147. then emulation must be stopped because further calls to z80_do_cycles()
  148. will have no effect. The exception flag can be reset with z80_power().
  149. */
  150. bool z80_do_cycles(Z80 *z80, double cycles)
  151. {
  152. cycles -= z80->pending_cycles;
  153. while (cycles > 0 && !z80->except) {
  154. uint8_t opcode = mmu_read_byte(z80->mmu, z80->regfile.pc);
  155. increment_refresh_counter(z80);
  156. cycles -= (*instruction_lookup_table[opcode])(z80, opcode);
  157. }
  158. z80->pending_cycles = -cycles;
  159. return z80->except;
  160. }
  161. #ifdef DEBUG_MODE
  162. /*
  163. DEBUG FUNCTION: Print out all register values to stdout.
  164. */
  165. void z80_dump_registers(const Z80 *z80)
  166. {
  167. const Z80RegFile *rf = &z80->regfile;
  168. DEBUG("Dumping Z80 register values:")
  169. DEBUG("- AF: 0x%02X%02X (%03d, %03d)", rf->a, rf->f, rf->a, rf->f)
  170. DEBUG("- BC: 0x%02X%02X (%03d, %03d)", rf->b, rf->c, rf->b, rf->c)
  171. DEBUG("- DE: 0x%02X%02X (%03d, %03d)", rf->d, rf->e, rf->d, rf->e)
  172. DEBUG("- HL: 0x%02X%02X (%03d, %03d)", rf->h, rf->l, rf->h, rf->l)
  173. DEBUG("- AF': 0x%02X%02X (%03d, %03d)", rf->a_, rf->f_, rf->a_, rf->f_)
  174. DEBUG("- BC': 0x%02X%02X (%03d, %03d)", rf->b_, rf->c_, rf->b_, rf->c_)
  175. DEBUG("- DE': 0x%02X%02X (%03d, %03d)", rf->d_, rf->e_, rf->d_, rf->e_)
  176. DEBUG("- HL': 0x%02X%02X (%03d, %03d)", rf->h_, rf->l_, rf->h_, rf->l_)
  177. DEBUG("- IX: 0x%04X (%05d)", rf->ix, rf->ix)
  178. DEBUG("- IY: 0x%04X (%05d)", rf->iy, rf->iy)
  179. DEBUG("- SP: 0x%04X (%05d)", rf->sp, rf->sp)
  180. DEBUG("- PC: 0x%04X (%05d)", rf->pc, rf->pc)
  181. DEBUG("- I: 0x%2X (%03d)", rf->i, rf->i)
  182. DEBUG("- R: 0x%2X (%03d)", rf->r, rf->r)
  183. DEBUG("- F: "BINARY_FMT" (C: %u, N: %u, P/V: %u, H: %u, Z: %u, S: %u)",
  184. BINARY_VAL(rf->f),
  185. get_flag(z80, FLAG_CARRY),
  186. get_flag(z80, FLAG_SUBTRACT),
  187. get_flag(z80, FLAG_PARITY),
  188. get_flag(z80, FLAG_HALFCARRY),
  189. get_flag(z80, FLAG_ZERO),
  190. get_flag(z80, FLAG_SIGN))
  191. DEBUG("- F': "BINARY_FMT" (C: %u, N: %u, P/V: %u, H: %u, Z: %u, S: %u)",
  192. BINARY_VAL(rf->f_),
  193. get_shadow_flag(z80, FLAG_CARRY),
  194. get_shadow_flag(z80, FLAG_SUBTRACT),
  195. get_shadow_flag(z80, FLAG_PARITY),
  196. get_shadow_flag(z80, FLAG_HALFCARRY),
  197. get_shadow_flag(z80, FLAG_ZERO),
  198. get_shadow_flag(z80, FLAG_SIGN))
  199. DEBUG("- IM: 0b%u%u (mode: %u)", rf->im_a, rf->im_b,
  200. get_interrupt_mode(z80))
  201. DEBUG("- IFF1: %u", rf->iff1)
  202. DEBUG("- IFF2: %u", rf->iff2)
  203. }
  204. #endif