25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu.c,v 1.376 2007/04/19 15:18:15 debug Exp $ |
* $Id: cpu.c,v 1.389 2007/06/15 17:02:37 debug Exp $ |
29 |
* |
* |
30 |
* Common routines for CPU emulation. (Not specific to any CPU type.) |
* Common routines for CPU emulation. (Not specific to any CPU type.) |
31 |
*/ |
*/ |
39 |
#include "cpu.h" |
#include "cpu.h" |
40 |
#include "machine.h" |
#include "machine.h" |
41 |
#include "memory.h" |
#include "memory.h" |
|
#include "misc.h" |
|
42 |
#include "settings.h" |
#include "settings.h" |
43 |
|
#include "timer.h" |
44 |
|
|
45 |
|
|
46 |
extern size_t dyntrans_cache_size; |
extern size_t dyntrans_cache_size; |
71 |
exit(1); |
exit(1); |
72 |
} |
} |
73 |
|
|
74 |
cpu_type_name = strdup(name); |
CHECK_ALLOCATION(cpu_type_name = strdup(name)); |
|
if (cpu_type_name == NULL) { |
|
|
fprintf(stderr, "cpu_new(): out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
75 |
|
|
76 |
cpu = zeroed_alloc(sizeof(struct cpu)); |
cpu = zeroed_alloc(sizeof(struct cpu)); |
77 |
|
|
78 |
cpu->path = malloc(strlen(machine->path) + 15); |
CHECK_ALLOCATION(cpu->path = malloc(strlen(machine->path) + 15)); |
|
if (cpu->path == NULL) { |
|
|
fprintf(stderr, "cpu_new(): out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
79 |
snprintf(cpu->path, strlen(machine->path) + 15, |
snprintf(cpu->path, strlen(machine->path) + 15, |
80 |
"%s.cpu[%i]", machine->path, cpu_id); |
"%s.cpu[%i]", machine->path, cpu_id); |
81 |
|
|
87 |
cpu->byte_order = EMUL_UNDEFINED_ENDIAN; |
cpu->byte_order = EMUL_UNDEFINED_ENDIAN; |
88 |
cpu->running = 0; |
cpu->running = 0; |
89 |
|
|
90 |
|
cpu->sampling_paddr = zeroed_alloc(N_PADDR_SAMPLES * sizeof(uint64_t)); |
91 |
|
|
92 |
/* Create settings, and attach to the machine: */ |
/* Create settings, and attach to the machine: */ |
93 |
cpu->settings = settings_new(); |
cpu->settings = settings_new(); |
94 |
snprintf(tmpstr, sizeof(tmpstr), "cpu[%i]", cpu_id); |
snprintf(tmpstr, sizeof(tmpstr), "cpu[%i]", cpu_id); |
97 |
|
|
98 |
settings_add(cpu->settings, "name", 0, SETTINGS_TYPE_STRING, |
settings_add(cpu->settings, "name", 0, SETTINGS_TYPE_STRING, |
99 |
SETTINGS_FORMAT_STRING, (void *) &cpu->name); |
SETTINGS_FORMAT_STRING, (void *) &cpu->name); |
100 |
settings_add(cpu->settings, "running", 0, SETTINGS_TYPE_INT, |
settings_add(cpu->settings, "running", 0, SETTINGS_TYPE_UINT8, |
101 |
SETTINGS_FORMAT_YESNO, (void *) &cpu->running); |
SETTINGS_FORMAT_YESNO, (void *) &cpu->running); |
102 |
|
|
103 |
cpu_create_or_reset_tc(cpu); |
cpu_create_or_reset_tc(cpu); |
144 |
*/ |
*/ |
145 |
void cpu_destroy(struct cpu *cpu) |
void cpu_destroy(struct cpu *cpu) |
146 |
{ |
{ |
147 |
|
if (cpu->sampling_timer != NULL) |
148 |
|
timer_remove(cpu->sampling_timer); |
149 |
|
|
150 |
settings_remove(cpu->settings, "name"); |
settings_remove(cpu->settings, "name"); |
151 |
settings_remove(cpu->settings, "running"); |
settings_remove(cpu->settings, "running"); |
152 |
|
|
226 |
*/ |
*/ |
227 |
void cpu_functioncall_trace(struct cpu *cpu, uint64_t f) |
void cpu_functioncall_trace(struct cpu *cpu, uint64_t f) |
228 |
{ |
{ |
229 |
|
int show_symbolic_function_name = 1; |
230 |
int i, n_args = -1; |
int i, n_args = -1; |
231 |
char *symbol; |
char *symbol; |
232 |
uint64_t offset; |
uint64_t offset; |
233 |
|
|
234 |
|
/* Special hack for M88K userspace: */ |
235 |
|
if (cpu->machine->arch == ARCH_M88K && |
236 |
|
!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)) |
237 |
|
show_symbolic_function_name = 0; |
238 |
|
|
239 |
if (cpu->machine->ncpus > 1) |
if (cpu->machine->ncpus > 1) |
240 |
fatal("cpu%i:\t", cpu->cpu_id); |
fatal("cpu%i:\t", cpu->cpu_id); |
241 |
|
|
|
cpu->trace_tree_depth ++; |
|
242 |
if (cpu->trace_tree_depth > 100) |
if (cpu->trace_tree_depth > 100) |
243 |
cpu->trace_tree_depth = 100; |
cpu->trace_tree_depth = 100; |
244 |
for (i=0; i<cpu->trace_tree_depth; i++) |
for (i=0; i<cpu->trace_tree_depth; i++) |
245 |
fatal(" "); |
fatal(" "); |
246 |
|
|
247 |
|
cpu->trace_tree_depth ++; |
248 |
|
|
249 |
fatal("<"); |
fatal("<"); |
250 |
symbol = get_symbol_name_and_n_args(&cpu->machine->symbol_context, |
symbol = get_symbol_name_and_n_args(&cpu->machine->symbol_context, |
251 |
f, &offset, &n_args); |
f, &offset, &n_args); |
252 |
if (symbol != NULL) |
if (symbol != NULL && show_symbolic_function_name) |
253 |
fatal("%s", symbol); |
fatal("%s", symbol); |
254 |
else { |
else { |
255 |
if (cpu->is_32bit) |
if (cpu->is_32bit) |
301 |
if (cpu->translation_cache == NULL) { |
if (cpu->translation_cache == NULL) { |
302 |
cpu->translation_cache = zeroed_alloc(s); |
cpu->translation_cache = zeroed_alloc(s); |
303 |
|
|
|
#ifdef NATIVE_CODE_GENERATION |
|
304 |
if (native_code_translation_enabled) { |
if (native_code_translation_enabled) { |
305 |
mprotect(cpu->translation_cache, s, |
mprotect(cpu->translation_cache, s, |
306 |
PROT_READ | PROT_WRITE | PROT_EXEC); |
PROT_READ | PROT_WRITE | PROT_EXEC); |
307 |
} |
} |
|
#endif |
|
308 |
} |
} |
309 |
|
|
|
#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 |
|
|
|
|
310 |
/* Create an empty table at the beginning of the translation cache: */ |
/* Create an empty table at the beginning of the translation cache: */ |
311 |
memset(cpu->translation_cache, 0, sizeof(uint32_t) |
memset(cpu->translation_cache, 0, sizeof(uint32_t) |
312 |
* N_BASE_TABLE_ENTRIES); |
* N_BASE_TABLE_ENTRIES); |
390 |
* TODO: This should be refactored when redesigning the mainbus |
* TODO: This should be refactored when redesigning the mainbus |
391 |
* concepts! |
* concepts! |
392 |
*/ |
*/ |
393 |
for (te=0; te<machine->n_tick_entries; te++) { |
for (te=0; te<machine->tick_functions.n_entries; te++) { |
394 |
machine->tick_func[te](machine->cpus[0], |
machine->tick_functions.f[te](machine->cpus[0], |
395 |
machine->tick_extra[te]); |
machine->tick_functions.extra[te]); |
396 |
machine->tick_func[te](machine->cpus[0], |
machine->tick_functions.f[te](machine->cpus[0], |
397 |
machine->tick_extra[te]); |
machine->tick_functions.extra[te]); |
398 |
} |
} |
399 |
|
|
400 |
if (machine->show_nr_of_instructions) |
if (machine->show_nr_of_instructions) |
424 |
pc = cpu->pc; |
pc = cpu->pc; |
425 |
|
|
426 |
gettimeofday(&tv, NULL); |
gettimeofday(&tv, NULL); |
427 |
mseconds = (tv.tv_sec - machine->starttime.tv_sec) * 1000 |
mseconds = (tv.tv_sec - cpu->starttime.tv_sec) * 1000 |
428 |
+ (tv.tv_usec - machine->starttime.tv_usec) / 1000; |
+ (tv.tv_usec - cpu->starttime.tv_usec) / 1000; |
429 |
|
|
430 |
if (mseconds == 0) |
if (mseconds == 0) |
431 |
mseconds = 1; |
mseconds = 1; |
433 |
if (mseconds - mseconds_last == 0) |
if (mseconds - mseconds_last == 0) |
434 |
mseconds ++; |
mseconds ++; |
435 |
|
|
436 |
ninstrs = machine->ninstrs_since_gettimeofday; |
ninstrs = cpu->ninstrs_since_gettimeofday; |
437 |
|
|
438 |
/* RETURN here, unless show_nr_of_instructions (-N) is turned on: */ |
/* RETURN here, unless show_nr_of_instructions (-N) is turned on: */ |
439 |
if (!machine->show_nr_of_instructions && !forced) |
if (!machine->show_nr_of_instructions && !forced) |
440 |
goto do_return; |
goto do_return; |
441 |
|
|
442 |
printf("[ %"PRIi64" instrs", (int64_t)machine->ninstrs); |
printf("[ %"PRIi64" instrs", (int64_t) cpu->ninstrs); |
443 |
|
|
444 |
/* Instructions per second, and average so far: */ |
/* Instructions per second, and average so far: */ |
445 |
is = 1000 * (ninstrs-ninstrs_last) / (mseconds-mseconds_last); |
is = 1000 * (ninstrs-ninstrs_last) / (mseconds-mseconds_last); |
464 |
printf("; pc=0x%016"PRIx64, (uint64_t) pc); |
printf("; pc=0x%016"PRIx64, (uint64_t) pc); |
465 |
} |
} |
466 |
|
|
467 |
|
/* Special hack for M88K userland: (Don't show symbols.) */ |
468 |
|
if (cpu->machine->arch == ARCH_M88K && |
469 |
|
!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)) |
470 |
|
symbol = NULL; |
471 |
|
|
472 |
if (symbol != NULL) |
if (symbol != NULL) |
473 |
printf(" <%s>", symbol); |
printf(" <%s>", symbol); |
474 |
printf(" ]\n"); |
printf(" ]\n"); |
487 |
*/ |
*/ |
488 |
void cpu_run_init(struct machine *machine) |
void cpu_run_init(struct machine *machine) |
489 |
{ |
{ |
490 |
machine->ninstrs_flush = 0; |
int i; |
491 |
machine->ninstrs = 0; |
for (i=0; i<machine->ncpus; i++) { |
492 |
machine->ninstrs_show = 0; |
struct cpu *cpu = machine->cpus[i]; |
493 |
|
|
494 |
/* For performance measurement: */ |
cpu->ninstrs_flush = 0; |
495 |
gettimeofday(&machine->starttime, NULL); |
cpu->ninstrs = 0; |
496 |
machine->ninstrs_since_gettimeofday = 0; |
cpu->ninstrs_show = 0; |
497 |
|
|
498 |
|
/* For performance measurement: */ |
499 |
|
gettimeofday(&cpu->starttime, NULL); |
500 |
|
cpu->ninstrs_since_gettimeofday = 0; |
501 |
|
} |
502 |
} |
} |
503 |
|
|
504 |
|
|
513 |
struct cpu_family *fp, *tmp; |
struct cpu_family *fp, *tmp; |
514 |
int res; |
int res; |
515 |
|
|
516 |
fp = malloc(sizeof(struct cpu_family)); |
CHECK_ALLOCATION(fp = malloc(sizeof(struct cpu_family))); |
|
if (fp == NULL) { |
|
|
fprintf(stderr, "add_cpu_family(): out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
517 |
memset(fp, 0, sizeof(struct cpu_family)); |
memset(fp, 0, sizeof(struct cpu_family)); |
518 |
|
|
519 |
/* |
/* |
568 |
* |
* |
569 |
* Should be called before any other cpu_*() function. |
* Should be called before any other cpu_*() function. |
570 |
* |
* |
571 |
* TODO: Make this nicer by moving out the conditional stuff to |
* This function calls add_cpu_family() for each processor architecture. |
572 |
* an automagically generated file? Or a define in config.h? |
* ADD_ALL_CPU_FAMILIES is defined in the config.h file generated by the |
573 |
|
* configure script. |
574 |
*/ |
*/ |
575 |
void cpu_init(void) |
void cpu_init(void) |
576 |
{ |
{ |
577 |
/* Note: These are registered in alphabetic order. */ |
ADD_ALL_CPU_FAMILIES; |
|
|
|
|
#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_M88K |
|
|
add_cpu_family(m88k_cpu_family_init, ARCH_M88K); |
|
|
#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 |
|
578 |
} |
} |
579 |
|
|