--- trunk/src/cpu.c 2007/10/08 16:18:00 4 +++ trunk/src/cpu.c 2007/10/08 16:19:56 24 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Anders Gavare. All rights reserved. + * Copyright (C) 2005-2006 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.292 2005/04/14 21:01:53 debug Exp $ + * $Id: cpu.c,v 1.342 2006/06/22 13:27:03 debug Exp $ * * Common routines for CPU emulation. (Not specific to any CPU type.) */ @@ -33,16 +33,16 @@ #include #include #include +#include #include #include "cpu.h" #include "machine.h" +#include "memory.h" #include "misc.h" extern int quiet_mode; -extern int show_opcode_statistics; - static struct cpu_family *first_cpu_family = NULL; @@ -56,7 +56,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,42 +71,40 @@ 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); - exit(1); -} - - -/* - * cpu_show_full_statistics(): - * - * Show detailed statistics on opcode usage on each cpu. - */ -void cpu_show_full_statistics(struct machine *m) -{ - if (m->cpu_family == NULL || - m->cpu_family->show_full_statistics == NULL) - fatal("cpu_show_full_statistics(): NULL\n"); - else - m->cpu_family->show_full_statistics(m); + fatal("\ncpu_new(): unknown cpu type '%s'\n", cpu_type_name); + return NULL; } @@ -151,14 +149,14 @@ * tracing. */ int cpu_disassemble_instr(struct machine *m, struct cpu *cpu, - unsigned char *instr, int running, uint64_t addr, int bintrans) + unsigned char *instr, int running, uint64_t addr) { if (m->cpu_family == NULL || m->cpu_family->disassemble_instr == NULL) { fatal("cpu_disassemble_instr(): NULL\n"); return 0; } else return m->cpu_family->disassemble_instr(cpu, instr, - running, addr, bintrans); + running, addr); } @@ -167,8 +165,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) @@ -181,6 +179,24 @@ /* + * 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. @@ -215,6 +231,98 @@ /* + * 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%"PRIx32, (uint32_t) f); + else + fatal("0x%"PRIx64, (uint64_t) f); + } + fatal("("); + + if (cpu->machine->cpu_family->functioncall_trace != NULL) + cpu->machine->cpu_family->functioncall_trace(cpu, f, n_args); + + fatal(")>\n"); + +#ifdef PRINT_MEMORY_CHECKSUM + /* Temporary hack for finding bugs: */ + fatal("call chksum=%016"PRIx64"\n", memory_checksum(cpu->mem)); +#endif +} + + +/* + * 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) +{ + size_t s = DYNTRANS_CACHE_SIZE + DYNTRANS_CACHE_MARGIN; + + if (cpu->translation_cache == NULL) + cpu->translation_cache = zeroed_alloc(s); + + /* 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 +344,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) { @@ -258,7 +366,7 @@ void cpu_list_available_types(void) { struct cpu_family *fp; - int iadd = 4; + int iadd = DEBUG_INDENTATION; fp = first_cpu_family; @@ -288,7 +396,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,11 +415,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); - - if (show_opcode_statistics) - cpu_show_full_statistics(machine); + cpu_show_cycles(machine, 1); fflush(stdout); } @@ -325,35 +429,22 @@ * 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; 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; - } - - 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,15 +452,17 @@ if (mseconds - mseconds_last == 0) mseconds ++; - ninstrs = ncycles * instrs_per_cycle; + ninstrs = machine->ncycles_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) - / instrs_per_cycle; + (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; @@ -382,8 +475,8 @@ cur_cycles_per_second) / 16; } - debug("[ updating emulated_hz to %lli Hz ]\n", - (long long)machine->emulated_hz); + /* fatal("[ updating emulated_hz to %"PRIi64" Hz ]\n", + machine->emulated_hz); */ } @@ -391,14 +484,13 @@ if (!machine->show_nr_of_instructions && !forced) goto do_return; - - printf("[ "); + printf("[ %"PRIi64" instrs", (int64_t)machine->ncycles); 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; @@ -406,28 +498,30 @@ s = ms / 1000; ms -= 1000 * s; - printf("emulated time = %02i:%02i:%02i.%03i; ", h, m, s, ms); + 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=%"PRIi64" avg=%"PRIi64, is, 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%08"PRIx32, (uint32_t) pc); + else + printf("; pc=0x%016"PRIx64, (uint64_t) pc); + } - printf(" <%s> ]\n", symbol? symbol : "no symbol"); + if (symbol != NULL) + printf(" <%s>", symbol); + printf(" ]\n"); do_return: ninstrs_last = ninstrs; @@ -441,7 +535,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; @@ -466,7 +560,7 @@ if (machine->a_few_cycles < 1) machine->a_few_cycles = 1; - if (ncpus > 1 && machine->max_random_cycles_per_chunk == 0) + if (ncpus > 1) machine->a_few_cycles = 1; /* debug("cpu_run_init(): a_few_cycles = %i\n", @@ -474,6 +568,7 @@ /* For performance measurement: */ gettimeofday(&machine->starttime, NULL); + machine->ncycles_since_gettimeofday = 0; } @@ -550,12 +645,53 @@ 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); - add_cpu_family(urisc_cpu_family_init, ARCH_URISC); +#endif + +#ifdef ENABLE_X86 add_cpu_family(x86_cpu_family_init, ARCH_X86); +#endif }