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.
 
 
 
 
 

191 lines
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. }