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.
 
 
 
 
 

256 lines
7.3 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 <string.h>
  5. #include "util.h"
  6. #if defined __APPLE__
  7. #include <mach/mach_time.h>
  8. #elif defined __linux__
  9. #include <time.h>
  10. #ifndef CLOCK_MONOTONIC
  11. #error "Unsupported operating system or compiler."
  12. #endif
  13. #else
  14. #error "Unsupported operating system or compiler."
  15. #endif
  16. #define NS_PER_SEC 1000000000
  17. /*
  18. Convert a decimal integer to BCD-encoded form.
  19. */
  20. uint8_t bcd_encode(uint8_t num)
  21. {
  22. return ((num / 10) << 4) | (num % 10);
  23. }
  24. /*
  25. Convert a BCD-encoded integer to decimal.
  26. */
  27. uint8_t bcd_decode(uint8_t num)
  28. {
  29. return ((num >> 4) * 10) + (num & 0x0F);
  30. }
  31. /*
  32. Return monotonic time, in nanoseconds.
  33. */
  34. uint64_t get_time_ns()
  35. {
  36. #if defined __APPLE__
  37. static mach_timebase_info_data_t tb_info;
  38. if (tb_info.denom == 0)
  39. mach_timebase_info(&tb_info);
  40. // Apple's docs pretty much say "screw overflow" here...
  41. return mach_absolute_time() * tb_info.numer / tb_info.denom;
  42. #elif defined __linux__
  43. struct timespec spec;
  44. clock_gettime(CLOCK_MONOTONIC, &spec);
  45. return spec.tv_sec * NS_PER_SEC + spec.tv_nsec;
  46. #endif
  47. }
  48. /*
  49. Return whether the given character is valid in a symbol (label, define).
  50. */
  51. bool is_valid_symbol_char(char c, bool first)
  52. {
  53. return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
  54. (!first && c >= '0' && c <= '9') || c == '_' || c == '.';
  55. }
  56. /*
  57. Return the name of the region encoded by the given region code.
  58. The given code should not be larger than one nibble. NULL is returned if
  59. the region code is invalid.
  60. Region code information is taken from:
  61. http://www.smspower.org/Development/ROMHeader
  62. */
  63. const char* region_code_to_string(uint8_t code)
  64. {
  65. switch (code) {
  66. case 3: return "SMS Japan";
  67. case 4: return "SMS Export";
  68. case 5: return "GG Japan";
  69. case 6: return "GG Export";
  70. case 7: return "GG International";
  71. default: return NULL;
  72. }
  73. }
  74. /*
  75. Return the region code that encodes the given region name.
  76. 0 is returned if the name is not known. This is not a valid region code.
  77. */
  78. uint8_t region_string_to_code(const char *name)
  79. {
  80. if (!strncmp(name, "SMS ", 4)) {
  81. name += 4;
  82. if (!strcmp(name, "Japan"))
  83. return 3;
  84. if (!strcmp(name, "Export"))
  85. return 4;
  86. } else if (!strncmp(name, "GG ", 3)) {
  87. name += 3;
  88. if (!strcmp(name, "Japan"))
  89. return 5;
  90. if (!strcmp(name, "Export"))
  91. return 6;
  92. if (!strcmp(name, "International"))
  93. return 7;
  94. }
  95. return 0;
  96. }
  97. /*
  98. Return the number of bytes in a ROM image based on its header size code.
  99. 0 is returned if the code is invalid.
  100. */
  101. size_t size_code_to_bytes(uint8_t code)
  102. {
  103. #define KB << 10
  104. #define MB << 20
  105. switch (code) {
  106. case 0xA: return 8 KB;
  107. case 0xB: return 16 KB;
  108. case 0xC: return 32 KB;
  109. case 0xD: return 48 KB;
  110. case 0xE: return 64 KB;
  111. case 0xF: return 128 KB;
  112. case 0x0: return 256 KB;
  113. case 0x1: return 512 KB;
  114. case 0x2: return 1 MB;
  115. default: return 0;
  116. }
  117. #undef KB
  118. #undef MB
  119. }
  120. /*
  121. Given the number of bytes in a ROM image, return the size code.
  122. INVALID_SIZE_CODE is returned if the size is invalid.
  123. */
  124. uint8_t size_bytes_to_code(size_t bytes)
  125. {
  126. if (bytes & ((1 << 10) - 1))
  127. return INVALID_SIZE_CODE; // Not an even number of KB
  128. switch (bytes >> 10) {
  129. case 8: return 0xA;
  130. case 16: return 0xB;
  131. case 32: return 0xC;
  132. case 48: return 0xD;
  133. case 64: return 0xE;
  134. case 128: return 0xF;
  135. case 256: return 0x0;
  136. case 512: return 0x1;
  137. case 1024: return 0x2;
  138. default: return INVALID_SIZE_CODE;
  139. }
  140. }
  141. /*
  142. Compute a ROM data checksum.
  143. If the summable region (as specified by the range parameter) is too large
  144. (as specified by the size parameter), we'll compute the checksum over the
  145. default range (0x0000-0x7FF0), or the largest possible range. If size is
  146. zero, we will compute it over the given range regardless.
  147. */
  148. uint16_t compute_checksum(const uint8_t *data, size_t size, uint8_t range)
  149. {
  150. size_t low_region, high_region;
  151. switch (range & 0xF) {
  152. case 0xA: low_region = 0x1FEF; high_region = 0; break;
  153. case 0xB: low_region = 0x3FEF; high_region = 0; break;
  154. case 0xC: low_region = 0x7FEF; high_region = 0; break;
  155. case 0xD: low_region = 0xBFEF; high_region = 0; break;
  156. case 0xE: low_region = 0x7FEF; high_region = 0x0FFFF; break;
  157. case 0xF: low_region = 0x7FEF; high_region = 0x1FFFF; break;
  158. case 0x0: low_region = 0x7FEF; high_region = 0x3FFFF; break;
  159. case 0x1: low_region = 0x7FEF; high_region = 0x7FFFF; break;
  160. case 0x2: low_region = 0x7FEF; high_region = 0xFFFFF; break;
  161. default: low_region = 0x7FEF; high_region = 0; break;
  162. }
  163. if (size && low_region >= size)
  164. low_region = (size >= 0x4000) ? 0x3FEF : 0x1FEF;
  165. if (size && high_region >= size)
  166. high_region = 0;
  167. uint16_t sum = 0;
  168. for (size_t index = 0; index <= low_region; index++)
  169. sum += data[index];
  170. if (high_region) {
  171. for (size_t index = 0x08000; index <= high_region; index++)
  172. sum += data[index];
  173. }
  174. return sum;
  175. }
  176. /*
  177. Return the name of the third-party developer identified by the given code.
  178. This method is imprecise and should not be relied on. NULL is returned if
  179. the developer is unknown.
  180. Information from (with modifications):
  181. http://www.smspower.org/Development/ProductCodes
  182. */
  183. const char* get_third_party_developer(uint8_t code)
  184. {
  185. switch (code) {
  186. case 11: return "Taito";
  187. case 14: return "Namco";
  188. case 15: return "SunSoft";
  189. case 22: return "Micronet";
  190. case 23: return "Vic Tokai";
  191. case 25: return "NCS";
  192. case 26: return "Sigma Enterprises";
  193. case 28: return "Genki";
  194. case 32: return "Wolf Team";
  195. case 33: return "Kaneko";
  196. case 44: return "Sanritsu/SIMS";
  197. case 45: return "Game Arts/Studio Alex";
  198. case 48: return "Tengen/Time Warner";
  199. case 49: return "Telenet Japan";
  200. case 50: return "EA";
  201. case 51: return "SystemSoft";
  202. case 52: return "Microcabin";
  203. case 53: return "Riverhillsoft";
  204. case 54: return "ASCII Corporation";
  205. case 60: return "Victor/Loriciel/Infogrames";
  206. case 65: return "Toei Animation";
  207. case 66: return "Compile";
  208. case 68: return "GRI";
  209. case 70: return "Virgin";
  210. case 79: return "U.S. Gold";
  211. case 81: return "Acclaim";
  212. case 83: return "GameTek";
  213. case 87: return "Mindscape";
  214. case 88: return "Domark";
  215. case 93: return "Sony";
  216. case 100: return "THQ";
  217. case 103: return "SNK";
  218. case 104: return "MicroProse";
  219. case 112: return "Disney";
  220. case 125: return "Beam Software";
  221. case 133: return "Bandai";
  222. case 139: return "Viacom";
  223. case 149: return "Infocom/Gremlin";
  224. case 151: return "Infogrames";
  225. case 154: return "Technos Japan";
  226. default: return NULL;
  227. }
  228. }