--- trunk/src/cpu.c 2007/10/08 16:17:48 2 +++ trunk/src/cpu.c 2007/10/08 16:19:23 20 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu.c,v 1.291 2005/03/13 09:36:08 debug Exp $ + * $Id: cpu.c,v 1.323 2005/11/13 22:34:21 debug Exp $ * * Common routines for CPU emulation. (Not specific to any CPU type.) */ @@ -37,6 +37,7 @@ #include "cpu.h" #include "machine.h" +#include "memory.h" #include "misc.h" @@ -56,7 +57,7 @@ struct cpu *cpu_new(struct memory *mem, struct machine *machine, int cpu_id, char *name) { - struct cpu *c; + struct cpu *cpu; struct cpu_family *fp; char *cpu_type_name; @@ -71,26 +72,39 @@ exit(1); } + 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; + + cpu_create_or_reset_tc(cpu); + fp = first_cpu_family; while (fp != NULL) { if (fp->cpu_new != NULL) { - c = fp->cpu_new(mem, machine, cpu_id, cpu_type_name); - if (c != NULL) { - /* Some sanity-checks: */ - if (c->memory_rw == NULL) { - fatal("No memory_rw?\n"); + if (fp->cpu_new(cpu, mem, machine, cpu_id, + cpu_type_name)) { + /* Sanity check: */ + if (cpu->memory_rw == NULL) { + fatal("\ncpu_new(): memory_rw == " + "NULL\n"); exit(1); } - - return c; + return cpu; } } fp = fp->next; } - fprintf(stderr, "cpu_new(): unknown cpu type '%s'\n", cpu_type_name); + fatal("\ncpu_new(): unknown cpu type '%s'\n", cpu_type_name); exit(1); } @@ -167,8 +181,8 @@ * * Dump cpu registers in a relatively readable format. * - * gprs: set to non-zero to dump GPRs. (CPU dependant.) - * coprocs: set bit 0..x to dump registers in coproc 0..x. (CPU dependant.) + * gprs: set to non-zero to dump GPRs. (CPU dependent.) + * coprocs: set bit 0..x to dump registers in coproc 0..x. (CPU dependent.) */ void cpu_register_dump(struct machine *m, struct cpu *cpu, int gprs, int coprocs) @@ -215,6 +229,92 @@ /* + * cpu_functioncall_trace(): + * + * This function should be called if machine->show_trace_tree is enabled, and + * a function call is being made. f contains the address of the function. + */ +void cpu_functioncall_trace(struct cpu *cpu, uint64_t f) +{ + int i, n_args = -1; + char *symbol; + uint64_t offset; + + 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(" "); + + fatal("<"); + symbol = get_symbol_name_and_n_args(&cpu->machine->symbol_context, + f, &offset, &n_args); + if (symbol != NULL) + fatal("%s", symbol); + else { + if (cpu->is_32bit) + fatal("0x%08x", (int)f); + else + fatal("0x%llx", (long long)f); + } + fatal("("); + + if (cpu->machine->cpu_family->functioncall_trace != NULL) + cpu->machine->cpu_family->functioncall_trace(cpu, f, n_args); + + fatal(")>\n"); +} + + +/* + * cpu_functioncall_trace_return(): + * + * This function should be called if machine->show_trace_tree is enabled, and + * a function is being returned from. + * + * TODO: Print return value? This could be implemented similar to the + * cpu->functioncall_trace function call above. + */ +void cpu_functioncall_trace_return(struct cpu *cpu) +{ + cpu->trace_tree_depth --; + if (cpu->trace_tree_depth < 0) + cpu->trace_tree_depth = 0; +} + + +/* + * cpu_create_or_reset_tc(): + * + * Create the translation cache in memory (ie allocate memory for it), if + * necessary, and then reset it to an initial state. + */ +void cpu_create_or_reset_tc(struct cpu *cpu) +{ + if (cpu->translation_cache == NULL) + cpu->translation_cache = zeroed_alloc(DYNTRANS_CACHE_SIZE + + DYNTRANS_CACHE_MARGIN); + + /* Create an empty table at the beginning of the translation cache: */ + memset(cpu->translation_cache, 0, sizeof(uint32_t) + * N_BASE_TABLE_ENTRIES); + + cpu->translation_cache_cur_ofs = + N_BASE_TABLE_ENTRIES * sizeof(uint32_t); + + /* + * There might be other translation pointers that still point to + * within the translation_cache region. Let's invalidate those too: + */ + if (cpu->invalidate_code_translation != NULL) + cpu->invalidate_code_translation(cpu, 0, INVALIDATE_ALL); +} + + +/* * cpu_run(): * * Run instructions on all CPUs in this machine, for a "medium duration" @@ -236,7 +336,7 @@ * cpu_dumpinfo(): * * Dumps info about a CPU using debug(). "cpu0: CPUNAME, running" (or similar) - * is outputed, and it is up to CPU dependant code to complete the line. + * is outputed, and it is up to CPU dependent code to complete the line. */ void cpu_dumpinfo(struct machine *m, struct cpu *cpu) { @@ -288,7 +388,7 @@ * Shuts down all CPUs in a machine when ending a simulation. (This function * should only need to be called once for each machine.) */ -void cpu_run_deinit(struct emul *emul, struct machine *machine) +void cpu_run_deinit(struct machine *machine) { int te; @@ -307,8 +407,7 @@ debug("cpu_run_deinit(): All CPUs halted.\n"); if (machine->show_nr_of_instructions || !quiet_mode) - cpu_show_cycles(machine, &machine->starttime, - machine->ncycles, 1); + cpu_show_cycles(machine, 1); if (show_opcode_statistics) cpu_show_full_statistics(machine); @@ -325,35 +424,29 @@ * line to stdout about how many instructions/cycles have been executed so * far. */ -void cpu_show_cycles(struct machine *machine, - struct timeval *starttime, int64_t ncycles, int forced) +void cpu_show_cycles(struct machine *machine, int forced) { uint64_t offset, pc; - int is_32bit = 0, instrs_per_cycle; char *symbol; - int64_t mseconds, ninstrs; + int64_t mseconds, ninstrs, is, avg; struct timeval tv; - int h, m, s, ms, d; + int h, m, s, ms, d, instrs_per_cycle = 1; static int64_t mseconds_last = 0; static int64_t ninstrs_last = -1; - if (machine->arch != ARCH_MIPS) { - fatal("cpu_show_cycles(): not yet for !MIPS\n"); - return; + switch (machine->arch) { + case ARCH_MIPS: + instrs_per_cycle = machine->cpus[machine->bootstrap_cpu]-> + cd.mips.cpu_type.instrs_per_cycle; + break; } - if (machine->cpus[machine->bootstrap_cpu]->cd.mips.cpu_type.isa_level - < 3 || machine->cpus[machine->bootstrap_cpu]->cd.mips.cpu_type. - isa_level == 32) - is_32bit = 1; pc = machine->cpus[machine->bootstrap_cpu]->pc; - instrs_per_cycle = machine->cpus[machine->bootstrap_cpu]-> - cd.mips.cpu_type.instrs_per_cycle; gettimeofday(&tv, NULL); - mseconds = (tv.tv_sec - starttime->tv_sec) * 1000 - + (tv.tv_usec - starttime->tv_usec) / 1000; + mseconds = (tv.tv_sec - machine->starttime.tv_sec) * 1000 + + (tv.tv_usec - machine->starttime.tv_usec) / 1000; if (mseconds == 0) mseconds = 1; @@ -361,7 +454,7 @@ if (mseconds - mseconds_last == 0) mseconds ++; - ninstrs = ncycles * instrs_per_cycle; + ninstrs = machine->ncycles_since_gettimeofday * instrs_per_cycle; if (machine->automatic_clock_adjustment) { static int first_adjustment = 1; @@ -382,8 +475,8 @@ cur_cycles_per_second) / 16; } - debug("[ updating emulated_hz to %lli Hz ]\n", - (long long)machine->emulated_hz); + /* debug("[ updating emulated_hz to %lli Hz ]\n", + (long long)machine->emulated_hz); */ } @@ -391,14 +484,14 @@ if (!machine->show_nr_of_instructions && !forced) goto do_return; - - printf("[ "); + printf("[ %lli instrs", + (long long)(machine->ncycles * instrs_per_cycle)); if (!machine->automatic_clock_adjustment) { d = machine->emulated_hz / 1000; if (d < 1) d = 1; - ms = ncycles / d; + ms = machine->ncycles / d; h = ms / 3600000; ms -= 3600000 * h; m = ms / 60000; @@ -409,25 +502,27 @@ printf("emulated time = %02i:%02i:%02i.%03i; ", h, m, s, ms); } - printf("cycles=%lli", (long long) ncycles); - - if (instrs_per_cycle > 1) - printf(" (%lli instrs)", (long long) ninstrs); - /* Instructions per second, and average so far: */ - printf("; i/s=%lli avg=%lli", - (long long) ((long long)1000 * (ninstrs-ninstrs_last) - / (mseconds-mseconds_last)), - (long long) ((long long)1000 * ninstrs / mseconds)); + is = 1000 * (ninstrs-ninstrs_last) / (mseconds-mseconds_last); + avg = (long long)1000 * ninstrs / mseconds; + if (is < 0) + is = 0; + if (avg < 0) + avg = 0; + printf("; i/s=%lli avg=%lli", (long long)is, (long long)avg); symbol = get_symbol_name(&machine->symbol_context, pc, &offset); - if (is_32bit) - printf("; pc=%08x", (int)pc); - else - printf("; pc=%016llx", (long long)pc); + if (machine->ncpus == 1) { + if (machine->cpus[machine->bootstrap_cpu]->is_32bit) + printf("; pc=0x%08x", (int)pc); + else + printf("; pc=0x%016llx", (long long)pc); + } - printf(" <%s> ]\n", symbol? symbol : "no symbol"); + if (symbol != NULL) + printf(" <%s>", symbol); + printf(" ]\n"); do_return: ninstrs_last = ninstrs; @@ -441,7 +536,7 @@ * Prepare to run instructions on all CPUs in this machine. (This function * should only need to be called once for each machine.) */ -void cpu_run_init(struct emul *emul, struct machine *machine) +void cpu_run_init(struct machine *machine) { int ncpus = machine->ncpus; int te; @@ -474,6 +569,7 @@ /* For performance measurement: */ gettimeofday(&machine->starttime, NULL); + machine->ncycles_since_gettimeofday = 0; } @@ -550,11 +646,57 @@ 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_NEWMIPS + add_cpu_family(newmips_cpu_family_init, ARCH_NEWMIPS); +#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); - add_cpu_family(urisc_cpu_family_init, ARCH_URISC); +#endif + +#ifdef ENABLE_X86 + add_cpu_family(x86_cpu_family_init, ARCH_X86); +#endif }