--- trunk/src/cpu.c 2007/10/08 16:18:27 10 +++ trunk/src/cpu.c 2007/10/08 16:19:37 22 @@ -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.298 2005/06/27 10:43:16 debug Exp $ + * $Id: cpu.c,v 1.329 2006/01/16 04:48:08 debug Exp $ * * Common routines for CPU emulation. (Not specific to any CPU type.) */ @@ -33,16 +33,18 @@ #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; - +extern int dyntrans_backend_enable; static struct cpu_family *first_cpu_family = NULL; @@ -71,13 +73,8 @@ exit(1); } - cpu = malloc(sizeof(struct cpu)); - if (cpu == NULL) { - fprintf(stderr, "out of memory\n"); - exit(1); - } + cpu = zeroed_alloc(sizeof(struct cpu)); - memset(cpu, 0, sizeof(struct cpu)); cpu->memory_rw = NULL; cpu->name = cpu_type_name; cpu->mem = mem; @@ -87,6 +84,8 @@ cpu->bootstrap_cpu_flag = 0; cpu->running = 0; + cpu_create_or_reset_tc(cpu); + fp = first_cpu_family; while (fp != NULL) { @@ -183,8 +182,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) @@ -231,6 +230,107 @@ /* + * 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) +{ + size_t s = DYNTRANS_CACHE_SIZE + DYNTRANS_CACHE_MARGIN; + + if (cpu->translation_cache == NULL) { +#ifdef DYNTRANS_BACKEND + if (dyntrans_backend_enable) { + cpu->translation_cache = (unsigned char *) mmap(NULL, + s, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | + MAP_PRIVATE, -1, 0); + if (cpu->translation_cache == NULL) { + dyntrans_backend_enable = 0; + fatal("%\n% WARNING! Dyntrans backend disabled" + ", because mmap() failed.\n%\n"); + } + } +#endif + 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" @@ -252,7 +352,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) { @@ -274,7 +374,7 @@ void cpu_list_available_types(void) { struct cpu_family *fp; - int iadd = 4; + int iadd = DEBUG_INDENTATION; fp = first_cpu_family; @@ -304,7 +404,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; @@ -343,27 +443,19 @@ void cpu_show_cycles(struct machine *machine, int forced) { uint64_t offset, pc; - int is_32bit = 0, instrs_per_cycle = 1; 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; switch (machine->arch) { case ARCH_MIPS: - 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; instrs_per_cycle = machine->cpus[machine->bootstrap_cpu]-> cd.mips.cpu_type.instrs_per_cycle; break; - case ARCH_ARM: - is_32bit = 1; - break; } pc = machine->cpus[machine->bootstrap_cpu]->pc; @@ -399,8 +491,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); */ } @@ -423,21 +515,26 @@ 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); } /* 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=0x%08x", (int)pc); - else - printf("pc=0x%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); + } if (symbol != NULL) printf(" <%s>", symbol); @@ -455,7 +552,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; @@ -557,6 +654,95 @@ } +#ifdef DYNTRANS_BACKEND +/* + * cpu_dtb_add_fixup(): + * + * Add a fixup entry to a currently ongoing dyntrans backend translation. + */ +void cpu_dtb_add_fixup(struct cpu *cpu, int type, void *addr, size_t data) +{ + struct dtb_fixup *fixup = malloc(sizeof (struct dtb_fixup)); + if (fixup == NULL) { + fprintf(stderr, "out of memory\n"), + exit(1); + } + + /* memset(fixup, 0, sizeof(struct dtb_fixup)); */ + + fixup->next = cpu->translation_context.fixups; + cpu->translation_context.fixups = fixup; + + fixup->type = type; + fixup->addr = addr; + fixup->data = data; + + /* printf("{ fixup added: host addr %p, data=%p }\n", addr, + (void *)data); */ +} + + +/* + * cpu_dtb_do_fixups(): + * + * This function should be called when a chunk of code has been translated, + * and post-fixup is to be applied (i.e. add data which for some reason was + * not included in the generated code). + * + * If no fixup is necessary for a specific host platform, then it still needs + * an empty do_fixups routine here (just set done = 1). + */ +void cpu_dtb_do_fixups(struct cpu *cpu) +{ + for (;;) { + int done = 0; + size_t omit_addr; + + struct dtb_fixup *fixup = cpu->translation_context.fixups; + if (fixup == NULL) + break; + + cpu->translation_context.fixups = fixup->next; + +#ifdef DYNTRANS_BACKEND_ALPHA + /* Add the data at the end of the new translation: */ +/*printf("%p %p\n", fixup->addr, fixup->data);*/ + omit_addr = (size_t)cpu->translation_context.p - + (size_t)cpu->translation_context.translation_buffer; +/*printf("omit_addr = %016llx\n", (long long)omit_addr);*/ + omit_addr = ((omit_addr - 1) | (sizeof(uint64_t) - 1)) + 1; +/*printf("omit_addr = %016llx\n", (long long)omit_addr);*/ + { + uint64_t *x = (void *)(omit_addr + (size_t)cpu-> + translation_context.translation_buffer); + uint32_t *fixup_instr = (void *)fixup->addr; + size_t ofs = omit_addr; + if (ofs > 0x7fff) { + fatal("Alpha fixup > 0x7fff!\n"); + exit(1); + } + *x = fixup->data; +/*printf("orig instr = 0x%08x\n", *fixup_instr);*/ + (*fixup_instr) &= ~0xffff; + (*fixup_instr) |= ofs; +/*printf("new instr = 0x%08x\n", *fixup_instr);*/ + } + omit_addr += sizeof(uint64_t); + cpu->translation_context.p = (void *) + ((size_t)cpu->translation_context.translation_buffer + + omit_addr); + done = 1; +#endif /* DYNTRANS_BACKEND_ALPHA */ + + if (!done) + fatal("!!! cpu_dtb_do_fixups() not implemented yet" + " for this host architecture!\n"); + } +} + +#endif /* DYNTRANS_BACKEND */ + + /* * cpu_init(): * @@ -565,10 +751,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); - add_cpu_family(urisc_cpu_family_init, ARCH_URISC); +#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_X86 add_cpu_family(x86_cpu_family_init, ARCH_X86); +#endif }