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.
 
 
 
 
 

191 lignes
5.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 <dirent.h>
  4. #include <errno.h>
  5. #include <stdbool.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sys/types.h>
  10. #include "src/errors.h"
  11. #include "src/rom.h"
  12. #include "src/version.h"
  13. #define ROMS_DIR "roms"
  14. /* Print command-line help/usage. */
  15. static void print_help(const char *arg1)
  16. {
  17. printf("%s [-h] [-v] [-f] [-s <n>] [<rom_path>] ...\n"
  18. "\n"
  19. "basic options:\n"
  20. " -h, --help show this help message and exit\n"
  21. " -v, --version show crater's version number and exit\n"
  22. " -f, --fullscreen enable fullscreen mode\n"
  23. " -s, --scale <n> scale the game screen by an integer factor\n"
  24. " (applies to windowed mode only)\n"
  25. " <rom_path> path to the rom file to execute; if not given, will look\n"
  26. " in the roms/ directory and prompt the user\n"
  27. "\n"
  28. "advanced options:\n"
  29. " -g, --debug display information about emulation state while running,\n"
  30. " including register and memory values; can also pause\n"
  31. " emulation, set breakpoints, and change state\n"
  32. " -a, --assemble <in> <out> convert z80 assembly source code into a\n"
  33. " binary file that can be run by crater\n"
  34. " -d, --disassemble <in> <out> convert a binary file into z80 assembly code\n",
  35. arg1);
  36. }
  37. /* Print crater's version. */
  38. static void print_version()
  39. {
  40. printf("crater %s\n", CRATER_VERSION);
  41. }
  42. /* Parse the command-line arguments for any special flags. */
  43. static void parse_args(int argc, char *argv[])
  44. {
  45. char *arg;
  46. int i;
  47. for (i = 1; i < argc; i++) {
  48. arg = argv[i];
  49. if (arg[0] != '-')
  50. continue;
  51. do
  52. arg++;
  53. while (arg[0] == '-');
  54. if (!strcmp(arg, "h") || !strcmp(arg, "help")) {
  55. print_help(argv[0]);
  56. exit(0);
  57. } else if (!strcmp(arg, "v") || !strcmp(arg, "version")) {
  58. print_version();
  59. exit(0);
  60. // f fullscreen
  61. // s scale
  62. // g debug
  63. // a assemble
  64. // d disassemble
  65. } else {
  66. FATAL("unknown argument: %s", argv[i])
  67. }
  68. }
  69. }
  70. /* Return whether the given string ends with the given suffix. */
  71. static bool ends_with(const char *input, const char *suffix)
  72. {
  73. size_t ilen = strlen(input), slen = strlen(suffix);
  74. if (ilen < slen)
  75. return false;
  76. return strcmp(input + (ilen - slen), suffix) == 0;
  77. }
  78. /* Load all potential ROM files in roms/ into a data structure. */
  79. static int get_rom_paths(char ***path_ptr)
  80. {
  81. DIR *dirp;
  82. struct dirent *entry;
  83. char **paths = NULL, *path;
  84. int psize = 8, npaths = 0;
  85. dirp = opendir(ROMS_DIR);
  86. if (dirp) {
  87. paths = malloc(sizeof(char*) * psize);
  88. if (!paths)
  89. OUT_OF_MEMORY()
  90. while ((entry = readdir(dirp))) {
  91. path = entry->d_name;
  92. if (ends_with(path, ".gg") || ends_with(path, ".bin")) {
  93. if (npaths >= psize) {
  94. paths = realloc(paths, sizeof(char*) * (psize *= 2));
  95. if (!paths)
  96. OUT_OF_MEMORY()
  97. }
  98. paths[npaths] = malloc(sizeof(char*) *
  99. (strlen(path) + strlen(ROMS_DIR) + 1));
  100. if (!paths[npaths])
  101. OUT_OF_MEMORY()
  102. strcpy(paths[npaths], ROMS_DIR "/");
  103. strcat(paths[npaths], path);
  104. npaths++;
  105. }
  106. }
  107. closedir(dirp);
  108. } else {
  109. WARN_ERRNO("couldn't open 'roms/'")
  110. }
  111. *path_ptr = paths;
  112. return npaths;
  113. }
  114. /* Find all potential ROM files in the roms/ directory, then ask the user which
  115. one they want to run. */
  116. static char* get_rom_path_from_user()
  117. {
  118. char **paths, *path, *input = NULL;
  119. int npaths, i;
  120. long int index;
  121. size_t size = 0;
  122. ssize_t len;
  123. npaths = get_rom_paths(&paths);
  124. for (i = 0; i < npaths; i++)
  125. printf("[%2d] %s\n", i + 1, paths[i]);
  126. if (npaths)
  127. printf("Enter a ROM number from above, or the path to a ROM image: ");
  128. else
  129. printf("Enter the path to a ROM image: ");
  130. len = getline(&input, &size, stdin);
  131. if (!input)
  132. OUT_OF_MEMORY()
  133. if (len > 0 && input[len - 1] == '\n')
  134. input[len - 1] = '\0';
  135. index = strtol(input, NULL, 10);
  136. if (index < 1 || index > npaths)
  137. path = input;
  138. else
  139. path = paths[index - 1];
  140. for (i = 0; i < npaths; i++) {
  141. if (paths[i] != path)
  142. free(paths[i]);
  143. }
  144. if (paths)
  145. free(paths);
  146. return path;
  147. }
  148. int main(int argc, char *argv[])
  149. {
  150. char *rom_path;
  151. rom_type *rom;
  152. parse_args(argc, argv);
  153. printf("crater: a Sega Game Gear emulator\n\n");
  154. rom_path = argc > 1 ? argv[1] : get_rom_path_from_user();
  155. if (rom_path[0] == '\0')
  156. FATAL("no image given")
  157. if (!(rom = rom_open(rom_path))) {
  158. if (errno == ENOMEM)
  159. OUT_OF_MEMORY()
  160. else
  161. FATAL_ERRNO("couldn't load ROM image '%s'", rom_path)
  162. }
  163. if (argc <= 1)
  164. free(rom_path);
  165. printf("Loaded ROM image: %s.\n", rom->name);
  166. // TODO: start from here
  167. rom_close(rom);
  168. return 0;
  169. }