/[gxemul]/trunk/src/machine.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/src/machine.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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


1 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