/[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

Annotation of /trunk/src/machines/machine.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 44 - (hide annotations)
Mon Oct 8 16:22:56 2007 UTC (16 years, 7 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 dpavlin 44 /*
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