void prepareVM(VMContext ctx, ScriptCInstruction inst, long code_length) { const void **table = (const void **)vm_execute(ctx, NULL); for(long i = 0; i < code_length; i++) { inst->addr = (const void*)table[inst->op]; ++inst; } }
void ddbg_continue_vm() { vm->halted = false; vm->sleep_cycles = 0; dbg_lua_handle_hook(&lstate, NULL, bautofree(bfromcstr("continue")), 0); vm_execute(vm, NULL); printd(LEVEL_DEFAULT, "\n"); }
void ddbg_step_over() { uint16_t inst, op_a, op_b, offset = 1, bp; inst = INSTRUCTION_GET_OP(vm->ram[vm->pc]); op_a = INSTRUCTION_GET_A(vm->ram[vm->pc]); op_b = INSTRUCTION_GET_B(vm->ram[vm->pc]); vm->sleep_cycles = 0; if (op_a == NXT) offset += 1; if (op_a == NXT_LIT) offset += 1; if (op_b == NXT) offset += 1; if (op_b == NXT_LIT) offset += 1; if (inst == NBOP_RESERVED) { if (op_b == NBOP_JSR) { bp = op_a; } } else { bp = vm->pc + offset; } list_append(&breakpoints, breakpoint_create(bp, true, true)); vm->halted = false; vm_execute(vm, NULL); // Handle custom Lua commands. dbg_lua_handle_hook(&lstate, NULL, bautofree(bfromcstr("next")), 0); }
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; }
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; // 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* legacy_mode = arg_lit0("l", "legacy", "Automatically initialize hardware to legacy values."); 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_end* end = arg_end(20); void* argtable[] = { input_file, debug_mode, execution_dump_file, terminate_mode, legacy_mode, little_endian_mode, verbose, quiet, end }; // Parse arguments. nerrors = arg_parse(argc, argv, argtable); version_print(bautofree(bfromcstr("Emulator"))); 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); // Set global path variable. osutil_setarg0(bautofree(bfromcstr(argv[0]))); // Set endianness. isetmode(little_endian_mode->count == 0 ? IMODE_BIG : IMODE_LITTLE); // 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) { fprintf(stderr, "emulator: unable to load %s from disk.\n", argv[1]); arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); return 1; } } else { // Windows needs stdin in binary mode. #ifdef _WIN32 _setmode(_fileno(stdin), _O_BINARY); #endif // Set load to stdin. load = stdin; } // 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)) { fprintf(stderr, "emulator: it appears you passed intermediate code for execution. link\n"); fprintf(stderr, " the input code with the toolchain linker to execute it.\n"); arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); return 1; } // And then use the VM. vm = vm_create(); vm->debug = (debug_mode->count > 0); vm_flash(vm, flash); vm_hw_timer_init(vm); vm_hw_io_init(vm); vm_hw_lem1802_init(vm); vm_hw_lua_init(vm); if (legacy_mode->count > 0) { vm_hw_lem1802_mem_set_screen(vm, 0x8000); vm_hw_io_set_legacy(true); } vm_execute(vm, execution_dump_file->count > 0 ? execution_dump_file->filename[0] : NULL); #ifdef __EMSCRIPTEN__ printd(LEVEL_WARNING, "warning: not cleaning up resources in Emscripten.\n"); #else 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_hw_timer_free(vm); vm_hw_io_free(vm); vm_hw_lem1802_free(vm); vm_free(vm); arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); return 0; #endif }
int main(int ac, char** av) { t_vm* vm = vm_initialize(); t_process* process = (t_process*) malloc(sizeof(t_process)); int32 i; t_display* display; int32 update_display = 0; int32 was_pressed = 0; t_ring_buffer* ring_buffer; ring_buffer = ring_buffer_initialize(10, free); if (load_cores(vm, ac, av) <= 0) return -1; display = display_initialize(800, 600); vm_set_print_callback(vm, main_debug_print, ring_buffer); if (1) { while (vm->process_count && !display_should_exit(display)) { vm->cycle_current++; update_display = 1; int process_count = vm->process_count; for (i = 0; i < process_count; ++i) { t_process* process = vm->processes[i]; if (process->cycle_wait <= 0) { update_display = 0; vm_reset_process_io_op(process); if (process->current_opcode) vm_execute(vm, process); vm_get_opcode(vm, process); } else process->cycle_wait--; } if (vm->cycle_current > vm->cycle_to_die) { vm->cycle_current = 0; vm_kill_process_if_no_live(vm); } vm_clean_dead_process(vm); // update_display = 0; if (display_update_input(display) || update_display == 0) { display_print_ring_buffer(display, 0, 0, ring_buffer); display_step(vm, display); } } } else { int32 execute_one = 0; int32 current_keys_state[GLFW_KEY_LAST]; int32 previous_keys_state[GLFW_KEY_LAST]; memset(previous_keys_state, 0, GLFW_KEY_LAST * sizeof(int32)); memset(current_keys_state, 0, GLFW_KEY_LAST * sizeof(int32)); display_step(vm, display); while (vm->process_count && !display_should_exit(display)) { int32 executed = 0; int32 print_processes; int32 process_count = 0; current_keys_state[GLFW_KEY_S] = display_key_pressed(display, GLFW_KEY_S); current_keys_state[GLFW_KEY_P] = display_key_pressed(display, GLFW_KEY_P); if (!execute_one) execute_one = previous_keys_state[GLFW_KEY_S] && !current_keys_state[GLFW_KEY_S]; print_processes = previous_keys_state[GLFW_KEY_P] && !current_keys_state[GLFW_KEY_P]; memcpy(previous_keys_state, current_keys_state, sizeof(int32) * GLFW_KEY_LAST); if (execute_one) vm->cycle_current++; for (i = 0; i < vm->process_count; ++i) { t_process* process = vm->processes[i]; if (print_processes) vm_debug_print_process(vm, process); if (execute_one) { if (process->cycle_wait <= 0) { vm_reset_process_io_op(process); vm_execute(vm, process); vm_get_opcode(vm, process); executed++; if (vm->live_count >= NBR_LIVE) { vm->live_count = 0; vm->cycle_to_die -= vm->cycle_delta; } } process->cycle_wait--; } } if (executed) execute_one = 0; if (vm->cycle_current > vm->cycle_to_die) { vm->cycle_current = 0; vm_kill_process_if_no_live(vm); } vm_clean_dead_process(vm); executed += display_update_input(display); if (executed) display_step(vm, display); else glfwPollEvents(); } } ring_buffer_destroy(ring_buffer); display_destroy(display); vm_destroy(vm); }
int main(int ac, char** av) { vm_t* vm; display_gl_t* display = NULL; int bound; int i; debugger_t* debugger = NULL; vm = vm_initialize(); if ( (parse_arguments(vm, ac, av) <= 0) || (check_core_endianess(vm) < 0)) { return -1; } bound = VM_MEMORY_SIZE / (vm->core_count - 1); for (i = 0; i < vm->core_count; ++i) { vm->cores[i]->bound.start = vm->cores[i]->start_address; vm->cores[i]->bound.size = bound; } memory_access_initialize(is_cpu_big_endian() != vm->big_endian); #if defined(_DEBUG) vm->full_screen = 0; #endif #ifdef RENDER_GL display = display_gl_initialize(1980, 1080, vm->full_screen); if (vm->step != -1) { debugger = debugger_init(vm->dbg_same_window ? display_gl_get_window(display) : NULL); } #endif while (vm->process_count && !display_gl_should_exit(display)) { int32 i; int update_display = 0; if (vm->cycle_barrier == vm->cycle_total) { for (i = 0; i < vm->core_count; ++i) { vm->cores[i]->bound.start = 0; vm->cores[i]->bound.size = vm->memory_size; } } if (vm->step != 0) { vm->cycle_current++; vm->cycle_total++; int32 process_count = vm->process_count; for (i = process_count; i > 0; --i) { process_t* process = vm->processes[i - 1]; process->cycle_wait--; if (process->cycle_wait <= 0) { vm_reset_process_io_op(process); vm_execute(vm, process); update_display = 1; if (vm->step > 0 && (vm->step_process == NULL || vm->step_process == process) ) { vm->step --; } } } if (vm->cycle_current > vm->cycle_to_die) { vm->cycle_current = 0; vm_kill_process_if_no_live(vm); vm_clean_dead_process(vm); } } else { update_display = 1; } #ifdef RENDER_GL update_display |= display_gl_update_input(display); if (update_display) { float y = 1; y = display_gl_text(display, 0, y, 0xffffffff, "cycle to die %d", vm->cycle_to_die); y = display_gl_text(display, 0, y, 0xffffffff, "live count %d ", vm->live_count); y = display_gl_text(display, 0, y, 0xffffffff, "process count %d ", vm->process_count); y = display_gl_text(display, 0, y, 0xffffffff, "cycle %d ", vm->cycle_total); y = display_gl_text(display, 0, y, 0xffffffff, "barrier %d ", vm->cycle_barrier); for (i = 0; i < vm->core_count; ++i) { core_t* core = vm->cores[i]; char* name = core->header ? core->header->name : "Unknow"; y = display_gl_text(display, 0, y, 0xffffffff, "%s %d", name, core->live_count); } display_gl_step(vm, display); display_gl_swap(display); } if (debugger && vm->step != 1) { debugger_render(debugger, vm); } #endif } print_winning_core(vm); if (debugger) { debugger_destroy(debugger); } #ifdef RENDER_GL display_gl_destroy(display); #endif vm_destroy(vm); }
void dbg_lua_handle_command(struct dbg_state* state, void* ud, freed_bstring name, list_t* parameters) { struct lua_debugst* ds; struct customarg_entry* carg; char* cstr; unsigned int i, k; int paramtbl; // Convert the name to lowercase. btolower(name.ref); cstr = bstr2cstr(name.ref, '0'); // Loop through all of the modules. for (k = 0; k < list_size(&modules); k++) { ds = list_get_at(&modules, k); // Set stack top (I don't know why the top of the // stack is negative!) lua_settop(ds->state, 0); // Search handler table for entries. lua_getglobal(ds->state, HANDLER_TABLE_COMMANDS_NAME); lua_getfield(ds->state, -1, cstr); if (!lua_istable(ds->state, -1)) { // No such entry. lua_pop(ds->state, 2); continue; } // Call the handler function. lua_getfield(ds->state, -1, HANDLER_FIELD_FUNCTION_NAME); dbg_lua_push_state(ds, state, ud); lua_newtable(ds->state); paramtbl = lua_gettop(ds->state); for (i = 0; i < list_size(parameters); i++) { carg = list_get_at(parameters, i); lua_newtable(ds->state); if (carg->type == DBG_CUSTOMARG_TYPE_PATH) lua_pushstring(ds->state, "PATH"); else if (carg->type == DBG_CUSTOMARG_TYPE_PARAM) lua_pushstring(ds->state, "PARAM"); else if (carg->type == DBG_CUSTOMARG_TYPE_STRING) lua_pushstring(ds->state, "STRING"); else lua_pushstring(ds->state, "NUMBER"); lua_setfield(ds->state, -2, "type"); if (carg->type == DBG_CUSTOMARG_TYPE_PATH) lua_pushstring(ds->state, carg->path->data); else if (carg->type == DBG_CUSTOMARG_TYPE_PARAM) lua_pushstring(ds->state, carg->param->data); else if (carg->type == DBG_CUSTOMARG_TYPE_STRING) lua_pushstring(ds->state, carg->string->data); else lua_pushnumber(ds->state, carg->number); lua_setfield(ds->state, -2, "value"); lua_rawseti(ds->state, paramtbl, i + 1); } if (lua_pcall(ds->state, 2, 0, 0) != 0) { printd(LEVEL_ERROR, "error: unable to call debugger command handler for '%s'.\n", name.ref->data); printd(LEVEL_ERROR, "%s\n", lua_tostring(ds->state, -1)); bautodestroy(name); bcstrfree(cstr); lua_pop(ds->state, 2); list_iterator_stop(&modules); list_destroy(parameters); return; } bautodestroy(name); bcstrfree(cstr); lua_pop(ds->state, 2); list_iterator_stop(&modules); list_destroy(parameters); // The command may have started the virtual machine, check the // status of the VM and execute if needed. if (state->get_vm()->halted == false) vm_execute(state->get_vm(), NULL); return; } // There is no command to handle this. printd(LEVEL_ERROR, "no such command found.\n"); // Clean up. list_destroy(parameters); bautodestroy(name); bcstrfree(cstr); }