--- trunk/src/cpu.c 2007/10/08 16:20:26 28 +++ trunk/src/cpu.c 2007/10/08 16:22:32 42 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2006 Anders Gavare. All rights reserved. + * Copyright (C) 2005-2007 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu.c,v 1.348 2006/07/20 21:52:59 debug Exp $ + * $Id: cpu.c,v 1.389 2007/06/15 17:02:37 debug Exp $ * * Common routines for CPU emulation. (Not specific to any CPU type.) */ @@ -39,9 +39,13 @@ #include "cpu.h" #include "machine.h" #include "memory.h" -#include "misc.h" +#include "settings.h" +#include "timer.h" +extern size_t dyntrans_cache_size; +extern int native_code_translation_enabled; + static struct cpu_family *first_cpu_family = NULL; @@ -50,6 +54,9 @@ * * Create a new cpu object. Each family is tried in sequence until a * CPU family recognizes the cpu_type_name. + * + * If there was no match, NULL is returned. Otherwise, a pointer to an + * initialized cpu struct is returned. */ struct cpu *cpu_new(struct memory *mem, struct machine *machine, int cpu_id, char *name) @@ -57,28 +64,41 @@ struct cpu *cpu; struct cpu_family *fp; char *cpu_type_name; + char tmpstr[30]; if (name == NULL) { fprintf(stderr, "cpu_new(): cpu name = NULL?\n"); exit(1); } - cpu_type_name = strdup(name); - if (cpu_type_name == NULL) { - fprintf(stderr, "cpu_new(): out of memory\n"); - exit(1); - } + CHECK_ALLOCATION(cpu_type_name = strdup(name)); cpu = zeroed_alloc(sizeof(struct cpu)); - cpu->memory_rw = NULL; - cpu->name = cpu_type_name; - cpu->mem = mem; - cpu->machine = machine; - cpu->cpu_id = cpu_id; - cpu->byte_order = EMUL_LITTLE_ENDIAN; - cpu->bootstrap_cpu_flag = 0; - cpu->running = 0; + CHECK_ALLOCATION(cpu->path = malloc(strlen(machine->path) + 15)); + snprintf(cpu->path, strlen(machine->path) + 15, + "%s.cpu[%i]", machine->path, cpu_id); + + cpu->memory_rw = NULL; + cpu->name = cpu_type_name; + cpu->mem = mem; + cpu->machine = machine; + cpu->cpu_id = cpu_id; + cpu->byte_order = EMUL_UNDEFINED_ENDIAN; + cpu->running = 0; + + cpu->sampling_paddr = zeroed_alloc(N_PADDR_SAMPLES * sizeof(uint64_t)); + + /* Create settings, and attach to the machine: */ + cpu->settings = settings_new(); + snprintf(tmpstr, sizeof(tmpstr), "cpu[%i]", cpu_id); + settings_add(machine->settings, tmpstr, 1, + SETTINGS_TYPE_SUBSETTINGS, 0, cpu->settings); + + settings_add(cpu->settings, "name", 0, SETTINGS_TYPE_STRING, + SETTINGS_FORMAT_STRING, (void *) &cpu->name); + settings_add(cpu->settings, "running", 0, SETTINGS_TYPE_UINT8, + SETTINGS_FORMAT_YESNO, (void *) &cpu->running); cpu_create_or_reset_tc(cpu); @@ -108,11 +128,43 @@ fp->init_tables(cpu); + if (cpu->byte_order == EMUL_UNDEFINED_ENDIAN) { + fatal("\ncpu_new(): Internal bug: Endianness not set.\n"); + exit(1); + } + return cpu; } /* + * cpu_destroy(): + * + * Destroy a cpu object. + */ +void cpu_destroy(struct cpu *cpu) +{ + if (cpu->sampling_timer != NULL) + timer_remove(cpu->sampling_timer); + + settings_remove(cpu->settings, "name"); + settings_remove(cpu->settings, "running"); + + /* Remove any remaining level-1 settings: */ + settings_remove_all(cpu->settings); + + settings_destroy(cpu->settings); + + if (cpu->path != NULL) + free(cpu->path); + + /* TODO: This assumes that zeroed_alloc() actually succeeded + with using mmap(), and not malloc()! */ + munmap((void *)cpu, sizeof(struct cpu)); +} + + +/* * cpu_tlbdump(): * * Called from the debugger to dump the TLB in a readable format. @@ -131,22 +183,6 @@ /* - * cpu_register_match(): - * - * Used by the debugger. - */ -void cpu_register_match(struct machine *m, char *name, - int writeflag, uint64_t *valuep, int *match_register) -{ - if (m->cpu_family == NULL || m->cpu_family->register_match == NULL) - fatal("cpu_register_match(): NULL\n"); - else - m->cpu_family->register_match(m, name, writeflag, - valuep, match_register); -} - - -/* * cpu_disassemble_instr(): * * Convert an instruction word into human readable format, for instruction @@ -183,58 +219,6 @@ /* - * cpu_gdb_stub(): - * - * Execute a "remote GDB" command. Return value is a pointer to a newly - * allocated response string, if the command was successfully executed. If - * there was an error, NULL is returned. - */ -char *cpu_gdb_stub(struct cpu *cpu, char *cmd) -{ - if (cpu->machine->cpu_family == NULL || - cpu->machine->cpu_family->gdb_stub == NULL) { - fatal("cpu_gdb_stub(): NULL\n"); - return NULL; - } else - return cpu->machine->cpu_family->gdb_stub(cpu, cmd); -} - - -/* - * cpu_interrupt(): - * - * Assert an interrupt. - * Return value is 1 if the interrupt was asserted, 0 otherwise. - */ -int cpu_interrupt(struct cpu *cpu, uint64_t irq_nr) -{ - if (cpu->machine->cpu_family == NULL || - cpu->machine->cpu_family->interrupt == NULL) { - fatal("cpu_interrupt(): NULL\n"); - return 0; - } else - return cpu->machine->cpu_family->interrupt(cpu, irq_nr); -} - - -/* - * cpu_interrupt_ack(): - * - * Acknowledge an interrupt. - * Return value is 1 if the interrupt was deasserted, 0 otherwise. - */ -int cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr) -{ - if (cpu->machine->cpu_family == NULL || - cpu->machine->cpu_family->interrupt_ack == NULL) { - /* debug("cpu_interrupt_ack(): NULL\n"); */ - return 0; - } else - return cpu->machine->cpu_family->interrupt_ack(cpu, irq_nr); -} - - -/* * cpu_functioncall_trace(): * * This function should be called if machine->show_trace_tree is enabled, and @@ -242,23 +226,30 @@ */ void cpu_functioncall_trace(struct cpu *cpu, uint64_t f) { + int show_symbolic_function_name = 1; int i, n_args = -1; char *symbol; uint64_t offset; + /* Special hack for M88K userspace: */ + if (cpu->machine->arch == ARCH_M88K && + !(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)) + show_symbolic_function_name = 0; + if (cpu->machine->ncpus > 1) fatal("cpu%i:\t", cpu->cpu_id); - cpu->trace_tree_depth ++; if (cpu->trace_tree_depth > 100) cpu->trace_tree_depth = 100; for (i=0; itrace_tree_depth; i++) fatal(" "); + cpu->trace_tree_depth ++; + fatal("<"); symbol = get_symbol_name_and_n_args(&cpu->machine->symbol_context, f, &offset, &n_args); - if (symbol != NULL) + if (symbol != NULL && show_symbolic_function_name) fatal("%s", symbol); else { if (cpu->is_32bit) @@ -305,11 +296,17 @@ */ void cpu_create_or_reset_tc(struct cpu *cpu) { - size_t s = DYNTRANS_CACHE_SIZE + DYNTRANS_CACHE_MARGIN; + size_t s = dyntrans_cache_size + DYNTRANS_CACHE_MARGIN; - if (cpu->translation_cache == NULL) + if (cpu->translation_cache == NULL) { cpu->translation_cache = zeroed_alloc(s); + if (native_code_translation_enabled) { + mprotect(cpu->translation_cache, s, + PROT_READ | PROT_WRITE | PROT_EXEC); + } + } + /* Create an empty table at the beginning of the translation cache: */ memset(cpu->translation_cache, 0, sizeof(uint32_t) * N_BASE_TABLE_ENTRIES); @@ -393,11 +390,11 @@ * TODO: This should be refactored when redesigning the mainbus * concepts! */ - for (te=0; ten_tick_entries; te++) { - machine->tick_func[te](machine->cpus[0], - machine->tick_extra[te]); - machine->tick_func[te](machine->cpus[0], - machine->tick_extra[te]); + for (te=0; tetick_functions.n_entries; te++) { + machine->tick_functions.f[te](machine->cpus[0], + machine->tick_functions.extra[te]); + machine->tick_functions.f[te](machine->cpus[0], + machine->tick_functions.extra[te]); } if (machine->show_nr_of_instructions) @@ -410,10 +407,8 @@ /* * cpu_show_cycles(): * - * If automatic adjustment of clock interrupts is turned on, then recalculate - * emulated_hz. Also, if show_nr_of_instructions is on, then print a - * line to stdout about how many instructions/cycles have been executed so - * far. + * If show_nr_of_instructions is on, then print a line to stdout about how + * many instructions/cycles have been executed so far. */ void cpu_show_cycles(struct machine *machine, int forced) { @@ -421,16 +416,16 @@ char *symbol; int64_t mseconds, ninstrs, is, avg; struct timeval tv; - int h, m, s, ms, d; + struct cpu *cpu = machine->cpus[machine->bootstrap_cpu]; static int64_t mseconds_last = 0; static int64_t ninstrs_last = -1; - pc = machine->cpus[machine->bootstrap_cpu]->pc; + pc = cpu->pc; gettimeofday(&tv, NULL); - mseconds = (tv.tv_sec - machine->starttime.tv_sec) * 1000 - + (tv.tv_usec - machine->starttime.tv_usec) / 1000; + mseconds = (tv.tv_sec - cpu->starttime.tv_sec) * 1000 + + (tv.tv_usec - cpu->starttime.tv_usec) / 1000; if (mseconds == 0) mseconds = 1; @@ -438,54 +433,13 @@ if (mseconds - mseconds_last == 0) mseconds ++; - ninstrs = machine->ninstrs_since_gettimeofday; - - if (machine->automatic_clock_adjustment) { - static int first_adjustment = 1; - - /* Current nr of cycles per second: */ - int64_t cur_cycles_per_second = 1000 * - (ninstrs-ninstrs_last) / (mseconds-mseconds_last); - - /* fatal("[ CYCLES PER SECOND = %"PRIi64" ]\n", - cur_cycles_per_second); */ - - if (cur_cycles_per_second < 1000000) - cur_cycles_per_second = 1000000; - - if (first_adjustment) { - machine->emulated_hz = cur_cycles_per_second; - first_adjustment = 0; - } else { - machine->emulated_hz = (15 * machine->emulated_hz + - cur_cycles_per_second) / 16; - } - - /* fatal("[ updating emulated_hz to %"PRIi64" Hz ]\n", - machine->emulated_hz); */ - } - + ninstrs = cpu->ninstrs_since_gettimeofday; /* RETURN here, unless show_nr_of_instructions (-N) is turned on: */ if (!machine->show_nr_of_instructions && !forced) goto do_return; - printf("[ %"PRIi64" instrs", (int64_t)machine->ninstrs); - - if (!machine->automatic_clock_adjustment) { - d = machine->emulated_hz / 1000; - if (d < 1) - d = 1; - ms = machine->ninstrs / d; - h = ms / 3600000; - ms -= 3600000 * h; - m = ms / 60000; - ms -= 60000 * m; - s = ms / 1000; - ms -= 1000 * s; - - printf(", emulated time = %02i:%02i:%02i.%03i; ", h, m, s, ms); - } + printf("[ %"PRIi64" instrs", (int64_t) cpu->ninstrs); /* Instructions per second, and average so far: */ is = 1000 * (ninstrs-ninstrs_last) / (mseconds-mseconds_last); @@ -494,17 +448,27 @@ is = 0; if (avg < 0) avg = 0; - printf("; i/s=%"PRIi64" avg=%"PRIi64, is, avg); + + if (cpu->has_been_idling) { + printf("; idling"); + cpu->has_been_idling = 0; + } else + printf("; i/s=%"PRIi64" avg=%"PRIi64, is, avg); symbol = get_symbol_name(&machine->symbol_context, pc, &offset); if (machine->ncpus == 1) { - if (machine->cpus[machine->bootstrap_cpu]->is_32bit) + if (cpu->is_32bit) printf("; pc=0x%08"PRIx32, (uint32_t) pc); else printf("; pc=0x%016"PRIx64, (uint64_t) pc); } + /* Special hack for M88K userland: (Don't show symbols.) */ + if (cpu->machine->arch == ARCH_M88K && + !(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)) + symbol = NULL; + if (symbol != NULL) printf(" <%s>", symbol); printf(" ]\n"); @@ -523,13 +487,18 @@ */ void cpu_run_init(struct machine *machine) { - machine->ninstrs_flush = 0; - machine->ninstrs = 0; - machine->ninstrs_show = 0; - - /* For performance measurement: */ - gettimeofday(&machine->starttime, NULL); - machine->ninstrs_since_gettimeofday = 0; + int i; + for (i=0; incpus; i++) { + struct cpu *cpu = machine->cpus[i]; + + cpu->ninstrs_flush = 0; + cpu->ninstrs = 0; + cpu->ninstrs_show = 0; + + /* For performance measurement: */ + gettimeofday(&cpu->starttime, NULL); + cpu->ninstrs_since_gettimeofday = 0; + } } @@ -544,11 +513,7 @@ struct cpu_family *fp, *tmp; int res; - fp = malloc(sizeof(struct cpu_family)); - if (fp == NULL) { - fprintf(stderr, "add_cpu_family(): out of memory\n"); - exit(1); - } + CHECK_ALLOCATION(fp = malloc(sizeof(struct cpu_family))); memset(fp, 0, sizeof(struct cpu_family)); /* @@ -602,61 +567,13 @@ * cpu_init(): * * Should be called before any other cpu_*() function. + * + * This function calls add_cpu_family() for each processor architecture. + * ADD_ALL_CPU_FAMILIES is defined in the config.h file generated by the + * configure script. */ void cpu_init(void) { - /* Note: These are registered in alphabetic order. */ - -#ifdef ENABLE_ALPHA - add_cpu_family(alpha_cpu_family_init, ARCH_ALPHA); -#endif - -#ifdef ENABLE_ARM - add_cpu_family(arm_cpu_family_init, ARCH_ARM); -#endif - -#ifdef ENABLE_AVR - add_cpu_family(avr_cpu_family_init, ARCH_AVR); -#endif - -#ifdef ENABLE_HPPA - add_cpu_family(hppa_cpu_family_init, ARCH_HPPA); -#endif - -#ifdef ENABLE_I960 - add_cpu_family(i960_cpu_family_init, ARCH_I960); -#endif - -#ifdef ENABLE_IA64 - add_cpu_family(ia64_cpu_family_init, ARCH_IA64); -#endif - -#ifdef ENABLE_M68K - add_cpu_family(m68k_cpu_family_init, ARCH_M68K); -#endif - -#ifdef ENABLE_MIPS - add_cpu_family(mips_cpu_family_init, ARCH_MIPS); -#endif - -#ifdef ENABLE_PPC - add_cpu_family(ppc_cpu_family_init, ARCH_PPC); -#endif - -#ifdef ENABLE_SH - add_cpu_family(sh_cpu_family_init, ARCH_SH); -#endif - -#ifdef ENABLE_SPARC - add_cpu_family(sparc_cpu_family_init, ARCH_SPARC); -#endif - -#ifdef ENABLE_TRANSPUTER - add_cpu_family(transputer_cpu_family_init, ARCH_TRANSPUTER); -#endif - -#ifdef ENABLE_X86 - add_cpu_family(x86_cpu_family_init, ARCH_X86); -#endif + ADD_ALL_CPU_FAMILIES; }