/[gxemul]/trunk/src/machines/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/machines/machine.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 44 - (show annotations)
Mon Oct 8 16:22:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 22371 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1632 2007/09/11 21:46:35 debug Exp $
20070616	Implementing the MIPS32/64 revision 2 "ror" instruction.
20070617	Adding a struct for each physpage which keeps track of which
		ranges within that page (base offset, length) that are
		continuously translatable. When running with native code
		generation enabled (-b), a range is added after each read-
		ahead loop.
		Experimenting with using the physical program counter sample
		data (implemented 20070608) together with the "translatable
		range" information, to figure out which physical address ranges
		would be worth translating to native code (if the number of
		samples falling within a range is above a certain threshold).
20070618	Adding automagic building of .index comment files for
		src/file/, src/promemul/, src src/useremul/ as well.
		Adding a "has been translated" bit to the ranges, so that only
		not-yet-translated ranges will be sampled.
20070619	Moving src/cpu.c and src/memory_rw.c into src/cpus/,
		src/device.c into src/devices/, and src/machine.c into
		src/machines/.
		Creating a skeleton cc/ld native backend module; beginning on
		the function which will detect cc command line, etc.
20070620	Continuing on the native code generation infrastructure.
20070621	Moving src/x11.c and src/console.c into a new src/console/
		subdir (for everything that is console or framebuffer related).
		Moving src/symbol*.c into a new src/symbol/, which should
		contain anything that is symbol handling related.
20070624	Making the program counter sampling threshold a "settings
		variable" (sampling_threshold), i.e. it can now be changed
		during runtime.
		Switching the RELEASE notes format from plain text to HTML.
		If the TMPDIR environment variable is set, it is used instead
		of "/tmp" for temporary files.
		Continuing on the cc/ld backend: simple .c code is generated,
		the compiler and linker are called, etc.
		Adding detection of host architecture to the configure script
		(again), and adding icache invalidation support (only
		implemented for Alpha hosts so far).
20070625	Simplifying the program counter sampling mechanism.
20070626	Removing the cc/ld native code generation stuff, program
		counter sampling, etc; it would not have worked well in the
		general case.
20070627	Removing everything related to native code generation.
20070629	Removing the (practically unusable) support for multiple
		emulations. (The single emulation allowed now still supports
		multiple simultaneous machines, as before.)
		Beginning on PCCTWO and M88K interrupts.
20070723	Adding a dummy skeleton for emulation of M32R processors.
20070901	Fixing a warning found by "gcc version 4.3.0 20070817
		(experimental)" on amd64.
20070905	Removing some more traces of the old "multiple emulations"
		code.
		Also looking in /usr/local/include and /usr/local/lib for
		X11 libs, when running configure.
20070909	Minor updates to the guest OS install instructions, in
		preparation for the NetBSD 4.0 release.
20070918	More testing of NetBSD 4.0 RC1.

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

  ViewVC Help
Powered by ViewVC 1.1.26