An emulator, assembler, and disassembler for the Sega Game Gear
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 

144 рядки
3.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 <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 BCD-encoded hexadecimal number to decimal.
  19. */
  20. uint8_t bcd_decode(uint8_t num)
  21. {
  22. return ((num >> 4) * 10) + (num & 0x0F);
  23. }
  24. /*
  25. Return monotonic time, in nanoseconds.
  26. */
  27. uint64_t get_time_ns()
  28. {
  29. #if defined __APPLE__
  30. static mach_timebase_info_data_t tb_info;
  31. if (tb_info.denom == 0)
  32. mach_timebase_info(&tb_info);
  33. // Apple's docs pretty much say "screw overflow" here...
  34. return mach_absolute_time() * tb_info.numer / tb_info.denom;
  35. #elif defined __linux__
  36. struct timespec spec;
  37. clock_gettime(CLOCK_MONOTONIC, &spec);
  38. return spec.tv_sec * NS_PER_SEC + spec.tv_nsec;
  39. #endif
  40. }
  41. /*
  42. Return the name of the region encoded by the given region code.
  43. The given code should not be larger than one nibble. NULL is returned if
  44. the region code is invalid.
  45. Region code information is taken from:
  46. http://www.smspower.org/Development/ROMHeader
  47. */
  48. const char* region_code_to_string(uint8_t code)
  49. {
  50. switch (code) {
  51. case 3: return "SMS Japan";
  52. case 4: return "SMS Export";
  53. case 5: return "GG Japan";
  54. case 6: return "GG Export";
  55. case 7: return "GG International";
  56. default: return NULL;
  57. }
  58. }
  59. /*
  60. Return the region code that encodes the given region name.
  61. 0 is returned if the name is not known. This is not a valid region code.
  62. */
  63. uint8_t region_string_to_code(const char *name)
  64. {
  65. if (!strncmp(name, "SMS ", 4)) {
  66. name += 4;
  67. if (!strcmp(name, "Japan"))
  68. return 3;
  69. if (!strcmp(name, "Export"))
  70. return 4;
  71. } else if (!strncmp(name, "GG ", 3)) {
  72. name += 3;
  73. if (!strcmp(name, "Japan"))
  74. return 5;
  75. if (!strcmp(name, "Export"))
  76. return 6;
  77. if (!strcmp(name, "International"))
  78. return 7;
  79. }
  80. return 0;
  81. }
  82. /*
  83. Return the number of bytes in a ROM image based on its header size code.
  84. 0 is returned if the code is invalid.
  85. */
  86. size_t size_code_to_bytes(uint8_t code)
  87. {
  88. #define KB << 10
  89. #define MB << 20
  90. switch (code) {
  91. case 0xA: return 8 KB;
  92. case 0xB: return 16 KB;
  93. case 0xC: return 32 KB;
  94. case 0xD: return 48 KB;
  95. case 0xE: return 64 KB;
  96. case 0xF: return 128 KB;
  97. case 0x0: return 256 KB;
  98. case 0x1: return 512 KB;
  99. case 0x2: return 1 MB;
  100. default: return 0;
  101. }
  102. #undef KB
  103. #undef MB
  104. }
  105. /*
  106. Given the number of bytes in a ROM image, return the size code.
  107. INVALID_SIZE_CODE is returned if the size is invalid.
  108. */
  109. uint8_t size_bytes_to_code(size_t bytes)
  110. {
  111. if (bytes & ((1 << 10) - 1))
  112. return 0; // Not an even number of KB
  113. switch (bytes >> 10) {
  114. case 8: return 0xA;
  115. case 16: return 0xB;
  116. case 32: return 0xC;
  117. case 48: return 0xD;
  118. case 64: return 0xE;
  119. case 128: return 0xF;
  120. case 256: return 0x0;
  121. case 512: return 0x1;
  122. case 1024: return 0x2;
  123. default: return INVALID_SIZE_CODE;
  124. }
  125. }