25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: emul.c,v 1.297 2007/06/15 17:02:37 debug Exp $ |
* $Id: emul.c,v 1.302 2007/08/29 20:36:49 debug Exp $ |
29 |
* |
* |
30 |
* Emulation startup and misc. routines. |
* Emulation startup and misc. routines. |
31 |
*/ |
*/ |
68 |
extern int old_instruction_trace; |
extern int old_instruction_trace; |
69 |
extern int old_quiet_mode; |
extern int old_quiet_mode; |
70 |
extern int quiet_mode; |
extern int quiet_mode; |
|
extern int native_code_translation_enabled; |
|
71 |
|
|
72 |
|
|
73 |
/* |
/* |
120 |
|
|
121 |
m->breakpoints.addr[i] = dp; |
m->breakpoints.addr[i] = dp; |
122 |
|
|
123 |
debug("breakpoint %i: 0x%llx", i, (long long)dp); |
debug("breakpoint %i: 0x%"PRIx64, i, dp); |
124 |
if (string_flag) |
if (string_flag) |
125 |
debug(" (%s)", m->breakpoints.string[i]); |
debug(" (%s)", m->breakpoints.string[i]); |
126 |
debug("\n"); |
debug("\n"); |
142 |
* |
* |
143 |
* Returns a reasonably initialized struct emul. |
* Returns a reasonably initialized struct emul. |
144 |
*/ |
*/ |
145 |
struct emul *emul_new(char *name, int id) |
struct emul *emul_new(char *name) |
146 |
{ |
{ |
147 |
struct emul *e; |
struct emul *e; |
148 |
|
|
149 |
CHECK_ALLOCATION(e = malloc(sizeof(struct emul))); |
CHECK_ALLOCATION(e = malloc(sizeof(struct emul))); |
150 |
memset(e, 0, sizeof(struct emul)); |
memset(e, 0, sizeof(struct emul)); |
151 |
|
|
|
CHECK_ALLOCATION(e->path = malloc(15)); |
|
|
snprintf(e->path, 15, "emul[%i]", id); |
|
|
|
|
152 |
e->settings = settings_new(); |
e->settings = settings_new(); |
153 |
|
|
154 |
settings_add(e->settings, "n_machines", 0, |
settings_add(e->settings, "n_machines", 0, |
361 |
uint64_t memory_amount, entrypoint = 0, gp = 0, toc = 0; |
uint64_t memory_amount, entrypoint = 0, gp = 0, toc = 0; |
362 |
int byte_order; |
int byte_order; |
363 |
|
|
364 |
debug("machine \"%s\":\n", m->name); |
if (m->name != NULL) |
365 |
|
debug("machine \"%s\":\n", m->name); |
366 |
|
else |
367 |
|
debug("machine:\n"); |
368 |
|
|
369 |
debug_indentation(iadd); |
debug_indentation(iadd); |
370 |
|
|
371 |
/* For userland-only, this decides which ARCH/cpu_name to use: */ |
/* For userland-only, this decides which ARCH/cpu_name to use: */ |
554 |
/* gunzip into new temp file: */ |
/* gunzip into new temp file: */ |
555 |
int tmpfile_handle; |
int tmpfile_handle; |
556 |
char *new_temp_name; |
char *new_temp_name; |
557 |
|
char *tmpdir = getenv("TMPDIR"); |
558 |
|
|
559 |
|
if (tmpdir == NULL) |
560 |
|
tmpdir = DEFAULT_TMP_DIR; |
561 |
|
|
562 |
CHECK_ALLOCATION(new_temp_name = |
CHECK_ALLOCATION(new_temp_name = |
563 |
strdup("/tmp/gxemul.XXXXXXXXXXXX")); |
malloc(300)); |
564 |
|
snprintf(new_temp_name, 300, |
565 |
|
"%s/gxemul.XXXXXXXXXXXX", tmpdir); |
566 |
|
|
567 |
tmpfile_handle = mkstemp(new_temp_name); |
tmpfile_handle = mkstemp(new_temp_name); |
568 |
close(tmpfile_handle); |
close(tmpfile_handle); |
569 |
snprintf(zz, zzlen, "gunzip -c '%s' > " |
snprintf(zz, zzlen, "gunzip -c '%s' > " |
610 |
cpu->pc &= 0xfffffffc; |
cpu->pc &= 0xfffffffc; |
611 |
break; |
break; |
612 |
|
|
613 |
|
case ARCH_M32R: |
614 |
|
if (cpu->pc & 3) { |
615 |
|
fatal("M32R: lowest bits of pc set: TODO\n"); |
616 |
|
exit(1); |
617 |
|
} |
618 |
|
cpu->pc &= 0xfffffffc; |
619 |
|
break; |
620 |
|
|
621 |
case ARCH_M88K: |
case ARCH_M88K: |
622 |
if (cpu->pc & 3) { |
if (cpu->pc & 3) { |
623 |
fatal("M88K: lowest bits of pc set: TODO\n"); |
fatal("M88K: lowest bits of pc set: TODO\n"); |
715 |
m->machine_type == MACHINE_SGI) && m->prom_emulation) |
m->machine_type == MACHINE_SGI) && m->prom_emulation) |
716 |
add_arc_components(m); |
add_arc_components(m); |
717 |
|
|
718 |
debug("starting cpu%i at ", m->bootstrap_cpu); |
debug("cpu%i: starting at ", m->bootstrap_cpu); |
|
switch (m->arch) { |
|
719 |
|
|
720 |
case ARCH_ARM: |
switch (m->arch) { |
|
/* ARM cpus aren't 64-bit: */ |
|
|
debug("0x%08"PRIx32, (uint32_t) entrypoint); |
|
|
break; |
|
721 |
|
|
722 |
case ARCH_MIPS: |
case ARCH_MIPS: |
723 |
if (cpu->is_32bit) { |
if (cpu->is_32bit) { |
736 |
} |
} |
737 |
break; |
break; |
738 |
|
|
|
case ARCH_PPC: |
|
|
if (cpu->cd.ppc.bits == 32) |
|
|
debug("0x%08"PRIx32, (uint32_t) entrypoint); |
|
|
else |
|
|
debug("0x%016"PRIx64, (uint64_t) entrypoint); |
|
|
break; |
|
|
|
|
739 |
default: |
default: |
740 |
if (cpu->is_32bit) |
if (cpu->is_32bit) |
741 |
debug("0x%08"PRIx32, (uint32_t) cpu->pc); |
debug("0x%08"PRIx32, (uint32_t) cpu->pc); |
755 |
*/ |
*/ |
756 |
void emul_dumpinfo(struct emul *e) |
void emul_dumpinfo(struct emul *e) |
757 |
{ |
{ |
758 |
int j, nm, iadd = DEBUG_INDENTATION; |
int i; |
759 |
|
|
760 |
if (e->net != NULL) |
if (e->net != NULL) |
761 |
net_dumpinfo(e->net); |
net_dumpinfo(e->net); |
762 |
|
|
763 |
nm = e->n_machines; |
for (i = 0; i < e->n_machines; i++) { |
764 |
for (j=0; j<nm; j++) { |
if (e->n_machines > 1) |
765 |
debug("machine %i: \"%s\"\n", j, e->machines[j]->name); |
debug("machine %i: \"%s\"\n", i, e->machines[i]->name); |
766 |
debug_indentation(iadd); |
else |
767 |
machine_dumpinfo(e->machines[j]); |
debug("machine:\n"); |
768 |
debug_indentation(-iadd); |
|
769 |
|
debug_indentation(DEBUG_INDENTATION); |
770 |
|
|
771 |
|
machine_dumpinfo(e->machines[i]); |
772 |
|
|
773 |
|
debug_indentation(-DEBUG_INDENTATION); |
774 |
} |
} |
775 |
} |
} |
776 |
|
|
826 |
* |
* |
827 |
* Create an emul struct by reading settings from a configuration file. |
* Create an emul struct by reading settings from a configuration file. |
828 |
*/ |
*/ |
829 |
struct emul *emul_create_from_configfile(char *fname, int id) |
struct emul *emul_create_from_configfile(char *fname) |
830 |
{ |
{ |
831 |
int iadd = DEBUG_INDENTATION; |
int iadd = DEBUG_INDENTATION; |
832 |
struct emul *e = emul_new(fname, id); |
struct emul *e = emul_new(fname); |
833 |
|
|
834 |
debug("Creating emulation from configfile \"%s\":\n", fname); |
debug("Creating emulation from configfile \"%s\":\n", fname); |
835 |
debug_indentation(iadd); |
debug_indentation(iadd); |
844 |
/* |
/* |
845 |
* emul_run(): |
* emul_run(): |
846 |
* |
* |
847 |
* o) Set up things needed before running emulations. |
* o) Set up things needed before running an emulation. |
848 |
* |
* |
849 |
* o) Run emulations (one or more, in parallel). |
* o) Run instructions in all machines. |
850 |
* |
* |
851 |
* o) De-initialize things. |
* o) De-initialize things. |
852 |
*/ |
*/ |
853 |
void emul_run(struct emul **emuls, int n_emuls) |
void emul_run(struct emul *emul) |
854 |
{ |
{ |
|
struct emul *e; |
|
855 |
int i = 0, j, go = 1, n, anything; |
int i = 0, j, go = 1, n, anything; |
856 |
|
|
|
if (n_emuls < 1) { |
|
|
fprintf(stderr, "emul_run(): no thing to do\n"); |
|
|
return; |
|
|
} |
|
|
|
|
857 |
atexit(fix_console); |
atexit(fix_console); |
858 |
|
|
859 |
/* Initialize the interactive debugger: */ |
/* Initialize the interactive debugger: */ |
860 |
debugger_init(emuls, n_emuls); |
debugger_init(emul); |
861 |
|
|
862 |
/* Run any additional debugger commands before starting: */ |
/* Run any additional debugger commands before starting: */ |
863 |
for (i=0; i<n_emuls; i++) { |
if (emul->n_debugger_cmds > 0) { |
864 |
struct emul *emul = emuls[i]; |
int j; |
865 |
if (emul->n_debugger_cmds > 0) { |
if (i == 0) |
866 |
int j; |
print_separator_line(); |
867 |
if (i == 0) |
for (j = 0; j < emul->n_debugger_cmds; j ++) { |
868 |
print_separator_line(); |
debug("> %s\n", emul->debugger_cmds[j]); |
869 |
for (j = 0; j < emul->n_debugger_cmds; j ++) { |
debugger_execute_cmd(emul->debugger_cmds[j], |
870 |
debug("> %s\n", emul->debugger_cmds[j]); |
strlen(emul->debugger_cmds[j])); |
|
debugger_execute_cmd(emul->debugger_cmds[j], |
|
|
strlen(emul->debugger_cmds[j])); |
|
|
} |
|
871 |
} |
} |
872 |
} |
} |
873 |
|
|
885 |
* (or sends SIGSTOP) and then continues. It makes sure that the |
* (or sends SIGSTOP) and then continues. It makes sure that the |
886 |
* terminal is in an expected state. |
* terminal is in an expected state. |
887 |
*/ |
*/ |
888 |
console_init_main(emuls[0]); /* TODO: what is a good argument? */ |
console_init_main(emul); |
889 |
|
|
890 |
signal(SIGINT, debugger_activate); |
signal(SIGINT, debugger_activate); |
891 |
signal(SIGCONT, console_sigcont); |
signal(SIGCONT, console_sigcont); |
892 |
|
|
894 |
if (!verbose) |
if (!verbose) |
895 |
quiet_mode = 1; |
quiet_mode = 1; |
896 |
|
|
897 |
/* Initialize all CPUs in all machines in all emulations: */ |
|
898 |
for (i=0; i<n_emuls; i++) { |
/* Initialize all CPUs in all machines: */ |
899 |
e = emuls[i]; |
for (j=0; j<emul->n_machines; j++) |
900 |
if (e == NULL) |
cpu_run_init(emul->machines[j]); |
|
continue; |
|
|
for (j=0; j<e->n_machines; j++) |
|
|
cpu_run_init(e->machines[j]); |
|
|
} |
|
901 |
|
|
902 |
/* TODO: Generalize: */ |
/* TODO: Generalize: */ |
903 |
if (emuls[0]->machines[0]->show_trace_tree) |
if (emul->machines[0]->show_trace_tree) |
904 |
cpu_functioncall_trace(emuls[0]->machines[0]->cpus[0], |
cpu_functioncall_trace(emul->machines[0]->cpus[0], |
905 |
emuls[0]->machines[0]->cpus[0]->pc); |
emul->machines[0]->cpus[0]->pc); |
906 |
|
|
907 |
/* Start emulated clocks: */ |
/* Start emulated clocks: */ |
908 |
timer_start(); |
timer_start(); |
909 |
|
|
910 |
|
|
911 |
/* |
/* |
912 |
* MAIN LOOP: |
* MAIN LOOP: |
913 |
* |
* |
914 |
* Run all emulations in parallel, running instructions from each |
* Run all emulations in parallel, running instructions from each |
915 |
* cpu in each machine in each emulation. |
* cpu in each machine. |
916 |
*/ |
*/ |
917 |
while (go) { |
while (go) { |
918 |
struct cpu *bootcpu = emuls[0]->machines[0]->cpus[ |
struct cpu *bootcpu = emul->machines[0]->cpus[ |
919 |
emuls[0]->machines[0]->bootstrap_cpu]; |
emul->machines[0]->bootstrap_cpu]; |
920 |
|
|
921 |
go = 0; |
go = 0; |
922 |
|
|
923 |
/* Flush X11 and serial console output every now and then: */ |
/* Flush X11 and serial console output every now and then: */ |
924 |
if (bootcpu->ninstrs > bootcpu->ninstrs_flush + (1<<19)) { |
if (bootcpu->ninstrs > bootcpu->ninstrs_flush + (1<<19)) { |
925 |
x11_check_event(emuls, n_emuls); |
x11_check_event(emul); |
926 |
console_flush(); |
console_flush(); |
927 |
bootcpu->ninstrs_flush = bootcpu->ninstrs; |
bootcpu->ninstrs_flush = bootcpu->ninstrs; |
928 |
} |
} |
930 |
if (bootcpu->ninstrs > bootcpu->ninstrs_show + (1<<25)) { |
if (bootcpu->ninstrs > bootcpu->ninstrs_show + (1<<25)) { |
931 |
bootcpu->ninstrs_since_gettimeofday += |
bootcpu->ninstrs_since_gettimeofday += |
932 |
(bootcpu->ninstrs - bootcpu->ninstrs_show); |
(bootcpu->ninstrs - bootcpu->ninstrs_show); |
933 |
cpu_show_cycles(emuls[0]->machines[0], 0); |
cpu_show_cycles(emul->machines[0], 0); |
934 |
bootcpu->ninstrs_show = bootcpu->ninstrs; |
bootcpu->ninstrs_show = bootcpu->ninstrs; |
935 |
} |
} |
936 |
|
|
937 |
if (single_step == ENTER_SINGLE_STEPPING) { |
if (single_step == ENTER_SINGLE_STEPPING) { |
938 |
/* TODO: Cleanup! */ |
/* TODO: Cleanup! */ |
939 |
old_instruction_trace = |
old_instruction_trace = |
940 |
emuls[0]->machines[0]->instruction_trace; |
emul->machines[0]->instruction_trace; |
941 |
old_quiet_mode = quiet_mode; |
old_quiet_mode = quiet_mode; |
942 |
old_show_trace_tree = |
old_show_trace_tree = |
943 |
emuls[0]->machines[0]->show_trace_tree; |
emul->machines[0]->show_trace_tree; |
944 |
emuls[0]->machines[0]->instruction_trace = 1; |
emul->machines[0]->instruction_trace = 1; |
945 |
emuls[0]->machines[0]->show_trace_tree = 1; |
emul->machines[0]->show_trace_tree = 1; |
946 |
quiet_mode = 0; |
quiet_mode = 0; |
947 |
single_step = SINGLE_STEPPING; |
single_step = SINGLE_STEPPING; |
948 |
} |
} |
950 |
if (single_step == SINGLE_STEPPING) |
if (single_step == SINGLE_STEPPING) |
951 |
debugger(); |
debugger(); |
952 |
|
|
953 |
for (i=0; i<n_emuls; i++) { |
for (j=0; j<emul->n_machines; j++) { |
954 |
e = emuls[i]; |
anything = machine_run(emul->machines[j]); |
955 |
|
if (anything) |
956 |
for (j=0; j<e->n_machines; j++) { |
go = 1; |
|
anything = machine_run(e->machines[j]); |
|
|
if (anything) |
|
|
go = 1; |
|
|
} |
|
957 |
} |
} |
958 |
} |
} |
959 |
|
|
960 |
/* Stop any running timers: */ |
/* Stop any running timers: */ |
961 |
timer_stop(); |
timer_stop(); |
962 |
|
|
963 |
/* Deinitialize all CPUs in all machines in all emulations: */ |
/* Deinitialize all CPUs in all machines: */ |
964 |
for (i=0; i<n_emuls; i++) { |
for (j=0; j<emul->n_machines; j++) |
965 |
e = emuls[i]; |
cpu_run_deinit(emul->machines[j]); |
|
if (e == NULL) |
|
|
continue; |
|
|
for (j=0; j<e->n_machines; j++) |
|
|
cpu_run_deinit(e->machines[j]); |
|
|
} |
|
966 |
|
|
967 |
/* force_debugger_at_exit flag set? Then enter the debugger: */ |
/* force_debugger_at_exit flag set? Then enter the debugger: */ |
968 |
if (force_debugger_at_exit) { |
if (force_debugger_at_exit) { |
973 |
|
|
974 |
/* Any machine using X11? Then wait before exiting: */ |
/* Any machine using X11? Then wait before exiting: */ |
975 |
n = 0; |
n = 0; |
976 |
for (i=0; i<n_emuls; i++) |
for (j=0; j<emul->n_machines; j++) |
977 |
for (j=0; j<emuls[i]->n_machines; j++) |
if (emul->machines[j]->x11_md.in_use) |
978 |
if (emuls[i]->machines[j]->x11_md.in_use) |
n++; |
979 |
n++; |
|
980 |
if (n > 0) { |
if (n > 0) { |
981 |
printf("Press enter to quit.\n"); |
printf("Press enter to quit.\n"); |
982 |
while (!console_charavail(MAIN_CONSOLE)) { |
while (!console_charavail(MAIN_CONSOLE)) { |
983 |
x11_check_event(emuls, n_emuls); |
x11_check_event(emul); |
984 |
usleep(10000); |
usleep(10000); |
985 |
} |
} |
986 |
console_readchar(MAIN_CONSOLE); |
console_readchar(MAIN_CONSOLE); |