An emulator, assembler, and disassembler for the Sega Game Gear
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 

166 lignes
4.0 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 <ctype.h>
  4. #include <errno.h>
  5. #include <stdbool.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sys/stat.h>
  10. #include "rom.h"
  11. #include "logging.h"
  12. #define NUM_LOCATIONS 3
  13. #define MAGIC_LEN 8
  14. #define HEADER_SIZE 16
  15. static size_t header_locations[NUM_LOCATIONS] = {0x7ff0, 0x1ff0, 0x3ff0};
  16. static const char header_magic[MAGIC_LEN + 1] = "TMR SEGA";
  17. /*
  18. Return whether or not the given ROM image size is valid.
  19. */
  20. static bool validate_size(off_t size)
  21. {
  22. if (size & (size - 1))
  23. return false; // Ensure size is a power of two
  24. off_t kbytes = size >> 10;
  25. return kbytes >= 8 && kbytes <= 1024;
  26. }
  27. #ifdef DEBUG_MODE
  28. /*
  29. DEBUG FUNCTION: Print out the header to stdout.
  30. */
  31. static void print_header(const char *header)
  32. {
  33. char header_hex[3 * HEADER_SIZE], header_chr[3 * HEADER_SIZE];
  34. for (int i = 0; i < HEADER_SIZE; i++) {
  35. snprintf(&header_hex[3 * i], 3, "%02x", header[i]);
  36. if (isprint(header[i]))
  37. snprintf(&header_chr[3 * i], 3, "%2c", header[i]);
  38. else {
  39. header_chr[3 * i] = ' ';
  40. header_chr[3 * i + 1] = '?';
  41. }
  42. header_hex[3 * i + 2] = header_chr[3 * i + 2] = ' ';
  43. }
  44. header_hex[3 * HEADER_SIZE - 1] = header_chr[3 * HEADER_SIZE - 1] = '\0';
  45. DEBUG("- header dump (hex): %s", header_hex)
  46. DEBUG("- header dump (chr): %s", header_chr)
  47. }
  48. #endif
  49. /*
  50. Read a ROM image's header, and return whether or not it is valid.
  51. */
  52. static bool read_header(ROM *rom)
  53. {
  54. size_t location, i;
  55. const char *header;
  56. DEBUG("- looking for header:")
  57. for (i = 0; i < NUM_LOCATIONS; i++) {
  58. location = header_locations[i];
  59. DEBUG(" - trying location 0x%zx:", location)
  60. header = &rom->data[location];
  61. if (memcmp(header, header_magic, MAGIC_LEN)) {
  62. DEBUG(" - magic not present")
  63. }
  64. else {
  65. DEBUG(" - magic found")
  66. #ifdef DEBUG_MODE
  67. print_header(header);
  68. #endif
  69. // TODO: parse header
  70. return true;
  71. }
  72. }
  73. DEBUG(" - could not find header")
  74. return false;
  75. }
  76. /*
  77. Create and load a ROM image located at the given path.
  78. rom_ptr will point to the new object if created successfully, and NULL will
  79. be returned. Otherwise, rom_ptr will not be modified and an error string
  80. will be returned. The error string should not be freed.
  81. */
  82. const char* rom_open(ROM **rom_ptr, const char *path)
  83. {
  84. ROM *rom;
  85. FILE* fp;
  86. struct stat st;
  87. if (!(fp = fopen(path, "r")))
  88. return strerror(errno);
  89. if (fstat(fileno(fp), &st)) {
  90. fclose(fp);
  91. return strerror(errno);
  92. }
  93. if (!(st.st_mode & S_IFREG)) {
  94. fclose(fp);
  95. return (st.st_mode & S_IFDIR) ? rom_err_isdir : rom_err_notfile;
  96. }
  97. if (!(rom = malloc(sizeof(ROM))))
  98. OUT_OF_MEMORY()
  99. // Set defaults:
  100. rom->name = NULL;
  101. rom->data = NULL;
  102. rom->size = 0;
  103. // Set rom->name:
  104. if (!(rom->name = malloc(sizeof(char) * (strlen(path) + 1))))
  105. OUT_OF_MEMORY()
  106. strcpy(rom->name, path);
  107. DEBUG("Loading ROM %s:", rom->name)
  108. // Set rom->size:
  109. DEBUG("- size: %lld", st.st_size)
  110. if (!validate_size(st.st_size)) {
  111. rom_close(rom);
  112. fclose(fp);
  113. return rom_err_badsize;
  114. }
  115. rom->size = st.st_size;
  116. // Set rom->data:
  117. if (!(rom->data = malloc(sizeof(char) * st.st_size)))
  118. OUT_OF_MEMORY()
  119. if (!(fread(rom->data, st.st_size, 1, fp))) {
  120. rom_close(rom);
  121. fclose(fp);
  122. return rom_err_badread;
  123. }
  124. fclose(fp);
  125. // Parse the header:
  126. if (!read_header(rom)) {
  127. rom_close(rom);
  128. return rom_err_badheader;
  129. }
  130. *rom_ptr = rom;
  131. return NULL;
  132. }
  133. /*
  134. Free a ROM object previously created with rom_open().
  135. */
  136. void rom_close(ROM *rom)
  137. {
  138. if (rom->name)
  139. free(rom->name);
  140. if (rom->data)
  141. free(rom->data);
  142. free(rom);
  143. }