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

Annotation of /upstream/0.4.6/src/machine.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 43 - (hide annotations)
Mon Oct 8 16:22:43 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 22544 byte(s)
0.4.6
1 dpavlin 2 /*
2 dpavlin 34 * Copyright (C) 2003-2007 Anders Gavare. All rights reserved.
3 dpavlin 2 *
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 dpavlin 42 * $Id: machine.c,v 1.704 2007/06/15 17:02:38 debug Exp $
29 dpavlin 2 */
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 dpavlin 32 #include "settings.h"
46 dpavlin 2 #include "symbol.h"
47 dpavlin 42 #include "useremul.h"
48 dpavlin 2
49 dpavlin 12
50 dpavlin 6 /* See main.c: */
51     extern int quiet_mode;
52 dpavlin 22 extern int verbose;
53 dpavlin 6
54    
55 dpavlin 2 /* This is initialized by machine_init(): */
56 dpavlin 22 struct machine_entry *first_machine_entry = NULL;
57 dpavlin 2
58    
59     /*
60     * machine_new():
61     *
62     * Returns a reasonably initialized struct machine.
63     */
64 dpavlin 34 struct machine *machine_new(char *name, struct emul *emul, int id)
65 dpavlin 2 {
66     struct machine *m;
67    
68 dpavlin 42 CHECK_ALLOCATION(m = malloc(sizeof(struct machine)));
69 dpavlin 2 memset(m, 0, sizeof(struct machine));
70    
71 dpavlin 32 /* Pointer back to the emul object that this machine belongs to: */
72 dpavlin 2 m->emul = emul;
73    
74 dpavlin 42 CHECK_ALLOCATION(m->name = strdup(name));
75 dpavlin 2
76 dpavlin 34 /* Full path, e.g. "emul[0].machine[0]": */
77 dpavlin 42 CHECK_ALLOCATION(m->path = malloc(strlen(emul->path) + 20));
78 dpavlin 34 snprintf(m->path, strlen(emul->path) + 20, "%s.machine[%i]",
79     emul->path, id);
80    
81 dpavlin 2 /* Sane default values: */
82 dpavlin 10 m->serial_nr = 1;
83 dpavlin 2 m->machine_type = MACHINE_NONE;
84     m->machine_subtype = MACHINE_NONE;
85 dpavlin 12 m->arch_pagesize = 4096; /* Should be overriden in
86     emul.c for other pagesizes. */
87 dpavlin 2 m->prom_emulation = 1;
88 dpavlin 28 m->allow_instruction_combinations = 1;
89 dpavlin 2 m->byte_order_override = NO_BYTE_ORDER_OVERRIDE;
90     m->boot_kernel_filename = "";
91     m->boot_string_argument = NULL;
92 dpavlin 42 m->x11_md.scaledown = 1;
93     m->x11_md.scaleup = 1;
94 dpavlin 2 m->n_gfx_cards = 1;
95     symbol_init(&m->symbol_context);
96    
97 dpavlin 32 /* 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 dpavlin 2 return m;
122     }
123    
124    
125     /*
126 dpavlin 32 * 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 dpavlin 34 if (machine->path != NULL)
141     free(machine->path);
142    
143 dpavlin 32 /* 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 dpavlin 2 * 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 dpavlin 12 int i, j, k, nmatches = 0;
165 dpavlin 2
166     *type = MACHINE_NONE;
167     *subtype = 0;
168    
169 dpavlin 12 /* Check stype, and optionally ssubtype: */
170 dpavlin 2 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 dpavlin 6 fatal("Unknown subtype '%s' for emulation"
194 dpavlin 2 " '%s'\n", ssubtype, stype);
195 dpavlin 6 if (!ssubtype[0])
196     fatal("(Maybe you forgot the -e"
197     " command line option?)\n");
198 dpavlin 2 exit(1);
199     }
200    
201     me = me->next;
202     }
203    
204 dpavlin 12 /* 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 dpavlin 2 return 0;
247     }
248    
249    
250     /*
251 dpavlin 42 * 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 dpavlin 2 * 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 dpavlin 24 *
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 dpavlin 2 */
284     void machine_add_tickfunction(struct machine *machine, void (*func)
285 dpavlin 42 (struct cpu *, void *), void *extra, int tickshift)
286 dpavlin 2 {
287 dpavlin 42 int n = machine->tick_functions.n_entries;
288 dpavlin 2
289 dpavlin 42 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 dpavlin 2 exit(1);
308     }
309    
310 dpavlin 42 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 dpavlin 2
315 dpavlin 42 machine->tick_functions.n_entries = n + 1;
316 dpavlin 2 }
317    
318    
319 dpavlin 22 /*
320 dpavlin 28 * 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 dpavlin 42 CHECK_ALLOCATION(machine->statistics_fields = malloc(1));
342     machine->statistics_fields[0] = '\0';
343 dpavlin 28
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 dpavlin 42 CHECK_ALLOCATION(machine->statistics_fields = realloc(
362     machine->statistics_fields, strlen(
363     machine->statistics_fields) + 2));
364 dpavlin 28 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 dpavlin 42 CHECK_ALLOCATION(machine->statistics_filename = strdup(fname));
386 dpavlin 28 machine->statistics_file = fopen(machine->statistics_filename, mode);
387     }
388    
389    
390     /*
391 dpavlin 22 * 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 dpavlin 42 if (m->x11_md.in_use) {
425 dpavlin 22 debug("Using X11");
426 dpavlin 42 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 dpavlin 22 debug(i? ", " : " (");
433 dpavlin 42 debug("\"%s\"", m->x11_md.display_names[i]);
434 dpavlin 22 }
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 dpavlin 2 * 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 dpavlin 22 struct machine_entry *me;
457 dpavlin 2
458     /* Abreviation: :-) */
459     struct cpu *cpu = machine->cpus[machine->bootstrap_cpu];
460    
461 dpavlin 22 machine->bootdev_id = diskimage_bootdev(machine,
462     &machine->bootdev_type);
463 dpavlin 2
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 dpavlin 16 case MACHINE_CATS:
474     machine->boot_string_argument = "-A";
475     break;
476 dpavlin 22 case MACHINE_PMAX:
477 dpavlin 2 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 dpavlin 22 /*
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 dpavlin 2
492 dpavlin 22 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 dpavlin 2 break;
498     }
499 dpavlin 22 me = me->next;
500     }
501 dpavlin 2
502 dpavlin 22 if (me == NULL) {
503 dpavlin 2 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 dpavlin 22 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 dpavlin 2 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 dpavlin 22 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 dpavlin 2 break;
545     }
546 dpavlin 22 me = me->next;
547 dpavlin 2 }
548     }
549    
550 dpavlin 22 /* Special SGI memory offsets: (TODO: move this somewhere else) */
551 dpavlin 2 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 dpavlin 22 * Sets m->cpu_name, if it isn't already set, depending on the machine type.
575 dpavlin 2 */
576     void machine_default_cputype(struct machine *m)
577     {
578 dpavlin 22 struct machine_entry *me;
579    
580 dpavlin 2 if (m == NULL) {
581     fatal("machine_default_cputype(): m == NULL?\n");
582     exit(1);
583     }
584    
585 dpavlin 22 /* Already set? Then return. */
586 dpavlin 2 if (m->cpu_name != NULL)
587     return;
588    
589 dpavlin 22 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 dpavlin 2 break;
595     }
596 dpavlin 22 me = me->next;
597 dpavlin 2 }
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 dpavlin 26 /*****************************************************************************/
609    
610    
611 dpavlin 2 /*
612 dpavlin 26 * 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 dpavlin 28 int instrs_run = cpus[i]->run_instr(cpus[i]);
629 dpavlin 26 if (i == 0)
630     cpu0instrs += instrs_run;
631     }
632     }
633    
634     /*
635     * Hardware 'ticks': (clocks, interrupt sources...)
636     *
637 dpavlin 28 * Here, cpu0instrs is the number of instructions executed on cpu0.
638     *
639     * TODO: This should be redesigned into some "mainbus" stuff instead!
640 dpavlin 26 */
641    
642 dpavlin 42 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 dpavlin 26 }
650    
651 dpavlin 42 machine->tick_functions.f[te](cpus[0],
652     machine->tick_functions.extra[te]);
653 dpavlin 26 }
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 dpavlin 2 * 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 dpavlin 26 * passed as arguments to this function, such as alias names and machine
674     * subtypes.
675 dpavlin 2 */
676 dpavlin 26 struct machine_entry *machine_entry_new(const char *name, int arch,
677     int oldstyle_type)
678 dpavlin 2 {
679     struct machine_entry *me;
680    
681 dpavlin 42 CHECK_ALLOCATION(me = malloc(sizeof(struct machine_entry)));
682 dpavlin 2 memset(me, 0, sizeof(struct machine_entry));
683    
684     me->name = name;
685     me->arch = arch;
686     me->machine_type = oldstyle_type;
687 dpavlin 26 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 dpavlin 2
705 dpavlin 42 CHECK_ALLOCATION(me->aliases = realloc(me->aliases,
706     sizeof(char *) * me->n_aliases));
707    
708 dpavlin 26 me->aliases[me->n_aliases - 1] = (char *) name;
709 dpavlin 2 }
710    
711    
712     /*
713 dpavlin 26 * machine_entry_add_subtype():
714 dpavlin 2 *
715 dpavlin 26 * 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 dpavlin 2 *
718 dpavlin 26 * machine_entry_add_subtype(me, "Machine X", MACHINE_X,
719     * "machine-x", "x", NULL);
720 dpavlin 2 */
721 dpavlin 26 void machine_entry_add_subtype(struct machine_entry *me, const char *name,
722     int oldstyle_subtype, ...)
723 dpavlin 2 {
724 dpavlin 26 va_list argp;
725 dpavlin 2 struct machine_entry_subtype *mes;
726    
727 dpavlin 26 /* Allocate a new subtype struct: */
728 dpavlin 42 CHECK_ALLOCATION(mes = malloc(sizeof(struct machine_entry_subtype)));
729 dpavlin 2
730 dpavlin 26 /* Add the subtype to the machine entry: */
731     me->n_subtypes ++;
732 dpavlin 42 CHECK_ALLOCATION(me->subtype = realloc(me->subtype, sizeof(struct
733     machine_entry_subtype *) * me->n_subtypes));
734 dpavlin 26 me->subtype[me->n_subtypes - 1] = mes;
735    
736     /* Fill the struct with subtype data: */
737 dpavlin 2 memset(mes, 0, sizeof(struct machine_entry_subtype));
738     mes->name = name;
739 dpavlin 26 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 dpavlin 42 CHECK_ALLOCATION(mes->aliases =
754     realloc(mes->aliases, sizeof(char *) * mes->n_aliases));
755 dpavlin 26
756     mes->aliases[mes->n_aliases - 1] = s;
757 dpavlin 2 }
758    
759 dpavlin 26 va_end(argp);
760 dpavlin 2 }
761    
762    
763     /*
764 dpavlin 26 * machine_entry_register():
765 dpavlin 22 *
766     * Inserts a new machine_entry into the machine entries list.
767     */
768 dpavlin 26 void machine_entry_register(struct machine_entry *me, int arch)
769 dpavlin 22 {
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 dpavlin 2 * 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 dpavlin 22 int iadd = DEBUG_INDENTATION * 2;
808 dpavlin 2
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 dpavlin 22 int i, j, iadd = DEBUG_INDENTATION;
828 dpavlin 2
829 dpavlin 22 debug("%s [%s] (", me->name,
830     cpu_family_ptr_by_number(me->arch)->name);
831 dpavlin 2 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 dpavlin 20 "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 dpavlin 2
857     debug("\n");
858    
859     useremul_list_emuls();
860 dpavlin 12 debug("Userland emulation works for programs with the complexity"
861     " of Hello World,\nbut not much more.\n");
862 dpavlin 2 }
863    
864    
865     /*
866     * machine_init():
867     *
868     * This function should be called before any other machine_*() function
869 dpavlin 22 * is used. automachine_init() registers all machines in src/machines/.
870 dpavlin 2 */
871     void machine_init(void)
872     {
873 dpavlin 22 if (first_machine_entry != NULL) {
874     fatal("machine_init(): already called?\n");
875     exit(1);
876 dpavlin 14 }
877    
878 dpavlin 22 automachine_init();
879 dpavlin 2 }
880    

  ViewVC Help
Powered by ViewVC 1.1.26