/[gxemul]/trunk/src/machine.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/machine.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 34 - (show annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 32422 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1480 2007/02/19 01:34:42 debug Exp $
20061029	Changing usleep(1) calls in the debugger to usleep(10000)
20061107	Adding a new disk image option (-d o...) which sets the ISO9660
		filesystem base offset; also making some other hacks to allow
		NetBSD/dreamcast and homebrew demos/games to boot directly
		from a filesystem image.
		Moving Dreamcast-specific stuff in the documentation to its
		own page (dreamcast.html).
		Adding a border to the Dreamcast PVR framebuffer.
20061108	Adding a -T command line option (again?), for halting the
		emulator on unimplemented memory accesses.
20061109	Continuing on various SH4 and Dreamcast related things.
		The emulator should now halt on more unimplemented device
		accesses, instead of just printing a warning, forcing me to
		actually implement missing stuff :)
20061111	Continuing on SH4 and Dreamcast stuff.
		Adding a bogus Landisk (SH4) machine mode.
20061112	Implementing some parts of the Dreamcast GDROM device. With
		some ugly hacks, NetBSD can (barely) mount an ISO image.
20061113	NetBSD/dreamcast now starts booting from the Live CD image,
		but crashes randomly quite early on in the boot process.
20061122	Beginning on a skeleton interrupt.h and interrupt.c for the
		new interrupt subsystem.
20061124	Continuing on the new interrupt system; taking the first steps
		to attempt to connect CPUs (SuperH and MIPS) and devices
		(dev_cons and SH4 timer interrupts) to it. Many things will
		probably break from now on.
20061125	Converting dev_ns16550, dev_8253 to the new interrupt system.
		Attempting to begin to convert the ISA bus.
20061130	Incorporating a patch from Brian Foley for the configure
		script, which checks for X11 libs in /usr/X11R6/lib64 (which
		is used on some Linux systems).
20061227	Adding a note in the man page about booting from Dreamcast
		CDROM images (i.e. that no external kernel is needed).
20061229	Continuing on the interrupt system rewrite: beginning to
		convert more devices, adding abort() calls for legacy interrupt
		system calls so that everything now _has_ to be rewritten!
		Almost all machine modes are now completely broken.
20061230	More progress on removing old interrupt code, mostly related
		to the ISA bus + devices, the LCA bus (on AlphaBook1), and
		the Footbridge bus (for CATS). And some minor PCI stuff.
		Connecting the ARM cpu to the new interrupt system.
		The CATS, NetWinder, and QEMU_MIPS machine modes now work with
		the new interrupt system :)
20061231	Connecting PowerPC CPUs to the new interrupt system.
		Making PReP machines (IBM 6050) work again.
		Beginning to convert the GT PCI controller (for e.g. Malta
		and Cobalt emulation). Some things work, but not everything.
		Updating Copyright notices for 2007.
20070101	Converting dev_kn02 from legacy style to devinit; the 3max
		machine mode now works with the new interrupt system :-]
20070105	Beginning to convert the SGI O2 machine to the new interrupt
		system; finally converting O2 (IP32) devices to devinit, etc.
20070106	Continuing on the interrupt system redesign/rewrite; KN01
		(PMAX), KN230, and Dreamcast ASIC interrupts should work again,
		moving out stuff from machine.h and devices.h into the
		corresponding devices, beginning the rewrite of i80321
		interrupts, etc.
20070107	Beginning on the rewrite of Eagle interrupt stuff (PReP, etc).
20070117	Beginning the rewrite of Algor (V3) interrupts (finally
		changing dev_v3 into devinit style).
20070118	Removing the "bus" registry concept from machine.h, because
		it was practically meaningless.
		Continuing on the rewrite of Algor V3 ISA interrupts.
20070121	More work on Algor interrupts; they are now working again,
		well enough to run NetBSD/algor. :-)
20070122	Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips
		can be installed using the new interrupt system :-)
20070123	Making the testmips mode work with the new interrupt system.
20070127	Beginning to convert DEC5800 devices to devinit, and to the
		new interrupt system.
		Converting Playstation 2 devices to devinit, and converting
		the interrupt system. Also fixing a severe bug: the interrupt
		mask register on Playstation 2 is bitwise _toggled_ on writes.
20070128	Removing the dummy NetGear machine mode and the 8250 device
		(which was only used by the NetGear machine).
		Beginning to convert the MacPPC GC (Grand Central) interrupt
		controller to the new interrupt system.
		Converting Jazz interrupts (PICA61 etc.) to the new interrupt
		system. NetBSD/arc can be installed again :-)
		Fixing the JAZZ timer (hardcoding it at 100 Hz, works with
		NetBSD and it is better than a completely dummy timer as it
		was before).
		Converting dev_mp to the new interrupt system, although I
		haven't had time to actually test it yet.
		Completely removing src/machines/interrupts.c, cpu_interrupt
		and cpu_interrupt_ack in src/cpu.c, and
		src/include/machine_interrupts.h! Adding fatal error messages
		+ abort() in the few places that are left to fix.
		Converting dev_z8530 to the new interrupt system.
		FINALLY removing the md_int struct completely from the
		machine struct.
		SH4 fixes (adding a PADDR invalidation in the ITLB replacement
		code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs
		all the way to the login prompt, and can be interacted with :-)
		Converting the CPC700 controller (PCI and interrupt controller
		for PM/PPC) to the new interrupt system.
20070129	Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/
		sgimips' and OpenBSD/sgi's ramdisk kernels can now be
		interacted with again.
20070130	Moving out the MIPS multi_lw and _sw instruction combinations
		so that they are auto-generated at compile time instead.
20070131	Adding detection of amd64/x86_64 hosts in the configure script,
		for doing initial experiments (again :-) with native code
		generation.
		Adding a -k command line option to set the size of the dyntrans
		cache, and a -B command line option to disable native code
		generation, even if GXemul was compiled with support for
		native code generation for the specific host CPU architecture.
20070201	Experimenting with a skeleton for native code generation.
		Changing the default behaviour, so that native code generation
		is now disabled by default, and has to be enabled by using
		-b on the command line.
20070202	Continuing the native code generation experiments.
		Making PCI interrupts work for Footbridge again.
20070203	More native code generation experiments.
		Removing most of the native code generation experimental code,
		it does not make sense to include any quick hacks like this.
		Minor cleanup/removal of some more legacy MIPS interrupt code.
20070204	Making i80321 interrupts work again (for NetBSD/evbarm etc.),
		and fixing the timer at 100 Hz.
20070206	Experimenting with removing the wdc interrupt slowness hack.
20070207	Lowering the number of dyntrans TLB entries for MIPS from
		192 to 128, resulting in a minor speed improvement.
		Minor optimization to the code invalidation routine in
		cpu_dyntrans.c.
20070208	Increasing (experimentally) the nr of dyntrans instructions per
		loop from 60 to 120.
20070210	Commenting out (experimentally) the dyntrans_device_danger
		detection in memory_rw.c.
		Changing the testmips and baremips machines to use a revision 2
		MIPS64 CPU by default, instead of revision 1.
		Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC
		files, the PC bios emulation, and the Olivetti M700 (ARC) and
		db64360 emulation modes.
20070211	Adding an "mp" demo to the demos directory, which tests the
		SMP functionality of the testmips machine.
		Fixing PReP interrupts some more. NetBSD/prep now boots again.
20070216	Adding a "nop workaround" for booting Mach/PMAX to the
		documentation; thanks to Artur Bujdoso for the values.
		Converting more of the MacPPC interrupt stuff to the new
		system.
		Beginning to convert BeBox interrupts to the new system.
		PPC603e should NOT have the PPC_NO_DEC flag! Removing it.
		Correcting BeBox clock speed (it was set to 100 in the NetBSD
		bootinfo block, but should be 33000000/4), allowing NetBSD
		to start without using the (incorrect) PPC_NO_DEC hack.
20070217	Implementing (slow) AltiVec vector loads and stores, allowing
		NetBSD/macppc to finally boot using the GENERIC kernel :-)
		Updating the documentation with install instructions for
		NetBSD/macppc.
20070218-19	Regression testing for the release.

==============  RELEASE 0.4.4  ==============


1 /*
2 * Copyright (C) 2003-2007 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: machine.c,v 1.693 2007/01/28 14:15:29 debug Exp $
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #include <string.h>
35 #include <time.h>
36 #include <unistd.h>
37
38 #include "arcbios.h"
39 #include "bus_isa.h"
40 #include "bus_pci.h"
41 #include "cpu.h"
42 #include "debugger.h"
43 #include "device.h"
44 #include "devices.h"
45 #include "diskimage.h"
46 #include "emul.h"
47 #include "machine.h"
48 #include "memory.h"
49 #include "misc.h"
50 #include "net.h"
51 #include "settings.h"
52 #include "symbol.h"
53
54
55 /* See main.c: */
56 extern int quiet_mode;
57 extern int verbose;
58
59
60 /* This is initialized by machine_init(): */
61 struct machine_entry *first_machine_entry = NULL;
62
63
64 /*
65 * machine_new():
66 *
67 * Returns a reasonably initialized struct machine.
68 */
69 struct machine *machine_new(char *name, struct emul *emul, int id)
70 {
71 struct machine *m;
72 m = malloc(sizeof(struct machine));
73 if (m == NULL) {
74 fprintf(stderr, "machine_new(): out of memory\n");
75 exit(1);
76 }
77
78 memset(m, 0, sizeof(struct machine));
79
80 /* Pointer back to the emul object that this machine belongs to: */
81 m->emul = emul;
82
83 m->name = strdup(name);
84
85 /* Full path, e.g. "emul[0].machine[0]": */
86 m->path = malloc(strlen(emul->path) + 20);
87 if (m->path == NULL) {
88 fprintf(stderr, "out of memory\n");
89 exit(1);
90 }
91 snprintf(m->path, strlen(emul->path) + 20, "%s.machine[%i]",
92 emul->path, id);
93
94 /* Sane default values: */
95 m->serial_nr = 1;
96 m->machine_type = MACHINE_NONE;
97 m->machine_subtype = MACHINE_NONE;
98 m->arch_pagesize = 4096; /* Should be overriden in
99 emul.c for other pagesizes. */
100 m->prom_emulation = 1;
101 m->allow_instruction_combinations = 1;
102 m->byte_order_override = NO_BYTE_ORDER_OVERRIDE;
103 m->boot_kernel_filename = "";
104 m->boot_string_argument = NULL;
105 m->x11_scaledown = 1;
106 m->x11_scaleup = 1;
107 m->n_gfx_cards = 1;
108 m->dbe_on_nonexistant_memaccess = 1;
109 m->show_symbolic_register_names = 1;
110 symbol_init(&m->symbol_context);
111
112 /* Settings: */
113 m->settings = settings_new();
114 settings_add(m->settings, "name", 0,
115 SETTINGS_TYPE_STRING, SETTINGS_FORMAT_STRING,
116 (void *) &m->name);
117 settings_add(m->settings, "serial_nr", 0,
118 SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
119 (void *) &m->serial_nr);
120 settings_add(m->settings, "arch_pagesize", 0,
121 SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
122 (void *) &m->arch_pagesize);
123 settings_add(m->settings, "prom_emulation", 0,
124 SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
125 (void *) &m->prom_emulation);
126 settings_add(m->settings, "allow_instruction_combinations", 0,
127 SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
128 (void *) &m->allow_instruction_combinations);
129 settings_add(m->settings, "n_gfx_cards", 0,
130 SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
131 (void *) &m->n_gfx_cards);
132 settings_add(m->settings, "show_symbolic_register_names", 1,
133 SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
134 (void *) &m->show_symbolic_register_names);
135 settings_add(m->settings, "statistics_enabled", 1,
136 SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
137 (void *) &m->statistics_enabled);
138
139 return m;
140 }
141
142
143 /*
144 * machine_destroy():
145 *
146 * Destroys a machine object.
147 */
148 void machine_destroy(struct machine *machine)
149 {
150 int i;
151
152 for (i=0; i<machine->ncpus; i++)
153 cpu_destroy(machine->cpus[i]);
154
155 if (machine->name != NULL)
156 free(machine->name);
157
158 if (machine->path != NULL)
159 free(machine->path);
160
161 /* Remove any remaining level-1 settings: */
162 settings_remove_all(machine->settings);
163 settings_destroy(machine->settings);
164
165 free(machine);
166 }
167
168
169 /*
170 * machine_name_to_type():
171 *
172 * Take a type and a subtype as strings, and convert them into numeric
173 * values used internally throughout the code.
174 *
175 * Return value is 1 on success, 0 if there was no match.
176 * Also, any errors/warnings are printed using fatal()/debug().
177 */
178 int machine_name_to_type(char *stype, char *ssubtype,
179 int *type, int *subtype, int *arch)
180 {
181 struct machine_entry *me;
182 int i, j, k, nmatches = 0;
183
184 *type = MACHINE_NONE;
185 *subtype = 0;
186
187 /* Check stype, and optionally ssubtype: */
188 me = first_machine_entry;
189 while (me != NULL) {
190 for (i=0; i<me->n_aliases; i++)
191 if (strcasecmp(me->aliases[i], stype) == 0) {
192 /* Found a type: */
193 *type = me->machine_type;
194 *arch = me->arch;
195
196 if (me->n_subtypes == 0)
197 return 1;
198
199 /* Check for subtype: */
200 for (j=0; j<me->n_subtypes; j++)
201 for (k=0; k<me->subtype[j]->n_aliases;
202 k++)
203 if (strcasecmp(ssubtype,
204 me->subtype[j]->aliases[k]
205 ) == 0) {
206 *subtype = me->subtype[
207 j]->machine_subtype;
208 return 1;
209 }
210
211 fatal("Unknown subtype '%s' for emulation"
212 " '%s'\n", ssubtype, stype);
213 if (!ssubtype[0])
214 fatal("(Maybe you forgot the -e"
215 " command line option?)\n");
216 exit(1);
217 }
218
219 me = me->next;
220 }
221
222 /* Not found? Then just check ssubtype: */
223 me = first_machine_entry;
224 while (me != NULL) {
225 if (me->n_subtypes == 0) {
226 me = me->next;
227 continue;
228 }
229
230 /* Check for subtype: */
231 for (j=0; j<me->n_subtypes; j++)
232 for (k=0; k<me->subtype[j]->n_aliases; k++)
233 if (strcasecmp(ssubtype, me->subtype[j]->
234 aliases[k]) == 0) {
235 *type = me->machine_type;
236 *arch = me->arch;
237 *subtype = me->subtype[j]->
238 machine_subtype;
239 nmatches ++;
240 }
241
242 me = me->next;
243 }
244
245 switch (nmatches) {
246 case 0: fatal("\nSorry, emulation \"%s\"", stype);
247 if (ssubtype != NULL && ssubtype[0] != '\0')
248 fatal(" (subtype \"%s\")", ssubtype);
249 fatal(" is unknown.\n");
250 break;
251 case 1: return 1;
252 default:fatal("\nSorry, multiple matches for \"%s\"", stype);
253 if (ssubtype != NULL && ssubtype[0] != '\0')
254 fatal(" (subtype \"%s\")", ssubtype);
255 fatal(".\n");
256 }
257
258 *type = MACHINE_NONE;
259 *subtype = 0;
260
261 fatal("Use the -H command line option to get a list of "
262 "available types and subtypes.\n\n");
263
264 return 0;
265 }
266
267
268 /*
269 * machine_add_tickfunction():
270 *
271 * Adds a tick function (a function called every now and then, depending on
272 * clock cycle count) to a machine.
273 *
274 * If tickshift is non-zero, a tick will occur every (1 << tickshift) cycles.
275 * This is used for the normal (fast dyntrans) emulation modes.
276 *
277 * If tickshift is zero, then this is a cycle-accurate tick function.
278 * The hz value is used in this case.
279 */
280 void machine_add_tickfunction(struct machine *machine, void (*func)
281 (struct cpu *, void *), void *extra, int tickshift, double hz)
282 {
283 int n = machine->n_tick_entries;
284
285 if (n >= MAX_TICK_FUNCTIONS) {
286 fprintf(stderr, "machine_add_tickfunction(): too "
287 "many tick functions\n");
288 exit(1);
289 }
290
291 if (!machine->cycle_accurate) {
292 /*
293 * The dyntrans subsystem wants to run code in relatively
294 * large chunks without checking for external interrupts;
295 * too low tickshifts are not allowed.
296 */
297 if (tickshift < N_SAFE_DYNTRANS_LIMIT_SHIFT) {
298 fatal("ERROR! tickshift = %i, less than "
299 "N_SAFE_DYNTRANS_LIMIT_SHIFT (%i)\n",
300 tickshift, N_SAFE_DYNTRANS_LIMIT_SHIFT);
301 exit(1);
302 }
303 }
304
305 machine->ticks_till_next[n] = 0;
306 machine->ticks_reset_value[n] = 1 << tickshift;
307 machine->tick_func[n] = func;
308 machine->tick_extra[n] = extra;
309 machine->tick_hz[n] = hz;
310
311 machine->n_tick_entries ++;
312 }
313
314
315 /*
316 * machine_statistics_init():
317 *
318 * Initialize the parts of a machine struct that deal with instruction
319 * statistics gathering.
320 *
321 * Note: The fname argument contains "flags:filename".
322 */
323 void machine_statistics_init(struct machine *machine, char *fname)
324 {
325 int n_fields = 0;
326 char *pcolon = fname;
327 char *mode = "a"; /* Append by default */
328
329 machine->allow_instruction_combinations = 0;
330
331 if (machine->statistics_fields != NULL) {
332 fprintf(stderr, "Only one -s option is allowed.\n");
333 exit(1);
334 }
335
336 machine->statistics_fields = malloc(MAX_STATISTICS_FIELDS + 1);
337 machine->statistics_enabled = 1;
338
339 while (*pcolon && *pcolon != ':')
340 pcolon ++;
341
342 if (*pcolon != ':') {
343 fprintf(stderr, "The syntax for the -s option is: "
344 "-s flags:filename\nYou omitted the flags. Run g"
345 "xemul -h for a list of available flags.\n");
346 exit(1);
347 }
348
349 while (*fname != ':') {
350 switch (*fname) {
351
352 /* Type flags: */
353 case 'v':
354 case 'i':
355 case 'p':
356 machine->statistics_fields[n_fields ++] = *fname;
357 if (n_fields >= MAX_STATISTICS_FIELDS) {
358 fprintf(stderr, "Internal error: Too many "
359 "statistics fields used. Increase "
360 "MAX_STATISTICS_FIELDS.\n");
361 exit(1);
362 }
363 machine->statistics_fields[n_fields] = '\0';
364 break;
365
366 /* Optional flags: */
367 case 'o':
368 mode = "w";
369 break;
370 case 'd':
371 machine->statistics_enabled = 0;
372 break;
373
374 default:fprintf(stderr, "Unknown flag '%c' used with the"
375 " -s option. Aborting.\n", *fname);
376 exit(1);
377 }
378 fname ++;
379 }
380
381 fname ++; /* point to the filename after the colon */
382
383 machine->statistics_filename = strdup(fname);
384 machine->statistics_file = fopen(machine->statistics_filename, mode);
385 }
386
387
388 /*
389 * machine_dumpinfo():
390 *
391 * Dumps info about a machine in some kind of readable format. (Used by
392 * the 'machine' debugger command.)
393 */
394 void machine_dumpinfo(struct machine *m)
395 {
396 int i;
397
398 debug("serial nr: %i", m->serial_nr);
399 if (m->nr_of_nics > 0)
400 debug(" (nr of NICs: %i)", m->nr_of_nics);
401 debug("\n");
402
403 debug("memory: %i MB", m->physical_ram_in_mb);
404 if (m->memory_offset_in_mb != 0)
405 debug(" (offset by %i MB)", m->memory_offset_in_mb);
406 if (m->random_mem_contents)
407 debug(", randomized contents");
408 if (m->dbe_on_nonexistant_memaccess)
409 debug(", dbe_on_nonexistant_memaccess");
410 debug("\n");
411
412 if (!m->prom_emulation)
413 debug("PROM emulation disabled\n");
414
415 for (i=0; i<m->ncpus; i++)
416 cpu_dumpinfo(m, m->cpus[i]);
417
418 if (m->ncpus > 1)
419 debug("Bootstrap cpu is nr %i\n", m->bootstrap_cpu);
420
421 if (m->slow_serial_interrupts_hack_for_linux)
422 debug("Using slow_serial_interrupts_hack_for_linux\n");
423
424 if (m->use_x11) {
425 debug("Using X11");
426 if (m->x11_scaledown > 1)
427 debug(", scaledown %i", m->x11_scaledown);
428 if (m->x11_scaleup > 1)
429 debug(", scaleup %i", m->x11_scaleup);
430 if (m->x11_n_display_names > 0) {
431 for (i=0; i<m->x11_n_display_names; i++) {
432 debug(i? ", " : " (");
433 debug("\"%s\"", m->x11_display_names[i]);
434 }
435 debug(")");
436 }
437 debug("\n");
438 }
439
440 diskimage_dump_info(m);
441
442 if (m->force_netboot)
443 debug("Forced netboot\n");
444 }
445
446
447 /*
448 * dump_mem_string():
449 *
450 * Dump the contents of emulated RAM as readable text. Bytes that aren't
451 * readable are dumped in [xx] notation, where xx is in hexadecimal.
452 * Dumping ends after DUMP_MEM_STRING_MAX bytes, or when a terminating
453 * zero byte is found.
454 */
455 #define DUMP_MEM_STRING_MAX 45
456 void dump_mem_string(struct cpu *cpu, uint64_t addr)
457 {
458 int i;
459 for (i=0; i<DUMP_MEM_STRING_MAX; i++) {
460 unsigned char ch = '\0';
461
462 cpu->memory_rw(cpu, cpu->mem, addr + i, &ch, sizeof(ch),
463 MEM_READ, CACHE_DATA | NO_EXCEPTIONS);
464 if (ch == '\0')
465 return;
466 if (ch >= ' ' && ch < 126)
467 debug("%c", ch);
468 else
469 debug("[%02x]", ch);
470 }
471 }
472
473
474 /*
475 * store_byte():
476 *
477 * Stores a byte in emulated ram. (Helper function.)
478 */
479 void store_byte(struct cpu *cpu, uint64_t addr, uint8_t data)
480 {
481 if ((addr >> 32) == 0)
482 addr = (int64_t)(int32_t)addr;
483 cpu->memory_rw(cpu, cpu->mem,
484 addr, &data, sizeof(data), MEM_WRITE, CACHE_DATA);
485 }
486
487
488 /*
489 * store_string():
490 *
491 * Stores chars into emulated RAM until a zero byte (string terminating
492 * character) is found. The zero byte is also copied.
493 * (strcpy()-like helper function, host-RAM-to-emulated-RAM.)
494 */
495 void store_string(struct cpu *cpu, uint64_t addr, char *s)
496 {
497 do {
498 store_byte(cpu, addr++, *s);
499 } while (*s++);
500 }
501
502
503 /*
504 * add_environment_string():
505 *
506 * Like store_string(), but advances the pointer afterwards. The most
507 * obvious use is to place a number of strings (such as environment variable
508 * strings) after one-another in emulated memory.
509 */
510 void add_environment_string(struct cpu *cpu, char *s, uint64_t *addr)
511 {
512 store_string(cpu, *addr, s);
513 (*addr) += strlen(s) + 1;
514 }
515
516
517 /*
518 * add_environment_string_dual():
519 *
520 * Add "dual" environment strings, one for the variable name and one for the
521 * value, and update pointers afterwards.
522 */
523 void add_environment_string_dual(struct cpu *cpu,
524 uint64_t *ptrp, uint64_t *addrp, char *s1, char *s2)
525 {
526 uint64_t ptr = *ptrp, addr = *addrp;
527
528 store_32bit_word(cpu, ptr, addr);
529 ptr += sizeof(uint32_t);
530 if (addr != 0) {
531 store_string(cpu, addr, s1);
532 addr += strlen(s1) + 1;
533 }
534 store_32bit_word(cpu, ptr, addr);
535 ptr += sizeof(uint32_t);
536 if (addr != 0) {
537 store_string(cpu, addr, s2);
538 addr += strlen(s2) + 1;
539 }
540
541 *ptrp = ptr;
542 *addrp = addr;
543 }
544
545
546 /*
547 * store_64bit_word():
548 *
549 * Stores a 64-bit word in emulated RAM. Byte order is taken into account.
550 * Helper function.
551 */
552 int store_64bit_word(struct cpu *cpu, uint64_t addr, uint64_t data64)
553 {
554 unsigned char data[8];
555 if ((addr >> 32) == 0)
556 addr = (int64_t)(int32_t)addr;
557 data[0] = (data64 >> 56) & 255;
558 data[1] = (data64 >> 48) & 255;
559 data[2] = (data64 >> 40) & 255;
560 data[3] = (data64 >> 32) & 255;
561 data[4] = (data64 >> 24) & 255;
562 data[5] = (data64 >> 16) & 255;
563 data[6] = (data64 >> 8) & 255;
564 data[7] = (data64) & 255;
565 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
566 int tmp = data[0]; data[0] = data[7]; data[7] = tmp;
567 tmp = data[1]; data[1] = data[6]; data[6] = tmp;
568 tmp = data[2]; data[2] = data[5]; data[5] = tmp;
569 tmp = data[3]; data[3] = data[4]; data[4] = tmp;
570 }
571 return cpu->memory_rw(cpu, cpu->mem,
572 addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
573 }
574
575
576 /*
577 * store_32bit_word():
578 *
579 * Stores a 32-bit word in emulated RAM. Byte order is taken into account.
580 * (This function takes a 64-bit word as argument, to suppress some
581 * warnings, but only the lowest 32 bits are used.)
582 */
583 int store_32bit_word(struct cpu *cpu, uint64_t addr, uint64_t data32)
584 {
585 unsigned char data[4];
586
587 /* TODO: REMOVE THIS once everything is more stable! */
588 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
589 addr = (int64_t)(int32_t)addr;
590
591 data[0] = (data32 >> 24) & 255;
592 data[1] = (data32 >> 16) & 255;
593 data[2] = (data32 >> 8) & 255;
594 data[3] = (data32) & 255;
595 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
596 int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
597 tmp = data[1]; data[1] = data[2]; data[2] = tmp;
598 }
599 return cpu->memory_rw(cpu, cpu->mem,
600 addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
601 }
602
603
604 /*
605 * store_16bit_word():
606 *
607 * Stores a 16-bit word in emulated RAM. Byte order is taken into account.
608 * (This function takes a 64-bit word as argument, to suppress some
609 * warnings, but only the lowest 16 bits are used.)
610 */
611 int store_16bit_word(struct cpu *cpu, uint64_t addr, uint64_t data16)
612 {
613 unsigned char data[2];
614
615 /* TODO: REMOVE THIS once everything is more stable! */
616 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
617 addr = (int64_t)(int32_t)addr;
618
619 data[0] = (data16 >> 8) & 255;
620 data[1] = (data16) & 255;
621 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
622 int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
623 }
624 return cpu->memory_rw(cpu, cpu->mem,
625 addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
626 }
627
628
629 /*
630 * store_buf():
631 *
632 * memcpy()-like helper function, from host RAM to emulated RAM.
633 */
634 void store_buf(struct cpu *cpu, uint64_t addr, char *s, size_t len)
635 {
636 size_t psize = 1024; /* 1024 256 64 16 4 1 */
637
638 /* TODO: REMOVE THIS once everything is more stable! */
639 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
640 addr = (int64_t)(int32_t)addr;
641
642 while (len != 0) {
643 if ((addr & (psize-1)) == 0) {
644 while (len >= psize) {
645 cpu->memory_rw(cpu, cpu->mem, addr,
646 (unsigned char *)s, psize, MEM_WRITE,
647 CACHE_DATA);
648 addr += psize;
649 s += psize;
650 len -= psize;
651 }
652 }
653 psize >>= 2;
654 }
655
656 while (len-- != 0)
657 store_byte(cpu, addr++, *s++);
658 }
659
660
661 /*
662 * store_pointer_and_advance():
663 *
664 * Stores a 32-bit or 64-bit pointer in emulated RAM, and advances the
665 * target address. (Useful for e.g. ARCBIOS environment initialization.)
666 */
667 void store_pointer_and_advance(struct cpu *cpu, uint64_t *addrp,
668 uint64_t data, int flag64)
669 {
670 uint64_t addr = *addrp;
671 if (flag64) {
672 store_64bit_word(cpu, addr, data);
673 addr += 8;
674 } else {
675 store_32bit_word(cpu, addr, data);
676 addr += 4;
677 }
678 *addrp = addr;
679 }
680
681
682 /*
683 * load_64bit_word():
684 *
685 * Helper function. Emulated byte order is taken into account.
686 */
687 uint64_t load_64bit_word(struct cpu *cpu, uint64_t addr)
688 {
689 unsigned char data[8];
690
691 cpu->memory_rw(cpu, cpu->mem,
692 addr, data, sizeof(data), MEM_READ, CACHE_DATA);
693
694 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
695 int tmp = data[0]; data[0] = data[7]; data[7] = tmp;
696 tmp = data[1]; data[1] = data[6]; data[6] = tmp;
697 tmp = data[2]; data[2] = data[5]; data[5] = tmp;
698 tmp = data[3]; data[3] = data[4]; data[4] = tmp;
699 }
700
701 return
702 ((uint64_t)data[0] << 56) + ((uint64_t)data[1] << 48) +
703 ((uint64_t)data[2] << 40) + ((uint64_t)data[3] << 32) +
704 ((uint64_t)data[4] << 24) + ((uint64_t)data[5] << 16) +
705 ((uint64_t)data[6] << 8) + (uint64_t)data[7];
706 }
707
708
709 /*
710 * load_32bit_word():
711 *
712 * Helper function. Emulated byte order is taken into account.
713 */
714 uint32_t load_32bit_word(struct cpu *cpu, uint64_t addr)
715 {
716 unsigned char data[4];
717
718 /* TODO: REMOVE THIS once everything is more stable! */
719 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
720 addr = (int64_t)(int32_t)addr;
721
722 cpu->memory_rw(cpu, cpu->mem,
723 addr, data, sizeof(data), MEM_READ, CACHE_DATA);
724
725 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
726 int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
727 tmp = data[1]; data[1] = data[2]; data[2] = tmp;
728 }
729
730 return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3];
731 }
732
733
734 /*
735 * load_16bit_word():
736 *
737 * Helper function. Emulated byte order is taken into account.
738 */
739 uint16_t load_16bit_word(struct cpu *cpu, uint64_t addr)
740 {
741 unsigned char data[2];
742
743 /* TODO: REMOVE THIS once everything is more stable! */
744 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
745 addr = (int64_t)(int32_t)addr;
746
747 cpu->memory_rw(cpu, cpu->mem,
748 addr, data, sizeof(data), MEM_READ, CACHE_DATA);
749
750 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
751 int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
752 }
753
754 return (data[0] << 8) + data[1];
755 }
756
757
758 /*
759 * store_64bit_word_in_host():
760 *
761 * Stores a 64-bit word in the _host's_ RAM. Emulated byte order is taken
762 * into account. This is useful when building structs in the host's RAM
763 * which will later be copied into emulated RAM.
764 */
765 void store_64bit_word_in_host(struct cpu *cpu,
766 unsigned char *data, uint64_t data64)
767 {
768 data[0] = (data64 >> 56) & 255;
769 data[1] = (data64 >> 48) & 255;
770 data[2] = (data64 >> 40) & 255;
771 data[3] = (data64 >> 32) & 255;
772 data[4] = (data64 >> 24) & 255;
773 data[5] = (data64 >> 16) & 255;
774 data[6] = (data64 >> 8) & 255;
775 data[7] = (data64) & 255;
776 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
777 int tmp = data[0]; data[0] = data[7]; data[7] = tmp;
778 tmp = data[1]; data[1] = data[6]; data[6] = tmp;
779 tmp = data[2]; data[2] = data[5]; data[5] = tmp;
780 tmp = data[3]; data[3] = data[4]; data[4] = tmp;
781 }
782 }
783
784
785 /*
786 * store_32bit_word_in_host():
787 *
788 * See comment for store_64bit_word_in_host().
789 *
790 * (Note: The data32 parameter is a uint64_t. This is done to suppress
791 * some warnings.)
792 */
793 void store_32bit_word_in_host(struct cpu *cpu,
794 unsigned char *data, uint64_t data32)
795 {
796 data[0] = (data32 >> 24) & 255;
797 data[1] = (data32 >> 16) & 255;
798 data[2] = (data32 >> 8) & 255;
799 data[3] = (data32) & 255;
800 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
801 int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
802 tmp = data[1]; data[1] = data[2]; data[2] = tmp;
803 }
804 }
805
806
807 /*
808 * store_16bit_word_in_host():
809 *
810 * See comment for store_64bit_word_in_host().
811 */
812 void store_16bit_word_in_host(struct cpu *cpu,
813 unsigned char *data, uint16_t data16)
814 {
815 data[0] = (data16 >> 8) & 255;
816 data[1] = (data16) & 255;
817 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
818 int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
819 }
820 }
821
822
823 /*
824 * machine_setup():
825 *
826 * This (rather large) function initializes memory, registers, and/or devices
827 * required by specific machine emulations.
828 */
829 void machine_setup(struct machine *machine)
830 {
831 struct memory *mem;
832 struct machine_entry *me;
833
834 /* Abreviation: :-) */
835 struct cpu *cpu = machine->cpus[machine->bootstrap_cpu];
836
837 machine->bootdev_id = diskimage_bootdev(machine,
838 &machine->bootdev_type);
839
840 mem = cpu->mem;
841 machine->machine_name = NULL;
842
843 /* TODO: Move this somewhere else? */
844 if (machine->boot_string_argument == NULL) {
845 switch (machine->machine_type) {
846 case MACHINE_ARC:
847 machine->boot_string_argument = "-aN";
848 break;
849 case MACHINE_CATS:
850 machine->boot_string_argument = "-A";
851 break;
852 case MACHINE_PMAX:
853 machine->boot_string_argument = "-a";
854 break;
855 default:
856 /* Important, because boot_string_argument should
857 not be set to NULL: */
858 machine->boot_string_argument = "";
859 }
860 }
861
862
863 /*
864 * If the machine has a setup function in src/machines/machine_*.c
865 * then use that one, otherwise use the old hardcoded stuff here:
866 */
867
868 me = first_machine_entry;
869 while (me != NULL) {
870 if (machine->machine_type == me->machine_type &&
871 me->setup != NULL) {
872 me->setup(machine, cpu);
873 break;
874 }
875 me = me->next;
876 }
877
878 if (me == NULL) {
879 fatal("Unknown emulation type %i\n", machine->machine_type);
880 exit(1);
881 }
882
883 if (machine->machine_name != NULL)
884 debug("machine: %s", machine->machine_name);
885
886 if (machine->emulated_hz > 0)
887 debug(" (%.2f MHz)", (float)machine->emulated_hz / 1000000);
888 debug("\n");
889
890 if (machine->bootstr != NULL) {
891 debug("bootstring%s: %s", (machine->bootarg!=NULL &&
892 strlen(machine->bootarg) >= 1)? "(+bootarg)" : "",
893 machine->bootstr);
894 if (machine->bootarg != NULL && strlen(machine->bootarg) >= 1)
895 debug(" %s", machine->bootarg);
896 debug("\n");
897 }
898
899 if (!machine->stable)
900 fatal("!\n! NOTE: This machine type is not implemented well"
901 " enough yet to run\n! any real-world code!"
902 " (At least, it hasn't been verified to do so.)\n!\n"
903 "! Please read the GXemul documentation for information"
904 " about which\n! machine types that actually work.\n!\n");
905 }
906
907
908 /*
909 * machine_memsize_fix():
910 *
911 * Sets physical_ram_in_mb (if not already set), and memory_offset_in_mb,
912 * depending on machine type.
913 */
914 void machine_memsize_fix(struct machine *m)
915 {
916 if (m == NULL) {
917 fatal("machine_defaultmemsize(): m == NULL?\n");
918 exit(1);
919 }
920
921 if (m->physical_ram_in_mb == 0) {
922 struct machine_entry *me = first_machine_entry;
923 while (me != NULL) {
924 if (m->machine_type == me->machine_type &&
925 me->set_default_ram != NULL) {
926 me->set_default_ram(m);
927 break;
928 }
929 me = me->next;
930 }
931 }
932
933 /* Special hack for hpcmips machines: */
934 if (m->machine_type == MACHINE_HPCMIPS) {
935 m->dbe_on_nonexistant_memaccess = 0;
936 }
937
938 /* Special SGI memory offsets: (TODO: move this somewhere else) */
939 if (m->machine_type == MACHINE_SGI) {
940 switch (m->machine_subtype) {
941 case 20:
942 case 22:
943 case 24:
944 case 26:
945 m->memory_offset_in_mb = 128;
946 break;
947 case 28:
948 case 30:
949 m->memory_offset_in_mb = 512;
950 break;
951 }
952 }
953
954 if (m->physical_ram_in_mb == 0)
955 m->physical_ram_in_mb = DEFAULT_RAM_IN_MB;
956 }
957
958
959 /*
960 * machine_default_cputype():
961 *
962 * Sets m->cpu_name, if it isn't already set, depending on the machine type.
963 */
964 void machine_default_cputype(struct machine *m)
965 {
966 struct machine_entry *me;
967
968 if (m == NULL) {
969 fatal("machine_default_cputype(): m == NULL?\n");
970 exit(1);
971 }
972
973 /* Already set? Then return. */
974 if (m->cpu_name != NULL)
975 return;
976
977 me = first_machine_entry;
978 while (me != NULL) {
979 if (m->machine_type == me->machine_type &&
980 me->set_default_cpu != NULL) {
981 me->set_default_cpu(m);
982 break;
983 }
984 me = me->next;
985 }
986
987 if (m->cpu_name == NULL) {
988 fprintf(stderr, "machine_default_cputype(): no default"
989 " cpu for machine type %i subtype %i\n",
990 m->machine_type, m->machine_subtype);
991 exit(1);
992 }
993 }
994
995
996 /*****************************************************************************/
997
998
999 /*
1000 * machine_run():
1001 *
1002 * Run one or more instructions on all CPUs in this machine. (Usually,
1003 * around N_SAFE_DYNTRANS_LIMIT instructions will be run by the dyntrans
1004 * system.)
1005 *
1006 * Return value is 1 if any CPU in this machine is still running,
1007 * or 0 if all CPUs are stopped.
1008 */
1009 int machine_run(struct machine *machine)
1010 {
1011 struct cpu **cpus = machine->cpus;
1012 int ncpus = machine->ncpus, cpu0instrs = 0, i, te;
1013
1014 for (i=0; i<ncpus; i++) {
1015 if (cpus[i]->running) {
1016 int instrs_run = cpus[i]->run_instr(cpus[i]);
1017 if (i == 0)
1018 cpu0instrs += instrs_run;
1019 }
1020 }
1021
1022 /*
1023 * Hardware 'ticks': (clocks, interrupt sources...)
1024 *
1025 * Here, cpu0instrs is the number of instructions executed on cpu0.
1026 *
1027 * TODO: This should be redesigned into some "mainbus" stuff instead!
1028 */
1029
1030 machine->ninstrs += cpu0instrs;
1031
1032 for (te=0; te<machine->n_tick_entries; te++) {
1033 machine->ticks_till_next[te] -= cpu0instrs;
1034 if (machine->ticks_till_next[te] <= 0) {
1035 while (machine->ticks_till_next[te] <= 0) {
1036 machine->ticks_till_next[te] +=
1037 machine->ticks_reset_value[te];
1038 }
1039
1040 machine->tick_func[te](cpus[0],
1041 machine->tick_extra[te]);
1042 }
1043 }
1044
1045 /* Is any CPU still alive? */
1046 for (i=0; i<ncpus; i++)
1047 if (cpus[i]->running)
1048 return 1;
1049
1050 return 0;
1051 }
1052
1053
1054 /*****************************************************************************/
1055
1056
1057 /*
1058 * machine_entry_new():
1059 *
1060 * This function creates a new machine_entry struct, and fills it with some
1061 * valid data; it is up to the caller to add additional data that weren't
1062 * passed as arguments to this function, such as alias names and machine
1063 * subtypes.
1064 */
1065 struct machine_entry *machine_entry_new(const char *name, int arch,
1066 int oldstyle_type)
1067 {
1068 struct machine_entry *me;
1069
1070 me = malloc(sizeof(struct machine_entry));
1071 if (me == NULL) {
1072 fprintf(stderr, "machine_entry_new(): out of memory (1)\n");
1073 exit(1);
1074 }
1075
1076 memset(me, 0, sizeof(struct machine_entry));
1077
1078 me->name = name;
1079 me->arch = arch;
1080 me->machine_type = oldstyle_type;
1081 me->n_aliases = 0;
1082 me->aliases = NULL;
1083 me->n_subtypes = 0;
1084 me->setup = NULL;
1085
1086 return me;
1087 }
1088
1089
1090 /*
1091 * machine_entry_add_alias():
1092 *
1093 * This function adds an "alias" to a machine entry.
1094 */
1095 void machine_entry_add_alias(struct machine_entry *me, const char *name)
1096 {
1097 me->n_aliases ++;
1098 me->aliases = realloc(me->aliases, sizeof(char *) * me->n_aliases);
1099 if (me->aliases == NULL) {
1100 fprintf(stderr, "out of memory\n");
1101 exit(1);
1102 }
1103
1104 me->aliases[me->n_aliases - 1] = (char *) name;
1105 }
1106
1107
1108 /*
1109 * machine_entry_add_subtype():
1110 *
1111 * This function adds a subtype to a machine entry. The argument list after
1112 * oldstyle_subtype is a list of one or more char *, followed by NULL. E.g.:
1113 *
1114 * machine_entry_add_subtype(me, "Machine X", MACHINE_X,
1115 * "machine-x", "x", NULL);
1116 */
1117 void machine_entry_add_subtype(struct machine_entry *me, const char *name,
1118 int oldstyle_subtype, ...)
1119 {
1120 va_list argp;
1121 struct machine_entry_subtype *mes;
1122
1123 /* Allocate a new subtype struct: */
1124 mes = malloc(sizeof(struct machine_entry_subtype));
1125 if (mes == NULL) {
1126 fprintf(stderr, "machine_entry_subtype_new(): out "
1127 "of memory (1)\n");
1128 exit(1);
1129 }
1130
1131 /* Add the subtype to the machine entry: */
1132 me->n_subtypes ++;
1133 me->subtype = realloc(me->subtype, sizeof(struct
1134 machine_entry_subtype *) * me->n_subtypes);
1135 if (me->subtype == NULL) {
1136 fprintf(stderr, "out of memory\n");
1137 exit(1);
1138 }
1139 me->subtype[me->n_subtypes - 1] = mes;
1140
1141 /* Fill the struct with subtype data: */
1142 memset(mes, 0, sizeof(struct machine_entry_subtype));
1143 mes->name = name;
1144 mes->machine_subtype = oldstyle_subtype;
1145
1146 /* ... and all aliases: */
1147 mes->n_aliases = 0;
1148 mes->aliases = NULL;
1149
1150 va_start(argp, oldstyle_subtype);
1151
1152 for (;;) {
1153 char *s = va_arg(argp, char *);
1154 if (s == NULL)
1155 break;
1156
1157 mes->n_aliases ++;
1158 mes->aliases = realloc(mes->aliases, sizeof(char *) *
1159 mes->n_aliases);
1160 if (mes->aliases == NULL) {
1161 fprintf(stderr, "out of memory\n");
1162 exit(1);
1163 }
1164
1165 mes->aliases[mes->n_aliases - 1] = s;
1166 }
1167
1168 va_end(argp);
1169 }
1170
1171
1172 /*
1173 * machine_entry_register():
1174 *
1175 * Inserts a new machine_entry into the machine entries list.
1176 */
1177 void machine_entry_register(struct machine_entry *me, int arch)
1178 {
1179 struct machine_entry *prev, *next;
1180
1181 /* Only insert it if the architecture is implemented in this
1182 emulator configuration: */
1183 if (cpu_family_ptr_by_number(arch) == NULL)
1184 return;
1185
1186 prev = NULL;
1187 next = first_machine_entry;
1188
1189 for (;;) {
1190 if (next == NULL)
1191 break;
1192 if (strcasecmp(me->name, next->name) < 0)
1193 break;
1194
1195 prev = next;
1196 next = next->next;
1197 }
1198
1199 if (prev != NULL)
1200 prev->next = me;
1201 else
1202 first_machine_entry = me;
1203 me->next = next;
1204 }
1205
1206
1207 /*
1208 * machine_list_available_types_and_cpus():
1209 *
1210 * List all available machine types (for example when running the emulator
1211 * with just -H as command line argument).
1212 */
1213 void machine_list_available_types_and_cpus(void)
1214 {
1215 struct machine_entry *me;
1216 int iadd = DEBUG_INDENTATION * 2;
1217
1218 debug("Available CPU types:\n\n");
1219
1220 debug_indentation(iadd);
1221 cpu_list_available_types();
1222 debug_indentation(-iadd);
1223
1224 debug("\nMost of the CPU types are bogus, and not really implemented."
1225 " The main effect of\nselecting a specific CPU type is to choose "
1226 "what kind of 'id' it will have.\n\nAvailable machine types (with "
1227 "aliases) and their subtypes:\n\n");
1228
1229 debug_indentation(iadd);
1230 me = first_machine_entry;
1231
1232 if (me == NULL)
1233 fatal("No machines defined!\n");
1234
1235 while (me != NULL) {
1236 int i, j, iadd = DEBUG_INDENTATION;
1237
1238 debug("%s [%s] (", me->name,
1239 cpu_family_ptr_by_number(me->arch)->name);
1240 for (i=0; i<me->n_aliases; i++)
1241 debug("%s\"%s\"", i? ", " : "", me->aliases[i]);
1242 debug(")\n");
1243
1244 debug_indentation(iadd);
1245 for (i=0; i<me->n_subtypes; i++) {
1246 struct machine_entry_subtype *mes;
1247 mes = me->subtype[i];
1248 debug("- %s", mes->name);
1249 debug(" (");
1250 for (j=0; j<mes->n_aliases; j++)
1251 debug("%s\"%s\"", j? ", " : "",
1252 mes->aliases[j]);
1253 debug(")\n");
1254 }
1255 debug_indentation(-iadd);
1256
1257 me = me->next;
1258 }
1259 debug_indentation(-iadd);
1260
1261 debug("\nMost of the machine types are bogus too. Please read the "
1262 "GXemul documentation\nfor information about which machine types "
1263 "that actually work. Use the alias\nwhen selecting a machine type "
1264 "or subtype, not the real name.\n");
1265
1266 #ifdef UNSTABLE_DEVEL
1267 debug("\n");
1268
1269 useremul_list_emuls();
1270 debug("Userland emulation works for programs with the complexity"
1271 " of Hello World,\nbut not much more.\n");
1272 #endif
1273 }
1274
1275
1276 /*
1277 * machine_init():
1278 *
1279 * This function should be called before any other machine_*() function
1280 * is used. automachine_init() registers all machines in src/machines/.
1281 */
1282 void machine_init(void)
1283 {
1284 if (first_machine_entry != NULL) {
1285 fatal("machine_init(): already called?\n");
1286 exit(1);
1287 }
1288
1289 automachine_init();
1290 }
1291

  ViewVC Help
Powered by ViewVC 1.1.26