// print a disassembly starting from addr void debug_disassemble(unsigned int addr) { char s[160] = { 0 }; int line = 0; const char *name = NULL; // print this many lines because that's how many our console can show at a time while (line < 13) { name = g_game->get_address_name(addr); // check to see if this address has a name // if so, it's a label name, so print it if (name) { outstr(name); printline(":"); line++; } sprintf(s, "%04x: ", addr); outstr(s); addr += get_cpu_struct(g_which_cpu)->dasm_callback(s, addr); printline(s); line++; } }
static inline void acpi_cstate_halt(void) { cpu_ent *cpu = get_cpu_struct(); if (cpu->invoke_scheduler) return; asm("hlt"); }
static inline void acpi_cstate_ffh_enter(CpuidleCstate *cState) { cpu_ent *cpu = get_cpu_struct(); if (cpu->invoke_scheduler) return; x86_monitor((void *)&cpu->invoke_scheduler, 0, 0); if (!cpu->invoke_scheduler) x86_mwait((unsigned long)cState->pData, 1); }
static void acpi_cstate_quirks(acpi_cpuidle_driver_info *device) { cpu_ent *cpu = get_cpu_struct(); // Calculated Model Value: M = (Extended Model << 4) + Model uint32 model = (cpu->arch.extended_model << 4) + cpu->arch.model; // On all recent Intel platforms, ARB_DIS is not necessary if (cpu->arch.vendor != VENDOR_INTEL) return; if (cpu->arch.family > 0xf || (cpu->arch.family == 6 && model >= 0xf)) device->flags &= ~ACPI_FLAG_C_ARB; }
// I called this MAME_Debug so that I could test mame cpu cores with daphne (obviously I can't ship mame cpu cores with // daphne due to licensing issues) void MAME_Debug(void) { // if we are in trace mode OR if we've got our desired breakpoint if (g_cpu_trace || (g_break && (get_cpu_struct(g_which_cpu)->getpc_callback() == g_breakpoint))) { // if the active cpu is the one to be debugged if (cpu_getactivecpu() == g_which_cpu) { // since we may be at the debug prompt for a long time, we pause the cpu timer here cpu_pause(); debug_prompt(); // give them a prompt cpu_unpause(); } } }
// prints cpu registers and flags (keep it on 2 lines) void print_cpu_context() { char tmpstr[160] = { 0 }; char nextinstr[160]; cpudef *cpu = get_cpu_struct(g_which_cpu); const char *s = NULL; // results returned by CPU ascii callback int reg = CPU_INFO_REG; // base register int x = 0; // our X position so we can apply word wrap // fill nextinstr with the disassembly of the next instruction cpu->dasm_callback(nextinstr, cpu->getpc_callback()); // print all registers we can for (reg = CPU_INFO_REG; reg < MAX_REGS; reg++) { s = cpu->ascii_info_callback(NULL, reg); // if we got something back ... if (s[0] != 0) { outstr(s); outstr(" "); // spacer after register info x += strlen(s) + 1; // +1 because we take into account space // if it's time to do a line feed ... if (x > 76) { newline(); x = 0; } } }; newline(); sprintf(tmpstr, "AT PC: [%02X - %s] FLAGS: [%s] ", cpu->getpc_callback(), nextinstr, cpu->ascii_info_callback(NULL, CPU_INFO_FLAGS) ); printline(tmpstr); }
void debug_prompt() { char s[81] = { 0 }; UINT8 done = 0; struct cpudef *cpu = get_cpu_struct(g_which_cpu); unsigned int addr = cpu->getpc_callback(); // this function relies on addr being initialized to PC g_break = 0; // once they get here, don't break anymore // they have to issue a proper command to get out of the prompt while (!done && !get_quitflag()) { newline(); print_cpu_context(); // show registers and stuff sprintf(s, "[#%u][%04x Command,'?']-> ", g_which_cpu, cpu->getpc_callback()); outstr(s); con_getline(s, 80); switch(toupper(s[0])) { case 'S': // this might help with debugging *shrug* g_ldp->pre_step_forward(); printline("Stepping forward one frame..."); break; case 'C': // continue execution g_cpu_trace = 0; done = 1; break; case 'D': // disassemble // if they entered in an address to disassemble at ... if (strlen(s) > 1) { addr = (unsigned int) strtol(&s[1], NULL, 16); // convert base 16 text to a number } // else if they entered no parameters, disassemble from PC debug_disassemble(addr); break; case 'F': // display current laserdisc frame g_ldp->print_frame_info(); print_ldv1000_info(); break; case 'I': // break at end of interrupt printline("This feature not implemented yet =]"); break; case '=': // set a new breakpoint // if they entered in an address to disassemble at ... if (strlen(s) > 1) { g_breakpoint = (UINT32) strtol(&s[1], NULL, 16); // convert base 16 text to a number g_break = 1; g_cpu_trace = 0; done = 1; } // else if they entered no parameters, disassemble from PC else { printline("You must specify an address to break at."); } break; case 'M': // memory dump if (strlen(s) > 1) { addr = (unsigned int) strtol(&s[1], NULL, 16); } print_memory_dump(addr); break; case 'N': // next CPU g_which_cpu++; // if we've run out of CPU's to debug, wrap back around to the first cpu if (get_cpu_struct(g_which_cpu) == NULL) g_which_cpu = 0; break; case 0: // carriage return g_cpu_trace = 1; done = 1; break; case 'Q': // quit emulator set_quitflag(); break; case 'W': // write byte at address if (strlen(s) > 1) { int i = 2; // skip the W and the first whitespace Uint32 addr = 0; Uint8 val = 0; // find next whitespace while (s[i] != ' ') { i++; } s[i] = 0; // terminate string so we can do a strtol addr = (Uint32) strtol(&s[1], NULL, 16); // convert base 16 text to a number val = (Uint8) strtol(&s[i+1], NULL, 16); // i+1 because we skip the NULL-terminator we added before g_game->cpu_mem_write((Uint16) addr, val); // assume 16-bit for now } break; case '?': // get menu debug_menu(); break; default: printline("Unknown command, press ? to get a menu"); break; } } // end while }
/*! Actually process an interrupt via the handlers registered for that vector (IRQ). */ int int_io_interrupt_handler(int vector, bool levelTriggered) { int status = B_UNHANDLED_INTERRUPT; struct io_handler* io; bool handled = false; bigtime_t start = system_time(); // exceptions and syscalls have their own handlers ASSERT(sVectors[vector].type != INTERRUPT_TYPE_EXCEPTION && sVectors[vector].type != INTERRUPT_TYPE_SYSCALL); if (!sVectors[vector].no_lock_vector) acquire_spinlock(&sVectors[vector].vector_lock); #if !DEBUG_INTERRUPTS // The list can be empty at this place if (sVectors[vector].handler_list == NULL) { dprintf("unhandled io interrupt %d\n", vector); if (!sVectors[vector].no_lock_vector) release_spinlock(&sVectors[vector].vector_lock); return B_UNHANDLED_INTERRUPT; } #endif // For level-triggered interrupts, we actually handle the return // value (ie. B_HANDLED_INTERRUPT) to decide whether or not we // want to call another interrupt handler. // For edge-triggered interrupts, however, we always need to call // all handlers, as multiple interrupts cannot be identified. We // still make sure the return code of this function will issue // whatever the driver thought would be useful. for (io = sVectors[vector].handler_list; io != NULL; io = io->next) { status = io->func(io->data); #if DEBUG_INTERRUPTS if (status != B_UNHANDLED_INTERRUPT) io->handled_count++; #endif if (levelTriggered && status != B_UNHANDLED_INTERRUPT) break; if (status == B_HANDLED_INTERRUPT || status == B_INVOKE_SCHEDULER) handled = true; } #if DEBUG_INTERRUPTS sVectors[vector].trigger_count++; if (status != B_UNHANDLED_INTERRUPT || handled) { sVectors[vector].handled_count++; } else { sVectors[vector].unhandled_count++; sVectors[vector].ignored_count++; } if (sVectors[vector].trigger_count > 10000) { if (sVectors[vector].ignored_count > 9900) { struct io_handler *last = sVectors[vector].handler_list; while (last && last->next) last = last->next; if (last != NULL && last->no_handled_info) { // we have an interrupt handler installed that does not // know whether or not it has actually handled the interrupt, // so this unhandled count is inaccurate and we can't just // disable } else { if (sVectors[vector].handler_list == NULL || sVectors[vector].handler_list->next == NULL) { // this interrupt vector is not shared, disable it sVectors[vector].enable_count = -100; arch_int_disable_io_interrupt(vector); dprintf("Disabling unhandled io interrupt %d\n", vector); } else { // this is a shared interrupt vector, we cannot just disable it dprintf("More than 99%% interrupts of vector %d are unhandled\n", vector); } } } sVectors[vector].trigger_count = 0; sVectors[vector].ignored_count = 0; } #endif if (!sVectors[vector].no_lock_vector) release_spinlock(&sVectors[vector].vector_lock); SpinLocker vectorLocker(sVectors[vector].load_lock); bigtime_t deltaTime = system_time() - start; sVectors[vector].last_measure_active += deltaTime; vectorLocker.Unlock(); cpu_ent* cpu = get_cpu_struct(); if (sVectors[vector].type == INTERRUPT_TYPE_IRQ || sVectors[vector].type == INTERRUPT_TYPE_ICI || sVectors[vector].type == INTERRUPT_TYPE_LOCAL_IRQ) { cpu->interrupt_time += deltaTime; if (sVectors[vector].type == INTERRUPT_TYPE_IRQ) cpu->irq_time += deltaTime; } update_int_load(vector); if (levelTriggered) return status; // edge triggered return value if (handled) return B_HANDLED_INTERRUPT; return B_UNHANDLED_INTERRUPT; }
static status_t acpi_cstate_add(acpi_object_type *object, CpuidleCstate *cState) { acpi_cstate_info *ci = (acpi_cstate_info *)malloc(sizeof(acpi_cstate_info)); if (!ci) return B_NO_MEMORY; if (object->object_type != ACPI_TYPE_PACKAGE) { dprintf("invalid _CST object\n"); return B_ERROR; } if (object->data.package.count != 4) { dprintf("invalid _CST number\n"); return B_ERROR; } // type acpi_object_type * pointer = &object->data.package.objects[1]; if (pointer->object_type != ACPI_TYPE_INTEGER) { dprintf("invalid _CST elem type\n"); return B_ERROR; } uint32 n = pointer->data.integer; if (n < 1 || n > 3) { dprintf("invalid _CST elem value\n"); return B_ERROR; } ci->type = n; dprintf("C%" B_PRId32 "\n", n); snprintf(cState->name, sizeof(cState->name), "C%" B_PRId32, n); // Latency pointer = &object->data.package.objects[2]; if (pointer->object_type != ACPI_TYPE_INTEGER) { dprintf("invalid _CST elem type\n"); return B_ERROR; } n = pointer->data.integer; cState->latency = n; dprintf("Latency: %" B_PRId32 "\n", n); // power pointer = &object->data.package.objects[3]; if (pointer->object_type != ACPI_TYPE_INTEGER) { dprintf("invalid _CST elem type\n"); return B_ERROR; } n = pointer->data.integer; dprintf("power: %" B_PRId32 "\n", n); // register pointer = &object->data.package.objects[0]; if (pointer->object_type != ACPI_TYPE_BUFFER) { dprintf("invalid _CST elem type\n"); return B_ERROR; } if (pointer->data.buffer.length < 15) { dprintf("invalid _CST elem length\n"); return B_ERROR; } struct acpicpu_reg *reg = (struct acpicpu_reg *)pointer->data.buffer.buffer; switch (reg->reg_spaceid) { case ACPI_ADR_SPACE_SYSTEM_IO: dprintf("IO method\n"); if (reg->reg_addr == 0) { dprintf("illegal address\n"); return B_ERROR; } if (reg->reg_bitwidth != 8) { dprintf("invalid source length\n"); return B_ERROR; } ci->address = reg->reg_addr; ci->method = ACPI_CSTATE_SYSIO; break; case ACPI_ADR_SPACE_FIXED_HARDWARE: { dprintf("FFH method\n"); ci->method = ACPI_CSTATE_FFH; ci->address = reg->reg_addr; // skip checking BM_STS if ACPI_PDC_GAS_BM is cleared cpu_ent *cpu = get_cpu_struct(); if ((cpu->arch.vendor == VENDOR_INTEL) && !(reg->reg_accesssize & ACPI_PDC_GAS_BM)) ci->skip_bm_sts = 1; break; } default: dprintf("invalid spaceid %" B_PRId8 "\n", reg->reg_spaceid); break; } cState->pData = ci; cState->EnterIdle = acpi_cstate_idle; return B_OK; }