25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: machine.c,v 1.664 2006/02/05 10:26:35 debug Exp $ |
* $Id: machine.c,v 1.679 2006/07/16 13:32:25 debug Exp $ |
29 |
*/ |
*/ |
30 |
|
|
31 |
#include <stdio.h> |
#include <stdio.h> |
32 |
#include <stdlib.h> |
#include <stdlib.h> |
33 |
#include <stdarg.h> |
#include <stdarg.h> |
|
#ifdef SOLARIS |
|
|
/* TODO: is this strings vs string separation really necessary? */ |
|
|
#include <strings.h> |
|
|
#else |
|
34 |
#include <string.h> |
#include <string.h> |
|
#endif |
|
35 |
#include <time.h> |
#include <time.h> |
36 |
#include <unistd.h> |
#include <unistd.h> |
37 |
|
|
39 |
#include "bus_isa.h" |
#include "bus_isa.h" |
40 |
#include "bus_pci.h" |
#include "bus_pci.h" |
41 |
#include "cpu.h" |
#include "cpu.h" |
42 |
|
#include "debugger.h" |
43 |
#include "device.h" |
#include "device.h" |
44 |
#include "devices.h" |
#include "devices.h" |
45 |
#include "diskimage.h" |
#include "diskimage.h" |
86 |
m->serial_nr = 1; |
m->serial_nr = 1; |
87 |
m->machine_type = MACHINE_NONE; |
m->machine_type = MACHINE_NONE; |
88 |
m->machine_subtype = MACHINE_NONE; |
m->machine_subtype = MACHINE_NONE; |
|
#ifdef BINTRANS |
|
|
m->bintrans_enable = 1; |
|
|
m->old_bintrans_enable = 1; |
|
|
#endif |
|
89 |
m->arch_pagesize = 4096; /* Should be overriden in |
m->arch_pagesize = 4096; /* Should be overriden in |
90 |
emul.c for other pagesizes. */ |
emul.c for other pagesizes. */ |
|
m->dyntrans_alignment_check = 1; |
|
91 |
m->prom_emulation = 1; |
m->prom_emulation = 1; |
92 |
m->speed_tricks = 1; |
m->allow_instruction_combinations = 1; |
93 |
m->byte_order_override = NO_BYTE_ORDER_OVERRIDE; |
m->byte_order_override = NO_BYTE_ORDER_OVERRIDE; |
94 |
m->boot_kernel_filename = ""; |
m->boot_kernel_filename = ""; |
95 |
m->boot_string_argument = NULL; |
m->boot_string_argument = NULL; |
99 |
m->n_gfx_cards = 1; |
m->n_gfx_cards = 1; |
100 |
m->dbe_on_nonexistant_memaccess = 1; |
m->dbe_on_nonexistant_memaccess = 1; |
101 |
m->show_symbolic_register_names = 1; |
m->show_symbolic_register_names = 1; |
|
m->bintrans_size = DEFAULT_BINTRANS_SIZE_IN_MB * 1048576; |
|
102 |
symbol_init(&m->symbol_context); |
symbol_init(&m->symbol_context); |
103 |
|
|
104 |
return m; |
return m; |
209 |
* |
* |
210 |
* Adds a tick function (a function called every now and then, depending on |
* Adds a tick function (a function called every now and then, depending on |
211 |
* clock cycle count) to a machine. |
* clock cycle count) to a machine. |
212 |
|
* |
213 |
|
* If tickshift is non-zero, a tick will occur every (1 << tickshift) cycles. |
214 |
|
* This is used for the normal (fast dyntrans) emulation modes. |
215 |
|
* |
216 |
|
* If tickshift is zero, then this is a cycle-accurate tick function. |
217 |
|
* The hz value is used in this case. |
218 |
*/ |
*/ |
219 |
void machine_add_tickfunction(struct machine *machine, void (*func) |
void machine_add_tickfunction(struct machine *machine, void (*func) |
220 |
(struct cpu *, void *), void *extra, int clockshift) |
(struct cpu *, void *), void *extra, int tickshift, double hz) |
221 |
{ |
{ |
222 |
int n = machine->n_tick_entries; |
int n = machine->n_tick_entries; |
223 |
|
|
227 |
exit(1); |
exit(1); |
228 |
} |
} |
229 |
|
|
230 |
/* Don't use too low clockshifts, that would be too inefficient |
if (!machine->cycle_accurate) { |
231 |
with bintrans. */ |
/* |
232 |
if (clockshift < N_SAFE_BINTRANS_LIMIT_SHIFT) |
* The dyntrans subsystem wants to run code in relatively |
233 |
fatal("WARNING! clockshift = %i, less than " |
* large chunks without checking for external interrupts, |
234 |
"N_SAFE_BINTRANS_LIMIT_SHIFT (%i)\n", |
* so we cannot allow too low tickshifts: |
235 |
clockshift, N_SAFE_BINTRANS_LIMIT_SHIFT); |
*/ |
236 |
|
if (tickshift < N_SAFE_DYNTRANS_LIMIT_SHIFT) { |
237 |
|
fatal("ERROR! tickshift = %i, less than " |
238 |
|
"N_SAFE_DYNTRANS_LIMIT_SHIFT (%i)\n", |
239 |
|
tickshift, N_SAFE_DYNTRANS_LIMIT_SHIFT); |
240 |
|
exit(1); |
241 |
|
} |
242 |
|
} |
243 |
|
|
244 |
machine->ticks_till_next[n] = 0; |
machine->ticks_till_next[n] = 0; |
245 |
machine->ticks_reset_value[n] = 1 << clockshift; |
machine->ticks_reset_value[n] = 1 << tickshift; |
246 |
machine->tick_func[n] = func; |
machine->tick_func[n] = func; |
247 |
machine->tick_extra[n] = extra; |
machine->tick_extra[n] = extra; |
248 |
|
machine->tick_hz[n] = hz; |
249 |
|
|
250 |
machine->n_tick_entries ++; |
machine->n_tick_entries ++; |
251 |
} |
} |
252 |
|
|
253 |
|
|
254 |
/* |
/* |
255 |
|
* machine_statistics_init(): |
256 |
|
* |
257 |
|
* Initialize the parts of a machine struct that deal with instruction |
258 |
|
* statistics gathering. |
259 |
|
* |
260 |
|
* Note: The fname argument contains "flags:filename". |
261 |
|
*/ |
262 |
|
void machine_statistics_init(struct machine *machine, char *fname) |
263 |
|
{ |
264 |
|
int n_fields = 0; |
265 |
|
char *pcolon = fname; |
266 |
|
char *mode = "a"; /* Append by default */ |
267 |
|
|
268 |
|
machine->allow_instruction_combinations = 0; |
269 |
|
|
270 |
|
if (machine->statistics_fields != NULL) { |
271 |
|
fprintf(stderr, "Only one -s option is allowed.\n"); |
272 |
|
exit(1); |
273 |
|
} |
274 |
|
|
275 |
|
machine->statistics_fields = malloc(MAX_STATISTICS_FIELDS + 1); |
276 |
|
machine->statistics_enabled = 1; |
277 |
|
|
278 |
|
while (*pcolon && *pcolon != ':') |
279 |
|
pcolon ++; |
280 |
|
|
281 |
|
if (*pcolon != ':') { |
282 |
|
fprintf(stderr, "The syntax for the -s option is: " |
283 |
|
"-s flags:filename\nYou omitted the flags. Run g" |
284 |
|
"xemul -h for a list of available flags.\n"); |
285 |
|
exit(1); |
286 |
|
} |
287 |
|
|
288 |
|
while (*fname != ':') { |
289 |
|
switch (*fname) { |
290 |
|
|
291 |
|
/* Type flags: */ |
292 |
|
case 'v': |
293 |
|
case 'i': |
294 |
|
case 'p': |
295 |
|
machine->statistics_fields[n_fields ++] = *fname; |
296 |
|
if (n_fields >= MAX_STATISTICS_FIELDS) { |
297 |
|
fprintf(stderr, "Internal error: Too many " |
298 |
|
"statistics fields used. Increase " |
299 |
|
"MAX_STATISTICS_FIELDS.\n"); |
300 |
|
exit(1); |
301 |
|
} |
302 |
|
machine->statistics_fields[n_fields] = '\0'; |
303 |
|
break; |
304 |
|
|
305 |
|
/* Optional flags: */ |
306 |
|
case 'o': |
307 |
|
mode = "w"; |
308 |
|
break; |
309 |
|
case 'd': |
310 |
|
machine->statistics_enabled = 0; |
311 |
|
break; |
312 |
|
|
313 |
|
default:fprintf(stderr, "Unknown flag '%c' used with the" |
314 |
|
" -s option. Aborting.\n", *fname); |
315 |
|
exit(1); |
316 |
|
} |
317 |
|
fname ++; |
318 |
|
} |
319 |
|
|
320 |
|
fname ++; /* point to the filename after the colon */ |
321 |
|
|
322 |
|
machine->statistics_filename = strdup(fname); |
323 |
|
machine->statistics_file = fopen(machine->statistics_filename, mode); |
324 |
|
} |
325 |
|
|
326 |
|
|
327 |
|
/* |
328 |
* machine_bus_register(): |
* machine_bus_register(): |
329 |
* |
* |
330 |
* Registers a bus in a machine. |
* Registers a bus in a machine. |
400 |
debug(", dbe_on_nonexistant_memaccess"); |
debug(", dbe_on_nonexistant_memaccess"); |
401 |
debug("\n"); |
debug("\n"); |
402 |
|
|
|
if (m->single_step_on_bad_addr) |
|
|
debug("single-step on bad addresses\n"); |
|
|
|
|
|
if (m->arch == ARCH_MIPS) { |
|
|
if (m->bintrans_enable) |
|
|
debug("bintrans enabled (%i MB cache)\n", |
|
|
(int) (m->bintrans_size / 1048576)); |
|
|
else |
|
|
debug("bintrans disabled, other speedtricks %s\n", |
|
|
m->speed_tricks? "enabled" : "disabled"); |
|
|
} |
|
|
|
|
403 |
debug("clock: "); |
debug("clock: "); |
404 |
if (m->automatic_clock_adjustment) |
if (m->automatic_clock_adjustment) |
405 |
debug("adjusted automatically"); |
debug("adjusted automatically"); |
964 |
} |
} |
965 |
|
|
966 |
|
|
967 |
|
/*****************************************************************************/ |
968 |
|
|
969 |
|
|
970 |
|
/* |
971 |
|
* machine_run(): |
972 |
|
* |
973 |
|
* Run one or more instructions on all CPUs in this machine. (Usually, |
974 |
|
* around N_SAFE_DYNTRANS_LIMIT instructions will be run by the dyntrans |
975 |
|
* system.) |
976 |
|
* |
977 |
|
* Return value is 1 if any CPU in this machine is still running, |
978 |
|
* or 0 if all CPUs are stopped. |
979 |
|
*/ |
980 |
|
int machine_run(struct machine *machine) |
981 |
|
{ |
982 |
|
struct cpu **cpus = machine->cpus; |
983 |
|
int ncpus = machine->ncpus, cpu0instrs = 0, i, te; |
984 |
|
|
985 |
|
for (i=0; i<ncpus; i++) { |
986 |
|
if (cpus[i]->running) { |
987 |
|
int instrs_run = cpus[i]->run_instr(cpus[i]); |
988 |
|
if (i == 0) |
989 |
|
cpu0instrs += instrs_run; |
990 |
|
} |
991 |
|
} |
992 |
|
|
993 |
|
/* |
994 |
|
* Hardware 'ticks': (clocks, interrupt sources...) |
995 |
|
* |
996 |
|
* Here, cpu0instrs is the number of instructions executed on cpu0. |
997 |
|
* |
998 |
|
* TODO: This should be redesigned into some "mainbus" stuff instead! |
999 |
|
*/ |
1000 |
|
|
1001 |
|
machine->ninstrs += cpu0instrs; |
1002 |
|
|
1003 |
|
for (te=0; te<machine->n_tick_entries; te++) { |
1004 |
|
machine->ticks_till_next[te] -= cpu0instrs; |
1005 |
|
if (machine->ticks_till_next[te] <= 0) { |
1006 |
|
while (machine->ticks_till_next[te] <= 0) { |
1007 |
|
machine->ticks_till_next[te] += |
1008 |
|
machine->ticks_reset_value[te]; |
1009 |
|
} |
1010 |
|
|
1011 |
|
machine->tick_func[te](cpus[0], |
1012 |
|
machine->tick_extra[te]); |
1013 |
|
} |
1014 |
|
} |
1015 |
|
|
1016 |
|
/* Is any CPU still alive? */ |
1017 |
|
for (i=0; i<ncpus; i++) |
1018 |
|
if (cpus[i]->running) |
1019 |
|
return 1; |
1020 |
|
|
1021 |
|
return 0; |
1022 |
|
} |
1023 |
|
|
1024 |
|
|
1025 |
|
/*****************************************************************************/ |
1026 |
|
|
1027 |
|
|
1028 |
/* |
/* |
1029 |
* machine_entry_new(): |
* machine_entry_new(): |
1030 |
* |
* |
1031 |
* This function creates a new machine_entry struct, and fills it with some |
* This function creates a new machine_entry struct, and fills it with some |
1032 |
* valid data; it is up to the caller to add additional data that weren't |
* valid data; it is up to the caller to add additional data that weren't |
1033 |
* passed as arguments to this function. |
* passed as arguments to this function, such as alias names and machine |
1034 |
|
* subtypes. |
1035 |
*/ |
*/ |
1036 |
struct machine_entry *machine_entry_new(const char *name, |
struct machine_entry *machine_entry_new(const char *name, int arch, |
1037 |
int arch, int oldstyle_type, int n_aliases, int n_subtypes) |
int oldstyle_type) |
1038 |
{ |
{ |
1039 |
struct machine_entry *me; |
struct machine_entry *me; |
1040 |
|
|
1049 |
me->name = name; |
me->name = name; |
1050 |
me->arch = arch; |
me->arch = arch; |
1051 |
me->machine_type = oldstyle_type; |
me->machine_type = oldstyle_type; |
1052 |
me->n_aliases = n_aliases; |
me->n_aliases = 0; |
1053 |
me->aliases = malloc(sizeof(char *) * n_aliases); |
me->aliases = NULL; |
1054 |
if (me->aliases == NULL) { |
me->n_subtypes = 0; |
|
fprintf(stderr, "machine_entry_new(): out of memory (2)\n"); |
|
|
exit(1); |
|
|
} |
|
|
me->n_subtypes = n_subtypes; |
|
1055 |
me->setup = NULL; |
me->setup = NULL; |
1056 |
|
|
1057 |
if (n_subtypes > 0) { |
return me; |
1058 |
me->subtype = malloc(sizeof(struct machine_entry_subtype *) * |
} |
1059 |
n_subtypes); |
|
1060 |
if (me->subtype == NULL) { |
|
1061 |
fprintf(stderr, "machine_entry_new(): out of " |
/* |
1062 |
"memory (3)\n"); |
* machine_entry_add_alias(): |
1063 |
exit(1); |
* |
1064 |
} |
* This function adds an "alias" to a machine entry. |
1065 |
|
*/ |
1066 |
|
void machine_entry_add_alias(struct machine_entry *me, const char *name) |
1067 |
|
{ |
1068 |
|
me->n_aliases ++; |
1069 |
|
me->aliases = realloc(me->aliases, sizeof(char *) * me->n_aliases); |
1070 |
|
if (me->aliases == NULL) { |
1071 |
|
fprintf(stderr, "out of memory\n"); |
1072 |
|
exit(1); |
1073 |
} |
} |
1074 |
|
|
1075 |
return me; |
me->aliases[me->n_aliases - 1] = (char *) name; |
1076 |
} |
} |
1077 |
|
|
1078 |
|
|
1079 |
/* |
/* |
1080 |
* machine_entry_subtype_new(): |
* machine_entry_add_subtype(): |
1081 |
* |
* |
1082 |
* This function creates a new machine_entry_subtype struct, and fills it with |
* This function adds a subtype to a machine entry. The argument list after |
1083 |
* some valid data; it is up to the caller to add additional data that weren't |
* oldstyle_subtype is a list of one or more char *, followed by NULL. E.g.: |
|
* passed as arguments to this function. |
|
1084 |
* |
* |
1085 |
* For internal use. |
* machine_entry_add_subtype(me, "Machine X", MACHINE_X, |
1086 |
|
* "machine-x", "x", NULL); |
1087 |
*/ |
*/ |
1088 |
struct machine_entry_subtype *machine_entry_subtype_new( |
void machine_entry_add_subtype(struct machine_entry *me, const char *name, |
1089 |
const char *name, int oldstyle_type, int n_aliases) |
int oldstyle_subtype, ...) |
1090 |
{ |
{ |
1091 |
|
va_list argp; |
1092 |
struct machine_entry_subtype *mes; |
struct machine_entry_subtype *mes; |
1093 |
|
|
1094 |
|
/* Allocate a new subtype struct: */ |
1095 |
mes = malloc(sizeof(struct machine_entry_subtype)); |
mes = malloc(sizeof(struct machine_entry_subtype)); |
1096 |
if (mes == NULL) { |
if (mes == NULL) { |
1097 |
fprintf(stderr, "machine_entry_subtype_new(): out " |
fprintf(stderr, "machine_entry_subtype_new(): out " |
1099 |
exit(1); |
exit(1); |
1100 |
} |
} |
1101 |
|
|
1102 |
|
/* Add the subtype to the machine entry: */ |
1103 |
|
me->n_subtypes ++; |
1104 |
|
me->subtype = realloc(me->subtype, sizeof(struct |
1105 |
|
machine_entry_subtype *) * me->n_subtypes); |
1106 |
|
if (me->subtype == NULL) { |
1107 |
|
fprintf(stderr, "out of memory\n"); |
1108 |
|
exit(1); |
1109 |
|
} |
1110 |
|
me->subtype[me->n_subtypes - 1] = mes; |
1111 |
|
|
1112 |
|
/* Fill the struct with subtype data: */ |
1113 |
memset(mes, 0, sizeof(struct machine_entry_subtype)); |
memset(mes, 0, sizeof(struct machine_entry_subtype)); |
1114 |
mes->name = name; |
mes->name = name; |
1115 |
mes->machine_subtype = oldstyle_type; |
mes->machine_subtype = oldstyle_subtype; |
1116 |
mes->n_aliases = n_aliases; |
|
1117 |
mes->aliases = malloc(sizeof(char *) * n_aliases); |
/* ... and all aliases: */ |
1118 |
if (mes->aliases == NULL) { |
mes->n_aliases = 0; |
1119 |
fprintf(stderr, "machine_entry_subtype_new(): " |
mes->aliases = NULL; |
1120 |
"out of memory (2)\n"); |
|
1121 |
exit(1); |
va_start(argp, oldstyle_subtype); |
1122 |
|
|
1123 |
|
for (;;) { |
1124 |
|
char *s = va_arg(argp, char *); |
1125 |
|
if (s == NULL) |
1126 |
|
break; |
1127 |
|
|
1128 |
|
mes->n_aliases ++; |
1129 |
|
mes->aliases = realloc(mes->aliases, sizeof(char *) * |
1130 |
|
mes->n_aliases); |
1131 |
|
if (mes->aliases == NULL) { |
1132 |
|
fprintf(stderr, "out of memory\n"); |
1133 |
|
exit(1); |
1134 |
|
} |
1135 |
|
|
1136 |
|
mes->aliases[mes->n_aliases - 1] = s; |
1137 |
} |
} |
1138 |
|
|
1139 |
return mes; |
va_end(argp); |
1140 |
} |
} |
1141 |
|
|
1142 |
|
|
1143 |
/* |
/* |
1144 |
* machine_entry_add(): |
* machine_entry_register(): |
1145 |
* |
* |
1146 |
* Inserts a new machine_entry into the machine entries list. |
* Inserts a new machine_entry into the machine entries list. |
1147 |
*/ |
*/ |
1148 |
void machine_entry_add(struct machine_entry *me, int arch) |
void machine_entry_register(struct machine_entry *me, int arch) |
1149 |
{ |
{ |
1150 |
struct machine_entry *prev, *next; |
struct machine_entry *prev, *next; |
1151 |
|
|
1234 |
"that actually work. Use the alias\nwhen selecting a machine type " |
"that actually work. Use the alias\nwhen selecting a machine type " |
1235 |
"or subtype, not the real name.\n"); |
"or subtype, not the real name.\n"); |
1236 |
|
|
1237 |
|
#ifdef UNSTABLE_DEVEL |
1238 |
debug("\n"); |
debug("\n"); |
1239 |
|
|
1240 |
useremul_list_emuls(); |
useremul_list_emuls(); |
1241 |
debug("Userland emulation works for programs with the complexity" |
debug("Userland emulation works for programs with the complexity" |
1242 |
" of Hello World,\nbut not much more.\n"); |
" of Hello World,\nbut not much more.\n"); |
1243 |
|
#endif |
1244 |
} |
} |
1245 |
|
|
1246 |
|
|