/[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 32 - (hide annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 33190 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1421 2006/11/06 05:32:37 debug Exp $
20060816	Adding a framework for emulated/virtual timers (src/timer.c),
		using only setitimer().
		Rewriting the mc146818 to use the new timer framework.
20060817	Adding a call to gettimeofday() every now and then (once every
		second, at the moment) to resynch the timer if it drifts.
		Beginning to convert the ISA timer interrupt mechanism (8253
		and 8259) to use the new timer framework.
		Removing the -I command line option.
20060819	Adding the -I command line option again, with new semantics.
		Working on Footbridge timer interrupts; NetBSD/NetWinder and
		NetBSD/CATS now run at correct speed, but unfortunately with
		HUGE delays during bootup.
20060821	Some minor m68k updates. Adding the first instruction: nop. :)
		Minor Alpha emulation updates.
20060822	Adding a FreeBSD development specific YAMON environment
		variable ("khz") (as suggested by Bruce M. Simpson).
		Moving YAMON environment variable initialization from
		machine_evbmips.c into promemul/yamon.c, and adding some more
		variables.
		Continuing on the LCA PCI bus controller (for Alpha machines).
20060823	Continuing on the timer stuff: experimenting with MIPS count/
		compare interrupts connected to the timer framework.
20060825	Adding bogus SCSI commands 0x51 (SCSICDROM_READ_DISCINFO) and
		0x52 (SCSICDROM_READ_TRACKINFO) to the SCSI emulation layer,
		to allow NetBSD/pmax 4.0_BETA to be installed from CDROM.
		Minor updates to the LCA PCI controller.
20060827	Implementing a CHIP8 cpu mode, and a corresponding CHIP8
		machine, for fun. Disassembly support for all instructions,
		and most of the common instructions have been implemented: mvi,
		mov_imm, add_imm, jmp, rand, cls, sprite, skeq_imm, jsr,
		skne_imm, bcd, rts, ldr, str, mov, or, and, xor, add, sub,
		font, ssound, sdelay, gdelay, bogus skup/skpr, skeq, skne.
20060828	Beginning to convert the CHIP8 cpu in the CHIP8 machine to a
		(more correct) RCA 180x cpu. (Disassembly for all 1802
		instructions has been implemented, but no execution yet, and
		no 1805 extended instructions.)
20060829	Minor Alpha emulation updates.
20060830	Beginning to experiment a little with PCI IDE for SGI O2.
		Fixing the cursor key mappings for MobilePro 770 emulation.
		Fixing the LK201 warning caused by recent NetBSD/pmax.
		The MIPS R41xx standby, suspend, and hibernate instructions now
		behave like the RM52xx/MIPS32/MIPS64 wait instruction.
		Fixing dev_wdc so it calculates correct (64-bit) offsets before
		giving them to diskimage_access().
20060831	Continuing on Alpha emulation (OSF1 PALcode).
20060901	Minor Alpha updates; beginning on virtual memory pagetables.
		Removed the limit for max nr of devices (in preparation for
		allowing devices' base addresses to be changed during runtime).
		Adding a hack for MIPS [d]mfc0 select 0 (except the count
		register), so that the coproc register is simply copied.
		The MIPS suspend instruction now exits the emulator, instead
		of being treated as a wait instruction (this causes NetBSD/
		hpcmips to get correct 'halt' behavior).
		The VR41xx RTC now returns correct time.
		Connecting the VR41xx timer to the timer framework (fixed at
		128 Hz, for now).
		Continuing on SPARC emulation, adding more instructions:
		restore, ba_xcc, ble. The rectangle drawing demo works :)
		Removing the last traces of the old ENABLE_CACHE_EMULATION
		MIPS stuff (not usable with dyntrans anyway).
20060902	Splitting up src/net.c into several smaller files in its own
		subdirectory (src/net/).
20060903	Cleanup of the files in src/net/, to make them less ugly.
20060904	Continuing on the 'settings' subsystem.
		Minor progress on the SPARC emulation mode.
20060905	Cleanup of various things, and connecting the settings
		infrastructure to various subsystems (emul, machine, cpu, etc).
		Changing the lk201 mouse update routine to not rely on any
		emulated hardware framebuffer cursor coordinates, but instead
		always do (semi-usable) relative movements.
20060906	Continuing on the lk201 mouse stuff. Mouse behaviour with
		multiple framebuffers (which was working in Ultrix) is now
		semi-broken (but it still works, in a way).
		Moving the documentation about networking into its own file
		(networking.html), and refreshing it a bit. Adding an example
		of how to use ethernet frame direct-access (udp_snoop).
20060907	Continuing on the settings infrastructure.
20060908	Minor updates to SH emulation: for 32-bit emulation: delay
		slots and the 'jsr @Rn' instruction. I'm putting 64-bit SH5 on
		ice, for now.
20060909-10	Implementing some more 32-bit SH instructions. Removing the
		64-bit mode completely. Enough has now been implemented to run
		the rectangle drawing demo. :-)
20060912	Adding more SH instructions.
20060916	Continuing on SH emulation (some more instructions: div0u,
		div1, rotcl/rotcr, more mov instructions, dt, braf, sets, sett,
		tst_imm, dmuls.l, subc, ldc_rm_vbr, movt, clrt, clrs, clrmac).
		Continuing on the settings subsystem (beginning on reading/
		writing settings, removing bugs, and connecting more cpus to
		the framework).
20060919	More work on SH emulation; adding an ldc banked instruction,
		and attaching a 640x480 framebuffer to the Dreamcast machine
		mode (NetBSD/dreamcast prints the NetBSD copyright banner :-),
		and then panics).
20060920	Continuing on the settings subsystem.
20060921	Fixing the Footbridge timer stuff so that NetBSD/cats and
		NetBSD/netwinder boot up without the delays.
20060922	Temporarily hardcoding MIPS timer interrupt to 100 Hz. With
		'wait' support disabled, NetBSD/malta and Linux/malta run at
		correct speed.
20060923	Connecting dev_gt to the timer framework, so that NetBSD/cobalt
		runs at correct speed.
		Moving SH4-specific memory mapped registers into its own
		device (dev_sh4.c).
		Running with -N now prints "idling" instead of bogus nr of
		instrs/second (which isn't valid anyway) while idling.
20060924	Algor emulation should now run at correct speed.
		Adding disassembly support for some MIPS64 revision 2
		instructions: ext, dext, dextm, dextu.
20060926	The timer framework now works also when the MIPS wait
		instruction is used.
20060928	Re-implementing checks for coprocessor availability for MIPS
		cop0 instructions. (Thanks to Carl van Schaik for noticing the
		lack of cop0 availability checks.)
20060929	Implementing an instruction combination hack which treats
		NetBSD/pmax' idle loop as a wait-like instruction.
20060930	The ENTRYHI_R_MASK was missing in (at least) memory_mips_v2p.c,
		causing TLB lookups to sometimes succeed when they should have
		failed. (A big thank you to Juli Mallett for noticing the
		problem.)
		Adding disassembly support for more MIPS64 revision 2 opcodes
		(seb, seh, wsbh, jalr.hb, jr.hb, synci, ins, dins, dinsu,
		dinsm, dsbh, dshd, ror, dror, rorv, drorv, dror32). Also
		implementing seb, seh, dsbh, dshd, and wsbh.
		Implementing an instruction combination hack for Linux/pmax'
		idle loop, similar to the NetBSD/pmax case.
20061001	Changing the NetBSD/sgimips install instructions to extract
		files from an iso image, instead of downloading them via ftp.
20061002	More-than-31-bit userland addresses in memory_mips_v2p.c were
		not actually working; applying a fix from Carl van Schaik to
		enable them to work + making some other updates (adding kuseg
		support).
		Fixing hpcmips (vr41xx) timer initialization.
		Experimenting with O(n)->O(1) reduction in the MIPS TLB lookup
		loop. Seems to work both for R3000 and non-R3000.
20061003	Continuing a little on SH emulation (adding more control
		registers; mini-cleanup of memory_sh.c).
20061004	Beginning on a dev_rtc, a clock/timer device for the test
		machines; also adding a demo, and some documentation.
		Fixing a bug in SH "mov.w @(disp,pc),Rn" (the result wasn't
		sign-extended), and adding the addc and ldtlb instructions.
20061005	Contining on SH emulation: virtual to physical address
		translation, and a skeleton exception mechanism.
20061006	Adding more SH instructions (various loads and stores, rte,
		negc, muls.w, various privileged register-move instructions).
20061007	More SH instructions: various move instructions, trapa, div0s,
		float, fdiv, ftrc.
		Continuing on dev_rtc; removing the rtc demo.
20061008	Adding a dummy Dreamcast PROM module. (Homebrew Dreamcast
		programs using KOS libs need this.)
		Adding more SH instructions: "stc vbr,rn", rotl, rotr, fsca,
		fmul, fadd, various floating-point moves, etc. A 256-byte
		demo for Dreamcast runs :-)
20061012	Adding the SH "lds Rm,pr" and bsr instructions.
20061013	More SH instructions: "sts fpscr,rn", tas.b, and some more
		floating point instructions, cmp/str, and more moves.
		Adding a dummy dev_pvr (Dreamcast graphics controller).
20061014	Generalizing the expression evaluator (used in the built-in
		debugger) to support parentheses and +-*/%^&|.
20061015	Removing the experimental tlb index hint code in
		mips_memory_v2p.c, since it didn't really have any effect.
20061017	Minor SH updates; adding the "sts pr,Rn", fcmp/gt, fneg,
		frchg, and some other instructions. Fixing missing sign-
		extension in an 8-bit load instruction.
20061019	Adding a simple dev_dreamcast_rtc.
		Implementing memory-mapped access to the SH ITLB/UTLB arrays.
20061021	Continuing on various SH and Dreamcast things: sh4 timers,
		debug messages for dev_pvr, fixing some virtual address
		translation bugs, adding the bsrf instruction.
		The NetBSD/dreamcast GENERIC_MD kernel now reaches userland :)
		Adding a dummy dev_dreamcast_asic.c (not really useful yet).
		Implementing simple support for Store Queues.
		Beginning on the PVR Tile Accelerator.
20061022	Generalizing the PVR framebuffer to support off-screen drawing,
		multiple bit-depths, etc. (A small speed penalty, but most
		likely worth it.)
		Adding more SH instructions (mulu.w, fcmp/eq, fsub, fmac,
		fschg, and some more); correcting bugs in "fsca" and "float".
20061024	Adding the SH ftrv (matrix * vector) instruction. Marcus
		Comstedt's "tatest" example runs :) (wireframe only).
		Correcting disassembly for SH floating point instructions that
		use the xd* registers.
		Adding the SH fsts instruction.
		In memory_device_dyntrans_access(), only the currently used
		range is now invalidated, and not the entire device range.
20061025	Adding a dummy AVR32 cpu mode skeleton.
20061026	Various Dreamcast updates; beginning on a Maple bus controller.
20061027	Continuing on the Maple bus. A bogus Controller, Keyboard, and
		Mouse can now be detected by NetBSD and KOS homebrew programs.
		Cleaning up the SH4 Timer Management Unit, and beginning on
		SH4 interrupts.
		Implementing the Dreamcast SYSASIC.
20061028	Continuing on the SYSASIC.
		Adding the SH fsqrt instruction.
		memory_sh.c now actually scans the ITLB.
		Fixing a bug in dev_sh4.c, related to associative writes into
		the memory-mapped UTLB array. NetBSD/dreamcast now reaches
		userland stably, and prints the "Terminal type?" message :-]
		Implementing enough of the Dreamcast keyboard to make NetBSD
		accept it for input.
		Enabling SuperH for stable (non-development) builds.
		Adding NetBSD/dreamcast to the documentation, although it
		doesn't support root-on-nfs yet.
20061029	Changing usleep(1) calls in the debugger to to usleep(10000)
		(according to Brian Foley, this makes GXemul run better on
		MacOS X).
		Making the Maple "Controller" do something (enough to barely
		interact with dcircus.elf).
20061030-31	Some progress on the PVR. More test programs start running (but
		with strange output).
		Various other SH4-related updates.
20061102	Various Dreamcast and SH4 updates; more KOS demos run now.
20061104	Adding a skeleton dev_mb8696x.c (the Dreamcast's LAN adapter).
20061105	Continuing on the MB8696x; NetBSD/dreamcast detects it as mbe0.
		Testing for the release.

==============  RELEASE 0.4.3  ==============


1 dpavlin 2 /*
2 dpavlin 22 * Copyright (C) 2003-2006 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 32 * $Id: machine.c,v 1.689 2006/10/04 11:56:40 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 "arcbios.h"
39 dpavlin 20 #include "bus_isa.h"
40 dpavlin 2 #include "bus_pci.h"
41     #include "cpu.h"
42 dpavlin 26 #include "debugger.h"
43 dpavlin 2 #include "device.h"
44     #include "devices.h"
45     #include "diskimage.h"
46     #include "emul.h"
47     #include "machine.h"
48 dpavlin 22 #include "machine_interrupts.h"
49 dpavlin 2 #include "memory.h"
50     #include "misc.h"
51     #include "net.h"
52 dpavlin 32 #include "settings.h"
53 dpavlin 2 #include "symbol.h"
54    
55 dpavlin 12
56 dpavlin 6 /* See main.c: */
57     extern int quiet_mode;
58 dpavlin 22 extern int verbose;
59 dpavlin 6
60    
61 dpavlin 2 /* This is initialized by machine_init(): */
62 dpavlin 22 struct machine_entry *first_machine_entry = NULL;
63 dpavlin 2
64    
65     /*
66     * machine_new():
67     *
68     * Returns a reasonably initialized struct machine.
69     */
70     struct machine *machine_new(char *name, struct emul *emul)
71     {
72     struct machine *m;
73     m = malloc(sizeof(struct machine));
74     if (m == NULL) {
75     fprintf(stderr, "machine_new(): out of memory\n");
76     exit(1);
77     }
78    
79     memset(m, 0, sizeof(struct machine));
80    
81 dpavlin 32 /* Pointer back to the emul object that this machine belongs to: */
82 dpavlin 2 m->emul = emul;
83    
84     m->name = strdup(name);
85    
86     /* Sane default values: */
87 dpavlin 10 m->serial_nr = 1;
88 dpavlin 2 m->machine_type = MACHINE_NONE;
89     m->machine_subtype = MACHINE_NONE;
90 dpavlin 12 m->arch_pagesize = 4096; /* Should be overriden in
91     emul.c for other pagesizes. */
92 dpavlin 2 m->prom_emulation = 1;
93 dpavlin 28 m->allow_instruction_combinations = 1;
94 dpavlin 2 m->byte_order_override = NO_BYTE_ORDER_OVERRIDE;
95     m->boot_kernel_filename = "";
96     m->boot_string_argument = NULL;
97     m->x11_scaledown = 1;
98 dpavlin 20 m->x11_scaleup = 1;
99 dpavlin 2 m->n_gfx_cards = 1;
100     m->dbe_on_nonexistant_memaccess = 1;
101     m->show_symbolic_register_names = 1;
102     symbol_init(&m->symbol_context);
103    
104 dpavlin 32 /* Settings: */
105     m->settings = settings_new();
106     settings_add(m->settings, "name", 0,
107     SETTINGS_TYPE_STRING, SETTINGS_FORMAT_STRING,
108     (void *) &m->name);
109     settings_add(m->settings, "serial_nr", 0,
110     SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
111     (void *) &m->serial_nr);
112     settings_add(m->settings, "arch_pagesize", 0,
113     SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
114     (void *) &m->arch_pagesize);
115     settings_add(m->settings, "prom_emulation", 0,
116     SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
117     (void *) &m->prom_emulation);
118     settings_add(m->settings, "allow_instruction_combinations", 0,
119     SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
120     (void *) &m->allow_instruction_combinations);
121     settings_add(m->settings, "n_gfx_cards", 0,
122     SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
123     (void *) &m->n_gfx_cards);
124     settings_add(m->settings, "show_symbolic_register_names", 1,
125     SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
126     (void *) &m->show_symbolic_register_names);
127     settings_add(m->settings, "statistics_enabled", 1,
128     SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
129     (void *) &m->statistics_enabled);
130    
131 dpavlin 2 return m;
132     }
133    
134    
135     /*
136 dpavlin 32 * machine_destroy():
137     *
138     * Destroys a machine object.
139     */
140     void machine_destroy(struct machine *machine)
141     {
142     int i;
143    
144     for (i=0; i<machine->ncpus; i++)
145     cpu_destroy(machine->cpus[i]);
146    
147     if (machine->name != NULL)
148     free(machine->name);
149    
150     /* Remove any remaining level-1 settings: */
151     settings_remove_all(machine->settings);
152     settings_destroy(machine->settings);
153    
154     free(machine);
155     }
156    
157    
158     /*
159 dpavlin 2 * machine_name_to_type():
160     *
161     * Take a type and a subtype as strings, and convert them into numeric
162     * values used internally throughout the code.
163     *
164     * Return value is 1 on success, 0 if there was no match.
165     * Also, any errors/warnings are printed using fatal()/debug().
166     */
167     int machine_name_to_type(char *stype, char *ssubtype,
168     int *type, int *subtype, int *arch)
169     {
170     struct machine_entry *me;
171 dpavlin 12 int i, j, k, nmatches = 0;
172 dpavlin 2
173     *type = MACHINE_NONE;
174     *subtype = 0;
175    
176 dpavlin 12 /* Check stype, and optionally ssubtype: */
177 dpavlin 2 me = first_machine_entry;
178     while (me != NULL) {
179     for (i=0; i<me->n_aliases; i++)
180     if (strcasecmp(me->aliases[i], stype) == 0) {
181     /* Found a type: */
182     *type = me->machine_type;
183     *arch = me->arch;
184    
185     if (me->n_subtypes == 0)
186     return 1;
187    
188     /* Check for subtype: */
189     for (j=0; j<me->n_subtypes; j++)
190     for (k=0; k<me->subtype[j]->n_aliases;
191     k++)
192     if (strcasecmp(ssubtype,
193     me->subtype[j]->aliases[k]
194     ) == 0) {
195     *subtype = me->subtype[
196     j]->machine_subtype;
197     return 1;
198     }
199    
200 dpavlin 6 fatal("Unknown subtype '%s' for emulation"
201 dpavlin 2 " '%s'\n", ssubtype, stype);
202 dpavlin 6 if (!ssubtype[0])
203     fatal("(Maybe you forgot the -e"
204     " command line option?)\n");
205 dpavlin 2 exit(1);
206     }
207    
208     me = me->next;
209     }
210    
211 dpavlin 12 /* Not found? Then just check ssubtype: */
212     me = first_machine_entry;
213     while (me != NULL) {
214     if (me->n_subtypes == 0) {
215     me = me->next;
216     continue;
217     }
218    
219     /* Check for subtype: */
220     for (j=0; j<me->n_subtypes; j++)
221     for (k=0; k<me->subtype[j]->n_aliases; k++)
222     if (strcasecmp(ssubtype, me->subtype[j]->
223     aliases[k]) == 0) {
224     *type = me->machine_type;
225     *arch = me->arch;
226     *subtype = me->subtype[j]->
227     machine_subtype;
228     nmatches ++;
229     }
230    
231     me = me->next;
232     }
233    
234     switch (nmatches) {
235     case 0: fatal("\nSorry, emulation \"%s\"", stype);
236     if (ssubtype != NULL && ssubtype[0] != '\0')
237     fatal(" (subtype \"%s\")", ssubtype);
238     fatal(" is unknown.\n");
239     break;
240     case 1: return 1;
241     default:fatal("\nSorry, multiple matches for \"%s\"", stype);
242     if (ssubtype != NULL && ssubtype[0] != '\0')
243     fatal(" (subtype \"%s\")", ssubtype);
244     fatal(".\n");
245     }
246    
247     *type = MACHINE_NONE;
248     *subtype = 0;
249    
250     fatal("Use the -H command line option to get a list of "
251     "available types and subtypes.\n\n");
252    
253 dpavlin 2 return 0;
254     }
255    
256    
257     /*
258     * machine_add_tickfunction():
259     *
260     * Adds a tick function (a function called every now and then, depending on
261     * clock cycle count) to a machine.
262 dpavlin 24 *
263     * If tickshift is non-zero, a tick will occur every (1 << tickshift) cycles.
264     * This is used for the normal (fast dyntrans) emulation modes.
265     *
266     * If tickshift is zero, then this is a cycle-accurate tick function.
267     * The hz value is used in this case.
268 dpavlin 2 */
269     void machine_add_tickfunction(struct machine *machine, void (*func)
270 dpavlin 24 (struct cpu *, void *), void *extra, int tickshift, double hz)
271 dpavlin 2 {
272     int n = machine->n_tick_entries;
273    
274     if (n >= MAX_TICK_FUNCTIONS) {
275     fprintf(stderr, "machine_add_tickfunction(): too "
276     "many tick functions\n");
277     exit(1);
278     }
279    
280 dpavlin 24 if (!machine->cycle_accurate) {
281     /*
282     * The dyntrans subsystem wants to run code in relatively
283 dpavlin 32 * large chunks without checking for external interrupts;
284     * too low tickshifts are not allowed.
285 dpavlin 24 */
286     if (tickshift < N_SAFE_DYNTRANS_LIMIT_SHIFT) {
287     fatal("ERROR! tickshift = %i, less than "
288     "N_SAFE_DYNTRANS_LIMIT_SHIFT (%i)\n",
289     tickshift, N_SAFE_DYNTRANS_LIMIT_SHIFT);
290     exit(1);
291     }
292     }
293 dpavlin 2
294     machine->ticks_till_next[n] = 0;
295 dpavlin 24 machine->ticks_reset_value[n] = 1 << tickshift;
296 dpavlin 2 machine->tick_func[n] = func;
297     machine->tick_extra[n] = extra;
298 dpavlin 24 machine->tick_hz[n] = hz;
299 dpavlin 2
300     machine->n_tick_entries ++;
301     }
302    
303    
304 dpavlin 22 /*
305 dpavlin 28 * machine_statistics_init():
306     *
307     * Initialize the parts of a machine struct that deal with instruction
308     * statistics gathering.
309     *
310     * Note: The fname argument contains "flags:filename".
311     */
312     void machine_statistics_init(struct machine *machine, char *fname)
313     {
314     int n_fields = 0;
315     char *pcolon = fname;
316     char *mode = "a"; /* Append by default */
317    
318     machine->allow_instruction_combinations = 0;
319    
320     if (machine->statistics_fields != NULL) {
321     fprintf(stderr, "Only one -s option is allowed.\n");
322     exit(1);
323     }
324    
325     machine->statistics_fields = malloc(MAX_STATISTICS_FIELDS + 1);
326     machine->statistics_enabled = 1;
327    
328     while (*pcolon && *pcolon != ':')
329     pcolon ++;
330    
331     if (*pcolon != ':') {
332     fprintf(stderr, "The syntax for the -s option is: "
333     "-s flags:filename\nYou omitted the flags. Run g"
334     "xemul -h for a list of available flags.\n");
335     exit(1);
336     }
337    
338     while (*fname != ':') {
339     switch (*fname) {
340    
341     /* Type flags: */
342     case 'v':
343     case 'i':
344     case 'p':
345     machine->statistics_fields[n_fields ++] = *fname;
346     if (n_fields >= MAX_STATISTICS_FIELDS) {
347     fprintf(stderr, "Internal error: Too many "
348     "statistics fields used. Increase "
349     "MAX_STATISTICS_FIELDS.\n");
350     exit(1);
351     }
352     machine->statistics_fields[n_fields] = '\0';
353     break;
354    
355     /* Optional flags: */
356     case 'o':
357     mode = "w";
358     break;
359     case 'd':
360     machine->statistics_enabled = 0;
361     break;
362    
363     default:fprintf(stderr, "Unknown flag '%c' used with the"
364     " -s option. Aborting.\n", *fname);
365     exit(1);
366     }
367     fname ++;
368     }
369    
370     fname ++; /* point to the filename after the colon */
371    
372     machine->statistics_filename = strdup(fname);
373     machine->statistics_file = fopen(machine->statistics_filename, mode);
374     }
375    
376    
377     /*
378 dpavlin 22 * machine_bus_register():
379     *
380     * Registers a bus in a machine.
381     */
382     void machine_bus_register(struct machine *machine, char *busname,
383     void (*debug_dump)(void *), void *extra)
384     {
385     struct machine_bus *tmp, *last = NULL, *new;
386 dpavlin 2
387 dpavlin 22 new = zeroed_alloc(sizeof(struct machine_bus));
388     new->name = strdup(busname);
389     new->debug_dump = debug_dump;
390     new->extra = extra;
391 dpavlin 2
392 dpavlin 22 /* Register last in the bus list: */
393     tmp = machine->first_bus;
394     while (tmp != NULL) {
395     last = tmp;
396     tmp = tmp->next;
397     }
398    
399     if (last == NULL)
400     machine->first_bus = new;
401     else
402     last->next = new;
403    
404     machine->n_busses ++;
405     }
406    
407    
408     /*
409     * machine_dump_bus_info():
410     *
411     * Dumps info about registered busses.
412     */
413     void machine_dump_bus_info(struct machine *m)
414 dpavlin 2 {
415 dpavlin 22 struct machine_bus *bus = m->first_bus;
416     int iadd = DEBUG_INDENTATION;
417    
418     if (m->n_busses > 0)
419     debug("busses:\n");
420     debug_indentation(iadd);
421     while (bus != NULL) {
422     bus->debug_dump(bus->extra);
423     bus = bus->next;
424     }
425     debug_indentation(-iadd);
426 dpavlin 2 }
427    
428    
429     /*
430 dpavlin 22 * machine_dumpinfo():
431     *
432     * Dumps info about a machine in some kind of readable format. (Used by
433     * the 'machine' debugger command.)
434     */
435     void machine_dumpinfo(struct machine *m)
436     {
437     int i;
438    
439     debug("serial nr: %i", m->serial_nr);
440     if (m->nr_of_nics > 0)
441     debug(" (nr of NICs: %i)", m->nr_of_nics);
442     debug("\n");
443    
444     debug("memory: %i MB", m->physical_ram_in_mb);
445     if (m->memory_offset_in_mb != 0)
446     debug(" (offset by %i MB)", m->memory_offset_in_mb);
447     if (m->random_mem_contents)
448     debug(", randomized contents");
449     if (m->dbe_on_nonexistant_memaccess)
450     debug(", dbe_on_nonexistant_memaccess");
451     debug("\n");
452    
453     if (!m->prom_emulation)
454     debug("PROM emulation disabled\n");
455    
456     for (i=0; i<m->ncpus; i++)
457     cpu_dumpinfo(m, m->cpus[i]);
458    
459     if (m->ncpus > 1)
460     debug("Bootstrap cpu is nr %i\n", m->bootstrap_cpu);
461    
462     if (m->slow_serial_interrupts_hack_for_linux)
463     debug("Using slow_serial_interrupts_hack_for_linux\n");
464    
465     if (m->use_x11) {
466     debug("Using X11");
467     if (m->x11_scaledown > 1)
468     debug(", scaledown %i", m->x11_scaledown);
469     if (m->x11_scaleup > 1)
470     debug(", scaleup %i", m->x11_scaleup);
471     if (m->x11_n_display_names > 0) {
472     for (i=0; i<m->x11_n_display_names; i++) {
473     debug(i? ", " : " (");
474     debug("\"%s\"", m->x11_display_names[i]);
475     }
476     debug(")");
477     }
478     debug("\n");
479     }
480    
481     machine_dump_bus_info(m);
482    
483     diskimage_dump_info(m);
484    
485     if (m->force_netboot)
486     debug("Forced netboot\n");
487     }
488    
489    
490     /*
491 dpavlin 2 * dump_mem_string():
492     *
493     * Dump the contents of emulated RAM as readable text. Bytes that aren't
494     * readable are dumped in [xx] notation, where xx is in hexadecimal.
495     * Dumping ends after DUMP_MEM_STRING_MAX bytes, or when a terminating
496     * zero byte is found.
497     */
498     #define DUMP_MEM_STRING_MAX 45
499     void dump_mem_string(struct cpu *cpu, uint64_t addr)
500     {
501     int i;
502     for (i=0; i<DUMP_MEM_STRING_MAX; i++) {
503     unsigned char ch = '\0';
504    
505     cpu->memory_rw(cpu, cpu->mem, addr + i, &ch, sizeof(ch),
506     MEM_READ, CACHE_DATA | NO_EXCEPTIONS);
507     if (ch == '\0')
508     return;
509     if (ch >= ' ' && ch < 126)
510     debug("%c", ch);
511     else
512     debug("[%02x]", ch);
513     }
514     }
515    
516    
517     /*
518     * store_byte():
519     *
520     * Stores a byte in emulated ram. (Helper function.)
521     */
522     void store_byte(struct cpu *cpu, uint64_t addr, uint8_t data)
523     {
524     if ((addr >> 32) == 0)
525     addr = (int64_t)(int32_t)addr;
526     cpu->memory_rw(cpu, cpu->mem,
527     addr, &data, sizeof(data), MEM_WRITE, CACHE_DATA);
528     }
529    
530    
531     /*
532     * store_string():
533     *
534     * Stores chars into emulated RAM until a zero byte (string terminating
535     * character) is found. The zero byte is also copied.
536     * (strcpy()-like helper function, host-RAM-to-emulated-RAM.)
537     */
538     void store_string(struct cpu *cpu, uint64_t addr, char *s)
539     {
540     do {
541     store_byte(cpu, addr++, *s);
542     } while (*s++);
543     }
544    
545    
546     /*
547     * add_environment_string():
548     *
549     * Like store_string(), but advances the pointer afterwards. The most
550     * obvious use is to place a number of strings (such as environment variable
551     * strings) after one-another in emulated memory.
552     */
553     void add_environment_string(struct cpu *cpu, char *s, uint64_t *addr)
554     {
555     store_string(cpu, *addr, s);
556     (*addr) += strlen(s) + 1;
557     }
558    
559    
560     /*
561 dpavlin 12 * add_environment_string_dual():
562     *
563     * Add "dual" environment strings, one for the variable name and one for the
564     * value, and update pointers afterwards.
565     */
566     void add_environment_string_dual(struct cpu *cpu,
567     uint64_t *ptrp, uint64_t *addrp, char *s1, char *s2)
568     {
569     uint64_t ptr = *ptrp, addr = *addrp;
570    
571     store_32bit_word(cpu, ptr, addr);
572     ptr += sizeof(uint32_t);
573     if (addr != 0) {
574     store_string(cpu, addr, s1);
575     addr += strlen(s1) + 1;
576     }
577     store_32bit_word(cpu, ptr, addr);
578     ptr += sizeof(uint32_t);
579     if (addr != 0) {
580     store_string(cpu, addr, s2);
581     addr += strlen(s2) + 1;
582     }
583    
584     *ptrp = ptr;
585     *addrp = addr;
586     }
587    
588    
589     /*
590 dpavlin 2 * store_64bit_word():
591     *
592     * Stores a 64-bit word in emulated RAM. Byte order is taken into account.
593     * Helper function.
594     */
595     int store_64bit_word(struct cpu *cpu, uint64_t addr, uint64_t data64)
596     {
597     unsigned char data[8];
598     if ((addr >> 32) == 0)
599     addr = (int64_t)(int32_t)addr;
600     data[0] = (data64 >> 56) & 255;
601     data[1] = (data64 >> 48) & 255;
602     data[2] = (data64 >> 40) & 255;
603     data[3] = (data64 >> 32) & 255;
604     data[4] = (data64 >> 24) & 255;
605     data[5] = (data64 >> 16) & 255;
606     data[6] = (data64 >> 8) & 255;
607     data[7] = (data64) & 255;
608     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
609     int tmp = data[0]; data[0] = data[7]; data[7] = tmp;
610     tmp = data[1]; data[1] = data[6]; data[6] = tmp;
611     tmp = data[2]; data[2] = data[5]; data[5] = tmp;
612     tmp = data[3]; data[3] = data[4]; data[4] = tmp;
613     }
614     return cpu->memory_rw(cpu, cpu->mem,
615     addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
616     }
617    
618    
619     /*
620     * store_32bit_word():
621     *
622     * Stores a 32-bit word in emulated RAM. Byte order is taken into account.
623     * (This function takes a 64-bit word as argument, to suppress some
624     * warnings, but only the lowest 32 bits are used.)
625     */
626     int store_32bit_word(struct cpu *cpu, uint64_t addr, uint64_t data32)
627     {
628     unsigned char data[4];
629 dpavlin 32
630     /* TODO: REMOVE THIS once everything is more stable! */
631 dpavlin 14 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
632 dpavlin 2 addr = (int64_t)(int32_t)addr;
633 dpavlin 32
634 dpavlin 2 data[0] = (data32 >> 24) & 255;
635     data[1] = (data32 >> 16) & 255;
636     data[2] = (data32 >> 8) & 255;
637     data[3] = (data32) & 255;
638     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
639     int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
640     tmp = data[1]; data[1] = data[2]; data[2] = tmp;
641     }
642     return cpu->memory_rw(cpu, cpu->mem,
643     addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
644     }
645    
646    
647     /*
648     * store_16bit_word():
649     *
650     * Stores a 16-bit word in emulated RAM. Byte order is taken into account.
651     * (This function takes a 64-bit word as argument, to suppress some
652     * warnings, but only the lowest 16 bits are used.)
653     */
654     int store_16bit_word(struct cpu *cpu, uint64_t addr, uint64_t data16)
655     {
656     unsigned char data[2];
657 dpavlin 32
658     /* TODO: REMOVE THIS once everything is more stable! */
659 dpavlin 14 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
660 dpavlin 2 addr = (int64_t)(int32_t)addr;
661 dpavlin 32
662 dpavlin 2 data[0] = (data16 >> 8) & 255;
663     data[1] = (data16) & 255;
664     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
665     int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
666     }
667     return cpu->memory_rw(cpu, cpu->mem,
668     addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
669     }
670    
671    
672     /*
673     * store_buf():
674     *
675     * memcpy()-like helper function, from host RAM to emulated RAM.
676     */
677     void store_buf(struct cpu *cpu, uint64_t addr, char *s, size_t len)
678     {
679 dpavlin 22 size_t psize = 1024; /* 1024 256 64 16 4 1 */
680 dpavlin 6
681 dpavlin 32 /* TODO: REMOVE THIS once everything is more stable! */
682 dpavlin 14 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
683 dpavlin 2 addr = (int64_t)(int32_t)addr;
684    
685 dpavlin 6 while (len != 0) {
686     if ((addr & (psize-1)) == 0) {
687     while (len >= psize) {
688     cpu->memory_rw(cpu, cpu->mem, addr,
689     (unsigned char *)s, psize, MEM_WRITE,
690     CACHE_DATA);
691     addr += psize;
692     s += psize;
693     len -= psize;
694     }
695 dpavlin 2 }
696 dpavlin 6 psize >>= 2;
697 dpavlin 2 }
698    
699     while (len-- != 0)
700     store_byte(cpu, addr++, *s++);
701     }
702    
703    
704     /*
705     * store_pointer_and_advance():
706     *
707     * Stores a 32-bit or 64-bit pointer in emulated RAM, and advances the
708 dpavlin 22 * target address. (Useful for e.g. ARCBIOS environment initialization.)
709 dpavlin 2 */
710     void store_pointer_and_advance(struct cpu *cpu, uint64_t *addrp,
711     uint64_t data, int flag64)
712     {
713     uint64_t addr = *addrp;
714     if (flag64) {
715     store_64bit_word(cpu, addr, data);
716     addr += 8;
717     } else {
718     store_32bit_word(cpu, addr, data);
719     addr += 4;
720     }
721     *addrp = addr;
722     }
723    
724    
725     /*
726 dpavlin 32 * load_64bit_word():
727     *
728     * Helper function. Emulated byte order is taken into account.
729     */
730     uint64_t load_64bit_word(struct cpu *cpu, uint64_t addr)
731     {
732     unsigned char data[8];
733    
734     cpu->memory_rw(cpu, cpu->mem,
735     addr, data, sizeof(data), MEM_READ, CACHE_DATA);
736    
737     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
738     int tmp = data[0]; data[0] = data[7]; data[7] = tmp;
739     tmp = data[1]; data[1] = data[6]; data[6] = tmp;
740     tmp = data[2]; data[2] = data[5]; data[5] = tmp;
741     tmp = data[3]; data[3] = data[4]; data[4] = tmp;
742     }
743    
744     return
745     ((uint64_t)data[0] << 56) + ((uint64_t)data[1] << 48) +
746     ((uint64_t)data[2] << 40) + ((uint64_t)data[3] << 32) +
747     ((uint64_t)data[4] << 24) + ((uint64_t)data[5] << 16) +
748     ((uint64_t)data[6] << 8) + (uint64_t)data[7];
749     }
750    
751    
752     /*
753 dpavlin 2 * load_32bit_word():
754     *
755 dpavlin 32 * Helper function. Emulated byte order is taken into account.
756 dpavlin 2 */
757     uint32_t load_32bit_word(struct cpu *cpu, uint64_t addr)
758     {
759     unsigned char data[4];
760    
761 dpavlin 32 /* TODO: REMOVE THIS once everything is more stable! */
762 dpavlin 14 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
763 dpavlin 2 addr = (int64_t)(int32_t)addr;
764 dpavlin 32
765 dpavlin 2 cpu->memory_rw(cpu, cpu->mem,
766     addr, data, sizeof(data), MEM_READ, CACHE_DATA);
767    
768     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
769     int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
770     tmp = data[1]; data[1] = data[2]; data[2] = tmp;
771     }
772    
773     return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3];
774     }
775    
776    
777     /*
778 dpavlin 4 * load_16bit_word():
779     *
780 dpavlin 32 * Helper function. Emulated byte order is taken into account.
781 dpavlin 4 */
782     uint16_t load_16bit_word(struct cpu *cpu, uint64_t addr)
783     {
784     unsigned char data[2];
785    
786 dpavlin 32 /* TODO: REMOVE THIS once everything is more stable! */
787 dpavlin 14 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
788 dpavlin 4 addr = (int64_t)(int32_t)addr;
789 dpavlin 32
790 dpavlin 4 cpu->memory_rw(cpu, cpu->mem,
791     addr, data, sizeof(data), MEM_READ, CACHE_DATA);
792    
793     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
794     int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
795     }
796    
797     return (data[0] << 8) + data[1];
798     }
799    
800    
801     /*
802 dpavlin 2 * store_64bit_word_in_host():
803     *
804     * Stores a 64-bit word in the _host's_ RAM. Emulated byte order is taken
805     * into account. This is useful when building structs in the host's RAM
806     * which will later be copied into emulated RAM.
807     */
808     void store_64bit_word_in_host(struct cpu *cpu,
809     unsigned char *data, uint64_t data64)
810     {
811     data[0] = (data64 >> 56) & 255;
812     data[1] = (data64 >> 48) & 255;
813     data[2] = (data64 >> 40) & 255;
814     data[3] = (data64 >> 32) & 255;
815     data[4] = (data64 >> 24) & 255;
816     data[5] = (data64 >> 16) & 255;
817     data[6] = (data64 >> 8) & 255;
818     data[7] = (data64) & 255;
819     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
820     int tmp = data[0]; data[0] = data[7]; data[7] = tmp;
821     tmp = data[1]; data[1] = data[6]; data[6] = tmp;
822     tmp = data[2]; data[2] = data[5]; data[5] = tmp;
823     tmp = data[3]; data[3] = data[4]; data[4] = tmp;
824     }
825     }
826    
827    
828     /*
829     * store_32bit_word_in_host():
830     *
831     * See comment for store_64bit_word_in_host().
832     *
833     * (Note: The data32 parameter is a uint64_t. This is done to suppress
834     * some warnings.)
835     */
836     void store_32bit_word_in_host(struct cpu *cpu,
837     unsigned char *data, uint64_t data32)
838     {
839     data[0] = (data32 >> 24) & 255;
840     data[1] = (data32 >> 16) & 255;
841     data[2] = (data32 >> 8) & 255;
842     data[3] = (data32) & 255;
843     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
844     int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
845     tmp = data[1]; data[1] = data[2]; data[2] = tmp;
846     }
847     }
848    
849    
850     /*
851     * store_16bit_word_in_host():
852     *
853     * See comment for store_64bit_word_in_host().
854     */
855     void store_16bit_word_in_host(struct cpu *cpu,
856     unsigned char *data, uint16_t data16)
857     {
858     data[0] = (data16 >> 8) & 255;
859     data[1] = (data16) & 255;
860     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
861     int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
862     }
863     }
864    
865    
866     /*
867     * machine_setup():
868     *
869     * This (rather large) function initializes memory, registers, and/or devices
870     * required by specific machine emulations.
871     */
872     void machine_setup(struct machine *machine)
873     {
874     struct memory *mem;
875 dpavlin 22 struct machine_entry *me;
876 dpavlin 2
877     /* Abreviation: :-) */
878     struct cpu *cpu = machine->cpus[machine->bootstrap_cpu];
879    
880 dpavlin 22 machine->bootdev_id = diskimage_bootdev(machine,
881     &machine->bootdev_type);
882 dpavlin 2
883     mem = cpu->mem;
884     machine->machine_name = NULL;
885    
886     /* TODO: Move this somewhere else? */
887     if (machine->boot_string_argument == NULL) {
888     switch (machine->machine_type) {
889     case MACHINE_ARC:
890     machine->boot_string_argument = "-aN";
891     break;
892 dpavlin 16 case MACHINE_CATS:
893     machine->boot_string_argument = "-A";
894     break;
895 dpavlin 22 case MACHINE_PMAX:
896 dpavlin 2 machine->boot_string_argument = "-a";
897     break;
898     default:
899     /* Important, because boot_string_argument should
900     not be set to NULL: */
901     machine->boot_string_argument = "";
902     }
903     }
904    
905    
906 dpavlin 22 /*
907     * If the machine has a setup function in src/machines/machine_*.c
908     * then use that one, otherwise use the old hardcoded stuff here:
909     */
910 dpavlin 2
911 dpavlin 22 me = first_machine_entry;
912     while (me != NULL) {
913     if (machine->machine_type == me->machine_type &&
914     me->setup != NULL) {
915     me->setup(machine, cpu);
916 dpavlin 2 break;
917     }
918 dpavlin 22 me = me->next;
919     }
920 dpavlin 2
921 dpavlin 22 if (me == NULL) {
922 dpavlin 2 fatal("Unknown emulation type %i\n", machine->machine_type);
923     exit(1);
924     }
925    
926     if (machine->machine_name != NULL)
927     debug("machine: %s", machine->machine_name);
928    
929     if (machine->emulated_hz > 0)
930     debug(" (%.2f MHz)", (float)machine->emulated_hz / 1000000);
931     debug("\n");
932    
933 dpavlin 22 if (machine->bootstr != NULL) {
934     debug("bootstring%s: %s", (machine->bootarg!=NULL &&
935     strlen(machine->bootarg) >= 1)? "(+bootarg)" : "",
936     machine->bootstr);
937     if (machine->bootarg != NULL && strlen(machine->bootarg) >= 1)
938     debug(" %s", machine->bootarg);
939 dpavlin 2 debug("\n");
940     }
941 dpavlin 22
942     if (verbose >= 2)
943     machine_dump_bus_info(machine);
944    
945     if (!machine->stable)
946     fatal("!\n! NOTE: This machine type is not implemented well"
947     " enough yet to run\n! any real-world code!"
948     " (At least, it hasn't been verified to do so.)\n!\n"
949     "! Please read the GXemul documentation for information"
950     " about which\n! machine types that actually work.\n!\n");
951 dpavlin 2 }
952    
953    
954     /*
955     * machine_memsize_fix():
956     *
957     * Sets physical_ram_in_mb (if not already set), and memory_offset_in_mb,
958     * depending on machine type.
959     */
960     void machine_memsize_fix(struct machine *m)
961     {
962     if (m == NULL) {
963     fatal("machine_defaultmemsize(): m == NULL?\n");
964     exit(1);
965     }
966    
967     if (m->physical_ram_in_mb == 0) {
968 dpavlin 22 struct machine_entry *me = first_machine_entry;
969     while (me != NULL) {
970     if (m->machine_type == me->machine_type &&
971     me->set_default_ram != NULL) {
972     me->set_default_ram(m);
973 dpavlin 2 break;
974     }
975 dpavlin 22 me = me->next;
976 dpavlin 2 }
977     }
978    
979 dpavlin 6 /* Special hack for hpcmips machines: */
980     if (m->machine_type == MACHINE_HPCMIPS) {
981 dpavlin 2 m->dbe_on_nonexistant_memaccess = 0;
982     }
983    
984 dpavlin 22 /* Special SGI memory offsets: (TODO: move this somewhere else) */
985 dpavlin 2 if (m->machine_type == MACHINE_SGI) {
986     switch (m->machine_subtype) {
987     case 20:
988     case 22:
989     case 24:
990     case 26:
991     m->memory_offset_in_mb = 128;
992     break;
993     case 28:
994     case 30:
995     m->memory_offset_in_mb = 512;
996     break;
997     }
998     }
999    
1000     if (m->physical_ram_in_mb == 0)
1001     m->physical_ram_in_mb = DEFAULT_RAM_IN_MB;
1002     }
1003    
1004    
1005     /*
1006     * machine_default_cputype():
1007     *
1008 dpavlin 22 * Sets m->cpu_name, if it isn't already set, depending on the machine type.
1009 dpavlin 2 */
1010     void machine_default_cputype(struct machine *m)
1011     {
1012 dpavlin 22 struct machine_entry *me;
1013    
1014 dpavlin 2 if (m == NULL) {
1015     fatal("machine_default_cputype(): m == NULL?\n");
1016     exit(1);
1017     }
1018    
1019 dpavlin 22 /* Already set? Then return. */
1020 dpavlin 2 if (m->cpu_name != NULL)
1021     return;
1022    
1023 dpavlin 22 me = first_machine_entry;
1024     while (me != NULL) {
1025     if (m->machine_type == me->machine_type &&
1026     me->set_default_cpu != NULL) {
1027     me->set_default_cpu(m);
1028 dpavlin 2 break;
1029     }
1030 dpavlin 22 me = me->next;
1031 dpavlin 2 }
1032    
1033     if (m->cpu_name == NULL) {
1034     fprintf(stderr, "machine_default_cputype(): no default"
1035     " cpu for machine type %i subtype %i\n",
1036     m->machine_type, m->machine_subtype);
1037     exit(1);
1038     }
1039     }
1040    
1041    
1042 dpavlin 26 /*****************************************************************************/
1043    
1044    
1045 dpavlin 2 /*
1046 dpavlin 26 * machine_run():
1047     *
1048     * Run one or more instructions on all CPUs in this machine. (Usually,
1049     * around N_SAFE_DYNTRANS_LIMIT instructions will be run by the dyntrans
1050     * system.)
1051     *
1052     * Return value is 1 if any CPU in this machine is still running,
1053     * or 0 if all CPUs are stopped.
1054     */
1055     int machine_run(struct machine *machine)
1056     {
1057     struct cpu **cpus = machine->cpus;
1058     int ncpus = machine->ncpus, cpu0instrs = 0, i, te;
1059    
1060     for (i=0; i<ncpus; i++) {
1061     if (cpus[i]->running) {
1062 dpavlin 28 int instrs_run = cpus[i]->run_instr(cpus[i]);
1063 dpavlin 26 if (i == 0)
1064     cpu0instrs += instrs_run;
1065     }
1066     }
1067    
1068     /*
1069     * Hardware 'ticks': (clocks, interrupt sources...)
1070     *
1071 dpavlin 28 * Here, cpu0instrs is the number of instructions executed on cpu0.
1072     *
1073     * TODO: This should be redesigned into some "mainbus" stuff instead!
1074 dpavlin 26 */
1075    
1076 dpavlin 28 machine->ninstrs += cpu0instrs;
1077 dpavlin 26
1078     for (te=0; te<machine->n_tick_entries; te++) {
1079     machine->ticks_till_next[te] -= cpu0instrs;
1080     if (machine->ticks_till_next[te] <= 0) {
1081     while (machine->ticks_till_next[te] <= 0) {
1082     machine->ticks_till_next[te] +=
1083     machine->ticks_reset_value[te];
1084     }
1085    
1086     machine->tick_func[te](cpus[0],
1087     machine->tick_extra[te]);
1088     }
1089     }
1090    
1091     /* Is any CPU still alive? */
1092     for (i=0; i<ncpus; i++)
1093     if (cpus[i]->running)
1094     return 1;
1095    
1096     return 0;
1097     }
1098    
1099    
1100     /*****************************************************************************/
1101    
1102    
1103     /*
1104 dpavlin 2 * machine_entry_new():
1105     *
1106     * This function creates a new machine_entry struct, and fills it with some
1107     * valid data; it is up to the caller to add additional data that weren't
1108 dpavlin 26 * passed as arguments to this function, such as alias names and machine
1109     * subtypes.
1110 dpavlin 2 */
1111 dpavlin 26 struct machine_entry *machine_entry_new(const char *name, int arch,
1112     int oldstyle_type)
1113 dpavlin 2 {
1114     struct machine_entry *me;
1115    
1116     me = malloc(sizeof(struct machine_entry));
1117     if (me == NULL) {
1118     fprintf(stderr, "machine_entry_new(): out of memory (1)\n");
1119     exit(1);
1120     }
1121    
1122     memset(me, 0, sizeof(struct machine_entry));
1123    
1124     me->name = name;
1125     me->arch = arch;
1126     me->machine_type = oldstyle_type;
1127 dpavlin 26 me->n_aliases = 0;
1128     me->aliases = NULL;
1129     me->n_subtypes = 0;
1130     me->setup = NULL;
1131    
1132     return me;
1133     }
1134    
1135    
1136     /*
1137     * machine_entry_add_alias():
1138     *
1139     * This function adds an "alias" to a machine entry.
1140     */
1141     void machine_entry_add_alias(struct machine_entry *me, const char *name)
1142     {
1143     me->n_aliases ++;
1144     me->aliases = realloc(me->aliases, sizeof(char *) * me->n_aliases);
1145 dpavlin 2 if (me->aliases == NULL) {
1146 dpavlin 26 fprintf(stderr, "out of memory\n");
1147 dpavlin 2 exit(1);
1148     }
1149    
1150 dpavlin 26 me->aliases[me->n_aliases - 1] = (char *) name;
1151 dpavlin 2 }
1152    
1153    
1154     /*
1155 dpavlin 26 * machine_entry_add_subtype():
1156 dpavlin 2 *
1157 dpavlin 26 * This function adds a subtype to a machine entry. The argument list after
1158     * oldstyle_subtype is a list of one or more char *, followed by NULL. E.g.:
1159 dpavlin 2 *
1160 dpavlin 26 * machine_entry_add_subtype(me, "Machine X", MACHINE_X,
1161     * "machine-x", "x", NULL);
1162 dpavlin 2 */
1163 dpavlin 26 void machine_entry_add_subtype(struct machine_entry *me, const char *name,
1164     int oldstyle_subtype, ...)
1165 dpavlin 2 {
1166 dpavlin 26 va_list argp;
1167 dpavlin 2 struct machine_entry_subtype *mes;
1168    
1169 dpavlin 26 /* Allocate a new subtype struct: */
1170 dpavlin 2 mes = malloc(sizeof(struct machine_entry_subtype));
1171     if (mes == NULL) {
1172     fprintf(stderr, "machine_entry_subtype_new(): out "
1173     "of memory (1)\n");
1174     exit(1);
1175     }
1176    
1177 dpavlin 26 /* Add the subtype to the machine entry: */
1178     me->n_subtypes ++;
1179     me->subtype = realloc(me->subtype, sizeof(struct
1180     machine_entry_subtype *) * me->n_subtypes);
1181     if (me->subtype == NULL) {
1182     fprintf(stderr, "out of memory\n");
1183     exit(1);
1184     }
1185     me->subtype[me->n_subtypes - 1] = mes;
1186    
1187     /* Fill the struct with subtype data: */
1188 dpavlin 2 memset(mes, 0, sizeof(struct machine_entry_subtype));
1189     mes->name = name;
1190 dpavlin 26 mes->machine_subtype = oldstyle_subtype;
1191    
1192     /* ... and all aliases: */
1193     mes->n_aliases = 0;
1194     mes->aliases = NULL;
1195    
1196     va_start(argp, oldstyle_subtype);
1197    
1198     for (;;) {
1199     char *s = va_arg(argp, char *);
1200     if (s == NULL)
1201     break;
1202    
1203     mes->n_aliases ++;
1204     mes->aliases = realloc(mes->aliases, sizeof(char *) *
1205     mes->n_aliases);
1206     if (mes->aliases == NULL) {
1207     fprintf(stderr, "out of memory\n");
1208     exit(1);
1209     }
1210    
1211     mes->aliases[mes->n_aliases - 1] = s;
1212 dpavlin 2 }
1213    
1214 dpavlin 26 va_end(argp);
1215 dpavlin 2 }
1216    
1217    
1218     /*
1219 dpavlin 26 * machine_entry_register():
1220 dpavlin 22 *
1221     * Inserts a new machine_entry into the machine entries list.
1222     */
1223 dpavlin 26 void machine_entry_register(struct machine_entry *me, int arch)
1224 dpavlin 22 {
1225     struct machine_entry *prev, *next;
1226    
1227     /* Only insert it if the architecture is implemented in this
1228     emulator configuration: */
1229     if (cpu_family_ptr_by_number(arch) == NULL)
1230     return;
1231    
1232     prev = NULL;
1233     next = first_machine_entry;
1234    
1235     for (;;) {
1236     if (next == NULL)
1237     break;
1238     if (strcasecmp(me->name, next->name) < 0)
1239     break;
1240    
1241     prev = next;
1242     next = next->next;
1243     }
1244    
1245     if (prev != NULL)
1246     prev->next = me;
1247     else
1248     first_machine_entry = me;
1249     me->next = next;
1250     }
1251    
1252    
1253     /*
1254 dpavlin 2 * machine_list_available_types_and_cpus():
1255     *
1256     * List all available machine types (for example when running the emulator
1257     * with just -H as command line argument).
1258     */
1259     void machine_list_available_types_and_cpus(void)
1260     {
1261     struct machine_entry *me;
1262 dpavlin 22 int iadd = DEBUG_INDENTATION * 2;
1263 dpavlin 2
1264     debug("Available CPU types:\n\n");
1265    
1266     debug_indentation(iadd);
1267     cpu_list_available_types();
1268     debug_indentation(-iadd);
1269    
1270     debug("\nMost of the CPU types are bogus, and not really implemented."
1271     " The main effect of\nselecting a specific CPU type is to choose "
1272     "what kind of 'id' it will have.\n\nAvailable machine types (with "
1273     "aliases) and their subtypes:\n\n");
1274    
1275     debug_indentation(iadd);
1276     me = first_machine_entry;
1277    
1278     if (me == NULL)
1279     fatal("No machines defined!\n");
1280    
1281     while (me != NULL) {
1282 dpavlin 22 int i, j, iadd = DEBUG_INDENTATION;
1283 dpavlin 2
1284 dpavlin 22 debug("%s [%s] (", me->name,
1285     cpu_family_ptr_by_number(me->arch)->name);
1286 dpavlin 2 for (i=0; i<me->n_aliases; i++)
1287     debug("%s\"%s\"", i? ", " : "", me->aliases[i]);
1288     debug(")\n");
1289    
1290     debug_indentation(iadd);
1291     for (i=0; i<me->n_subtypes; i++) {
1292     struct machine_entry_subtype *mes;
1293     mes = me->subtype[i];
1294     debug("- %s", mes->name);
1295     debug(" (");
1296     for (j=0; j<mes->n_aliases; j++)
1297     debug("%s\"%s\"", j? ", " : "",
1298     mes->aliases[j]);
1299     debug(")\n");
1300     }
1301     debug_indentation(-iadd);
1302    
1303     me = me->next;
1304     }
1305     debug_indentation(-iadd);
1306    
1307     debug("\nMost of the machine types are bogus too. Please read the "
1308 dpavlin 20 "GXemul documentation\nfor information about which machine types "
1309     "that actually work. Use the alias\nwhen selecting a machine type "
1310     "or subtype, not the real name.\n");
1311 dpavlin 2
1312 dpavlin 24 #ifdef UNSTABLE_DEVEL
1313 dpavlin 2 debug("\n");
1314    
1315     useremul_list_emuls();
1316 dpavlin 12 debug("Userland emulation works for programs with the complexity"
1317     " of Hello World,\nbut not much more.\n");
1318 dpavlin 24 #endif
1319 dpavlin 2 }
1320    
1321    
1322     /*
1323     * machine_init():
1324     *
1325     * This function should be called before any other machine_*() function
1326 dpavlin 22 * is used. automachine_init() registers all machines in src/machines/.
1327 dpavlin 2 */
1328     void machine_init(void)
1329     {
1330 dpavlin 22 if (first_machine_entry != NULL) {
1331     fatal("machine_init(): already called?\n");
1332     exit(1);
1333 dpavlin 14 }
1334    
1335 dpavlin 22 automachine_init();
1336 dpavlin 2 }
1337    

  ViewVC Help
Powered by ViewVC 1.1.26