int main(){ load_memory(); load_disk(); printf("memory loaded...\n"); visit_memory(0x0330); visit_memory(0x1e6f); visit_memory(0x6653); visit_memory(0x1c13); visit_memory(0x6890); visit_memory(0x0af6); visit_memory(0x1e6f); }
int main(void) { init_environment(); MACHINE *mach = make_machine(); for (int i = 0; i < 23; i++) printf("ins %d: %08x\n", i, factorial_ins[i]); printf("\n"); init_machine(mach); load_memory(factorial_ins, 100, mach, 0); run_machine(mach); free_machine(mach); return 0; }
void load_rom(const char *fname, const char *sname, int zoom) { uint8_t *start_of_rom; int cart_type; init_memory(); fp = os_open_file_r(fname); if (fp == INVALID_FILE_HANDLE) { os_perr("Couldn't read ROM file"); exit_err(); } save = os_open_file_rw(sname); if (save == INVALID_FILE_HANDLE) { save = os_create_file_rw(sname); if (save == INVALID_FILE_HANDLE) { os_close_file(fp); os_perr("Couldn't create save file"); exit_err(); } } start_of_rom = alloc_mem(0x150); if (start_of_rom == NULL) { os_perr("Couldn't allocate memory"); exit_err(); } os_file_read(fp, 0x150, start_of_rom); if (memcmp(id, start_of_rom + 0x104, sizeof(id))) { os_eprint("Bad ROM!\n"); exit_err(); } os_print("Loading \""); for (int i = 0x134; i < 0x143; i++) { if (!start_of_rom[i]) break; os_print("%c", start_of_rom[i]); } if (start_of_rom[0x143] & 0x80) gbc_mode = 1; else gbc_mode = 0; os_print("\", %s...\n", gbc_mode ? "GBC" : "GB"); cart_type = start_of_rom[0x147]; rom_size = start_of_rom[0x148]; ram_size = start_of_rom[0x149]; switch (rom_size) { case 0x52: rom_size = 72; break; case 0x53: rom_size = 80; break; case 0x54: rom_size = 96; break; default: if (rom_size > 6) { os_eprint("Invalid ROM size 0x%02X.\n", rom_size); exit_err(); } rom_size = 2 << rom_size; } switch (ram_size) { case 0: ram_size = 0; break; case 1: case 2: ram_size = 1; break; case 3: ram_size = 4; break; case 4: ram_size = 16; break; default: os_eprint("Invalid RAM size 0x%02X.\n", ram_size); exit_err(); } os_print("%i ROM banks, %i RAM banks.\n", rom_size, ram_size); #ifdef MAP_BATTERY os_resize_file(save, ram_size * 8192); #endif switch (cart_type) { CART_TYPE(0x00, 0, 0, 0, 0, 0); CART_TYPE(0x01, 1, 0, 0, 0, 0); CART_TYPE(0x02, 1, 1, 0, 0, 0); CART_TYPE(0x03, 1, 1, 1, 0, 0); CART_TYPE(0x05, 2, 0, 0, 0, 0); CART_TYPE(0x06, 2, 0, 1, 0, 0); CART_TYPE(0x08, 0, 1, 0, 0, 0); CART_TYPE(0x09, 0, 1, 1, 0, 0); CART_TYPE(0x0F, 3, 0, 1, 1, 0); CART_TYPE(0x10, 3, 1, 1, 1, 0); CART_TYPE(0x11, 3, 0, 0, 0, 0); CART_TYPE(0x12, 3, 1, 0, 0, 0); CART_TYPE(0x13, 3, 1, 1, 0, 0); CART_TYPE(0x19, 5, 0, 0, 0, 0); CART_TYPE(0x1A, 5, 1, 0, 0, 0); CART_TYPE(0x1B, 5, 1, 1, 0, 0); CART_TYPE(0x1C, 5, 0, 0, 0, 1); CART_TYPE(0x1D, 5, 1, 0, 0, 1); CART_TYPE(0x1E, 5, 1, 1, 0, 1); default: os_eprint("Unknown cartridge type 0x%02X.\n", cart_type); exit_err(); } os_print("Cartridge type: ROM"); if (mbc) os_print("+MBC%i", mbc); if (ext_ram) os_print("+RAM"); if (batt) os_print("+BATT"); if (rtc) os_print("+TIMER"); if (rmbl) os_print("+RUMBLE"); os_print("\n"); load_memory(); run(zoom); }
void *daemon_thread(void *arg) { TID_t next_tid = 0; TID_t hw_tid = 0; int rv, hw_ret_val, regCount; hthread_t junk_tid; flag hw_available, hw_done; sched_param_t my_priority; Hint my_policy; // Display the daemon's priority hthread_getschedparam(hthread_self(),&my_policy,&my_priority); //printf("Daemon priority = %d\n", my_priority.sched_priority); // Create a pointer to the Daemon's communication struct with main. DaemonComm *dc = (DaemonComm *)arg; // Create a buffer for software interpreters to export/import their state to. ExportBuffer export_buffer; ImportBuffer import_buffer; // The software_interpreter_list holds active threads that are being interpreted by // the software interpreter. TCBNode software_interpreter_list[MAX_SW_THREAD]; // The cur_tcb and the tcb_index are used to reference TCBs in the software interpreter list. TCBNode *cur_tcb; TCB *new_tcb; int tcb_index; // Initialize TCB List for (cur_tcb = software_interpreter_list; cur_tcb < software_interpreter_list + MAX_SW_THREAD; cur_tcb++) { UNSET(cur_tcb->valid); } // Initialize hardware flags SET(hw_available); SET(hw_done); printf(" ...DAEMON running.\n"); // The daemon will run forever. Currently we have no clean shutdown mechanism. while(1) { // Process each TCB in the software interpreter list. for (cur_tcb = software_interpreter_list; cur_tcb < software_interpreter_list + MAX_SW_THREAD; cur_tcb++) { // If the TCB is invalid, then skip it. if (! ISSET(cur_tcb->valid)) continue; // If a thread is done interpreting, then print its return value and invalidate the TCB. if (ISSET(cur_tcb->entry.communication.control.done_interpreting)) { printf("DAEMON: Thread id %u (running in SW) returned %d\n", cur_tcb->entry.tid, cur_tcb->entry.communication.data.return_value); UNSET(cur_tcb->valid); continue; } // If the thread is done exporting to hardware, then invalidate the TCB and start // the hardware interpretation process. if (ISSET(cur_tcb->entry.communication.control.done_exporting)) { // TODO: If a software thread has finished exporting, but in the meantime a // a new "run this thread only in hardware" request has come in, we need to copy // the thread state from the export buffer *back* into a software thread to make // room for the hw->sw migration we're about to do. // If there is new bytecode available to execute, then process it. if (ISSET(dc->new_code) & ISSET(dc->in_hw)) { // Kick thread back into SW // Find an invalid TCB. for (tcb_index = 0; tcb_index < MAX_SW_THREAD; tcb_index++) { if (! ISSET(software_interpreter_list[tcb_index].valid)) break; } // If an available TCB is found, then tcb_index must be less // then MAX_SW_THREAD. if (tcb_index < MAX_SW_THREAD) { // If an invalid TCB exists, initialize it and start // the software interpreter. // Initialize software_interpreter_list[tcb_index] new_tcb = &software_interpreter_list[tcb_index].entry; new_tcb->tid = cur_tcb->entry.tid; new_tcb->virtualization.base_addr = software_interpreter_list[tcb_index].memory; new_tcb->communication.data.export_buffer_addr = & export_buffer; new_tcb->communication.data.import_buffer_addr = & import_buffer; UNSET(new_tcb->communication.control.done_interpreting); UNSET(new_tcb->communication.control.start_exporting); UNSET(new_tcb->communication.control.done_exporting); SET(software_interpreter_list[tcb_index].valid); // Copy program/state to interpreter memory space for (regCount = 0; regCount < NUMBER_REGISTERS ; regCount++) { import_buffer.register_file[regCount] = export_buffer.register_file[regCount]; } memcpy(software_interpreter_list[tcb_index].memory, cur_tcb->memory, export_buffer.register_file[SP]); //start_software_interpreter(); rv = hthread_create(&junk_tid, NULL, interpreter_entry_point_import, (void *)&(software_interpreter_list[tcb_index].entry)); } else { // If the software_interpreter_list is full, issue an error message. fprintf(stderr, "Preallocated TCB list is full.\n"); } } else { // Move the thread into HW // Grab the SW thread's TID hw_tid = cur_tcb->entry.tid; // Migrate state from export buffer into HW interpreter reset_HVM(); printf("DAEMON: Migrating thread id %u from SW to HW...",hw_tid); import_state_HVM(&export_buffer, cur_tcb->memory); printf("COMPLETE\n"); // Start HW interpreter execution light_LED(hw_tid); UNSET(hw_done); run_HVM(); // Invalidate TCB UNSET(cur_tcb->valid); } } } // Is the hardware done interpreting if (is_HVM_done()) { // Export HVM state and grab return value light_LED(0); SET(hw_done); export_state_HVM(); wait_export_complete_HVM(); hw_ret_val = get_HVM_return_value(); // Display return value printf("DAEMON: Thread id %u (running in HW) returned %d\n", hw_tid, hw_ret_val); // Check to see if any SW threads exist that can now be run in HW for (tcb_index = 0; tcb_index < MAX_SW_THREAD; tcb_index++) { if (software_interpreter_list[tcb_index].valid) break; } // If a valid SW thread exists, begin it's export process so that it can be migrated (otherwise, make the HW available again) if (tcb_index < MAX_SW_THREAD) { SET(software_interpreter_list[tcb_index].entry.communication.control.start_exporting); } else { printf("DAEMON: HW is available for the taking!\n"); SET(hw_available); } } // If there is new bytecode available to execute, then process it. if (ISSET(dc->new_code)) { // Increment the TID counter next_tid++; // If told to run this thread in HW, check to see if we need to force the HW to be available (migrating a thread from HW to SW) if (ISSET(dc->in_hw)) { // Check to see if HW is even available if (!ISSET(hw_available) & !ISSET(hw_done)) { // It's not, so we must make it available // export hardware to software, if needed printf("DAEMON: Migrating thread id %u from HW to SW...", hw_tid); // Stop HVM and export its state light_LED(0); export_state_HVM(); //wait_export_complete_HVM(); // This function waits for exported PC to be all F's and this won't be the case in a pre-empted program delay(99999999); // Use a delay instead to wait for export process to finish printf("COMPLETE\n"); // migrate HW state to import buffer (registers now, and program/stack later - just below) migrate_HVM_registers_to_buffer(&import_buffer); // create new SW based on import buffer // Find an invalid TCB. for (tcb_index = 0; tcb_index < MAX_SW_THREAD; tcb_index++) { if (! ISSET(software_interpreter_list[tcb_index].valid)) break; } // If an available TCB is found, then tcb_index must be less // then MAX_SW_THREAD. if (tcb_index < MAX_SW_THREAD) { // If an invalid TCB exists, initialize it and start // the software interpreter. // Initialize software_interpreter_list[tcb_index] new_tcb = &software_interpreter_list[tcb_index].entry; new_tcb->tid = hw_tid; new_tcb->virtualization.base_addr = software_interpreter_list[tcb_index].memory; new_tcb->communication.data.export_buffer_addr = & export_buffer; new_tcb->communication.data.import_buffer_addr = & import_buffer; UNSET(new_tcb->communication.control.done_interpreting); UNSET(new_tcb->communication.control.start_exporting); UNSET(new_tcb->communication.control.done_exporting); SET(software_interpreter_list[tcb_index].valid); // Copy program/state to interpreter memory space //memcpy(software_interpreter_list[tcb_index].memory, dc->new_code_address, dc->new_code_size); memcpy(software_interpreter_list[tcb_index].memory, hvm_prog_mem, get_current_SP_HVM()); //start_software_interpreter(); rv = hthread_create(&junk_tid, NULL, interpreter_entry_point_import, (void *)&(software_interpreter_list[tcb_index].entry)); } else { // If the software_interpreter_list is full, issue an error message. fprintf(stderr, "Preallocated TCB list is full.\n"); } // Set HW available flag, so the new thread falls through and is created by the code below SET(hw_available); } else if (!ISSET(hw_available) & ISSET(hw_done)) { // If its not available, but the thread in HW is complete, then there is no need to migrate the thread... // Just change the availalbility flag for the code below to take care of SET(hw_available); } } // TODO: I don't think we need this else, now. The dc->in_hw flag just forces a // hw -> sw migration, making the hw available to the new thread. // If HW available, run the thread in HW if ISSET(hw_available) { // De-asser ready flag UNSET(hw_available); // Download fresh code hw_tid = next_tid; printf("DAEMON: Started thread id %u in HW\n", hw_tid); load_memory(hvm_prog_mem, dc->new_code_size, dc->new_code_address); // Reset and run the interpreter reset_HVM(); light_LED(hw_tid); UNSET(hw_done); run_HVM(); } // Otherwise run the thread in SW else { // This bytecode will run in software. Therefore it needs // to given a TCB in the software interpreter list. // Find an invalid TCB. for (tcb_index = 0; tcb_index < MAX_SW_THREAD; tcb_index++) { if (! ISSET(software_interpreter_list[tcb_index].valid)) break; } // If an available TCB is found, then tcb_index must be less // then MAX_SW_THREAD. if (tcb_index < MAX_SW_THREAD) { // If an invalid TCB exists, initialize it and start // the software interpreter. // Initialize software_interpreter_list[tcb_index] new_tcb = &software_interpreter_list[tcb_index].entry; new_tcb->tid = next_tid; new_tcb->virtualization.base_addr = software_interpreter_list[tcb_index].memory; new_tcb->communication.data.export_buffer_addr = & export_buffer; new_tcb->communication.data.import_buffer_addr = & import_buffer; UNSET(new_tcb->communication.control.done_interpreting); UNSET(new_tcb->communication.control.start_exporting); UNSET(new_tcb->communication.control.done_exporting); SET(software_interpreter_list[tcb_index].valid); memcpy(software_interpreter_list[tcb_index].memory, dc->new_code_address, dc->new_code_size); //start_software_interpreter(); printf("DAEMON: Started thread id %u in SW\n", next_tid); rv = hthread_create(&junk_tid, NULL, interpreter_entry_point, (void *)&(software_interpreter_list[tcb_index].entry)); } else { // If the software_interpreter_list is full, issue an error message. fprintf(stderr, "Preallocated TCB list is full.\n"); } } // Unset the new_code flag UNSET(dc->new_code); }
int main(int argc, char *argv[]) { char *configfile = DEFAULT_CONFIG_FILE; char *base_path = DEFAULT_DEBUG_FIFO; int option; int step = 0; int debuglevel = 2; pthread_t run_tid; int running=1; while((option = getopt(argc, argv, "d:sc:b:")) != -1) { switch(option) { case 'd': debuglevel = atoi(optarg); break; case 'c': configfile = optarg; break; case 'b': base_path = optarg; break; case 's': step = 1; break; default: fprintf(stderr,"Srsly?"); exit(EXIT_FAILURE); } } debug_level(debuglevel); config_init(&main_config); if(config_read_file(&main_config, configfile) != CONFIG_TRUE) { FATAL("Can't read config file (%s, line %d): %s", configfile, config_error_line(&main_config), config_error_text(&main_config)); exit(EXIT_FAILURE); } if(step) step_init(NULL); memory_init(); if(!load_memory()) exit(EXIT_FAILURE); cpu_init(); if(step) { if(pthread_create(&run_tid, NULL, stepwise_proc, &running) < 0) { perror("pthread_create"); exit(EXIT_FAILURE); } } else { } /* here, we should run the event loop required by any drivers. * really, this means the SDL video driver. for osx, all * event polling/pumping has to be done in the main thread, * not background threads. that's kind of a fail. */ while(running) { memory_run_eventloop(); } exit(EXIT_SUCCESS); }