/[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 42 - (show annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 22544 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


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.704 2007/06/15 17:02:38 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 "cpu.h"
39 #include "device.h"
40 #include "diskimage.h"
41 #include "emul.h"
42 #include "machine.h"
43 #include "memory.h"
44 #include "misc.h"
45 #include "settings.h"
46 #include "symbol.h"
47 #include "useremul.h"
48
49
50 /* See main.c: */
51 extern int quiet_mode;
52 extern int verbose;
53
54
55 /* This is initialized by machine_init(): */
56 struct machine_entry *first_machine_entry = NULL;
57
58
59 /*
60 * machine_new():
61 *
62 * Returns a reasonably initialized struct machine.
63 */
64 struct machine *machine_new(char *name, struct emul *emul, int id)
65 {
66 struct machine *m;
67
68 CHECK_ALLOCATION(m = malloc(sizeof(struct machine)));
69 memset(m, 0, sizeof(struct machine));
70
71 /* Pointer back to the emul object that this machine belongs to: */
72 m->emul = emul;
73
74 CHECK_ALLOCATION(m->name = strdup(name));
75
76 /* Full path, e.g. "emul[0].machine[0]": */
77 CHECK_ALLOCATION(m->path = malloc(strlen(emul->path) + 20));
78 snprintf(m->path, strlen(emul->path) + 20, "%s.machine[%i]",
79 emul->path, id);
80
81 /* Sane default values: */
82 m->serial_nr = 1;
83 m->machine_type = MACHINE_NONE;
84 m->machine_subtype = MACHINE_NONE;
85 m->arch_pagesize = 4096; /* Should be overriden in
86 emul.c for other pagesizes. */
87 m->prom_emulation = 1;
88 m->allow_instruction_combinations = 1;
89 m->byte_order_override = NO_BYTE_ORDER_OVERRIDE;
90 m->boot_kernel_filename = "";
91 m->boot_string_argument = NULL;
92 m->x11_md.scaledown = 1;
93 m->x11_md.scaleup = 1;
94 m->n_gfx_cards = 1;
95 symbol_init(&m->symbol_context);
96
97 /* Settings: */
98 m->settings = settings_new();
99 settings_add(m->settings, "name", 0,
100 SETTINGS_TYPE_STRING, SETTINGS_FORMAT_STRING,
101 (void *) &m->name);
102 settings_add(m->settings, "serial_nr", 0,
103 SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
104 (void *) &m->serial_nr);
105 settings_add(m->settings, "arch_pagesize", 0,
106 SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
107 (void *) &m->arch_pagesize);
108 settings_add(m->settings, "prom_emulation", 0,
109 SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
110 (void *) &m->prom_emulation);
111 settings_add(m->settings, "allow_instruction_combinations", 0,
112 SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
113 (void *) &m->allow_instruction_combinations);
114 settings_add(m->settings, "n_gfx_cards", 0,
115 SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
116 (void *) &m->n_gfx_cards);
117 settings_add(m->settings, "statistics_enabled", 1,
118 SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
119 (void *) &m->statistics_enabled);
120
121 return m;
122 }
123
124
125 /*
126 * machine_destroy():
127 *
128 * Destroys a machine object.
129 */
130 void machine_destroy(struct machine *machine)
131 {
132 int i;
133
134 for (i=0; i<machine->ncpus; i++)
135 cpu_destroy(machine->cpus[i]);
136
137 if (machine->name != NULL)
138 free(machine->name);
139
140 if (machine->path != NULL)
141 free(machine->path);
142
143 /* Remove any remaining level-1 settings: */
144 settings_remove_all(machine->settings);
145 settings_destroy(machine->settings);
146
147 free(machine);
148 }
149
150
151 /*
152 * machine_name_to_type():
153 *
154 * Take a type and a subtype as strings, and convert them into numeric
155 * values used internally throughout the code.
156 *
157 * Return value is 1 on success, 0 if there was no match.
158 * Also, any errors/warnings are printed using fatal()/debug().
159 */
160 int machine_name_to_type(char *stype, char *ssubtype,
161 int *type, int *subtype, int *arch)
162 {
163 struct machine_entry *me;
164 int i, j, k, nmatches = 0;
165
166 *type = MACHINE_NONE;
167 *subtype = 0;
168
169 /* Check stype, and optionally ssubtype: */
170 me = first_machine_entry;
171 while (me != NULL) {
172 for (i=0; i<me->n_aliases; i++)
173 if (strcasecmp(me->aliases[i], stype) == 0) {
174 /* Found a type: */
175 *type = me->machine_type;
176 *arch = me->arch;
177
178 if (me->n_subtypes == 0)
179 return 1;
180
181 /* Check for subtype: */
182 for (j=0; j<me->n_subtypes; j++)
183 for (k=0; k<me->subtype[j]->n_aliases;
184 k++)
185 if (strcasecmp(ssubtype,
186 me->subtype[j]->aliases[k]
187 ) == 0) {
188 *subtype = me->subtype[
189 j]->machine_subtype;
190 return 1;
191 }
192
193 fatal("Unknown subtype '%s' for emulation"
194 " '%s'\n", ssubtype, stype);
195 if (!ssubtype[0])
196 fatal("(Maybe you forgot the -e"
197 " command line option?)\n");
198 exit(1);
199 }
200
201 me = me->next;
202 }
203
204 /* Not found? Then just check ssubtype: */
205 me = first_machine_entry;
206 while (me != NULL) {
207 if (me->n_subtypes == 0) {
208 me = me->next;
209 continue;
210 }
211
212 /* Check for subtype: */
213 for (j=0; j<me->n_subtypes; j++)
214 for (k=0; k<me->subtype[j]->n_aliases; k++)
215 if (strcasecmp(ssubtype, me->subtype[j]->
216 aliases[k]) == 0) {
217 *type = me->machine_type;
218 *arch = me->arch;
219 *subtype = me->subtype[j]->
220 machine_subtype;
221 nmatches ++;
222 }
223
224 me = me->next;
225 }
226
227 switch (nmatches) {
228 case 0: fatal("\nSorry, emulation \"%s\"", stype);
229 if (ssubtype != NULL && ssubtype[0] != '\0')
230 fatal(" (subtype \"%s\")", ssubtype);
231 fatal(" is unknown.\n");
232 break;
233 case 1: return 1;
234 default:fatal("\nSorry, multiple matches for \"%s\"", stype);
235 if (ssubtype != NULL && ssubtype[0] != '\0')
236 fatal(" (subtype \"%s\")", ssubtype);
237 fatal(".\n");
238 }
239
240 *type = MACHINE_NONE;
241 *subtype = 0;
242
243 fatal("Use the -H command line option to get a list of "
244 "available types and subtypes.\n\n");
245
246 return 0;
247 }
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():
274 *
275 * Adds a tick function (a function called every now and then, depending on
276 * clock cycle count) to a machine.
277 *
278 * If tickshift is non-zero, a tick will occur every (1 << tickshift) cycles.
279 * This is used for the normal (fast dyntrans) emulation modes.
280 *
281 * If tickshift is zero, then this is a cycle-accurate tick function.
282 * The hz value is used in this case.
283 */
284 void machine_add_tickfunction(struct machine *machine, void (*func)
285 (struct cpu *, void *), void *extra, int tickshift)
286 {
287 int n = machine->tick_functions.n_entries;
288
289 CHECK_ALLOCATION(machine->tick_functions.ticks_till_next = realloc(
290 machine->tick_functions.ticks_till_next, (n+1) * sizeof(int)));
291 CHECK_ALLOCATION(machine->tick_functions.ticks_reset_value = realloc(
292 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 /*
299 * The dyntrans subsystem wants to run code in relatively
300 * large chunks without checking for external interrupts;
301 * too low tickshifts are not allowed.
302 */
303 if (tickshift < N_SAFE_DYNTRANS_LIMIT_SHIFT) {
304 fatal("ERROR! tickshift = %i, less than "
305 "N_SAFE_DYNTRANS_LIMIT_SHIFT (%i)\n",
306 tickshift, N_SAFE_DYNTRANS_LIMIT_SHIFT);
307 exit(1);
308 }
309
310 machine->tick_functions.ticks_till_next[n] = 0;
311 machine->tick_functions.ticks_reset_value[n] = 1 << tickshift;
312 machine->tick_functions.f[n] = func;
313 machine->tick_functions.extra[n] = extra;
314
315 machine->tick_functions.n_entries = n + 1;
316 }
317
318
319 /*
320 * machine_statistics_init():
321 *
322 * Initialize the parts of a machine struct that deal with instruction
323 * statistics gathering.
324 *
325 * Note: The fname argument contains "flags:filename".
326 */
327 void machine_statistics_init(struct machine *machine, char *fname)
328 {
329 int n_fields = 0;
330 char *pcolon = fname;
331 char *mode = "a"; /* Append by default */
332
333 machine->allow_instruction_combinations = 0;
334
335 if (machine->statistics_fields != NULL) {
336 fprintf(stderr, "Only one -s option is allowed.\n");
337 exit(1);
338 }
339
340 machine->statistics_enabled = 1;
341 CHECK_ALLOCATION(machine->statistics_fields = malloc(1));
342 machine->statistics_fields[0] = '\0';
343
344 while (*pcolon && *pcolon != ':')
345 pcolon ++;
346
347 if (*pcolon != ':') {
348 fprintf(stderr, "The syntax for the -s option is: "
349 "-s flags:filename\nYou omitted the flags. Run g"
350 "xemul -h for a list of available flags.\n");
351 exit(1);
352 }
353
354 while (*fname != ':') {
355 switch (*fname) {
356
357 /* Type flags: */
358 case 'v':
359 case 'i':
360 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;
365 machine->statistics_fields[n_fields] = '\0';
366 break;
367
368 /* Optional flags: */
369 case 'o':
370 mode = "w";
371 break;
372 case 'd':
373 machine->statistics_enabled = 0;
374 break;
375
376 default:fprintf(stderr, "Unknown flag '%c' used with the"
377 " -s option. Aborting.\n", *fname);
378 exit(1);
379 }
380 fname ++;
381 }
382
383 fname ++; /* point to the filename after the colon */
384
385 CHECK_ALLOCATION(machine->statistics_filename = strdup(fname));
386 machine->statistics_file = fopen(machine->statistics_filename, mode);
387 }
388
389
390 /*
391 * machine_dumpinfo():
392 *
393 * Dumps info about a machine in some kind of readable format. (Used by
394 * the 'machine' debugger command.)
395 */
396 void machine_dumpinfo(struct machine *m)
397 {
398 int i;
399
400 debug("serial nr: %i", m->serial_nr);
401 if (m->nr_of_nics > 0)
402 debug(" (nr of NICs: %i)", m->nr_of_nics);
403 debug("\n");
404
405 debug("memory: %i MB", m->physical_ram_in_mb);
406 if (m->memory_offset_in_mb != 0)
407 debug(" (offset by %i MB)", m->memory_offset_in_mb);
408 if (m->random_mem_contents)
409 debug(", randomized contents");
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->x11_md.in_use) {
425 debug("Using X11");
426 if (m->x11_md.scaledown > 1)
427 debug(", scaledown %i", m->x11_md.scaledown);
428 if (m->x11_md.scaleup > 1)
429 debug(", scaleup %i", m->x11_md.scaleup);
430 if (m->x11_md.n_display_names > 0) {
431 for (i=0; i<m->x11_md.n_display_names; i++) {
432 debug(i? ", " : " (");
433 debug("\"%s\"", m->x11_md.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 * machine_setup():
449 *
450 * This (rather large) function initializes memory, registers, and/or devices
451 * required by specific machine emulations.
452 */
453 void machine_setup(struct machine *machine)
454 {
455 struct memory *mem;
456 struct machine_entry *me;
457
458 /* Abreviation: :-) */
459 struct cpu *cpu = machine->cpus[machine->bootstrap_cpu];
460
461 machine->bootdev_id = diskimage_bootdev(machine,
462 &machine->bootdev_type);
463
464 mem = cpu->mem;
465 machine->machine_name = NULL;
466
467 /* TODO: Move this somewhere else? */
468 if (machine->boot_string_argument == NULL) {
469 switch (machine->machine_type) {
470 case MACHINE_ARC:
471 machine->boot_string_argument = "-aN";
472 break;
473 case MACHINE_CATS:
474 machine->boot_string_argument = "-A";
475 break;
476 case MACHINE_PMAX:
477 machine->boot_string_argument = "-a";
478 break;
479 default:
480 /* Important, because boot_string_argument should
481 not be set to NULL: */
482 machine->boot_string_argument = "";
483 }
484 }
485
486
487 /*
488 * If the machine has a setup function in src/machines/machine_*.c
489 * then use that one, otherwise use the old hardcoded stuff here:
490 */
491
492 me = first_machine_entry;
493 while (me != NULL) {
494 if (machine->machine_type == me->machine_type &&
495 me->setup != NULL) {
496 me->setup(machine, cpu);
497 break;
498 }
499 me = me->next;
500 }
501
502 if (me == NULL) {
503 fatal("Unknown emulation type %i\n", machine->machine_type);
504 exit(1);
505 }
506
507 if (machine->machine_name != NULL)
508 debug("machine: %s", machine->machine_name);
509
510 if (machine->emulated_hz > 0)
511 debug(" (%.2f MHz)", (float)machine->emulated_hz / 1000000);
512 debug("\n");
513
514 if (machine->bootstr != NULL) {
515 debug("bootstring%s: %s", (machine->bootarg!=NULL &&
516 strlen(machine->bootarg) >= 1)? "(+bootarg)" : "",
517 machine->bootstr);
518 if (machine->bootarg != NULL && strlen(machine->bootarg) >= 1)
519 debug(" %s", machine->bootarg);
520 debug("\n");
521 }
522 }
523
524
525 /*
526 * machine_memsize_fix():
527 *
528 * Sets physical_ram_in_mb (if not already set), and memory_offset_in_mb,
529 * depending on machine type.
530 */
531 void machine_memsize_fix(struct machine *m)
532 {
533 if (m == NULL) {
534 fatal("machine_defaultmemsize(): m == NULL?\n");
535 exit(1);
536 }
537
538 if (m->physical_ram_in_mb == 0) {
539 struct machine_entry *me = first_machine_entry;
540 while (me != NULL) {
541 if (m->machine_type == me->machine_type &&
542 me->set_default_ram != NULL) {
543 me->set_default_ram(m);
544 break;
545 }
546 me = me->next;
547 }
548 }
549
550 /* Special SGI memory offsets: (TODO: move this somewhere else) */
551 if (m->machine_type == MACHINE_SGI) {
552 switch (m->machine_subtype) {
553 case 20:
554 case 22:
555 case 24:
556 case 26:
557 m->memory_offset_in_mb = 128;
558 break;
559 case 28:
560 case 30:
561 m->memory_offset_in_mb = 512;
562 break;
563 }
564 }
565
566 if (m->physical_ram_in_mb == 0)
567 m->physical_ram_in_mb = DEFAULT_RAM_IN_MB;
568 }
569
570
571 /*
572 * machine_default_cputype():
573 *
574 * Sets m->cpu_name, if it isn't already set, depending on the machine type.
575 */
576 void machine_default_cputype(struct machine *m)
577 {
578 struct machine_entry *me;
579
580 if (m == NULL) {
581 fatal("machine_default_cputype(): m == NULL?\n");
582 exit(1);
583 }
584
585 /* Already set? Then return. */
586 if (m->cpu_name != NULL)
587 return;
588
589 me = first_machine_entry;
590 while (me != NULL) {
591 if (m->machine_type == me->machine_type &&
592 me->set_default_cpu != NULL) {
593 me->set_default_cpu(m);
594 break;
595 }
596 me = me->next;
597 }
598
599 if (m->cpu_name == NULL) {
600 fprintf(stderr, "machine_default_cputype(): no default"
601 " cpu for machine type %i subtype %i\n",
602 m->machine_type, m->machine_subtype);
603 exit(1);
604 }
605 }
606
607
608 /*****************************************************************************/
609
610
611 /*
612 * machine_run():
613 *
614 * Run one or more instructions on all CPUs in this machine. (Usually,
615 * around N_SAFE_DYNTRANS_LIMIT instructions will be run by the dyntrans
616 * system.)
617 *
618 * Return value is 1 if any CPU in this machine is still running,
619 * or 0 if all CPUs are stopped.
620 */
621 int machine_run(struct machine *machine)
622 {
623 struct cpu **cpus = machine->cpus;
624 int ncpus = machine->ncpus, cpu0instrs = 0, i, te;
625
626 for (i=0; i<ncpus; i++) {
627 if (cpus[i]->running) {
628 int instrs_run = cpus[i]->run_instr(cpus[i]);
629 if (i == 0)
630 cpu0instrs += instrs_run;
631 }
632 }
633
634 /*
635 * Hardware 'ticks': (clocks, interrupt sources...)
636 *
637 * Here, cpu0instrs is the number of instructions executed on cpu0.
638 *
639 * TODO: This should be redesigned into some "mainbus" stuff instead!
640 */
641
642 for (te=0; te<machine->tick_functions.n_entries; te++) {
643 machine->tick_functions.ticks_till_next[te] -= cpu0instrs;
644 if (machine->tick_functions.ticks_till_next[te] <= 0) {
645 while (machine->tick_functions.ticks_till_next[te]<=0) {
646 machine->tick_functions.ticks_till_next[te] +=
647 machine->tick_functions.
648 ticks_reset_value[te];
649 }
650
651 machine->tick_functions.f[te](cpus[0],
652 machine->tick_functions.extra[te]);
653 }
654 }
655
656 /* Is any CPU still alive? */
657 for (i=0; i<ncpus; i++)
658 if (cpus[i]->running)
659 return 1;
660
661 return 0;
662 }
663
664
665 /*****************************************************************************/
666
667
668 /*
669 * machine_entry_new():
670 *
671 * This function creates a new machine_entry struct, and fills it with some
672 * valid data; it is up to the caller to add additional data that weren't
673 * passed as arguments to this function, such as alias names and machine
674 * subtypes.
675 */
676 struct machine_entry *machine_entry_new(const char *name, int arch,
677 int oldstyle_type)
678 {
679 struct machine_entry *me;
680
681 CHECK_ALLOCATION(me = malloc(sizeof(struct machine_entry)));
682 memset(me, 0, sizeof(struct machine_entry));
683
684 me->name = name;
685 me->arch = arch;
686 me->machine_type = oldstyle_type;
687 me->n_aliases = 0;
688 me->aliases = NULL;
689 me->n_subtypes = 0;
690 me->setup = NULL;
691
692 return me;
693 }
694
695
696 /*
697 * machine_entry_add_alias():
698 *
699 * This function adds an "alias" to a machine entry.
700 */
701 void machine_entry_add_alias(struct machine_entry *me, const char *name)
702 {
703 me->n_aliases ++;
704
705 CHECK_ALLOCATION(me->aliases = realloc(me->aliases,
706 sizeof(char *) * me->n_aliases));
707
708 me->aliases[me->n_aliases - 1] = (char *) name;
709 }
710
711
712 /*
713 * machine_entry_add_subtype():
714 *
715 * This function adds a subtype to a machine entry. The argument list after
716 * oldstyle_subtype is a list of one or more char *, followed by NULL. E.g.:
717 *
718 * machine_entry_add_subtype(me, "Machine X", MACHINE_X,
719 * "machine-x", "x", NULL);
720 */
721 void machine_entry_add_subtype(struct machine_entry *me, const char *name,
722 int oldstyle_subtype, ...)
723 {
724 va_list argp;
725 struct machine_entry_subtype *mes;
726
727 /* Allocate a new subtype struct: */
728 CHECK_ALLOCATION(mes = malloc(sizeof(struct machine_entry_subtype)));
729
730 /* Add the subtype to the machine entry: */
731 me->n_subtypes ++;
732 CHECK_ALLOCATION(me->subtype = realloc(me->subtype, sizeof(struct
733 machine_entry_subtype *) * me->n_subtypes));
734 me->subtype[me->n_subtypes - 1] = mes;
735
736 /* Fill the struct with subtype data: */
737 memset(mes, 0, sizeof(struct machine_entry_subtype));
738 mes->name = name;
739 mes->machine_subtype = oldstyle_subtype;
740
741 /* ... and all aliases: */
742 mes->n_aliases = 0;
743 mes->aliases = NULL;
744
745 va_start(argp, oldstyle_subtype);
746
747 for (;;) {
748 char *s = va_arg(argp, char *);
749 if (s == NULL)
750 break;
751
752 mes->n_aliases ++;
753 CHECK_ALLOCATION(mes->aliases =
754 realloc(mes->aliases, sizeof(char *) * mes->n_aliases));
755
756 mes->aliases[mes->n_aliases - 1] = s;
757 }
758
759 va_end(argp);
760 }
761
762
763 /*
764 * machine_entry_register():
765 *
766 * Inserts a new machine_entry into the machine entries list.
767 */
768 void machine_entry_register(struct machine_entry *me, int arch)
769 {
770 struct machine_entry *prev, *next;
771
772 /* Only insert it if the architecture is implemented in this
773 emulator configuration: */
774 if (cpu_family_ptr_by_number(arch) == NULL)
775 return;
776
777 prev = NULL;
778 next = first_machine_entry;
779
780 for (;;) {
781 if (next == NULL)
782 break;
783 if (strcasecmp(me->name, next->name) < 0)
784 break;
785
786 prev = next;
787 next = next->next;
788 }
789
790 if (prev != NULL)
791 prev->next = me;
792 else
793 first_machine_entry = me;
794 me->next = next;
795 }
796
797
798 /*
799 * machine_list_available_types_and_cpus():
800 *
801 * List all available machine types (for example when running the emulator
802 * with just -H as command line argument).
803 */
804 void machine_list_available_types_and_cpus(void)
805 {
806 struct machine_entry *me;
807 int iadd = DEBUG_INDENTATION * 2;
808
809 debug("Available CPU types:\n\n");
810
811 debug_indentation(iadd);
812 cpu_list_available_types();
813 debug_indentation(-iadd);
814
815 debug("\nMost of the CPU types are bogus, and not really implemented."
816 " The main effect of\nselecting a specific CPU type is to choose "
817 "what kind of 'id' it will have.\n\nAvailable machine types (with "
818 "aliases) and their subtypes:\n\n");
819
820 debug_indentation(iadd);
821 me = first_machine_entry;
822
823 if (me == NULL)
824 fatal("No machines defined!\n");
825
826 while (me != NULL) {
827 int i, j, iadd = DEBUG_INDENTATION;
828
829 debug("%s [%s] (", me->name,
830 cpu_family_ptr_by_number(me->arch)->name);
831 for (i=0; i<me->n_aliases; i++)
832 debug("%s\"%s\"", i? ", " : "", me->aliases[i]);
833 debug(")\n");
834
835 debug_indentation(iadd);
836 for (i=0; i<me->n_subtypes; i++) {
837 struct machine_entry_subtype *mes;
838 mes = me->subtype[i];
839 debug("- %s", mes->name);
840 debug(" (");
841 for (j=0; j<mes->n_aliases; j++)
842 debug("%s\"%s\"", j? ", " : "",
843 mes->aliases[j]);
844 debug(")\n");
845 }
846 debug_indentation(-iadd);
847
848 me = me->next;
849 }
850 debug_indentation(-iadd);
851
852 debug("\nMost of the machine types are bogus too. Please read the "
853 "GXemul documentation\nfor information about which machine types "
854 "that actually work. Use the alias\nwhen selecting a machine type "
855 "or subtype, not the real name.\n");
856
857 debug("\n");
858
859 useremul_list_emuls();
860 debug("Userland emulation works for programs with the complexity"
861 " of Hello World,\nbut not much more.\n");
862 }
863
864
865 /*
866 * machine_init():
867 *
868 * This function should be called before any other machine_*() function
869 * is used. automachine_init() registers all machines in src/machines/.
870 */
871 void machine_init(void)
872 {
873 if (first_machine_entry != NULL) {
874 fatal("machine_init(): already called?\n");
875 exit(1);
876 }
877
878 automachine_init();
879 }
880

  ViewVC Help
Powered by ViewVC 1.1.26