--- trunk/src/cpu.c 2007/10/08 16:18:51 14 +++ trunk/src/cpu.c 2007/10/08 16:22:11 40 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 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.321 2005/10/03 01:07:40 debug Exp $ + * $Id: cpu.c,v 1.376 2007/04/19 15:18:15 debug Exp $ * * Common routines for CPU emulation. (Not specific to any CPU type.) */ @@ -33,17 +33,18 @@ #include #include #include +#include #include #include "cpu.h" #include "machine.h" #include "memory.h" #include "misc.h" +#include "settings.h" -extern int quiet_mode; -extern int show_opcode_statistics; - +extern size_t dyntrans_cache_size; +extern int native_code_translation_enabled; static struct cpu_family *first_cpu_family = NULL; @@ -53,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) @@ -60,6 +64,7 @@ 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"); @@ -74,14 +79,32 @@ 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->path = malloc(strlen(machine->path) + 15); + if (cpu->path == NULL) { + fprintf(stderr, "cpu_new(): out of memory\n"); + exit(1); + } + 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; + + /* 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_INT, + SETTINGS_FORMAT_YESNO, (void *) &cpu->running); cpu_create_or_reset_tc(cpu); @@ -97,30 +120,50 @@ "NULL\n"); exit(1); } - return cpu; + break; } } fp = fp->next; } - fatal("\ncpu_new(): unknown cpu type '%s'\n", cpu_type_name); - exit(1); + if (fp == NULL) { + fatal("\ncpu_new(): unknown cpu type '%s'\n", cpu_type_name); + return NULL; + } + + 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_show_full_statistics(): + * cpu_destroy(): * - * Show detailed statistics on opcode usage on each cpu. + * Destroy a cpu object. */ -void cpu_show_full_statistics(struct machine *m) +void cpu_destroy(struct cpu *cpu) { - 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); + 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)); } @@ -143,36 +186,20 @@ /* - * 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 * 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); } @@ -181,8 +208,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) @@ -195,40 +222,6 @@ /* - * 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 @@ -256,9 +249,9 @@ fatal("%s", symbol); else { if (cpu->is_32bit) - fatal("0x%08x", (int)f); + fatal("0x%"PRIx32, (uint32_t) f); else - fatal("0x%llx", (long long)f); + fatal("0x%"PRIx64, (uint64_t) f); } fatal("("); @@ -266,6 +259,11 @@ 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 } @@ -294,9 +292,26 @@ */ 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); + size_t s = dyntrans_cache_size + DYNTRANS_CACHE_MARGIN; + + if (cpu->translation_cache == NULL) { + cpu->translation_cache = zeroed_alloc(s); + +#ifdef NATIVE_CODE_GENERATION + if (native_code_translation_enabled) { + mprotect(cpu->translation_cache, s, + PROT_READ | PROT_WRITE | PROT_EXEC); + } +#endif + } + +#ifdef NATIVE_CODE_GENERATION + if (native_code_translation_enabled && cpu->inr.inr_entries == NULL) + cpu->inr.inr_entries = zeroed_alloc( + sizeof(struct inr_entry) * INR_MAX_ENTRIES); + + cpu->inr.nr_inr_entries_used = 0; +#endif /* Create an empty table at the beginning of the translation cache: */ memset(cpu->translation_cache, 0, sizeof(uint32_t) @@ -315,28 +330,10 @@ /* - * cpu_run(): - * - * Run instructions on all CPUs in this machine, for a "medium duration" - * (or until all CPUs have halted). - * - * Return value is 1 if anything happened, 0 if all CPUs are stopped. - */ -int cpu_run(struct emul *emul, struct machine *m) -{ - if (m->cpu_family == NULL || m->cpu_family->run == NULL) { - fatal("cpu_run(): NULL\n"); - return 0; - } else - return m->cpu_family->run(emul, m); -} - - -/* * 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) { @@ -358,7 +355,7 @@ void cpu_list_available_types(void) { struct cpu_family *fp; - int iadd = 4; + int iadd = DEBUG_INDENTATION; fp = first_cpu_family; @@ -393,9 +390,11 @@ int te; /* - * Two last ticks of every hardware device. This will allow - * framebuffers to draw the last updates to the screen before - * halting. + * Two last ticks of every hardware device. This will allow e.g. + * framebuffers to draw the last updates to the screen before halting. + * + * TODO: This should be refactored when redesigning the mainbus + * concepts! */ for (te=0; ten_tick_entries; te++) { machine->tick_func[te](machine->cpus[0], @@ -404,14 +403,9 @@ machine->tick_extra[te]); } - debug("cpu_run_deinit(): All CPUs halted.\n"); - - if (machine->show_nr_of_instructions || !quiet_mode) + if (machine->show_nr_of_instructions) cpu_show_cycles(machine, 1); - if (show_opcode_statistics) - cpu_show_full_statistics(machine); - fflush(stdout); } @@ -419,10 +413,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) { @@ -430,19 +422,12 @@ char *symbol; int64_t mseconds, ninstrs, is, avg; struct timeval tv; - int h, m, s, ms, d, instrs_per_cycle = 1; + struct cpu *cpu = machine->cpus[machine->bootstrap_cpu]; static int64_t mseconds_last = 0; static int64_t ninstrs_last = -1; - switch (machine->arch) { - case ARCH_MIPS: - instrs_per_cycle = machine->cpus[machine->bootstrap_cpu]-> - cd.mips.cpu_type.instrs_per_cycle; - break; - } - - pc = machine->cpus[machine->bootstrap_cpu]->pc; + pc = cpu->pc; gettimeofday(&tv, NULL); mseconds = (tv.tv_sec - machine->starttime.tv_sec) * 1000 @@ -454,53 +439,13 @@ if (mseconds - mseconds_last == 0) mseconds ++; - ninstrs = machine->ncycles_since_gettimeofday * instrs_per_cycle; - - 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; - - 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; - } - - /* debug("[ updating emulated_hz to %lli Hz ]\n", - (long long)machine->emulated_hz); */ - } - + ninstrs = machine->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("[ %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 = machine->ncycles / 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)machine->ninstrs); /* Instructions per second, and average so far: */ is = 1000 * (ninstrs-ninstrs_last) / (mseconds-mseconds_last); @@ -509,15 +454,20 @@ is = 0; if (avg < 0) avg = 0; - printf("; i/s=%lli avg=%lli", (long long)is, (long long)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) - printf("; pc=0x%08x", (int)pc); + if (cpu->is_32bit) + printf("; pc=0x%08"PRIx32, (uint32_t) pc); else - printf("; pc=0x%016llx", (long long)pc); + printf("; pc=0x%016"PRIx64, (uint64_t) pc); } if (symbol != NULL) @@ -538,38 +488,13 @@ */ void cpu_run_init(struct machine *machine) { - int ncpus = machine->ncpus; - int te; - - machine->a_few_cycles = 1048576; - machine->ncycles_flush = 0; - machine->ncycles = 0; - machine->ncycles_show = 0; - - /* - * Instead of doing { one cycle, check hardware ticks }, we - * can do { n cycles, check hardware ticks }, as long as - * n is at most as much as the lowest number of cycles/tick - * for any hardware device. - */ - for (te=0; ten_tick_entries; te++) { - if (machine->ticks_reset_value[te] < machine->a_few_cycles) - machine->a_few_cycles = machine->ticks_reset_value[te]; - } - - machine->a_few_cycles >>= 1; - if (machine->a_few_cycles < 1) - machine->a_few_cycles = 1; - - if (ncpus > 1 && machine->max_random_cycles_per_chunk == 0) - machine->a_few_cycles = 1; - - /* debug("cpu_run_init(): a_few_cycles = %i\n", - machine->a_few_cycles); */ + machine->ninstrs_flush = 0; + machine->ninstrs = 0; + machine->ninstrs_show = 0; /* For performance measurement: */ gettimeofday(&machine->starttime, NULL); - machine->ncycles_since_gettimeofday = 0; + machine->ninstrs_since_gettimeofday = 0; } @@ -642,6 +567,9 @@ * cpu_init(): * * Should be called before any other cpu_*() function. + * + * TODO: Make this nicer by moving out the conditional stuff to + * an automagically generated file? Or a define in config.h? */ void cpu_init(void) { @@ -659,20 +587,8 @@ 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); +#ifdef ENABLE_M88K + add_cpu_family(m88k_cpu_family_init, ARCH_M88K); #endif #ifdef ENABLE_MIPS @@ -690,9 +606,5 @@ #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 }