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.
 
 
 
 
 

181 lignes
4.7 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 <errno.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <sys/stat.h>
  8. #include "assembler.h"
  9. #include "logging.h"
  10. /*
  11. Deallocate a LineBuffer previously created with read_source_file().
  12. */
  13. static void free_line_buffer(LineBuffer *buffer)
  14. {
  15. for (size_t i = 0; i < buffer->length; i++)
  16. free(buffer->lines[i].data);
  17. free(buffer->lines);
  18. free(buffer);
  19. }
  20. /*
  21. Read the contents of the source file at the given path into a line buffer.
  22. Return the buffer if reading was successful; it must be freed with
  23. free_line_buffer() when done. Return NULL if an error occurred while
  24. reading. A message will be printed to stderr in this case.
  25. */
  26. static LineBuffer* read_source_file(const char *path)
  27. {
  28. FILE* fp;
  29. struct stat st;
  30. if (!(fp = fopen(path, "r"))) {
  31. ERROR_ERRNO("couldn't open source file")
  32. return NULL;
  33. }
  34. if (fstat(fileno(fp), &st)) {
  35. fclose(fp);
  36. ERROR_ERRNO("couldn't open source file")
  37. return NULL;
  38. }
  39. if (!(st.st_mode & S_IFREG)) {
  40. fclose(fp);
  41. ERROR("couldn't open source file: %s", st.st_mode & S_IFDIR ?
  42. "Is a directory" : "Is not a regular file")
  43. return NULL;
  44. }
  45. size_t capacity = 16;
  46. LineBuffer *source = malloc(sizeof(LineBuffer));
  47. if (!source)
  48. OUT_OF_MEMORY()
  49. source->length = 0;
  50. source->lines = malloc(sizeof(Line) * capacity);
  51. if (!source->lines)
  52. OUT_OF_MEMORY()
  53. while (1) {
  54. char *line = NULL;
  55. size_t lcap = 0;
  56. ssize_t len;
  57. if ((len = getline(&line, &lcap, fp)) < 0) {
  58. if (feof(fp))
  59. break;
  60. if (errno == ENOMEM)
  61. OUT_OF_MEMORY()
  62. ERROR_ERRNO("couldn't read source file")
  63. free_line_buffer(source);
  64. source = NULL;
  65. break;
  66. }
  67. if (capacity <= source->length + 1) {
  68. capacity <<= 2;
  69. source->lines = realloc(source->lines, sizeof(Line) * capacity);
  70. if (!source->lines)
  71. OUT_OF_MEMORY()
  72. }
  73. source->lines[source->length++] = (Line) {line, len};
  74. if (feof(fp)) {
  75. source->lines[source->length].length--;
  76. break;
  77. }
  78. }
  79. fclose(fp);
  80. return source;
  81. }
  82. /*
  83. Write an assembled binary file to the given path.
  84. Return whether the file was written successfully. On error, a message is
  85. printed to stderr.
  86. */
  87. static bool write_binary_file(const char *path, const uint8_t *data, size_t size)
  88. {
  89. // TODO
  90. return false;
  91. }
  92. /*
  93. Print an ErrorInfo object returned by assemble() to the given file.
  94. The same LineBuffer passed to assemble() should be passed to this function.
  95. Passing NULL if it is unavailable will still work, but source code snippets
  96. where errors were noted will not be printed.
  97. */
  98. void error_info_print(const ErrorInfo *error_info, FILE *file, const LineBuffer *source)
  99. {
  100. // TODO
  101. }
  102. /*
  103. Destroy an ErrorInfo object created by assemble().
  104. */
  105. void error_info_destroy(ErrorInfo *error_info)
  106. {
  107. if (!error_info)
  108. return;
  109. // TODO
  110. free(error_info);
  111. }
  112. /*
  113. Assemble the z80 source code in the source code buffer into binary data.
  114. If successful, return the size of the assembled binary data and change
  115. *binary_ptr to point to the assembled ROM data buffer. *binary_ptr must be
  116. free()'d when finished.
  117. If an error occurred, return 0 and update *ei_ptr to point to an ErrorInfo
  118. object which can be shown to the user with error_info_print(). The
  119. ErrorInfo object must be destroyed with error_info_destroy() when finished.
  120. In either case, only one of *binary_ptr and *ei_ptr is modified.
  121. */
  122. size_t assemble(const LineBuffer *source, uint8_t **binary_ptr, ErrorInfo **ei_ptr)
  123. {
  124. // TODO
  125. return 0;
  126. }
  127. /*
  128. Assemble the z80 source code at the input path into a binary file.
  129. Return true if the operation was a success and false if it was a failure.
  130. Errors are printed to STDOUT; if the operation was successful then nothing
  131. is printed.
  132. */
  133. bool assemble_file(const char *src_path, const char *dst_path)
  134. {
  135. LineBuffer *source = read_source_file(src_path);
  136. if (!source)
  137. return false;
  138. uint8_t *binary;
  139. ErrorInfo *error_info;
  140. size_t size = assemble(source, &binary, &error_info);
  141. if (!size) {
  142. error_info_print(error_info, stderr, source);
  143. error_info_destroy(error_info);
  144. free_line_buffer(source);
  145. return false;
  146. }
  147. bool success = write_binary_file(dst_path, binary, size);
  148. free(binary);
  149. free_line_buffer(source);
  150. return success;
  151. }