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

Contents of /trunk/src/machine.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (show 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 /*
2 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: machine.c,v 1.689 2006/10/04 11:56:40 debug Exp $
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #include <string.h>
35 #include <time.h>
36 #include <unistd.h>
37
38 #include "arcbios.h"
39 #include "bus_isa.h"
40 #include "bus_pci.h"
41 #include "cpu.h"
42 #include "debugger.h"
43 #include "device.h"
44 #include "devices.h"
45 #include "diskimage.h"
46 #include "emul.h"
47 #include "machine.h"
48 #include "machine_interrupts.h"
49 #include "memory.h"
50 #include "misc.h"
51 #include "net.h"
52 #include "settings.h"
53 #include "symbol.h"
54
55
56 /* See main.c: */
57 extern int quiet_mode;
58 extern int verbose;
59
60
61 /* This is initialized by machine_init(): */
62 struct machine_entry *first_machine_entry = NULL;
63
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 /* Pointer back to the emul object that this machine belongs to: */
82 m->emul = emul;
83
84 m->name = strdup(name);
85
86 /* Sane default values: */
87 m->serial_nr = 1;
88 m->machine_type = MACHINE_NONE;
89 m->machine_subtype = MACHINE_NONE;
90 m->arch_pagesize = 4096; /* Should be overriden in
91 emul.c for other pagesizes. */
92 m->prom_emulation = 1;
93 m->allow_instruction_combinations = 1;
94 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 m->x11_scaleup = 1;
99 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 /* 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 return m;
132 }
133
134
135 /*
136 * 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 * 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 int i, j, k, nmatches = 0;
172
173 *type = MACHINE_NONE;
174 *subtype = 0;
175
176 /* Check stype, and optionally ssubtype: */
177 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 fatal("Unknown subtype '%s' for emulation"
201 " '%s'\n", ssubtype, stype);
202 if (!ssubtype[0])
203 fatal("(Maybe you forgot the -e"
204 " command line option?)\n");
205 exit(1);
206 }
207
208 me = me->next;
209 }
210
211 /* 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 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 *
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 */
269 void machine_add_tickfunction(struct machine *machine, void (*func)
270 (struct cpu *, void *), void *extra, int tickshift, double hz)
271 {
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 if (!machine->cycle_accurate) {
281 /*
282 * The dyntrans subsystem wants to run code in relatively
283 * large chunks without checking for external interrupts;
284 * too low tickshifts are not allowed.
285 */
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
294 machine->ticks_till_next[n] = 0;
295 machine->ticks_reset_value[n] = 1 << tickshift;
296 machine->tick_func[n] = func;
297 machine->tick_extra[n] = extra;
298 machine->tick_hz[n] = hz;
299
300 machine->n_tick_entries ++;
301 }
302
303
304 /*
305 * 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 * 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
387 new = zeroed_alloc(sizeof(struct machine_bus));
388 new->name = strdup(busname);
389 new->debug_dump = debug_dump;
390 new->extra = extra;
391
392 /* 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 {
415 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 }
427
428
429 /*
430 * 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 * 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 * 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 * 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
630 /* TODO: REMOVE THIS once everything is more stable! */
631 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
632 addr = (int64_t)(int32_t)addr;
633
634 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
658 /* TODO: REMOVE THIS once everything is more stable! */
659 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
660 addr = (int64_t)(int32_t)addr;
661
662 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 size_t psize = 1024; /* 1024 256 64 16 4 1 */
680
681 /* TODO: REMOVE THIS once everything is more stable! */
682 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
683 addr = (int64_t)(int32_t)addr;
684
685 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 }
696 psize >>= 2;
697 }
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 * target address. (Useful for e.g. ARCBIOS environment initialization.)
709 */
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 * 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 * load_32bit_word():
754 *
755 * Helper function. Emulated byte order is taken into account.
756 */
757 uint32_t load_32bit_word(struct cpu *cpu, uint64_t addr)
758 {
759 unsigned char data[4];
760
761 /* TODO: REMOVE THIS once everything is more stable! */
762 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
763 addr = (int64_t)(int32_t)addr;
764
765 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 * load_16bit_word():
779 *
780 * Helper function. Emulated byte order is taken into account.
781 */
782 uint16_t load_16bit_word(struct cpu *cpu, uint64_t addr)
783 {
784 unsigned char data[2];
785
786 /* TODO: REMOVE THIS once everything is more stable! */
787 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
788 addr = (int64_t)(int32_t)addr;
789
790 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 * 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 struct machine_entry *me;
876
877 /* Abreviation: :-) */
878 struct cpu *cpu = machine->cpus[machine->bootstrap_cpu];
879
880 machine->bootdev_id = diskimage_bootdev(machine,
881 &machine->bootdev_type);
882
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 case MACHINE_CATS:
893 machine->boot_string_argument = "-A";
894 break;
895 case MACHINE_PMAX:
896 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 /*
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
911 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 break;
917 }
918 me = me->next;
919 }
920
921 if (me == NULL) {
922 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 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 debug("\n");
940 }
941
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 }
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 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 break;
974 }
975 me = me->next;
976 }
977 }
978
979 /* Special hack for hpcmips machines: */
980 if (m->machine_type == MACHINE_HPCMIPS) {
981 m->dbe_on_nonexistant_memaccess = 0;
982 }
983
984 /* Special SGI memory offsets: (TODO: move this somewhere else) */
985 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 * Sets m->cpu_name, if it isn't already set, depending on the machine type.
1009 */
1010 void machine_default_cputype(struct machine *m)
1011 {
1012 struct machine_entry *me;
1013
1014 if (m == NULL) {
1015 fatal("machine_default_cputype(): m == NULL?\n");
1016 exit(1);
1017 }
1018
1019 /* Already set? Then return. */
1020 if (m->cpu_name != NULL)
1021 return;
1022
1023 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 break;
1029 }
1030 me = me->next;
1031 }
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 /*****************************************************************************/
1043
1044
1045 /*
1046 * 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 int instrs_run = cpus[i]->run_instr(cpus[i]);
1063 if (i == 0)
1064 cpu0instrs += instrs_run;
1065 }
1066 }
1067
1068 /*
1069 * Hardware 'ticks': (clocks, interrupt sources...)
1070 *
1071 * Here, cpu0instrs is the number of instructions executed on cpu0.
1072 *
1073 * TODO: This should be redesigned into some "mainbus" stuff instead!
1074 */
1075
1076 machine->ninstrs += cpu0instrs;
1077
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 * 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 * passed as arguments to this function, such as alias names and machine
1109 * subtypes.
1110 */
1111 struct machine_entry *machine_entry_new(const char *name, int arch,
1112 int oldstyle_type)
1113 {
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 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 if (me->aliases == NULL) {
1146 fprintf(stderr, "out of memory\n");
1147 exit(1);
1148 }
1149
1150 me->aliases[me->n_aliases - 1] = (char *) name;
1151 }
1152
1153
1154 /*
1155 * machine_entry_add_subtype():
1156 *
1157 * 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 *
1160 * machine_entry_add_subtype(me, "Machine X", MACHINE_X,
1161 * "machine-x", "x", NULL);
1162 */
1163 void machine_entry_add_subtype(struct machine_entry *me, const char *name,
1164 int oldstyle_subtype, ...)
1165 {
1166 va_list argp;
1167 struct machine_entry_subtype *mes;
1168
1169 /* Allocate a new subtype struct: */
1170 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 /* 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 memset(mes, 0, sizeof(struct machine_entry_subtype));
1189 mes->name = name;
1190 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 }
1213
1214 va_end(argp);
1215 }
1216
1217
1218 /*
1219 * machine_entry_register():
1220 *
1221 * Inserts a new machine_entry into the machine entries list.
1222 */
1223 void machine_entry_register(struct machine_entry *me, int arch)
1224 {
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 * 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 int iadd = DEBUG_INDENTATION * 2;
1263
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 int i, j, iadd = DEBUG_INDENTATION;
1283
1284 debug("%s [%s] (", me->name,
1285 cpu_family_ptr_by_number(me->arch)->name);
1286 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 "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
1312 #ifdef UNSTABLE_DEVEL
1313 debug("\n");
1314
1315 useremul_list_emuls();
1316 debug("Userland emulation works for programs with the complexity"
1317 " of Hello World,\nbut not much more.\n");
1318 #endif
1319 }
1320
1321
1322 /*
1323 * machine_init():
1324 *
1325 * This function should be called before any other machine_*() function
1326 * is used. automachine_init() registers all machines in src/machines/.
1327 */
1328 void machine_init(void)
1329 {
1330 if (first_machine_entry != NULL) {
1331 fatal("machine_init(): already called?\n");
1332 exit(1);
1333 }
1334
1335 automachine_init();
1336 }
1337

  ViewVC Help
Powered by ViewVC 1.1.26