An emulator, assembler, and disassembler for the Sega Game Gear
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

210 lines
5.5 KiB

  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 <stdlib.h>
  4. #include <unistd.h>
  5. #include "gamegear.h"
  6. #include "logging.h"
  7. #include "util.h"
  8. /* Clock speed in Hz was taken from the official Sega GG documentation */
  9. #define CPU_CLOCK_SPEED (3579545.)
  10. #define CYCLES_PER_FRAME (CPU_CLOCK_SPEED / GG_FPS)
  11. #define CYCLES_PER_LINE (CYCLES_PER_FRAME / VDP_LINES_PER_FRAME)
  12. #define NS_PER_FRAME (1000 * 1000 * 1000 / GG_FPS)
  13. #define SET_EXC(...) snprintf(gg->exc_buffer, GG_EXC_BUFF_SIZE, __VA_ARGS__);
  14. /*
  15. Create and return a pointer to a new GameGear object.
  16. */
  17. GameGear* gamegear_create()
  18. {
  19. GameGear *gg = cr_malloc(sizeof(GameGear));
  20. mmu_init(&gg->mmu);
  21. vdp_init(&gg->vdp);
  22. io_init(&gg->io, &gg->vdp);
  23. z80_init(&gg->cpu, &gg->mmu, &gg->io);
  24. gg->powered = false;
  25. gg->callback = NULL;
  26. gg->exc_buffer[0] = '\0';
  27. return gg;
  28. }
  29. /*
  30. Destroy a previously-allocated GameGear object.
  31. Does *not* destroy any loaded ROM objects.
  32. */
  33. void gamegear_destroy(GameGear *gg)
  34. {
  35. mmu_free(&gg->mmu);
  36. vdp_free(&gg->vdp);
  37. free(gg);
  38. }
  39. /*
  40. Load a ROM image into the GameGear object.
  41. Does *not* steal a reference to the ROM object, so it must be kept alive
  42. until another ROM is loaded or the GameGear is destroyed. Calling this
  43. function while the GameGear is powered on has no effect.
  44. */
  45. void gamegear_load(GameGear *gg, const ROM *rom)
  46. {
  47. if (gg->powered)
  48. return;
  49. mmu_load_rom(&gg->mmu, rom->data, rom->size);
  50. }
  51. /*
  52. Power on the GameGear.
  53. This clears the exception buffer and executes boot code (e.g. clearing
  54. memory and setting initial register values).
  55. */
  56. static void power_on(GameGear *gg)
  57. {
  58. gg->exc_buffer[0] = '\0';
  59. gg->powered = true;
  60. mmu_power(&gg->mmu);
  61. vdp_power(&gg->vdp);
  62. io_power(&gg->io);
  63. z80_power(&gg->cpu);
  64. }
  65. /*
  66. Power off the GameGear.
  67. This function *may* be used while the GameGear is running to trigger a safe
  68. shutdown at the next opportunity. It is also reentrant. If the GameGear is
  69. already off, it will do nothing.
  70. */
  71. void gamegear_power_off(GameGear *gg)
  72. {
  73. gg->powered = false;
  74. }
  75. /*
  76. Set a callback to be triggered whenever the GameGear completes a frame.
  77. */
  78. void gamegear_set_callback(GameGear *gg, GGFrameCallback callback)
  79. {
  80. gg->callback = callback;
  81. }
  82. /*
  83. Reset the GameGear's frame callback function.
  84. */
  85. void gamegear_clear_callback(GameGear *gg)
  86. {
  87. gg->callback = NULL;
  88. }
  89. /*
  90. Simulate the GameGear for one frame.
  91. This function simulates the number of clock cycles corresponding to 1/60th
  92. of a second. The return value indicates whether an exception flag has been
  93. set somewhere. If true, emulation must be stopped.
  94. */
  95. static bool simulate_frame(GameGear *gg)
  96. {
  97. size_t line;
  98. bool except;
  99. for (line = 0; line < VDP_LINES_PER_FRAME; line++) {
  100. vdp_simulate_line(&gg->vdp);
  101. except = z80_do_cycles(&gg->cpu, CYCLES_PER_LINE);
  102. if (except)
  103. return true;
  104. }
  105. return false;
  106. }
  107. /*
  108. Simulate the GameGear.
  109. The GameGear must start out in an unpowered state; it will be powered only
  110. during the simulation. This function blocks until the simulation ends,
  111. either by an exception occurring or someone setting the GameGear's
  112. 'powered' flag to false.
  113. If a callback has been set with gamegear_set_callback(), then we'll trigger
  114. it after every frame has been simulated (sixty times per second).
  115. Exceptions can be retrieved after this call with gamegear_get_exception().
  116. If the simulation ended normally, then that function will return NULL.
  117. */
  118. void gamegear_simulate(GameGear *gg)
  119. {
  120. if (gg->powered)
  121. return;
  122. DEBUG("GameGear: powering on")
  123. power_on(gg);
  124. while (gg->powered) {
  125. uint64_t start = get_time_ns(), delta;
  126. if (simulate_frame(gg) || !gg->powered)
  127. break;
  128. if (gg->callback)
  129. gg->callback(gg);
  130. delta = get_time_ns() - start;
  131. if (delta < NS_PER_FRAME)
  132. usleep((NS_PER_FRAME - delta) / 1000);
  133. }
  134. DEBUG("GameGear: powering off")
  135. gamegear_power_off(gg);
  136. }
  137. /*
  138. If an exception flag has been set in the GameGear, return the reason.
  139. This function returns a const pointer to a buffer holding a human-readable
  140. exception string (although it may be cryptic to an end-user). The buffer is
  141. owned by the GameGear object and should not be freed - its contents last
  142. until the GameGear is powered on. If no exception flag is set, this
  143. function returns NULL.
  144. */
  145. const char* gamegear_get_exception(GameGear *gg)
  146. {
  147. if (!gg->exc_buffer[0]) {
  148. if (gg->cpu.except) {
  149. switch (gg->cpu.exc_code) {
  150. case Z80_EXC_NOT_POWERED:
  151. SET_EXC("CPU not powered")
  152. break;
  153. case Z80_EXC_UNIMPLEMENTED_OPCODE:
  154. SET_EXC("unimplemented opcode: 0x%02X", gg->cpu.exc_data)
  155. break;
  156. case Z80_EXC_IO_ERROR:
  157. SET_EXC("I/O error on port 0x%02X", gg->cpu.exc_data)
  158. break;
  159. default:
  160. SET_EXC("unknown exception")
  161. break;
  162. }
  163. } else {
  164. return NULL;
  165. }
  166. }
  167. return gg->exc_buffer;
  168. }
  169. /*
  170. @DEBUG_LEVEL
  171. Print out some state info to stdout: Z80 and VDP register values, etc.
  172. */
  173. void gamegear_print_state(const GameGear *gg)
  174. {
  175. z80_dump_registers(&gg->cpu);
  176. }