25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: machine.c,v 1.693 2007/01/28 14:15:29 debug Exp $ |
* $Id: machine.c,v 1.704 2007/06/15 17:02:38 debug Exp $ |
29 |
*/ |
*/ |
30 |
|
|
31 |
#include <stdio.h> |
#include <stdio.h> |
35 |
#include <time.h> |
#include <time.h> |
36 |
#include <unistd.h> |
#include <unistd.h> |
37 |
|
|
|
#include "arcbios.h" |
|
|
#include "bus_isa.h" |
|
|
#include "bus_pci.h" |
|
38 |
#include "cpu.h" |
#include "cpu.h" |
|
#include "debugger.h" |
|
39 |
#include "device.h" |
#include "device.h" |
|
#include "devices.h" |
|
40 |
#include "diskimage.h" |
#include "diskimage.h" |
41 |
#include "emul.h" |
#include "emul.h" |
42 |
#include "machine.h" |
#include "machine.h" |
43 |
#include "memory.h" |
#include "memory.h" |
44 |
#include "misc.h" |
#include "misc.h" |
|
#include "net.h" |
|
45 |
#include "settings.h" |
#include "settings.h" |
46 |
#include "symbol.h" |
#include "symbol.h" |
47 |
|
#include "useremul.h" |
48 |
|
|
49 |
|
|
50 |
/* See main.c: */ |
/* See main.c: */ |
64 |
struct machine *machine_new(char *name, struct emul *emul, int id) |
struct machine *machine_new(char *name, struct emul *emul, int id) |
65 |
{ |
{ |
66 |
struct machine *m; |
struct machine *m; |
|
m = malloc(sizeof(struct machine)); |
|
|
if (m == NULL) { |
|
|
fprintf(stderr, "machine_new(): out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
67 |
|
|
68 |
|
CHECK_ALLOCATION(m = malloc(sizeof(struct machine))); |
69 |
memset(m, 0, sizeof(struct machine)); |
memset(m, 0, sizeof(struct machine)); |
70 |
|
|
71 |
/* Pointer back to the emul object that this machine belongs to: */ |
/* Pointer back to the emul object that this machine belongs to: */ |
72 |
m->emul = emul; |
m->emul = emul; |
73 |
|
|
74 |
m->name = strdup(name); |
CHECK_ALLOCATION(m->name = strdup(name)); |
75 |
|
|
76 |
/* Full path, e.g. "emul[0].machine[0]": */ |
/* Full path, e.g. "emul[0].machine[0]": */ |
77 |
m->path = malloc(strlen(emul->path) + 20); |
CHECK_ALLOCATION(m->path = malloc(strlen(emul->path) + 20)); |
|
if (m->path == NULL) { |
|
|
fprintf(stderr, "out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
78 |
snprintf(m->path, strlen(emul->path) + 20, "%s.machine[%i]", |
snprintf(m->path, strlen(emul->path) + 20, "%s.machine[%i]", |
79 |
emul->path, id); |
emul->path, id); |
80 |
|
|
89 |
m->byte_order_override = NO_BYTE_ORDER_OVERRIDE; |
m->byte_order_override = NO_BYTE_ORDER_OVERRIDE; |
90 |
m->boot_kernel_filename = ""; |
m->boot_kernel_filename = ""; |
91 |
m->boot_string_argument = NULL; |
m->boot_string_argument = NULL; |
92 |
m->x11_scaledown = 1; |
m->x11_md.scaledown = 1; |
93 |
m->x11_scaleup = 1; |
m->x11_md.scaleup = 1; |
94 |
m->n_gfx_cards = 1; |
m->n_gfx_cards = 1; |
|
m->dbe_on_nonexistant_memaccess = 1; |
|
|
m->show_symbolic_register_names = 1; |
|
95 |
symbol_init(&m->symbol_context); |
symbol_init(&m->symbol_context); |
96 |
|
|
97 |
/* Settings: */ |
/* Settings: */ |
114 |
settings_add(m->settings, "n_gfx_cards", 0, |
settings_add(m->settings, "n_gfx_cards", 0, |
115 |
SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL, |
SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL, |
116 |
(void *) &m->n_gfx_cards); |
(void *) &m->n_gfx_cards); |
|
settings_add(m->settings, "show_symbolic_register_names", 1, |
|
|
SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, |
|
|
(void *) &m->show_symbolic_register_names); |
|
117 |
settings_add(m->settings, "statistics_enabled", 1, |
settings_add(m->settings, "statistics_enabled", 1, |
118 |
SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, |
SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, |
119 |
(void *) &m->statistics_enabled); |
(void *) &m->statistics_enabled); |
248 |
|
|
249 |
|
|
250 |
/* |
/* |
251 |
|
* machine_add_breakpoint_string(): |
252 |
|
* |
253 |
|
* Add a breakpoint string to the machine. Later (in emul.c) these will be |
254 |
|
* converted to actual breakpoints. |
255 |
|
*/ |
256 |
|
void machine_add_breakpoint_string(struct machine *machine, char *str) |
257 |
|
{ |
258 |
|
int n = machine->breakpoints.n + 1; |
259 |
|
|
260 |
|
CHECK_ALLOCATION(machine->breakpoints.string = |
261 |
|
realloc(machine->breakpoints.string, n * sizeof(char *))); |
262 |
|
CHECK_ALLOCATION(machine->breakpoints.addr = |
263 |
|
realloc(machine->breakpoints.addr, n * sizeof(uint64_t))); |
264 |
|
CHECK_ALLOCATION(machine->breakpoints.string[machine->breakpoints.n] = |
265 |
|
strdup(optarg)); |
266 |
|
|
267 |
|
machine->breakpoints.addr[machine->breakpoints.n] = 0; |
268 |
|
machine->breakpoints.n ++; |
269 |
|
} |
270 |
|
|
271 |
|
|
272 |
|
/* |
273 |
* machine_add_tickfunction(): |
* machine_add_tickfunction(): |
274 |
* |
* |
275 |
* 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 |
282 |
* The hz value is used in this case. |
* The hz value is used in this case. |
283 |
*/ |
*/ |
284 |
void machine_add_tickfunction(struct machine *machine, void (*func) |
void machine_add_tickfunction(struct machine *machine, void (*func) |
285 |
(struct cpu *, void *), void *extra, int tickshift, double hz) |
(struct cpu *, void *), void *extra, int tickshift) |
286 |
{ |
{ |
287 |
int n = machine->n_tick_entries; |
int n = machine->tick_functions.n_entries; |
288 |
|
|
289 |
if (n >= MAX_TICK_FUNCTIONS) { |
CHECK_ALLOCATION(machine->tick_functions.ticks_till_next = realloc( |
290 |
fprintf(stderr, "machine_add_tickfunction(): too " |
machine->tick_functions.ticks_till_next, (n+1) * sizeof(int))); |
291 |
"many tick functions\n"); |
CHECK_ALLOCATION(machine->tick_functions.ticks_reset_value = realloc( |
292 |
exit(1); |
machine->tick_functions.ticks_reset_value, (n+1) * sizeof(int))); |
293 |
} |
CHECK_ALLOCATION(machine->tick_functions.f = realloc( |
294 |
|
machine->tick_functions.f, (n+1) * sizeof(void *))); |
295 |
|
CHECK_ALLOCATION(machine->tick_functions.extra = realloc( |
296 |
|
machine->tick_functions.extra, (n+1) * sizeof(void *))); |
297 |
|
|
298 |
if (!machine->cycle_accurate) { |
/* |
299 |
/* |
* The dyntrans subsystem wants to run code in relatively |
300 |
* The dyntrans subsystem wants to run code in relatively |
* large chunks without checking for external interrupts; |
301 |
* large chunks without checking for external interrupts; |
* too low tickshifts are not allowed. |
302 |
* too low tickshifts are not allowed. |
*/ |
303 |
*/ |
if (tickshift < N_SAFE_DYNTRANS_LIMIT_SHIFT) { |
304 |
if (tickshift < N_SAFE_DYNTRANS_LIMIT_SHIFT) { |
fatal("ERROR! tickshift = %i, less than " |
305 |
fatal("ERROR! tickshift = %i, less than " |
"N_SAFE_DYNTRANS_LIMIT_SHIFT (%i)\n", |
306 |
"N_SAFE_DYNTRANS_LIMIT_SHIFT (%i)\n", |
tickshift, N_SAFE_DYNTRANS_LIMIT_SHIFT); |
307 |
tickshift, N_SAFE_DYNTRANS_LIMIT_SHIFT); |
exit(1); |
|
exit(1); |
|
|
} |
|
308 |
} |
} |
309 |
|
|
310 |
machine->ticks_till_next[n] = 0; |
machine->tick_functions.ticks_till_next[n] = 0; |
311 |
machine->ticks_reset_value[n] = 1 << tickshift; |
machine->tick_functions.ticks_reset_value[n] = 1 << tickshift; |
312 |
machine->tick_func[n] = func; |
machine->tick_functions.f[n] = func; |
313 |
machine->tick_extra[n] = extra; |
machine->tick_functions.extra[n] = extra; |
|
machine->tick_hz[n] = hz; |
|
314 |
|
|
315 |
machine->n_tick_entries ++; |
machine->tick_functions.n_entries = n + 1; |
316 |
} |
} |
317 |
|
|
318 |
|
|
337 |
exit(1); |
exit(1); |
338 |
} |
} |
339 |
|
|
|
machine->statistics_fields = malloc(MAX_STATISTICS_FIELDS + 1); |
|
340 |
machine->statistics_enabled = 1; |
machine->statistics_enabled = 1; |
341 |
|
CHECK_ALLOCATION(machine->statistics_fields = malloc(1)); |
342 |
|
machine->statistics_fields[0] = '\0'; |
343 |
|
|
344 |
while (*pcolon && *pcolon != ':') |
while (*pcolon && *pcolon != ':') |
345 |
pcolon ++; |
pcolon ++; |
358 |
case 'v': |
case 'v': |
359 |
case 'i': |
case 'i': |
360 |
case 'p': |
case 'p': |
361 |
|
CHECK_ALLOCATION(machine->statistics_fields = realloc( |
362 |
|
machine->statistics_fields, strlen( |
363 |
|
machine->statistics_fields) + 2)); |
364 |
machine->statistics_fields[n_fields ++] = *fname; |
machine->statistics_fields[n_fields ++] = *fname; |
|
if (n_fields >= MAX_STATISTICS_FIELDS) { |
|
|
fprintf(stderr, "Internal error: Too many " |
|
|
"statistics fields used. Increase " |
|
|
"MAX_STATISTICS_FIELDS.\n"); |
|
|
exit(1); |
|
|
} |
|
365 |
machine->statistics_fields[n_fields] = '\0'; |
machine->statistics_fields[n_fields] = '\0'; |
366 |
break; |
break; |
367 |
|
|
382 |
|
|
383 |
fname ++; /* point to the filename after the colon */ |
fname ++; /* point to the filename after the colon */ |
384 |
|
|
385 |
machine->statistics_filename = strdup(fname); |
CHECK_ALLOCATION(machine->statistics_filename = strdup(fname)); |
386 |
machine->statistics_file = fopen(machine->statistics_filename, mode); |
machine->statistics_file = fopen(machine->statistics_filename, mode); |
387 |
} |
} |
388 |
|
|
407 |
debug(" (offset by %i MB)", m->memory_offset_in_mb); |
debug(" (offset by %i MB)", m->memory_offset_in_mb); |
408 |
if (m->random_mem_contents) |
if (m->random_mem_contents) |
409 |
debug(", randomized contents"); |
debug(", randomized contents"); |
|
if (m->dbe_on_nonexistant_memaccess) |
|
|
debug(", dbe_on_nonexistant_memaccess"); |
|
410 |
debug("\n"); |
debug("\n"); |
411 |
|
|
412 |
if (!m->prom_emulation) |
if (!m->prom_emulation) |
421 |
if (m->slow_serial_interrupts_hack_for_linux) |
if (m->slow_serial_interrupts_hack_for_linux) |
422 |
debug("Using slow_serial_interrupts_hack_for_linux\n"); |
debug("Using slow_serial_interrupts_hack_for_linux\n"); |
423 |
|
|
424 |
if (m->use_x11) { |
if (m->x11_md.in_use) { |
425 |
debug("Using X11"); |
debug("Using X11"); |
426 |
if (m->x11_scaledown > 1) |
if (m->x11_md.scaledown > 1) |
427 |
debug(", scaledown %i", m->x11_scaledown); |
debug(", scaledown %i", m->x11_md.scaledown); |
428 |
if (m->x11_scaleup > 1) |
if (m->x11_md.scaleup > 1) |
429 |
debug(", scaleup %i", m->x11_scaleup); |
debug(", scaleup %i", m->x11_md.scaleup); |
430 |
if (m->x11_n_display_names > 0) { |
if (m->x11_md.n_display_names > 0) { |
431 |
for (i=0; i<m->x11_n_display_names; i++) { |
for (i=0; i<m->x11_md.n_display_names; i++) { |
432 |
debug(i? ", " : " ("); |
debug(i? ", " : " ("); |
433 |
debug("\"%s\"", m->x11_display_names[i]); |
debug("\"%s\"", m->x11_md.display_names[i]); |
434 |
} |
} |
435 |
debug(")"); |
debug(")"); |
436 |
} |
} |
445 |
|
|
446 |
|
|
447 |
/* |
/* |
|
* dump_mem_string(): |
|
|
* |
|
|
* Dump the contents of emulated RAM as readable text. Bytes that aren't |
|
|
* readable are dumped in [xx] notation, where xx is in hexadecimal. |
|
|
* Dumping ends after DUMP_MEM_STRING_MAX bytes, or when a terminating |
|
|
* zero byte is found. |
|
|
*/ |
|
|
#define DUMP_MEM_STRING_MAX 45 |
|
|
void dump_mem_string(struct cpu *cpu, uint64_t addr) |
|
|
{ |
|
|
int i; |
|
|
for (i=0; i<DUMP_MEM_STRING_MAX; i++) { |
|
|
unsigned char ch = '\0'; |
|
|
|
|
|
cpu->memory_rw(cpu, cpu->mem, addr + i, &ch, sizeof(ch), |
|
|
MEM_READ, CACHE_DATA | NO_EXCEPTIONS); |
|
|
if (ch == '\0') |
|
|
return; |
|
|
if (ch >= ' ' && ch < 126) |
|
|
debug("%c", ch); |
|
|
else |
|
|
debug("[%02x]", ch); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* store_byte(): |
|
|
* |
|
|
* Stores a byte in emulated ram. (Helper function.) |
|
|
*/ |
|
|
void store_byte(struct cpu *cpu, uint64_t addr, uint8_t data) |
|
|
{ |
|
|
if ((addr >> 32) == 0) |
|
|
addr = (int64_t)(int32_t)addr; |
|
|
cpu->memory_rw(cpu, cpu->mem, |
|
|
addr, &data, sizeof(data), MEM_WRITE, CACHE_DATA); |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* store_string(): |
|
|
* |
|
|
* Stores chars into emulated RAM until a zero byte (string terminating |
|
|
* character) is found. The zero byte is also copied. |
|
|
* (strcpy()-like helper function, host-RAM-to-emulated-RAM.) |
|
|
*/ |
|
|
void store_string(struct cpu *cpu, uint64_t addr, char *s) |
|
|
{ |
|
|
do { |
|
|
store_byte(cpu, addr++, *s); |
|
|
} while (*s++); |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* add_environment_string(): |
|
|
* |
|
|
* Like store_string(), but advances the pointer afterwards. The most |
|
|
* obvious use is to place a number of strings (such as environment variable |
|
|
* strings) after one-another in emulated memory. |
|
|
*/ |
|
|
void add_environment_string(struct cpu *cpu, char *s, uint64_t *addr) |
|
|
{ |
|
|
store_string(cpu, *addr, s); |
|
|
(*addr) += strlen(s) + 1; |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* add_environment_string_dual(): |
|
|
* |
|
|
* Add "dual" environment strings, one for the variable name and one for the |
|
|
* value, and update pointers afterwards. |
|
|
*/ |
|
|
void add_environment_string_dual(struct cpu *cpu, |
|
|
uint64_t *ptrp, uint64_t *addrp, char *s1, char *s2) |
|
|
{ |
|
|
uint64_t ptr = *ptrp, addr = *addrp; |
|
|
|
|
|
store_32bit_word(cpu, ptr, addr); |
|
|
ptr += sizeof(uint32_t); |
|
|
if (addr != 0) { |
|
|
store_string(cpu, addr, s1); |
|
|
addr += strlen(s1) + 1; |
|
|
} |
|
|
store_32bit_word(cpu, ptr, addr); |
|
|
ptr += sizeof(uint32_t); |
|
|
if (addr != 0) { |
|
|
store_string(cpu, addr, s2); |
|
|
addr += strlen(s2) + 1; |
|
|
} |
|
|
|
|
|
*ptrp = ptr; |
|
|
*addrp = addr; |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* store_64bit_word(): |
|
|
* |
|
|
* Stores a 64-bit word in emulated RAM. Byte order is taken into account. |
|
|
* Helper function. |
|
|
*/ |
|
|
int store_64bit_word(struct cpu *cpu, uint64_t addr, uint64_t data64) |
|
|
{ |
|
|
unsigned char data[8]; |
|
|
if ((addr >> 32) == 0) |
|
|
addr = (int64_t)(int32_t)addr; |
|
|
data[0] = (data64 >> 56) & 255; |
|
|
data[1] = (data64 >> 48) & 255; |
|
|
data[2] = (data64 >> 40) & 255; |
|
|
data[3] = (data64 >> 32) & 255; |
|
|
data[4] = (data64 >> 24) & 255; |
|
|
data[5] = (data64 >> 16) & 255; |
|
|
data[6] = (data64 >> 8) & 255; |
|
|
data[7] = (data64) & 255; |
|
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
|
|
int tmp = data[0]; data[0] = data[7]; data[7] = tmp; |
|
|
tmp = data[1]; data[1] = data[6]; data[6] = tmp; |
|
|
tmp = data[2]; data[2] = data[5]; data[5] = tmp; |
|
|
tmp = data[3]; data[3] = data[4]; data[4] = tmp; |
|
|
} |
|
|
return cpu->memory_rw(cpu, cpu->mem, |
|
|
addr, data, sizeof(data), MEM_WRITE, CACHE_DATA); |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* store_32bit_word(): |
|
|
* |
|
|
* Stores a 32-bit word in emulated RAM. Byte order is taken into account. |
|
|
* (This function takes a 64-bit word as argument, to suppress some |
|
|
* warnings, but only the lowest 32 bits are used.) |
|
|
*/ |
|
|
int store_32bit_word(struct cpu *cpu, uint64_t addr, uint64_t data32) |
|
|
{ |
|
|
unsigned char data[4]; |
|
|
|
|
|
/* TODO: REMOVE THIS once everything is more stable! */ |
|
|
if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0) |
|
|
addr = (int64_t)(int32_t)addr; |
|
|
|
|
|
data[0] = (data32 >> 24) & 255; |
|
|
data[1] = (data32 >> 16) & 255; |
|
|
data[2] = (data32 >> 8) & 255; |
|
|
data[3] = (data32) & 255; |
|
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
|
|
int tmp = data[0]; data[0] = data[3]; data[3] = tmp; |
|
|
tmp = data[1]; data[1] = data[2]; data[2] = tmp; |
|
|
} |
|
|
return cpu->memory_rw(cpu, cpu->mem, |
|
|
addr, data, sizeof(data), MEM_WRITE, CACHE_DATA); |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* store_16bit_word(): |
|
|
* |
|
|
* Stores a 16-bit word in emulated RAM. Byte order is taken into account. |
|
|
* (This function takes a 64-bit word as argument, to suppress some |
|
|
* warnings, but only the lowest 16 bits are used.) |
|
|
*/ |
|
|
int store_16bit_word(struct cpu *cpu, uint64_t addr, uint64_t data16) |
|
|
{ |
|
|
unsigned char data[2]; |
|
|
|
|
|
/* TODO: REMOVE THIS once everything is more stable! */ |
|
|
if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0) |
|
|
addr = (int64_t)(int32_t)addr; |
|
|
|
|
|
data[0] = (data16 >> 8) & 255; |
|
|
data[1] = (data16) & 255; |
|
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
|
|
int tmp = data[0]; data[0] = data[1]; data[1] = tmp; |
|
|
} |
|
|
return cpu->memory_rw(cpu, cpu->mem, |
|
|
addr, data, sizeof(data), MEM_WRITE, CACHE_DATA); |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* store_buf(): |
|
|
* |
|
|
* memcpy()-like helper function, from host RAM to emulated RAM. |
|
|
*/ |
|
|
void store_buf(struct cpu *cpu, uint64_t addr, char *s, size_t len) |
|
|
{ |
|
|
size_t psize = 1024; /* 1024 256 64 16 4 1 */ |
|
|
|
|
|
/* TODO: REMOVE THIS once everything is more stable! */ |
|
|
if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0) |
|
|
addr = (int64_t)(int32_t)addr; |
|
|
|
|
|
while (len != 0) { |
|
|
if ((addr & (psize-1)) == 0) { |
|
|
while (len >= psize) { |
|
|
cpu->memory_rw(cpu, cpu->mem, addr, |
|
|
(unsigned char *)s, psize, MEM_WRITE, |
|
|
CACHE_DATA); |
|
|
addr += psize; |
|
|
s += psize; |
|
|
len -= psize; |
|
|
} |
|
|
} |
|
|
psize >>= 2; |
|
|
} |
|
|
|
|
|
while (len-- != 0) |
|
|
store_byte(cpu, addr++, *s++); |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* store_pointer_and_advance(): |
|
|
* |
|
|
* Stores a 32-bit or 64-bit pointer in emulated RAM, and advances the |
|
|
* target address. (Useful for e.g. ARCBIOS environment initialization.) |
|
|
*/ |
|
|
void store_pointer_and_advance(struct cpu *cpu, uint64_t *addrp, |
|
|
uint64_t data, int flag64) |
|
|
{ |
|
|
uint64_t addr = *addrp; |
|
|
if (flag64) { |
|
|
store_64bit_word(cpu, addr, data); |
|
|
addr += 8; |
|
|
} else { |
|
|
store_32bit_word(cpu, addr, data); |
|
|
addr += 4; |
|
|
} |
|
|
*addrp = addr; |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* load_64bit_word(): |
|
|
* |
|
|
* Helper function. Emulated byte order is taken into account. |
|
|
*/ |
|
|
uint64_t load_64bit_word(struct cpu *cpu, uint64_t addr) |
|
|
{ |
|
|
unsigned char data[8]; |
|
|
|
|
|
cpu->memory_rw(cpu, cpu->mem, |
|
|
addr, data, sizeof(data), MEM_READ, CACHE_DATA); |
|
|
|
|
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
|
|
int tmp = data[0]; data[0] = data[7]; data[7] = tmp; |
|
|
tmp = data[1]; data[1] = data[6]; data[6] = tmp; |
|
|
tmp = data[2]; data[2] = data[5]; data[5] = tmp; |
|
|
tmp = data[3]; data[3] = data[4]; data[4] = tmp; |
|
|
} |
|
|
|
|
|
return |
|
|
((uint64_t)data[0] << 56) + ((uint64_t)data[1] << 48) + |
|
|
((uint64_t)data[2] << 40) + ((uint64_t)data[3] << 32) + |
|
|
((uint64_t)data[4] << 24) + ((uint64_t)data[5] << 16) + |
|
|
((uint64_t)data[6] << 8) + (uint64_t)data[7]; |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* load_32bit_word(): |
|
|
* |
|
|
* Helper function. Emulated byte order is taken into account. |
|
|
*/ |
|
|
uint32_t load_32bit_word(struct cpu *cpu, uint64_t addr) |
|
|
{ |
|
|
unsigned char data[4]; |
|
|
|
|
|
/* TODO: REMOVE THIS once everything is more stable! */ |
|
|
if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0) |
|
|
addr = (int64_t)(int32_t)addr; |
|
|
|
|
|
cpu->memory_rw(cpu, cpu->mem, |
|
|
addr, data, sizeof(data), MEM_READ, CACHE_DATA); |
|
|
|
|
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
|
|
int tmp = data[0]; data[0] = data[3]; data[3] = tmp; |
|
|
tmp = data[1]; data[1] = data[2]; data[2] = tmp; |
|
|
} |
|
|
|
|
|
return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]; |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* load_16bit_word(): |
|
|
* |
|
|
* Helper function. Emulated byte order is taken into account. |
|
|
*/ |
|
|
uint16_t load_16bit_word(struct cpu *cpu, uint64_t addr) |
|
|
{ |
|
|
unsigned char data[2]; |
|
|
|
|
|
/* TODO: REMOVE THIS once everything is more stable! */ |
|
|
if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0) |
|
|
addr = (int64_t)(int32_t)addr; |
|
|
|
|
|
cpu->memory_rw(cpu, cpu->mem, |
|
|
addr, data, sizeof(data), MEM_READ, CACHE_DATA); |
|
|
|
|
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
|
|
int tmp = data[0]; data[0] = data[1]; data[1] = tmp; |
|
|
} |
|
|
|
|
|
return (data[0] << 8) + data[1]; |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* store_64bit_word_in_host(): |
|
|
* |
|
|
* Stores a 64-bit word in the _host's_ RAM. Emulated byte order is taken |
|
|
* into account. This is useful when building structs in the host's RAM |
|
|
* which will later be copied into emulated RAM. |
|
|
*/ |
|
|
void store_64bit_word_in_host(struct cpu *cpu, |
|
|
unsigned char *data, uint64_t data64) |
|
|
{ |
|
|
data[0] = (data64 >> 56) & 255; |
|
|
data[1] = (data64 >> 48) & 255; |
|
|
data[2] = (data64 >> 40) & 255; |
|
|
data[3] = (data64 >> 32) & 255; |
|
|
data[4] = (data64 >> 24) & 255; |
|
|
data[5] = (data64 >> 16) & 255; |
|
|
data[6] = (data64 >> 8) & 255; |
|
|
data[7] = (data64) & 255; |
|
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
|
|
int tmp = data[0]; data[0] = data[7]; data[7] = tmp; |
|
|
tmp = data[1]; data[1] = data[6]; data[6] = tmp; |
|
|
tmp = data[2]; data[2] = data[5]; data[5] = tmp; |
|
|
tmp = data[3]; data[3] = data[4]; data[4] = tmp; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* store_32bit_word_in_host(): |
|
|
* |
|
|
* See comment for store_64bit_word_in_host(). |
|
|
* |
|
|
* (Note: The data32 parameter is a uint64_t. This is done to suppress |
|
|
* some warnings.) |
|
|
*/ |
|
|
void store_32bit_word_in_host(struct cpu *cpu, |
|
|
unsigned char *data, uint64_t data32) |
|
|
{ |
|
|
data[0] = (data32 >> 24) & 255; |
|
|
data[1] = (data32 >> 16) & 255; |
|
|
data[2] = (data32 >> 8) & 255; |
|
|
data[3] = (data32) & 255; |
|
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
|
|
int tmp = data[0]; data[0] = data[3]; data[3] = tmp; |
|
|
tmp = data[1]; data[1] = data[2]; data[2] = tmp; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* store_16bit_word_in_host(): |
|
|
* |
|
|
* See comment for store_64bit_word_in_host(). |
|
|
*/ |
|
|
void store_16bit_word_in_host(struct cpu *cpu, |
|
|
unsigned char *data, uint16_t data16) |
|
|
{ |
|
|
data[0] = (data16 >> 8) & 255; |
|
|
data[1] = (data16) & 255; |
|
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
|
|
int tmp = data[0]; data[0] = data[1]; data[1] = tmp; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
448 |
* machine_setup(): |
* machine_setup(): |
449 |
* |
* |
450 |
* This (rather large) function initializes memory, registers, and/or devices |
* This (rather large) function initializes memory, registers, and/or devices |
519 |
debug(" %s", machine->bootarg); |
debug(" %s", machine->bootarg); |
520 |
debug("\n"); |
debug("\n"); |
521 |
} |
} |
|
|
|
|
if (!machine->stable) |
|
|
fatal("!\n! NOTE: This machine type is not implemented well" |
|
|
" enough yet to run\n! any real-world code!" |
|
|
" (At least, it hasn't been verified to do so.)\n!\n" |
|
|
"! Please read the GXemul documentation for information" |
|
|
" about which\n! machine types that actually work.\n!\n"); |
|
522 |
} |
} |
523 |
|
|
524 |
|
|
547 |
} |
} |
548 |
} |
} |
549 |
|
|
|
/* Special hack for hpcmips machines: */ |
|
|
if (m->machine_type == MACHINE_HPCMIPS) { |
|
|
m->dbe_on_nonexistant_memaccess = 0; |
|
|
} |
|
|
|
|
550 |
/* Special SGI memory offsets: (TODO: move this somewhere else) */ |
/* Special SGI memory offsets: (TODO: move this somewhere else) */ |
551 |
if (m->machine_type == MACHINE_SGI) { |
if (m->machine_type == MACHINE_SGI) { |
552 |
switch (m->machine_subtype) { |
switch (m->machine_subtype) { |
639 |
* TODO: This should be redesigned into some "mainbus" stuff instead! |
* TODO: This should be redesigned into some "mainbus" stuff instead! |
640 |
*/ |
*/ |
641 |
|
|
642 |
machine->ninstrs += cpu0instrs; |
for (te=0; te<machine->tick_functions.n_entries; te++) { |
643 |
|
machine->tick_functions.ticks_till_next[te] -= cpu0instrs; |
644 |
for (te=0; te<machine->n_tick_entries; te++) { |
if (machine->tick_functions.ticks_till_next[te] <= 0) { |
645 |
machine->ticks_till_next[te] -= cpu0instrs; |
while (machine->tick_functions.ticks_till_next[te]<=0) { |
646 |
if (machine->ticks_till_next[te] <= 0) { |
machine->tick_functions.ticks_till_next[te] += |
647 |
while (machine->ticks_till_next[te] <= 0) { |
machine->tick_functions. |
648 |
machine->ticks_till_next[te] += |
ticks_reset_value[te]; |
|
machine->ticks_reset_value[te]; |
|
649 |
} |
} |
650 |
|
|
651 |
machine->tick_func[te](cpus[0], |
machine->tick_functions.f[te](cpus[0], |
652 |
machine->tick_extra[te]); |
machine->tick_functions.extra[te]); |
653 |
} |
} |
654 |
} |
} |
655 |
|
|
678 |
{ |
{ |
679 |
struct machine_entry *me; |
struct machine_entry *me; |
680 |
|
|
681 |
me = malloc(sizeof(struct machine_entry)); |
CHECK_ALLOCATION(me = malloc(sizeof(struct machine_entry))); |
|
if (me == NULL) { |
|
|
fprintf(stderr, "machine_entry_new(): out of memory (1)\n"); |
|
|
exit(1); |
|
|
} |
|
|
|
|
682 |
memset(me, 0, sizeof(struct machine_entry)); |
memset(me, 0, sizeof(struct machine_entry)); |
683 |
|
|
684 |
me->name = name; |
me->name = name; |
701 |
void machine_entry_add_alias(struct machine_entry *me, const char *name) |
void machine_entry_add_alias(struct machine_entry *me, const char *name) |
702 |
{ |
{ |
703 |
me->n_aliases ++; |
me->n_aliases ++; |
704 |
me->aliases = realloc(me->aliases, sizeof(char *) * me->n_aliases); |
|
705 |
if (me->aliases == NULL) { |
CHECK_ALLOCATION(me->aliases = realloc(me->aliases, |
706 |
fprintf(stderr, "out of memory\n"); |
sizeof(char *) * me->n_aliases)); |
|
exit(1); |
|
|
} |
|
707 |
|
|
708 |
me->aliases[me->n_aliases - 1] = (char *) name; |
me->aliases[me->n_aliases - 1] = (char *) name; |
709 |
} |
} |
725 |
struct machine_entry_subtype *mes; |
struct machine_entry_subtype *mes; |
726 |
|
|
727 |
/* Allocate a new subtype struct: */ |
/* Allocate a new subtype struct: */ |
728 |
mes = malloc(sizeof(struct machine_entry_subtype)); |
CHECK_ALLOCATION(mes = malloc(sizeof(struct machine_entry_subtype))); |
|
if (mes == NULL) { |
|
|
fprintf(stderr, "machine_entry_subtype_new(): out " |
|
|
"of memory (1)\n"); |
|
|
exit(1); |
|
|
} |
|
729 |
|
|
730 |
/* Add the subtype to the machine entry: */ |
/* Add the subtype to the machine entry: */ |
731 |
me->n_subtypes ++; |
me->n_subtypes ++; |
732 |
me->subtype = realloc(me->subtype, sizeof(struct |
CHECK_ALLOCATION(me->subtype = realloc(me->subtype, sizeof(struct |
733 |
machine_entry_subtype *) * me->n_subtypes); |
machine_entry_subtype *) * me->n_subtypes)); |
|
if (me->subtype == NULL) { |
|
|
fprintf(stderr, "out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
734 |
me->subtype[me->n_subtypes - 1] = mes; |
me->subtype[me->n_subtypes - 1] = mes; |
735 |
|
|
736 |
/* Fill the struct with subtype data: */ |
/* Fill the struct with subtype data: */ |
750 |
break; |
break; |
751 |
|
|
752 |
mes->n_aliases ++; |
mes->n_aliases ++; |
753 |
mes->aliases = realloc(mes->aliases, sizeof(char *) * |
CHECK_ALLOCATION(mes->aliases = |
754 |
mes->n_aliases); |
realloc(mes->aliases, sizeof(char *) * mes->n_aliases)); |
|
if (mes->aliases == NULL) { |
|
|
fprintf(stderr, "out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
755 |
|
|
756 |
mes->aliases[mes->n_aliases - 1] = s; |
mes->aliases[mes->n_aliases - 1] = s; |
757 |
} |
} |
854 |
"that actually work. Use the alias\nwhen selecting a machine type " |
"that actually work. Use the alias\nwhen selecting a machine type " |
855 |
"or subtype, not the real name.\n"); |
"or subtype, not the real name.\n"); |
856 |
|
|
|
#ifdef UNSTABLE_DEVEL |
|
857 |
debug("\n"); |
debug("\n"); |
858 |
|
|
859 |
useremul_list_emuls(); |
useremul_list_emuls(); |
860 |
debug("Userland emulation works for programs with the complexity" |
debug("Userland emulation works for programs with the complexity" |
861 |
" of Hello World,\nbut not much more.\n"); |
" of Hello World,\nbut not much more.\n"); |
|
#endif |
|
862 |
} |
} |
863 |
|
|
864 |
|
|