An emulator, assembler, and disassembler for the Sega Game Gear
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 

200 rader
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 <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. inst->bytes[inst->loc.length - 2] = symbol->offset & 0xFF;
  79. inst->bytes[inst->loc.length - 1] = symbol->offset >> 8;
  80. free(inst->symbol);
  81. inst->symbol = NULL;
  82. }
  83. inst = inst->next;
  84. }
  85. return NULL;
  86. }
  87. /*
  88. Convert finalized ASMInstructions and ASMData into a binary data block.
  89. This function should never fail.
  90. */
  91. static void serialize_binary(AssemblerState *state, uint8_t *binary)
  92. {
  93. // TODO
  94. for (size_t i = 0; i < state->rom_size; i++)
  95. binary[i] = 'X';
  96. }
  97. /*
  98. Assemble the z80 source code in the source code buffer into binary data.
  99. If successful, return the size of the assembled binary data and change
  100. *binary_ptr to point to the assembled ROM data buffer. *binary_ptr must be
  101. free()'d when finished.
  102. If an error occurred, return 0 and update *ei_ptr to point to an ErrorInfo
  103. object which can be shown to the user with error_info_print(). The
  104. ErrorInfo object must be destroyed with error_info_destroy() when finished.
  105. In either case, only one of *binary_ptr and *ei_ptr is modified.
  106. */
  107. size_t assemble(const LineBuffer *source, uint8_t **binary_ptr, ErrorInfo **ei_ptr)
  108. {
  109. AssemblerState state;
  110. ErrorInfo *error_info;
  111. size_t retval = 0;
  112. state_init(&state);
  113. if ((error_info = preprocess(&state, source)))
  114. goto error;
  115. asm_symtable_init(&state.symtable);
  116. #ifdef DEBUG_MODE
  117. asm_lines_print(state.lines);
  118. #endif
  119. if ((error_info = tokenize(&state)))
  120. goto error;
  121. if ((error_info = resolve_defaults(&state)))
  122. goto error;
  123. if ((error_info = resolve_symbols(&state)))
  124. goto error;
  125. uint8_t *binary = malloc(sizeof(uint8_t) * state.rom_size);
  126. if (!binary)
  127. OUT_OF_MEMORY()
  128. serialize_binary(&state, binary);
  129. *binary_ptr = binary;
  130. retval = state.rom_size;
  131. goto cleanup;
  132. error:
  133. *ei_ptr = error_info;
  134. cleanup:
  135. state_free(&state);
  136. return retval;
  137. }
  138. /*
  139. Assemble the z80 source code at the input path into a binary file.
  140. Return true if the operation was a success and false if it was a failure.
  141. Errors are printed to STDOUT; if the operation was successful then nothing
  142. is printed.
  143. */
  144. bool assemble_file(const char *src_path, const char *dst_path)
  145. {
  146. LineBuffer *source = read_source_file(src_path, true);
  147. if (!source)
  148. return false;
  149. uint8_t *binary;
  150. ErrorInfo *error_info;
  151. size_t size = assemble(source, &binary, &error_info);
  152. line_buffer_free(source);
  153. if (!size) {
  154. error_info_print(error_info, stderr);
  155. error_info_destroy(error_info);
  156. return false;
  157. }
  158. bool success = write_binary_file(dst_path, binary, size);
  159. free(binary);
  160. return success;
  161. }