An emulator, assembler, and disassembler for the Sega Game Gear
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 
 

206 rindas
5.4 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 "assembler.h"
  5. #include "assembler/errors.h"
  6. #include "assembler/io.h"
  7. #include "assembler/preprocessor.h"
  8. #include "assembler/state.h"
  9. #include "assembler/tokenizer.h"
  10. #include "logging.h"
  11. #include "rom.h"
  12. #include "util.h"
  13. /*
  14. Return the smallest ROM size that can contain the given address.
  15. This uses bit twiddling hacks up to the largest possible ROM size.
  16. */
  17. static size_t bounding_rom_size(size_t size)
  18. {
  19. size--;
  20. size |= size >> 1;
  21. size |= size >> 2;
  22. size |= size >> 4;
  23. size |= size >> 8;
  24. size |= size >> 16;
  25. size++;
  26. return size;
  27. }
  28. /*
  29. Resolve default placeholder values in assembler state, such as ROM size.
  30. On success, no new heap objects are allocated. On error, an ErrorInfo
  31. object is returned.
  32. */
  33. static ErrorInfo* resolve_defaults(AssemblerState *state)
  34. {
  35. if (!state->rom_size) {
  36. state->rom_size = ROM_SIZE_MIN;
  37. const ASMInstruction *inst = state->instructions;
  38. while (inst) {
  39. size_t bound = inst->loc.offset + inst->loc.length;
  40. if (bound > state->rom_size)
  41. state->rom_size = bounding_rom_size(bound);
  42. inst = inst->next;
  43. }
  44. const ASMData *data = state->data;
  45. while (data) {
  46. size_t bound = data->loc.offset + data->loc.length;
  47. if (bound > state->rom_size)
  48. state->rom_size = bounding_rom_size(bound);
  49. data = data->next;
  50. }
  51. if (state->header.rom_size != INVALID_SIZE_CODE) {
  52. size_t decl_size = size_code_to_bytes(state->header.rom_size);
  53. if (decl_size > state->rom_size)
  54. state->rom_size = decl_size;
  55. }
  56. }
  57. if (state->header.rom_size == INVALID_SIZE_CODE)
  58. state->header.rom_size = size_bytes_to_code(state->rom_size);
  59. return NULL;
  60. }
  61. /*
  62. Resolve symbol placeholders in instructions such as jumps and branches.
  63. On success, no new heap objects are allocated. On error, an ErrorInfo
  64. object is returned.
  65. */
  66. static ErrorInfo* resolve_symbols(AssemblerState *state)
  67. {
  68. ErrorInfo *ei;
  69. ASMInstruction *inst = state->instructions;
  70. const ASMSymbol *symbol;
  71. while (inst) {
  72. if (inst->symbol) {
  73. symbol = asm_symtable_find(state->symtable, inst->symbol);
  74. if (!symbol) {
  75. ei = error_info_create(inst->line, ET_SYMBOL, ED_SYM_NO_LABEL);
  76. return ei;
  77. }
  78. if (inst->loc.length == 3) {
  79. inst->b2 = symbol->offset & 0xFF;
  80. inst->b3 = symbol->offset >> 8;
  81. } else {
  82. inst->b3 = symbol->offset & 0xFF;
  83. inst->b4 = symbol->offset >> 8;
  84. }
  85. free(inst->symbol);
  86. inst->symbol = NULL;
  87. }
  88. inst = inst->next;
  89. }
  90. return NULL;
  91. }
  92. /*
  93. Convert finalized ASMInstructions and ASMData into a binary data block.
  94. This function should never fail.
  95. */
  96. static void serialize_binary(AssemblerState *state, uint8_t *binary)
  97. {
  98. // TODO
  99. for (size_t i = 0; i < state->rom_size; i++)
  100. binary[i] = 'X';
  101. }
  102. /*
  103. Assemble the z80 source code in the source code buffer into binary data.
  104. If successful, return the size of the assembled binary data and change
  105. *binary_ptr to point to the assembled ROM data buffer. *binary_ptr must be
  106. free()'d when finished.
  107. If an error occurred, return 0 and update *ei_ptr to point to an ErrorInfo
  108. object which can be shown to the user with error_info_print(). The
  109. ErrorInfo object must be destroyed with error_info_destroy() when finished.
  110. In either case, only one of *binary_ptr and *ei_ptr is modified.
  111. */
  112. size_t assemble(const LineBuffer *source, uint8_t **binary_ptr, ErrorInfo **ei_ptr)
  113. {
  114. AssemblerState state;
  115. ErrorInfo *error_info;
  116. size_t retval = 0;
  117. state_init(&state);
  118. if ((error_info = preprocess(&state, source)))
  119. goto error;
  120. asm_symtable_init(&state.symtable);
  121. #ifdef DEBUG_MODE
  122. asm_lines_print(state.lines);
  123. #endif
  124. if ((error_info = tokenize(&state)))
  125. goto error;
  126. if ((error_info = resolve_defaults(&state)))
  127. goto error;
  128. if ((error_info = resolve_symbols(&state)))
  129. goto error;
  130. uint8_t *binary = malloc(sizeof(uint8_t) * state.rom_size);
  131. if (!binary)
  132. OUT_OF_MEMORY()
  133. serialize_binary(&state, binary);
  134. *binary_ptr = binary;
  135. retval = state.rom_size;
  136. goto cleanup;
  137. error:
  138. *ei_ptr = error_info;
  139. cleanup:
  140. state_free(&state);
  141. return retval;
  142. }
  143. /*
  144. Assemble the z80 source code at the input path into a binary file.
  145. Return true if the operation was a success and false if it was a failure.
  146. Errors are printed to STDOUT; if the operation was successful then nothing
  147. is printed.
  148. */
  149. bool assemble_file(const char *src_path, const char *dst_path)
  150. {
  151. LineBuffer *source = read_source_file(src_path, true);
  152. if (!source)
  153. return false;
  154. uint8_t *binary;
  155. ErrorInfo *error_info;
  156. size_t size = assemble(source, &binary, &error_info);
  157. line_buffer_free(source);
  158. if (!size) {
  159. error_info_print(error_info, stderr);
  160. error_info_destroy(error_info);
  161. return false;
  162. }
  163. bool success = write_binary_file(dst_path, binary, size);
  164. free(binary);
  165. return success;
  166. }