An emulator, assembler, and disassembler for the Sega Game Gear
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 

191 linhas
5.2 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 the name of the region encoded by the given region code.
  50. The given code should not be larger than one nibble. NULL is returned if
  51. the region code is invalid.
  52. Region code information is taken from:
  53. http://www.smspower.org/Development/ROMHeader
  54. */
  55. const char* region_code_to_string(uint8_t code)
  56. {
  57. switch (code) {
  58. case 3: return "SMS Japan";
  59. case 4: return "SMS Export";
  60. case 5: return "GG Japan";
  61. case 6: return "GG Export";
  62. case 7: return "GG International";
  63. default: return NULL;
  64. }
  65. }
  66. /*
  67. Return the region code that encodes the given region name.
  68. 0 is returned if the name is not known. This is not a valid region code.
  69. */
  70. uint8_t region_string_to_code(const char *name)
  71. {
  72. if (!strncmp(name, "SMS ", 4)) {
  73. name += 4;
  74. if (!strcmp(name, "Japan"))
  75. return 3;
  76. if (!strcmp(name, "Export"))
  77. return 4;
  78. } else if (!strncmp(name, "GG ", 3)) {
  79. name += 3;
  80. if (!strcmp(name, "Japan"))
  81. return 5;
  82. if (!strcmp(name, "Export"))
  83. return 6;
  84. if (!strcmp(name, "International"))
  85. return 7;
  86. }
  87. return 0;
  88. }
  89. /*
  90. Return the number of bytes in a ROM image based on its header size code.
  91. 0 is returned if the code is invalid.
  92. */
  93. size_t size_code_to_bytes(uint8_t code)
  94. {
  95. #define KB << 10
  96. #define MB << 20
  97. switch (code) {
  98. case 0xA: return 8 KB;
  99. case 0xB: return 16 KB;
  100. case 0xC: return 32 KB;
  101. case 0xD: return 48 KB;
  102. case 0xE: return 64 KB;
  103. case 0xF: return 128 KB;
  104. case 0x0: return 256 KB;
  105. case 0x1: return 512 KB;
  106. case 0x2: return 1 MB;
  107. default: return 0;
  108. }
  109. #undef KB
  110. #undef MB
  111. }
  112. /*
  113. Given the number of bytes in a ROM image, return the size code.
  114. INVALID_SIZE_CODE is returned if the size is invalid.
  115. */
  116. uint8_t size_bytes_to_code(size_t bytes)
  117. {
  118. if (bytes & ((1 << 10) - 1))
  119. return INVALID_SIZE_CODE; // Not an even number of KB
  120. switch (bytes >> 10) {
  121. case 8: return 0xA;
  122. case 16: return 0xB;
  123. case 32: return 0xC;
  124. case 48: return 0xD;
  125. case 64: return 0xE;
  126. case 128: return 0xF;
  127. case 256: return 0x0;
  128. case 512: return 0x1;
  129. case 1024: return 0x2;
  130. default: return INVALID_SIZE_CODE;
  131. }
  132. }
  133. /*
  134. Compute a ROM data checksum.
  135. If the summable region (as specified by the range parameter) is too large
  136. (as specified by the size parameter), we'll compute the checksum over the
  137. default range (0x0000-0x7FF0), or the largest possible range. If size is
  138. zero, we will compute it over the given range regardless.
  139. */
  140. uint16_t compute_checksum(const uint8_t *data, size_t size, uint8_t range)
  141. {
  142. size_t low_region, high_region;
  143. switch (range & 0xF) {
  144. case 0xA: low_region = 0x1FEF; high_region = 0; break;
  145. case 0xB: low_region = 0x3FEF; high_region = 0; break;
  146. case 0xC: low_region = 0x7FEF; high_region = 0; break;
  147. case 0xD: low_region = 0xBFEF; high_region = 0; break;
  148. case 0xE: low_region = 0x7FEF; high_region = 0x0FFFF; break;
  149. case 0xF: low_region = 0x7FEF; high_region = 0x1FFFF; break;
  150. case 0x0: low_region = 0x7FEF; high_region = 0x3FFFF; break;
  151. case 0x1: low_region = 0x7FEF; high_region = 0x7FFFF; break;
  152. case 0x2: low_region = 0x7FEF; high_region = 0xFFFFF; break;
  153. default: low_region = 0x7FEF; high_region = 0; break;
  154. }
  155. if (size && low_region >= size)
  156. low_region = (size >= 0x4000) ? 0x3FEF : 0x1FEF;
  157. if (size && high_region >= size)
  158. high_region = 0;
  159. uint16_t sum = 0;
  160. for (size_t index = 0; index <= low_region; index++)
  161. sum += data[index];
  162. if (high_region) {
  163. for (size_t index = 0x08000; index <= high_region; index++)
  164. sum += data[index];
  165. }
  166. return sum;
  167. }