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.
 
 
 
 
 

317 lines
8.6 KiB

  1. /* Copyright (C) 2014-2017 Ben Kurtovic <ben.kurtovic@gmail.com>
  2. Released under the terms of the MIT License. See LICENSE for details. */
  3. #include <ctype.h>
  4. #include <errno.h>
  5. #include <stdio.h>
  6. #include <stdbool.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sys/stat.h>
  10. #include "rom.h"
  11. #include "logging.h"
  12. #include "util.h"
  13. #define NUM_LOCATIONS 3
  14. #define SIZE_CODE_BUF 8
  15. static size_t header_locations[NUM_LOCATIONS] = {0x7FF0, 0x3FF0, 0x1FF0};
  16. /*
  17. @DEBUG_LEVEL
  18. Given a ROM size, return a pretty string.
  19. */
  20. static const char* size_to_string(size_t size)
  21. {
  22. static char buffer[SIZE_CODE_BUF];
  23. if (!size)
  24. strncpy(buffer, "unknown", SIZE_CODE_BUF);
  25. else if (size >= (1 << 20))
  26. snprintf(buffer, SIZE_CODE_BUF, "%zu MB", size >> 20);
  27. else
  28. snprintf(buffer, SIZE_CODE_BUF, "%zu KB", size >> 10);
  29. return buffer;
  30. }
  31. /*
  32. @DEBUG_LEVEL
  33. Print out the raw header to stdout.
  34. */
  35. static void print_header_dump(const uint8_t *header)
  36. {
  37. char header_hex[3 * HEADER_SIZE], header_chr[3 * HEADER_SIZE];
  38. for (int i = 0; i < HEADER_SIZE; i++) {
  39. snprintf(&header_hex[3 * i], 3, "%02X", header[i]);
  40. if (isprint(header[i]))
  41. snprintf(&header_chr[3 * i], 3, "%2c", header[i]);
  42. else {
  43. header_chr[3 * i] = ' ';
  44. header_chr[3 * i + 1] = '.';
  45. }
  46. header_hex[3 * i + 2] = header_chr[3 * i + 2] = ' ';
  47. }
  48. header_hex[3 * HEADER_SIZE - 1] = header_chr[3 * HEADER_SIZE - 1] = '\0';
  49. DEBUG("- header dump (hex): %s", header_hex)
  50. DEBUG("- header dump (chr): %s", header_chr)
  51. }
  52. /*
  53. @DEBUG_LEVEL
  54. Print out the analyzed header to stdout.
  55. */
  56. static void print_header_contents(const ROM *rom)
  57. {
  58. DEBUG("- header info:")
  59. if (rom->reported_checksum == rom->expected_checksum)
  60. DEBUG(" - checksum: 0x%04X (valid)", rom->reported_checksum)
  61. else
  62. DEBUG(" - checksum: 0x%04X (invalid, expected 0x%04X)",
  63. rom->reported_checksum, rom->expected_checksum)
  64. DEBUG(" - product code: %u (%s)", rom->product_code,
  65. rom_product(rom) ? rom_product(rom) : "unknown")
  66. DEBUG(" - version: %u", rom->version)
  67. DEBUG(" - region code: %u (%s)", rom->region_code,
  68. rom_region(rom) ? rom_region(rom) : "unknown")
  69. DEBUG(" - reported size: %s",
  70. size_to_string(size_code_to_bytes(rom->declared_size)))
  71. }
  72. /*
  73. Parse a ROM image's header, and return whether or not it is valid.
  74. The header is 16 bytes long, consisting of:
  75. byte 0: magic ('T')
  76. byte 1: magic ('M')
  77. byte 2: magic ('R')
  78. byte 3: magic (' ')
  79. byte 4: magic ('S')
  80. byte 5: magic ('E')
  81. byte 6: magic ('G')
  82. byte 7: magic ('A')
  83. byte 8: unused
  84. byte 9: unused
  85. byte A: checksum (LSB)
  86. byte B: checksum (MSB)
  87. byte C: product code (LSB)
  88. byte D: product code (middle byte)
  89. byte E (hi nibble): product code (most-significant nibble)
  90. byte E (lo nibble): version
  91. byte F (hi nibble): region code
  92. byte F (lo nibble): ROM size
  93. (Based on: http://www.smspower.org/Development/ROMHeader)
  94. */
  95. static bool parse_header(ROM *rom, const uint8_t *header)
  96. {
  97. if (DEBUG_LEVEL)
  98. print_header_dump(header);
  99. rom->reported_checksum = header[0xA] + (header[0xB] << 8);
  100. rom->expected_checksum = compute_checksum(rom->data, rom->size, header[0xF]);
  101. rom->product_code = bcd_decode(header[0xC]) +
  102. (bcd_decode(header[0xD]) * 100) + ((header[0xE] >> 4) * 10000);
  103. rom->version = header[0xE] & 0x0F;
  104. rom->region_code = header[0xF] >> 4;
  105. rom->declared_size = header[0xF] & 0xF;
  106. if (DEBUG_LEVEL)
  107. print_header_contents(rom);
  108. return true;
  109. }
  110. /*
  111. Find and read a ROM image's header, and return whether or not it is valid.
  112. */
  113. static bool find_and_read_header(ROM *rom)
  114. {
  115. size_t location, i;
  116. const uint8_t *header;
  117. DEBUG("- looking for header:")
  118. for (i = 0; i < NUM_LOCATIONS; i++) {
  119. location = header_locations[i];
  120. if (location + HEADER_SIZE > rom->size) {
  121. DEBUG(" - skipping location 0x%zX, out of range", location)
  122. continue;
  123. }
  124. DEBUG(" - trying location 0x%zX:", location)
  125. header = &rom->data[location];
  126. if (memcmp(header, rom_header_magic, HEADER_MAGIC_LEN)) {
  127. DEBUG(" - magic not present")
  128. }
  129. else {
  130. DEBUG(" - magic found")
  131. rom->header_location = location;
  132. return parse_header(rom, header);
  133. }
  134. }
  135. DEBUG(" - couldn't find header")
  136. return false;
  137. }
  138. /*
  139. Load a ROM image located at the given path.
  140. NULL will be returned if the ROM is opened successfully. Otherwise, and an
  141. error string will be returned. The error string should not be freed.
  142. */
  143. const char* rom_open(ROM *rom, const char *path)
  144. {
  145. FILE *fp;
  146. struct stat st;
  147. if (!(fp = fopen(path, "rb")))
  148. return strerror(errno);
  149. if (fstat(fileno(fp), &st)) {
  150. fclose(fp);
  151. return strerror(errno);
  152. }
  153. if (!(st.st_mode & S_IFREG)) {
  154. fclose(fp);
  155. return (st.st_mode & S_IFDIR) ? rom_err_isdir : rom_err_notfile;
  156. }
  157. // Set defaults:
  158. rom->name = NULL;
  159. rom->data = NULL;
  160. rom->size = 0;
  161. rom->header_location = 0;
  162. rom->reported_checksum = 0;
  163. rom->expected_checksum = 0;
  164. rom->product_code = 0;
  165. rom->version = 0;
  166. rom->region_code = 0;
  167. rom->declared_size = 0;
  168. // Set rom->name:
  169. rom->name = cr_malloc(sizeof(char) * (strlen(path) + 1));
  170. strcpy(rom->name, path);
  171. DEBUG("Loading ROM %s:", rom->name)
  172. // Set rom->size:
  173. DEBUG("- size: %lld bytes (%s)", st.st_size, size_to_string(st.st_size))
  174. if (size_bytes_to_code(st.st_size) == INVALID_SIZE_CODE) {
  175. rom_close(rom);
  176. fclose(fp);
  177. return rom_err_badsize;
  178. }
  179. rom->size = st.st_size;
  180. // Set rom->data:
  181. rom->data = cr_malloc(sizeof(uint8_t) * st.st_size);
  182. if (!(fread(rom->data, st.st_size, 1, fp))) {
  183. rom_close(rom);
  184. fclose(fp);
  185. return rom_err_badread;
  186. }
  187. fclose(fp);
  188. // Parse the header:
  189. if (!find_and_read_header(rom)) {
  190. rom_close(rom);
  191. return rom_err_badheader;
  192. }
  193. if (rom->region_code == 3 || rom->region_code == 4) {
  194. // TODO: support SMS ROMs eventually?
  195. rom_close(rom);
  196. return rom_err_sms;
  197. }
  198. return NULL;
  199. }
  200. /*
  201. Free memory previously allocated by the ROM during rom_open().
  202. */
  203. void rom_close(ROM *rom)
  204. {
  205. free(rom->name);
  206. free(rom->data);
  207. }
  208. /*
  209. Return a string explanation of this ROM's product code.
  210. NULL is returned if the product code is not known.
  211. Information from: http://www.smspower.org/Development/ProductCodes
  212. */
  213. const char* rom_product(const ROM *rom)
  214. {
  215. uint32_t developer = rom->product_code / 1000;
  216. if (developer == 2)
  217. return "Sega of America";
  218. if (developer == 3)
  219. return "Sega of Japan";
  220. if (developer > 10 && developer < 160)
  221. return get_third_party_developer(developer);
  222. return NULL;
  223. }
  224. /*
  225. Return the region this ROM was intended for, based on header information.
  226. NULL is returned if the region code is invalid.
  227. */
  228. const char* rom_region(const ROM *rom)
  229. {
  230. return region_code_to_string(rom->region_code);
  231. }
  232. /*
  233. Open a BIOS ROM from the given path.
  234. Return a BIOS pointer if successful, or NULL on error. An error message
  235. will be printed. The BIOS must be deallocated with bios_close().
  236. */
  237. BIOS* bios_open(const char *path)
  238. {
  239. FILE *fp;
  240. struct stat st;
  241. if (!(fp = fopen(path, "rb"))) {
  242. ERROR("couldn't load BIOS '%s': fopen(): %s", path, strerror(errno));
  243. return NULL;
  244. }
  245. if (fstat(fileno(fp), &st)) {
  246. ERROR("couldn't load BIOS '%s': fstat(): %s", path, strerror(errno));
  247. fclose(fp);
  248. return NULL;
  249. }
  250. if (!(st.st_mode & S_IFREG)) {
  251. ERROR("couldn't load BIOS '%s': not a regular file", path);
  252. fclose(fp);
  253. return NULL;
  254. }
  255. if (st.st_size != BIOS_SIZE) {
  256. ERROR("couldn't load BIOS '%s': incorrect size", path);
  257. fclose(fp);
  258. return NULL;
  259. }
  260. BIOS *bios = cr_malloc(sizeof(BIOS));
  261. if (!(fread(bios->data, BIOS_SIZE, 1, fp))) {
  262. ERROR("couldn't load BIOS '%s': fread(): %s", path, strerror(errno));
  263. fclose(fp);
  264. bios_close(bios);
  265. return NULL;
  266. }
  267. fclose(fp);
  268. return bios;
  269. }
  270. /*
  271. Deallocate a BIOS object previously returned by bios_open().
  272. */
  273. void bios_close(BIOS *bios)
  274. {
  275. free(bios);
  276. }