static uint16_t if_define_replace(bstring define) { // Search through all of the defines to find one where // the name matches. size_t i = 0; match_t* match; struct expr* tree; for (i = 0; i < list_size(&replace_state->handlers); i++) { match = list_get_at(&replace_state->handlers, i); if (biseq(match->text.ref, define)) { // Found a match. tree = expr_parse(match->userdata); if (tree == NULL) dhalt(ERR_PP_DEFINE_NOT_EXPRESSION, ppimpl_get_location(replace_state)); return expr_evaluate(tree, &if_define_replace, &dhalt_expression_exit_handler); } } dhalt(ERR_PP_DEFINE_NOT_FOUND, ppimpl_get_location(replace_state)); return 0; }
static void if_handle(state_t* state, match_t* match, bool* reprocess) { list_t* result = ppparam_get(state); struct expr* expr = NULL; uint16_t value; bstring output; bool stopped_at_else; // Ensure the parameter format is correct. if (list_size(result) == 1 && ((parameter_t*)list_get_at(result, 0))->type == EXPRESSION) { // Get the expression. expr = ((parameter_t*)list_get_at(result, 0))->expr; replace_state = state; value = expr_evaluate(expr, &if_define_replace, &dhalt_expression_exit_handler); replace_state = NULL; if (value) { output = skip_to_endif(state, true, &stopped_at_else); if (stopped_at_else) skip_to_endif(state, false, &stopped_at_else); } else { bassigncstr(output, ""); skip_to_endif(state, true, &stopped_at_else); if (stopped_at_else) { output = skip_to_endif(state, false, &stopped_at_else); } } // print the output to the pre processor input ppimpl_printf(state, "%s", output->data); } else dhalt(ERR_PP_ASM_IF_PARAMETERS_INCORRECT, ppimpl_get_location(state)); ppparam_free(result); }
struct process_parameter_results process_register(struct ast_node_register* param) { struct process_parameter_results result; struct register_mapping* registr; if (param->bracketed) printd(LEVEL_VERBOSE, "[%s]", param->value); else printd(LEVEL_VERBOSE, "%s", param->value); registr = get_register_by_name(param->value, param->bracketed); if (registr == NULL) { // Must be a label. result.v = 0x0; result.v_extra = 0x0; result.v_extra_used = false; result.v_label = param->value; result.v_label_bracketed = param->bracketed; result.v_raw = NULL; } else if (registr->value == BRACKETS_UNSUPPORTED) { // Attempt to use a register in brackets that can't be. printd(LEVEL_VERBOSE, "\n"); dhalt(ERR_BRACKETED_REGISTER_UNSUPPORTED, param->value); } else { // Must be a register. result.v = registr->value; result.v_extra = 0x0; result.v_extra_used = false; result.v_label = NULL; result.v_label_bracketed = false; result.v_raw = NULL; } return result; }
void* dtemu_create_context(const char* title, int width, int height, bool resizeable, void* ud) { GLFWwindow* context = malloc(sizeof(GLFWwindow)); if (!resizeable) glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); *context = (GLFWwindow) glfwCreateWindow(width, height, GLFW_WINDOWED, title, NULL); if (*context == NULL) dhalt(ERR_COULD_NOT_CREATE_OPENGL_CONTEXT, "glfwCreateWindow returned NULL."); glfwSetWindowUserPointer(*context, ud); glfwMakeContextCurrent(*context); glfwSetWindowCloseCallback(&vm_hw_glfw_close_window_callback); glfwSetWindowSizeCallback(&vm_hw_glfw_resize_window_callback); glfwSwapInterval(0); glfwSetTime(0.0); return context; }
int main(int argc, char* argv[]) { // Define our variables. int nerrors, i; int32_t saved = 0; // The number of words saved during compression and optimization. struct errinfo* errval; const char* prepend = "error: "; const char* warnprefix = "no-"; int msglen; char* msg; int target; // Define arguments. struct arg_lit* show_help = arg_lit0("h", "help", "Show this help."); struct arg_str* target_arg = arg_str0("l", "link-as", "target", "Link as the specified object, can be 'image', 'static' or 'kernel'."); struct arg_file* symbol_file = arg_file0("s", "symbols", "<file>", "Produce a combined symbol file (~triples memory usage!)."); struct arg_str* symbol_ext = arg_str0(NULL, "symbol-extension", "ext", "When -s is used, specifies the extension for symbol files. Defaults to \"dsym16\"."); struct arg_file* input_files = arg_filen(NULL, NULL, "<file>", 1, 100, "The input object files."); struct arg_file* output_file = arg_file1("o", "output", "<file>", "The output file (or - to send to standard output)."); struct arg_file* kernel_file = arg_file0("k", "kernel", "<file>", "Directly link in the specified kernel."); struct arg_file* jumplist_file = arg_file0("j", "jumplist", "<file>", "Link against the specified jumplist."); struct arg_str* warning_policies = arg_strn("W", NULL, "policy", 0, _WARN_COUNT * 2 + 10, "Modify warning policies."); struct arg_lit* keep_output_arg = arg_lit0(NULL, "keep-outputs", "Keep the .OUTPUT entries in the final static library (used for stdlib)."); struct arg_lit* little_endian_mode = arg_lit0(NULL, "little-endian", "Use little endian serialization (for compatibility with older versions)."); struct arg_lit* no_short_literals_arg = arg_lit0(NULL, "no-short-literals", "Do not compress literals to short literals."); struct arg_int* opt_level = arg_int0("O", NULL, "<level>", "The optimization level."); struct arg_lit* opt_mode = arg_lit0("S", NULL, "Favour runtime speed over size when optimizing."); struct arg_lit* verbose = arg_litn("v", NULL, 0, LEVEL_EVERYTHING - LEVEL_DEFAULT, "Increase verbosity."); struct arg_lit* quiet = arg_litn("q", NULL, 0, LEVEL_DEFAULT - LEVEL_SILENT, "Decrease verbosity."); struct arg_end* end = arg_end(20); void* argtable[] = { show_help, target_arg, keep_output_arg, little_endian_mode, opt_level, opt_mode, no_short_literals_arg, symbol_ext, symbol_file, kernel_file, jumplist_file, warning_policies, output_file, input_files, verbose, quiet, end }; // Parse arguments. nerrors = arg_parse(argc, argv, argtable); version_print(bautofree(bfromcstr("Linker"))); if (nerrors != 0 || show_help->count != 0) { if (show_help->count != 0) arg_print_errors(stdout, end, "linker"); printd(LEVEL_DEFAULT, "syntax:\n dtld"); arg_print_syntax(stderr, argtable, "\n"); printd(LEVEL_DEFAULT, "options:\n"); arg_print_glossary(stderr, argtable, " %-25s %s\n"); arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); return 1; } // Set verbosity level. debug_setlevel(LEVEL_DEFAULT + verbose->count - quiet->count); // Set global path variable. osutil_setarg0(bautofree(bfromcstr(argv[0]))); // Set endianness. isetmode(little_endian_mode->count == 0 ? IMODE_BIG : IMODE_LITTLE); // Set up warning policies. dsetwarnpolicy(warning_policies); // Set up error handling. if (dsethalt()) { errval = derrinfo(); // FIXME: Use bstrings here. msglen = strlen(derrstr[errval->errid]) + strlen(prepend) + 1; msg = malloc(msglen); memset(msg, '\0', msglen); strcat(msg, prepend); strcat(msg, derrstr[errval->errid]); printd(LEVEL_ERROR, msg, errval->errdata); // Handle the error. printd(LEVEL_ERROR, "linker: error occurred.\n"); arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); return 1; } // Check to make sure target is correct. if (target_arg->count == 0) target = IMAGE_APPLICATION; else { if (strcmp(target_arg->sval[0], "image") == 0) target = IMAGE_APPLICATION; else if (strcmp(target_arg->sval[0], "static") == 0) target = IMAGE_STATIC_LIBRARY; else if (strcmp(target_arg->sval[0], "kernel") == 0) target = IMAGE_KERNEL; else { // Invalid option. dhalt(ERR_INVALID_TARGET_NAME, NULL); } } // Load all passed objects and use linker bin system to // produce result. bins_init(); for (i = 0; i < input_files->count; i++) if (!bins_load(bautofree(bfromcstr(input_files->filename[i])), symbol_file->count > 0, (symbol_file->count > 0 && symbol_ext->count > 0) ? symbol_ext->sval[0] : "dsym16")) // Failed to load one of the input files. dhalt(ERR_BIN_LOAD_FAILED, input_files->filename[i]); bins_associate(); bins_sectionize(); bins_flatten(bautofree(bfromcstr("output"))); if (target == IMAGE_KERNEL) bins_write_jump(); saved = bins_optimize( opt_mode->count == 0 ? OPTIMIZE_SIZE : OPTIMIZE_SPEED, opt_level->count == 0 ? OPTIMIZE_NONE : opt_level->ival[0]); if (no_short_literals_arg->count == 0 && target != IMAGE_STATIC_LIBRARY) saved += bins_compress(); else if (no_short_literals_arg->count == 0) dwarn(WARN_SKIPPING_SHORT_LITERALS_TYPE, NULL); else dwarn(WARN_SKIPPING_SHORT_LITERALS_REQUEST, NULL); bins_resolve( target == IMAGE_STATIC_LIBRARY, target == IMAGE_STATIC_LIBRARY); bins_save( bautofree(bfromcstr("output")), bautofree(bfromcstr(output_file->filename[0])), target, keep_output_arg->count > 0, symbol_file->count > 0 ? symbol_file->filename[0] : NULL, jumplist_file->count > 0 ? jumplist_file->filename[0] : NULL); bins_free(); if (saved > 0) printd(LEVEL_DEFAULT, "linker: saved %i words during optimization.\n", saved); else if (saved < 0) printd(LEVEL_DEFAULT, "linker: increased by %i words during optimization.\n", -saved); arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); return 0; }
static void macro_handle(state_t* state, match_t* match, bool* reprocess) { bstring name; bstring temp; list_t parameters; list_t arguments; bool getting_name = true; bool getting_parameters = false; bool getting_arguments = false; struct replace_info* info = match->userdata; int i = 0; int argument_brackets = 0; char c; char* start_loc; match_t* new_match; struct replace_info* new_info; // Parse the parameters out of the name. list_init(¶meters); temp = bfromcstr(""); for (i = 0; i < blength(info->full); i++) { c = info->full->data[i]; if (getting_name) { if (c == '(') { getting_name = false; getting_parameters = true; name = bstrcpy(temp); bassigncstr(temp, ""); } else bconchar(temp, c); } else if (getting_parameters) { if (c == ',' || c == ')') { btrimws(temp); list_append(¶meters, bstrcpy(temp)); bassigncstr(temp, ""); if (c == ')') { getting_parameters = false; break; } } else bconchar(temp, c); } } // Attempt to accept an open bracket. c = ppimpl_get_input(state); while (c == '\1') { // Consume macro termination. i = 0; while (i < strlen("\1MACROTERMINATE\1")) { if (c != "\1MACROTERMINATE\1"[i++]) dhalt(ERR_PP_EXPECTED_OPEN_BRACKET, ppimpl_get_location(state)); c = ppimpl_get_input(state); } ppimpl_pop_scope(state); } if (c != '(') dhalt(ERR_PP_EXPECTED_OPEN_BRACKET, ppimpl_get_location(state)); // Read arguments. getting_arguments = true; list_init(&arguments); start_loc = ppimpl_get_location(state); bassigncstr(temp, ""); while (ppimpl_has_input(state) && getting_arguments) { c = ppimpl_get_input(state); if (c == '(') { argument_brackets++; bconchar(temp, c); } else if (c == ')' && argument_brackets != 0) { argument_brackets--; bconchar(temp, c); } else if (c == ')' && argument_brackets == 0) { list_append(&arguments, bstrcpy(temp)); bassigncstr(temp, ""); getting_arguments = false; break; } else if (c == ',' && argument_brackets == 0) { list_append(&arguments, bstrcpy(temp)); bassigncstr(temp, ""); } else bconchar(temp, c); } if (getting_arguments) dhalt(ERR_PP_NO_TERMINATING_BRACKET, start_loc); // Check to see if the argument count is correct. if (list_size(&arguments) > list_size(¶meters)) dhalt(ERR_PP_TOO_MANY_PARAMETERS, start_loc); else if (list_size(&arguments) < list_size(¶meters)) dhalt(ERR_PP_NOT_ENOUGH_PARAMETERS, start_loc); free(start_loc); // Create a new scope for macro evaluation. ppimpl_push_scope(state, true); // Define the new handlers. for (i = 0; i < list_size(¶meters); i++) { new_info = malloc(sizeof(struct replace_info)); new_info->full = list_get_at(¶meters, i); new_info->replacement = list_get_at(&arguments, i); if (biseq(new_info->full, new_info->replacement)) { free(new_info); continue; } new_match = malloc(sizeof(match_t)); new_match->text = bautofree(list_get_at(¶meters, i)); new_match->handler = replace_handle; new_match->line_start_only = false; new_match->identifier_only = true; new_match->userdata = new_info; new_match->case_insensitive = false; ppimpl_register(state, new_match); } // Print out the macro evaluation and terminator. ppimpl_printf(state, "%s\1MACROTERMINATE\1", info->replacement->data); }
static void define_handle(state_t* state, match_t* match, bool* reprocess) { // We need to parse this manually because we're interested in getting // the first word and then all of the content until a line that doesn't end // with "\". bstring name = bfromcstr(""); bstring word = bfromcstr(""); bstring definition = bfromcstr(""); bool getting_word = true; bool getting_definition = true; bool is_macro = false; match_t* new_match; struct replace_info* info; // Get the first word. while (getting_word) { char c = ppimpl_get_input(state); bconchar(word, c); if (!is_macro && c != '(') bconchar(name, c); bltrimws(word); // Handle termination. if (blength(word) > 0 && (c == ' ' || c == '\t') && !is_macro) { // End of word. btrimws(word); btrimws(name); getting_word = false; } else if (blength(word) > 0 && c == '(' && !is_macro) { // Start of macro. is_macro = true; } else if (blength(word) > 0 && c == '(' && is_macro) { // Second ( in a macro; error. dhalt(ERR_PP_MACRO_MALFORMED, ppimpl_get_location(state)); } else if (blength(word) > 0 && c == ')' && is_macro) { // End of macro name. btrimws(word); btrimws(name); getting_word = false; } else if (blength(word) == 0 && c == '\n') dhalt(ERR_PP_C_DEFINE_PARAMETERS_INCORRECT, ppimpl_get_location(state)); else if (blength(word) > 0 && c == '\n') { // End of word. btrimws(word); btrimws(name); getting_word = false; getting_definition = false; ppimpl_printf(state, "\n"); } } // Get the definition. while (getting_definition) { char c = ppimpl_get_input(state); bconchar(definition, c); bltrimws(definition); if (c == '\n') { if (blength(definition) > 1 && definition->data[blength(definition) - 2] == '\\') { // Remove the new slash. bdelete(definition, blength(definition) - 2, 1); ppimpl_oprintf(state, "\n"); } else { btrimws(definition); getting_definition = false; ppimpl_printf(state, "\n"); } } else if (c == '/' || c == '*') { if (blength(definition) > 1 && definition->data[blength(definition) - 2] == '/') { // a line or block comment ppimpl_iprintf(state, "/%c", c); // remove the slashes bdelete(definition, blength(definition) - 2, 2); btrimws(definition); getting_definition = false; } } } if (blength(definition) == 0 && !is_macro) bassigncstr(definition, "1"); // Create the new replacement handler. info = malloc(sizeof(struct replace_info)); info->full = word; info->replacement = definition; if (biseq(info->full, info->replacement)) { free(info); return; } new_match = malloc(sizeof(match_t)); new_match->text = bautofree(name); if (is_macro) new_match->handler = macro_handle; else new_match->handler = replace_handle; new_match->line_start_only = false; new_match->identifier_only = true; new_match->userdata = info; new_match->case_insensitive = false; ppimpl_register(state, new_match); *reprocess = true; }
int main(int argc, char* argv[]) { // Define our variables. FILE* load; uint16_t flash[0x10000]; char leading[0x100]; unsigned int i; bool uread = true; vm_t* vm; int nerrors; bstring ss, st; host_context_t* dtemu = malloc(sizeof(host_context_t)); const char* warnprefix = "no-"; // Define arguments. struct arg_lit* show_help = arg_lit0("h", "help", "Show this help."); struct arg_file* input_file = arg_file1(NULL, NULL, "<file>", "The input file, or - to read from standard input."); struct arg_file* execution_dump_file = arg_file0("e", "execution-dump", "<file>", "Produce a very large execution dump file."); struct arg_lit* debug_mode = arg_lit0("d", "debug", "Show each executed instruction."); struct arg_lit* terminate_mode = arg_lit0("t", "show-on-terminate", "Show state of machine when program is terminated."); struct arg_lit* headless_mode = arg_lit0("h", "headless", "Run machine witout displaying monitor and SPED output"); struct arg_lit* legacy_mode = arg_lit0("l", "legacy", "Automatically initialize hardware to legacy values."); struct arg_str* warning_policies = arg_strn("W", NULL, "policy", 0, _WARN_COUNT * 2 + 10, "Modify warning policies."); struct arg_lit* little_endian_mode = arg_lit0(NULL, "little-endian", "Use little endian serialization (for compatibility with older versions)."); struct arg_lit* verbose = arg_litn("v", NULL, 0, LEVEL_EVERYTHING - LEVEL_DEFAULT, "Increase verbosity."); struct arg_lit* quiet = arg_litn("q", NULL, 0, LEVEL_DEFAULT - LEVEL_SILENT, "Decrease verbosity."); struct arg_int* radiation = arg_intn("r", NULL, "<n>", 0, 1, "Radiation factor (higher is less radiation)"); struct arg_lit* catch_fire = arg_lit0("c", "catch-fire", "The virtual machine should catch fire instead of halting."); struct arg_end* end = arg_end(20); void* argtable[] = { input_file, warning_policies, debug_mode, execution_dump_file, terminate_mode, headless_mode, legacy_mode, little_endian_mode, radiation, catch_fire, verbose, quiet, end }; // Parse arguments. nerrors = arg_parse(argc, argv, argtable); if (nerrors != 0 || show_help->count != 0) { if (show_help->count != 0) arg_print_errors(stdout, end, "emulator"); printd(LEVEL_DEFAULT, "syntax:\n dtemu"); arg_print_syntax(stderr, argtable, "\n"); printd(LEVEL_DEFAULT, "options:\n"); arg_print_glossary(stderr, argtable, " %-25s %s\n"); arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); return 1; } // Set verbosity level. debug_setlevel(LEVEL_DEFAULT + verbose->count - quiet->count); // Show version information. version_print(bautofree(bfromcstr("Emulator"))); // Set global path variable. osutil_setarg0(bautofree(bfromcstr(argv[0]))); // Set endianness. isetmode(little_endian_mode->count == 0 ? IMODE_BIG : IMODE_LITTLE); // Set up warning policies. dsetwarnpolicy(warning_policies); // Set up error handling. if (dsethalt()) { // Handle the error. dautohandle(); printd(LEVEL_ERROR, "emulator: error occurred.\n"); arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); return 1; } // Zero out the flash space. for (i = 0; i < 0x10000; i++) flash[i] = 0x0; // Zero out the leading space. for (i = 0; i < 0x100; i++) leading[i] = 0x0; // Load from either file or stdin. if (strcmp(input_file->filename[0], "-") != 0) { // Open file. load = fopen(input_file->filename[0], "rb"); if (load == NULL) dhalt(ERR_EMU_LOAD_FILE_FAILED, input_file->filename[0]); } else { // Windows needs stdin in binary mode. #ifdef _WIN32 _setmode(_fileno(stdin), _O_BINARY); #endif // Set load to stdin. load = stdin; } // Read leading component. for (i = 0; i < strlen(ldata_objfmt); i++) leading[i] = fgetc(load); fseek(load, 0, SEEK_SET); // Read up to 0x10000 words. for (i = 0; i < 0x10000 && !feof(load); i++) iread(&flash[i], load); fclose(load); // Check to see if the first X bytes matches the header // for intermediate code and stop if it does. ss = bfromcstr(""); st = bfromcstr(ldata_objfmt); for (i = 0; i < strlen(ldata_objfmt); i++) bconchar(ss, leading[i]); if (biseq(ss, st)) dhalt(ERR_INTERMEDIATE_EXECUTION, NULL); // Set up the host context. glfwInit(); dtemu->create_context = &dtemu_create_context; dtemu->activate_context = &dtemu_activate_context; dtemu->swap_buffers = &dtemu_swap_buffers; dtemu->destroy_context = &dtemu_destroy_context; dtemu->get_ud = &dtemu_get_ud; // And then use the VM. vm = vm_create(); vm->debug = (debug_mode->count > 0); vm_flash(vm, flash); // Set radiation and catch fire settings. if (radiation->count == 1) vm->radiation_factor = radiation->ival[0]; if (catch_fire->count == 1) vm->can_fire = true; // Init hardware. vm_hw_clock_init(vm); if (headless_mode->count < 1) vm->host = dtemu; vm_hw_sped3_init(vm); vm_hw_lem1802_init(vm); vm_hw_m35fd_init(vm); vm_hw_lua_init(vm); if (legacy_mode->count > 0) { for (i = 0; i < vm_hw_count(vm); i++) { hw_t* device = vm_hw_get_device(vm, i); if (device == NULL) continue; if (device->id == 0x7349F615 && device->manufacturer == 0x1C6C8B36) { vm_hw_lem1802_mem_set_screen((struct lem1802_hardware*)device->userdata, 0x8000); break; } } } vm_execute(vm, execution_dump_file->count > 0 ? execution_dump_file->filename[0] : NULL); if (terminate_mode->count > 0) { fprintf(stderr, "\n"); fprintf(stderr, "A: 0x%04X [A]: 0x%04X\n", vm->registers[REG_A], vm->ram[vm->registers[REG_A]]); fprintf(stderr, "B: 0x%04X [B]: 0x%04X\n", vm->registers[REG_B], vm->ram[vm->registers[REG_B]]); fprintf(stderr, "C: 0x%04X [C]: 0x%04X\n", vm->registers[REG_C], vm->ram[vm->registers[REG_C]]); fprintf(stderr, "X: 0x%04X [X]: 0x%04X\n", vm->registers[REG_X], vm->ram[vm->registers[REG_X]]); fprintf(stderr, "Y: 0x%04X [Y]: 0x%04X\n", vm->registers[REG_Y], vm->ram[vm->registers[REG_Y]]); fprintf(stderr, "Z: 0x%04X [Z]: 0x%04X\n", vm->registers[REG_Z], vm->ram[vm->registers[REG_Z]]); fprintf(stderr, "I: 0x%04X [I]: 0x%04X\n", vm->registers[REG_I], vm->ram[vm->registers[REG_I]]); fprintf(stderr, "J: 0x%04X [J]: 0x%04X\n", vm->registers[REG_J], vm->ram[vm->registers[REG_J]]); fprintf(stderr, "PC: 0x%04X SP: 0x%04X\n", vm->pc, vm->sp); fprintf(stderr, "EX: 0x%04X IA: 0x%04X\n", vm->ex, vm->ia); } vm_hw_lua_free(vm); vm_free(vm); arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); glfwTerminate(); return 0; }
void process_line(struct ast_node_line* line) { struct instruction_mapping* insttype; struct process_parameters_results ppresults; struct process_parameter_results dparam; struct ast_node_parameter* dcurrent; uint32_t dchrproc; uint16_t i, flimit, fchar, opos; struct aout_byte* result = NULL; struct dbg_sym* newsym; // Change depending on the type of line. switch (line->type) { case type_keyword: switch (line->keyword) { case SYMBOL: printd(LEVEL_VERBOSE, ".SYMBOL %s", bstr2cstr(line->keyword_data_string, '0')); // Emit debugging symbol. list_append(&newsyms, dbgfmt_create_symbol(DBGFMT_SYMBOL_STRING, dbgfmt_create_symbol_string(line->keyword_data_string, DBGFMT_UNDETERMINED))); break; case SECTION: printd(LEVEL_VERBOSE, ".SECTION %s", bstr2cstr(line->keyword_data_string, '0')); // Emit section metadata. aout_emit(aout_create_metadata_section(bstr2cstr(line->keyword_data_string, '0'))); break; case OUTPUT: printd(LEVEL_VERBOSE, ".OUTPUT %s", bstr2cstr(line->keyword_data_string, '0')); // Emit output metadata. aout_emit(aout_create_metadata_output(bstr2cstr(line->keyword_data_string, '0'))); break; case BOUNDARY: printd(LEVEL_VERBOSE, ".BOUNDARY"); // Emit safety boundary of 16 NULL words. for (i = 0; i < 16; i += 1) aout_emit(aout_create_raw(0)); break; case FILL: printd(LEVEL_VERBOSE, ".FILL"); if (line->keyword_data_expr_1 == NULL || line->keyword_data_expr_2 == NULL) { if (line->keyword_data_string != NULL) dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, line->keyword_data_string->data); else dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, ""); } // Emit N words with value X flimit = expr_evaluate(line->keyword_data_expr_1, &dhalt_label_resolution_not_permitted, &dhalt_expression_exit_handler); fchar = expr_evaluate(line->keyword_data_expr_2, &dhalt_label_resolution_not_permitted, &dhalt_expression_exit_handler); for (i = 0; i < flimit; i++) aout_emit(aout_create_raw(fchar)); break; case EXTENSION: printd(LEVEL_VERBOSE, ".EXTENSION %s", bstr2cstr(line->keyword_data_string, '0')); // Emit extension metadata. aout_emit(aout_create_metadata_extension(bstr2cstr(line->keyword_data_string, '0'))); break; case INCBIN: printd(LEVEL_VERBOSE, ".INCBIN %s", bstr2cstr(line->keyword_data_string, '0')); // Emit binary include metadata. aout_emit(aout_create_metadata_incbin(bstr2cstr(line->keyword_data_string, '0'))); break; case ORIGIN: if (line->keyword_data_expr_1 == NULL) { if (line->keyword_data_string != NULL) dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, line->keyword_data_string->data); else dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, ""); } opos = expr_evaluate(line->keyword_data_expr_1, &dhalt_label_resolution_not_permitted, &dhalt_expression_exit_handler); printd(LEVEL_VERBOSE, ".ORIGIN 0x%04X", opos); // Emit origin set metadata. aout_emit(aout_create_metadata_origin(opos)); break; case SEEK: if (line->keyword_data_expr_1 == NULL) { if (line->keyword_data_string != NULL) dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, line->keyword_data_string->data); else dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, ""); } opos = expr_evaluate(line->keyword_data_expr_1, &dhalt_label_resolution_not_permitted, &dhalt_expression_exit_handler); printd(LEVEL_VERBOSE, ".SEEK 0x%04X", opos); // Emit seek metadata. aout_emit(aout_create_metadata_seek(opos)); break; case EXPORT: printd(LEVEL_VERBOSE, ".EXPORT %s", bstr2cstr(line->keyword_data_string, '0')); // Emit export metadata. aout_emit(aout_create_metadata_export(bstr2cstr(line->keyword_data_string, '0'))); break; case IMPORT: printd(LEVEL_VERBOSE, ".IMPORT %s", bstr2cstr(line->keyword_data_string, '0')); // Emit import metadata. aout_emit(aout_create_metadata_import(bstr2cstr(line->keyword_data_string, '0'))); break; case IMPORT_OPTIONAL: printd(LEVEL_VERBOSE, ".IMPORT OPTIONAL %s", bstr2cstr(line->keyword_data_string, '0')); // Emit import metadata. aout_emit(aout_create_metadata_import_optional(bstr2cstr(line->keyword_data_string, '0'))); break; case JUMP: if (line->keyword_data_string == NULL) printd(LEVEL_VERBOSE, ".JUMP <table>"); else printd(LEVEL_VERBOSE, ".JUMP %s", bstr2cstr(line->keyword_data_string, '0')); // Emit jump metadata. if (line->keyword_data_string == NULL) aout_emit(aout_create_metadata_jump(NULL)); else aout_emit(aout_create_metadata_jump(bstr2cstr(line->keyword_data_string, '0'))); break; default: printd(LEVEL_VERBOSE, "?? UNKNOWN KEYWORD\n"); dhalt(ERR_UNSUPPORTED_KEYWORD, NULL); } printd(LEVEL_VERBOSE, "\n"); break; case type_instruction: // Check to see if this is DAT. if (strcmp(line->instruction->instruction, "DAT") == 0) { // Handle data. printd(LEVEL_VERBOSE, "EMIT DAT"); // Process parameters as data. reverse_parameters(line->instruction->parameters); dcurrent = line->instruction->parameters->last; while (dcurrent != NULL) { // Process parameter normally. dparam = process_parameter(dcurrent); // Output depending on what kind of parameter it was. if (dparam.v_label != NULL) // If this is a label, output something that we need to replace. aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(dparam.v_label))))); else if (dparam.v_raw != NULL) // If the raw field is not null, get each character and output it. { printd(LEVEL_VERBOSE, " \"%s\"", dparam.v_raw->data); for (dchrproc = 0; dchrproc < (uint32_t)blength(dparam.v_raw); dchrproc++) aout_emit(aout_create_raw(dparam.v_raw->data[dchrproc])); } else if (dparam.v_extra_used == true) // Just a single address. aout_emit(aout_create_expr(dparam.v_extra)); else // Something that isn't handled by DAT. { printd(LEVEL_VERBOSE, "\n"); dhalt(ERR_DAT_UNSUPPORTED_PARAMETER, NULL); } dcurrent = dcurrent->prev; } } else { // Handle instruction. insttype = get_instruction_by_name(line->instruction->instruction); if (insttype == NULL) dhalt(ERR_UNKNOWN_OPCODE, line->instruction->instruction); printd(LEVEL_VERBOSE, "EMIT %s", insttype->name); // Check parameter count. if (line->instruction->parameters == NULL && strcmp(line->instruction->instruction, "RFI") == 0) { // Handle RFI (which can accept no parameters). result = aout_emit(aout_create_opcode(insttype->opcode, insttype->nbopcode, 0x21 /* 0 literal */)); printd(LEVEL_VERBOSE, "\n"); break; } else if (line->instruction->parameters == NULL) { // Halt and error. dhalt(ERR_INVALID_PARAMETER_COUNT, NULL); } // Process parameters normally. ppresults = process_parameters(line->instruction->parameters); // Force the parameter value to be NXT if it's a label. if (ppresults.a_label != NULL) ppresults.a = NXT_LIT; if (ppresults.b_label != NULL) ppresults.b = NXT_LIT; if (ppresults.a_label != NULL && ppresults.a_label_bracketed) ppresults.a = NXT; if (ppresults.b_label != NULL && ppresults.b_label_bracketed) ppresults.b = NXT; // Check for relative addressing. if ((insttype->opcode == OP_ADD || insttype->opcode == OP_SUB || insttype->opcode == OP_MUL || insttype->opcode == OP_DIV) && ppresults.a == PC) { // Warn about relative addressing portability. dwarn(WARN_RELATIVE_PC_ADDRESSING, NULL); } // Output the initial opcode. if (insttype->opcode != OP_NONBASIC) result = aout_emit(aout_create_opcode(insttype->opcode, ppresults.a, ppresults.b)); else result = aout_emit(aout_create_opcode(insttype->opcode, insttype->nbopcode, ppresults.a)); // If the parameter is a label or requires an extra word, output them. if (ppresults.b_label != NULL) aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(ppresults.b_label))))); else if (ppresults.b_extra_used) aout_emit(aout_create_expr(ppresults.b_extra)); if (ppresults.a_label != NULL) aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(ppresults.a_label))))); else if (ppresults.a_extra_used) aout_emit(aout_create_expr(ppresults.a_extra)); } printd(LEVEL_VERBOSE, "\n"); break; case type_label: // Handle label definition. list_append(&newsyms, dbgfmt_create_symbol(DBGFMT_SYMBOL_LABEL, dbgfmt_create_symbol_label(bfromcstr(line->label->name), DBGFMT_UNDETERMINED))); printd(LEVEL_VERBOSE, ":%s\n", line->label->name); aout_emit(aout_create_label(line->label->name)); break; default: assert(false); } // If we can associate debugging symbols with this instruction... if (result != NULL) { // While the new symbols list is not empty, copy those symbols // into the output and associate. while (list_size(&newsyms) > 0) { newsym = list_extract_at(&newsyms, 0); printd(LEVEL_DEBUG, "Debugging custom symbol: %i\n", newsym->length); list_append(&result->symbols, newsym); list_append(assem_dbg_symbols, newsym); } // If the line information is provided, output // debugging symbols. if (line != NULL && line->file != NULL) { // Output a file / line number debugging symbol here. newsym = dbgfmt_create_symbol(DBGFMT_SYMBOL_LINE, dbgfmt_create_symbol_line(line->file, line->line, DBGFMT_UNDETERMINED)); list_append(&result->symbols, newsym); list_append(assem_dbg_symbols, newsym); printd(LEVEL_DEBUG, "Debugging symbol: %i %s\n", line->line, line->file->data); } // If the higher-language line information is // provided, output debugging symbols. if (line != NULL && line->ufile != NULL) { // Output a file / line number debugging symbol here. newsym = dbgfmt_create_symbol(DBGFMT_SYMBOL_LINE, dbgfmt_create_symbol_line(line->ufile, line->uline, DBGFMT_UNDETERMINED)); list_append(&result->symbols, newsym); list_append(assem_dbg_symbols, newsym); printd(LEVEL_DEBUG, "High-level debugging symbol: %i %s\n", line->uline, line->ufile->data); } } }
struct process_parameters_results process_parameters(struct ast_node_parameters* params) { struct process_parameters_results result; struct process_parameter_results t; reverse_parameters(params); result.raw = NULL; if (params->last != NULL) { t = process_parameter(params->last); if (t.v_raw) { printd(LEVEL_VERBOSE, "\n"); dhalt(ERR_GEN_UNSUPPORTED_PARAMETER, NULL); } result.a = t.v; result.a_extra = t.v_extra; result.a_extra_used = t.v_extra_used; result.a_label = t.v_label; result.a_label_bracketed = t.v_label_bracketed; if (params->last->prev != NULL) { t = process_parameter(params->last->prev); if (t.v_raw) { printd(LEVEL_VERBOSE, "\n"); dhalt(ERR_GEN_UNSUPPORTED_PARAMETER, NULL); } result.b = t.v; result.b_extra = t.v_extra; result.b_extra_used = t.v_extra_used; result.b_label = t.v_label; result.b_label_bracketed = t.v_label_bracketed; } else { result.b = 0x0; result.b_extra = 0x0; result.b_extra_used = false; result.b_label = NULL; result.b_label_bracketed = false; } } else { result.a = 0x0; result.a_extra = 0x0; result.a_extra_used = false; result.a_label = NULL; result.b_label_bracketed = false; result.b = 0x0; result.b_extra = 0x0; result.b_extra_used = false; result.b_label = NULL; result.b_label_bracketed = false; } return result; }
struct process_parameter_results process_address(struct ast_node_address* param) { struct process_parameter_results result; struct register_mapping* registr; bstring btmp = NULL; result.v_raw = NULL; if (param->value != NULL) btmp = expr_representation(param->value); if (param->bracketed && param->added) { // This is of the form [0x1000+I]. registr = get_register_by_name_next(param->addcmpt); if (registr == NULL) { // Attempt to use a label in square brackets. Convert this // to an expression and then reinvoke ourselves with the // evaluated value. param->value = expr_new(expr_new_label(bautofree(bfromcstr(param->addcmpt))), EXPR_OP_ADD, param->value); param->addcmpt = ""; param->added = 0; param->bracketed = 0; bdestroy(btmp); return process_address(param); } else if (registr->value == VALUE_NEXT_UNSUPPORTED) { // Attempt to use a register in brackets that can't be. printd(LEVEL_VERBOSE, "\n"); dhalt(ERR_NEXTED_REGISTER_UNSUPPORTED, param->addcmpt); } printd(LEVEL_VERBOSE, "[%s+%s]", btmp->data, registr->name); result.v = registr->value; result.v_extra = param->value; result.v_extra_used = true; result.v_label = NULL; } else { // This is either the form 0x1000 or [0x1000]. if (param->bracketed) { printd(LEVEL_VERBOSE, "[%s]", btmp->data); result.v = NXT; } else { printd(LEVEL_VERBOSE, "%s", btmp->data); result.v = NXT_LIT; } result.v_extra = param->value; result.v_extra_used = true; result.v_label = NULL; } if (btmp != NULL) bdestroy(btmp); return result; }
static bstring skip_to_endif(state_t* state, bool stop_at_else, bool* stopped_at_else) { char c; bool fresh_line = true; bstring temp = bfromcstr(""); bstring temp_output = bfromcstr(""); bstring output = bfromcstr(""); int if_open = 1; while (ppimpl_has_input(state)) { c = ppimpl_get_input(state); switch(c) { case '#': case '.': if (!fresh_line) { bconchar(output, c); break; } bassigncstr(temp_output, "#"); // first skip spaces while (ppimpl_has_input(state)) { c = ppimpl_get_input(state); bconchar(temp_output, c); if (c != ' ' && c != '\t') break; } // read pp directive bassigncstr(temp, ""); bconchar(temp, c); while (ppimpl_has_input(state)) { c = ppimpl_get_input(state); bconchar(temp_output, c); if (c == ' ' || c == '\t' || c == '\n') break; bconchar(temp, c); } btolower(temp); if (biseq(temp, bfromcstr("endif"))) { if_open--; if (if_open == 0) { if (c != '\n') skip_to_endln(state); *stopped_at_else = false; return output; } } else if (biseq(temp, bfromcstr("if"))) { if_open++; } else if (biseq(temp, bfromcstr("else")) && stop_at_else) { if (if_open == 1) { if (c != '\n') skip_to_endln(state); *stopped_at_else = true; return output; } } bconcat(output, temp_output); fresh_line = (c == '\n'); break; case '\n': fresh_line = true; bconchar(output, c); break; case ' ': case '\t': bconchar(output, c); break; default: fresh_line = false; bconchar(output, c); break; } } // No .ENDIF was found. dhalt(ERR_PP_ASM_NO_ENDIF_TO_IF, ppimpl_get_location(state)); // dhalt will trigger before this, but the compiler warns about // control potentially reaching the end of this function. return NULL; }
static void endif_handle(state_t* state, match_t* match, bool* reprocess) { // free else encountered dhalt(ERR_PP_ASM_ENDIF_NO_IF, ppimpl_get_location(state)); }