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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 43 - (show annotations)
Mon Oct 8 16:22:43 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 22544 byte(s)
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