/[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 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 27237 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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.664 2006/02/05 10:26:35 debug Exp $
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #ifdef SOLARIS
35 /* TODO: is this strings vs string separation really necessary? */
36 #include <strings.h>
37 #else
38 #include <string.h>
39 #endif
40 #include <time.h>
41 #include <unistd.h>
42
43 #include "arcbios.h"
44 #include "bus_isa.h"
45 #include "bus_pci.h"
46 #include "cpu.h"
47 #include "device.h"
48 #include "devices.h"
49 #include "diskimage.h"
50 #include "emul.h"
51 #include "machine.h"
52 #include "machine_interrupts.h"
53 #include "memory.h"
54 #include "misc.h"
55 #include "net.h"
56 #include "symbol.h"
57
58
59 /* See main.c: */
60 extern int quiet_mode;
61 extern int verbose;
62
63
64 /* This is initialized by machine_init(): */
65 struct machine_entry *first_machine_entry = NULL;
66
67
68 /*
69 * machine_new():
70 *
71 * Returns a reasonably initialized struct machine.
72 */
73 struct machine *machine_new(char *name, struct emul *emul)
74 {
75 struct machine *m;
76 m = malloc(sizeof(struct machine));
77 if (m == NULL) {
78 fprintf(stderr, "machine_new(): out of memory\n");
79 exit(1);
80 }
81
82 memset(m, 0, sizeof(struct machine));
83
84 /* Back pointer: */
85 m->emul = emul;
86
87 m->name = strdup(name);
88
89 /* Sane default values: */
90 m->serial_nr = 1;
91 m->machine_type = MACHINE_NONE;
92 m->machine_subtype = MACHINE_NONE;
93 #ifdef BINTRANS
94 m->bintrans_enable = 1;
95 m->old_bintrans_enable = 1;
96 #endif
97 m->arch_pagesize = 4096; /* Should be overriden in
98 emul.c for other pagesizes. */
99 m->dyntrans_alignment_check = 1;
100 m->prom_emulation = 1;
101 m->speed_tricks = 1;
102 m->byte_order_override = NO_BYTE_ORDER_OVERRIDE;
103 m->boot_kernel_filename = "";
104 m->boot_string_argument = NULL;
105 m->automatic_clock_adjustment = 1;
106 m->x11_scaledown = 1;
107 m->x11_scaleup = 1;
108 m->n_gfx_cards = 1;
109 m->dbe_on_nonexistant_memaccess = 1;
110 m->show_symbolic_register_names = 1;
111 m->bintrans_size = DEFAULT_BINTRANS_SIZE_IN_MB * 1048576;
112 symbol_init(&m->symbol_context);
113
114 return m;
115 }
116
117
118 /*
119 * machine_name_to_type():
120 *
121 * Take a type and a subtype as strings, and convert them into numeric
122 * values used internally throughout the code.
123 *
124 * Return value is 1 on success, 0 if there was no match.
125 * Also, any errors/warnings are printed using fatal()/debug().
126 */
127 int machine_name_to_type(char *stype, char *ssubtype,
128 int *type, int *subtype, int *arch)
129 {
130 struct machine_entry *me;
131 int i, j, k, nmatches = 0;
132
133 *type = MACHINE_NONE;
134 *subtype = 0;
135
136 /* Check stype, and optionally ssubtype: */
137 me = first_machine_entry;
138 while (me != NULL) {
139 for (i=0; i<me->n_aliases; i++)
140 if (strcasecmp(me->aliases[i], stype) == 0) {
141 /* Found a type: */
142 *type = me->machine_type;
143 *arch = me->arch;
144
145 if (me->n_subtypes == 0)
146 return 1;
147
148 /* Check for subtype: */
149 for (j=0; j<me->n_subtypes; j++)
150 for (k=0; k<me->subtype[j]->n_aliases;
151 k++)
152 if (strcasecmp(ssubtype,
153 me->subtype[j]->aliases[k]
154 ) == 0) {
155 *subtype = me->subtype[
156 j]->machine_subtype;
157 return 1;
158 }
159
160 fatal("Unknown subtype '%s' for emulation"
161 " '%s'\n", ssubtype, stype);
162 if (!ssubtype[0])
163 fatal("(Maybe you forgot the -e"
164 " command line option?)\n");
165 exit(1);
166 }
167
168 me = me->next;
169 }
170
171 /* Not found? Then just check ssubtype: */
172 me = first_machine_entry;
173 while (me != NULL) {
174 if (me->n_subtypes == 0) {
175 me = me->next;
176 continue;
177 }
178
179 /* Check for subtype: */
180 for (j=0; j<me->n_subtypes; j++)
181 for (k=0; k<me->subtype[j]->n_aliases; k++)
182 if (strcasecmp(ssubtype, me->subtype[j]->
183 aliases[k]) == 0) {
184 *type = me->machine_type;
185 *arch = me->arch;
186 *subtype = me->subtype[j]->
187 machine_subtype;
188 nmatches ++;
189 }
190
191 me = me->next;
192 }
193
194 switch (nmatches) {
195 case 0: fatal("\nSorry, emulation \"%s\"", stype);
196 if (ssubtype != NULL && ssubtype[0] != '\0')
197 fatal(" (subtype \"%s\")", ssubtype);
198 fatal(" is unknown.\n");
199 break;
200 case 1: return 1;
201 default:fatal("\nSorry, multiple matches for \"%s\"", stype);
202 if (ssubtype != NULL && ssubtype[0] != '\0')
203 fatal(" (subtype \"%s\")", ssubtype);
204 fatal(".\n");
205 }
206
207 *type = MACHINE_NONE;
208 *subtype = 0;
209
210 fatal("Use the -H command line option to get a list of "
211 "available types and subtypes.\n\n");
212
213 return 0;
214 }
215
216
217 /*
218 * machine_add_tickfunction():
219 *
220 * Adds a tick function (a function called every now and then, depending on
221 * clock cycle count) to a machine.
222 */
223 void machine_add_tickfunction(struct machine *machine, void (*func)
224 (struct cpu *, void *), void *extra, int clockshift)
225 {
226 int n = machine->n_tick_entries;
227
228 if (n >= MAX_TICK_FUNCTIONS) {
229 fprintf(stderr, "machine_add_tickfunction(): too "
230 "many tick functions\n");
231 exit(1);
232 }
233
234 /* Don't use too low clockshifts, that would be too inefficient
235 with bintrans. */
236 if (clockshift < N_SAFE_BINTRANS_LIMIT_SHIFT)
237 fatal("WARNING! clockshift = %i, less than "
238 "N_SAFE_BINTRANS_LIMIT_SHIFT (%i)\n",
239 clockshift, N_SAFE_BINTRANS_LIMIT_SHIFT);
240
241 machine->ticks_till_next[n] = 0;
242 machine->ticks_reset_value[n] = 1 << clockshift;
243 machine->tick_func[n] = func;
244 machine->tick_extra[n] = extra;
245
246 machine->n_tick_entries ++;
247 }
248
249
250 /*
251 * machine_bus_register():
252 *
253 * Registers a bus in a machine.
254 */
255 void machine_bus_register(struct machine *machine, char *busname,
256 void (*debug_dump)(void *), void *extra)
257 {
258 struct machine_bus *tmp, *last = NULL, *new;
259
260 new = zeroed_alloc(sizeof(struct machine_bus));
261 new->name = strdup(busname);
262 new->debug_dump = debug_dump;
263 new->extra = extra;
264
265 /* Register last in the bus list: */
266 tmp = machine->first_bus;
267 while (tmp != NULL) {
268 last = tmp;
269 tmp = tmp->next;
270 }
271
272 if (last == NULL)
273 machine->first_bus = new;
274 else
275 last->next = new;
276
277 machine->n_busses ++;
278 }
279
280
281 /*
282 * machine_dump_bus_info():
283 *
284 * Dumps info about registered busses.
285 */
286 void machine_dump_bus_info(struct machine *m)
287 {
288 struct machine_bus *bus = m->first_bus;
289 int iadd = DEBUG_INDENTATION;
290
291 if (m->n_busses > 0)
292 debug("busses:\n");
293 debug_indentation(iadd);
294 while (bus != NULL) {
295 bus->debug_dump(bus->extra);
296 bus = bus->next;
297 }
298 debug_indentation(-iadd);
299 }
300
301
302 /*
303 * machine_dumpinfo():
304 *
305 * Dumps info about a machine in some kind of readable format. (Used by
306 * the 'machine' debugger command.)
307 */
308 void machine_dumpinfo(struct machine *m)
309 {
310 int i;
311
312 debug("serial nr: %i", m->serial_nr);
313 if (m->nr_of_nics > 0)
314 debug(" (nr of NICs: %i)", m->nr_of_nics);
315 debug("\n");
316
317 debug("memory: %i MB", m->physical_ram_in_mb);
318 if (m->memory_offset_in_mb != 0)
319 debug(" (offset by %i MB)", m->memory_offset_in_mb);
320 if (m->random_mem_contents)
321 debug(", randomized contents");
322 if (m->dbe_on_nonexistant_memaccess)
323 debug(", dbe_on_nonexistant_memaccess");
324 debug("\n");
325
326 if (m->single_step_on_bad_addr)
327 debug("single-step on bad addresses\n");
328
329 if (m->arch == ARCH_MIPS) {
330 if (m->bintrans_enable)
331 debug("bintrans enabled (%i MB cache)\n",
332 (int) (m->bintrans_size / 1048576));
333 else
334 debug("bintrans disabled, other speedtricks %s\n",
335 m->speed_tricks? "enabled" : "disabled");
336 }
337
338 debug("clock: ");
339 if (m->automatic_clock_adjustment)
340 debug("adjusted automatically");
341 else
342 debug("fixed at %i Hz", m->emulated_hz);
343 debug("\n");
344
345 if (!m->prom_emulation)
346 debug("PROM emulation disabled\n");
347
348 for (i=0; i<m->ncpus; i++)
349 cpu_dumpinfo(m, m->cpus[i]);
350
351 if (m->ncpus > 1)
352 debug("Bootstrap cpu is nr %i\n", m->bootstrap_cpu);
353
354 if (m->slow_serial_interrupts_hack_for_linux)
355 debug("Using slow_serial_interrupts_hack_for_linux\n");
356
357 if (m->use_x11) {
358 debug("Using X11");
359 if (m->x11_scaledown > 1)
360 debug(", scaledown %i", m->x11_scaledown);
361 if (m->x11_scaleup > 1)
362 debug(", scaleup %i", m->x11_scaleup);
363 if (m->x11_n_display_names > 0) {
364 for (i=0; i<m->x11_n_display_names; i++) {
365 debug(i? ", " : " (");
366 debug("\"%s\"", m->x11_display_names[i]);
367 }
368 debug(")");
369 }
370 debug("\n");
371 }
372
373 machine_dump_bus_info(m);
374
375 diskimage_dump_info(m);
376
377 if (m->force_netboot)
378 debug("Forced netboot\n");
379 }
380
381
382 /*
383 * dump_mem_string():
384 *
385 * Dump the contents of emulated RAM as readable text. Bytes that aren't
386 * readable are dumped in [xx] notation, where xx is in hexadecimal.
387 * Dumping ends after DUMP_MEM_STRING_MAX bytes, or when a terminating
388 * zero byte is found.
389 */
390 #define DUMP_MEM_STRING_MAX 45
391 void dump_mem_string(struct cpu *cpu, uint64_t addr)
392 {
393 int i;
394 for (i=0; i<DUMP_MEM_STRING_MAX; i++) {
395 unsigned char ch = '\0';
396
397 cpu->memory_rw(cpu, cpu->mem, addr + i, &ch, sizeof(ch),
398 MEM_READ, CACHE_DATA | NO_EXCEPTIONS);
399 if (ch == '\0')
400 return;
401 if (ch >= ' ' && ch < 126)
402 debug("%c", ch);
403 else
404 debug("[%02x]", ch);
405 }
406 }
407
408
409 /*
410 * store_byte():
411 *
412 * Stores a byte in emulated ram. (Helper function.)
413 */
414 void store_byte(struct cpu *cpu, uint64_t addr, uint8_t data)
415 {
416 if ((addr >> 32) == 0)
417 addr = (int64_t)(int32_t)addr;
418 cpu->memory_rw(cpu, cpu->mem,
419 addr, &data, sizeof(data), MEM_WRITE, CACHE_DATA);
420 }
421
422
423 /*
424 * store_string():
425 *
426 * Stores chars into emulated RAM until a zero byte (string terminating
427 * character) is found. The zero byte is also copied.
428 * (strcpy()-like helper function, host-RAM-to-emulated-RAM.)
429 */
430 void store_string(struct cpu *cpu, uint64_t addr, char *s)
431 {
432 do {
433 store_byte(cpu, addr++, *s);
434 } while (*s++);
435 }
436
437
438 /*
439 * add_environment_string():
440 *
441 * Like store_string(), but advances the pointer afterwards. The most
442 * obvious use is to place a number of strings (such as environment variable
443 * strings) after one-another in emulated memory.
444 */
445 void add_environment_string(struct cpu *cpu, char *s, uint64_t *addr)
446 {
447 store_string(cpu, *addr, s);
448 (*addr) += strlen(s) + 1;
449 }
450
451
452 /*
453 * add_environment_string_dual():
454 *
455 * Add "dual" environment strings, one for the variable name and one for the
456 * value, and update pointers afterwards.
457 */
458 void add_environment_string_dual(struct cpu *cpu,
459 uint64_t *ptrp, uint64_t *addrp, char *s1, char *s2)
460 {
461 uint64_t ptr = *ptrp, addr = *addrp;
462
463 store_32bit_word(cpu, ptr, addr);
464 ptr += sizeof(uint32_t);
465 if (addr != 0) {
466 store_string(cpu, addr, s1);
467 addr += strlen(s1) + 1;
468 }
469 store_32bit_word(cpu, ptr, addr);
470 ptr += sizeof(uint32_t);
471 if (addr != 0) {
472 store_string(cpu, addr, s2);
473 addr += strlen(s2) + 1;
474 }
475
476 *ptrp = ptr;
477 *addrp = addr;
478 }
479
480
481 /*
482 * store_64bit_word():
483 *
484 * Stores a 64-bit word in emulated RAM. Byte order is taken into account.
485 * Helper function.
486 */
487 int store_64bit_word(struct cpu *cpu, uint64_t addr, uint64_t data64)
488 {
489 unsigned char data[8];
490 if ((addr >> 32) == 0)
491 addr = (int64_t)(int32_t)addr;
492 data[0] = (data64 >> 56) & 255;
493 data[1] = (data64 >> 48) & 255;
494 data[2] = (data64 >> 40) & 255;
495 data[3] = (data64 >> 32) & 255;
496 data[4] = (data64 >> 24) & 255;
497 data[5] = (data64 >> 16) & 255;
498 data[6] = (data64 >> 8) & 255;
499 data[7] = (data64) & 255;
500 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
501 int tmp = data[0]; data[0] = data[7]; data[7] = tmp;
502 tmp = data[1]; data[1] = data[6]; data[6] = tmp;
503 tmp = data[2]; data[2] = data[5]; data[5] = tmp;
504 tmp = data[3]; data[3] = data[4]; data[4] = tmp;
505 }
506 return cpu->memory_rw(cpu, cpu->mem,
507 addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
508 }
509
510
511 /*
512 * store_32bit_word():
513 *
514 * Stores a 32-bit word in emulated RAM. Byte order is taken into account.
515 * (This function takes a 64-bit word as argument, to suppress some
516 * warnings, but only the lowest 32 bits are used.)
517 */
518 int store_32bit_word(struct cpu *cpu, uint64_t addr, uint64_t data32)
519 {
520 unsigned char data[4];
521 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
522 addr = (int64_t)(int32_t)addr;
523 data[0] = (data32 >> 24) & 255;
524 data[1] = (data32 >> 16) & 255;
525 data[2] = (data32 >> 8) & 255;
526 data[3] = (data32) & 255;
527 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
528 int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
529 tmp = data[1]; data[1] = data[2]; data[2] = tmp;
530 }
531 return cpu->memory_rw(cpu, cpu->mem,
532 addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
533 }
534
535
536 /*
537 * store_16bit_word():
538 *
539 * Stores a 16-bit word in emulated RAM. Byte order is taken into account.
540 * (This function takes a 64-bit word as argument, to suppress some
541 * warnings, but only the lowest 16 bits are used.)
542 */
543 int store_16bit_word(struct cpu *cpu, uint64_t addr, uint64_t data16)
544 {
545 unsigned char data[2];
546 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
547 addr = (int64_t)(int32_t)addr;
548 data[0] = (data16 >> 8) & 255;
549 data[1] = (data16) & 255;
550 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
551 int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
552 }
553 return cpu->memory_rw(cpu, cpu->mem,
554 addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
555 }
556
557
558 /*
559 * store_buf():
560 *
561 * memcpy()-like helper function, from host RAM to emulated RAM.
562 */
563 void store_buf(struct cpu *cpu, uint64_t addr, char *s, size_t len)
564 {
565 size_t psize = 1024; /* 1024 256 64 16 4 1 */
566
567 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
568 addr = (int64_t)(int32_t)addr;
569
570 while (len != 0) {
571 if ((addr & (psize-1)) == 0) {
572 while (len >= psize) {
573 cpu->memory_rw(cpu, cpu->mem, addr,
574 (unsigned char *)s, psize, MEM_WRITE,
575 CACHE_DATA);
576 addr += psize;
577 s += psize;
578 len -= psize;
579 }
580 }
581 psize >>= 2;
582 }
583
584 while (len-- != 0)
585 store_byte(cpu, addr++, *s++);
586 }
587
588
589 /*
590 * store_pointer_and_advance():
591 *
592 * Stores a 32-bit or 64-bit pointer in emulated RAM, and advances the
593 * target address. (Useful for e.g. ARCBIOS environment initialization.)
594 */
595 void store_pointer_and_advance(struct cpu *cpu, uint64_t *addrp,
596 uint64_t data, int flag64)
597 {
598 uint64_t addr = *addrp;
599 if (flag64) {
600 store_64bit_word(cpu, addr, data);
601 addr += 8;
602 } else {
603 store_32bit_word(cpu, addr, data);
604 addr += 4;
605 }
606 *addrp = addr;
607 }
608
609
610 /*
611 * load_32bit_word():
612 *
613 * Helper function. Prints a warning and returns 0, if the read failed.
614 * Emulated byte order is taken into account.
615 */
616 uint32_t load_32bit_word(struct cpu *cpu, uint64_t addr)
617 {
618 unsigned char data[4];
619
620 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
621 addr = (int64_t)(int32_t)addr;
622 cpu->memory_rw(cpu, cpu->mem,
623 addr, data, sizeof(data), MEM_READ, CACHE_DATA);
624
625 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
626 int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
627 tmp = data[1]; data[1] = data[2]; data[2] = tmp;
628 }
629
630 return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3];
631 }
632
633
634 /*
635 * load_16bit_word():
636 *
637 * Helper function. Prints a warning and returns 0, if the read failed.
638 * Emulated byte order is taken into account.
639 */
640 uint16_t load_16bit_word(struct cpu *cpu, uint64_t addr)
641 {
642 unsigned char data[2];
643
644 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
645 addr = (int64_t)(int32_t)addr;
646 cpu->memory_rw(cpu, cpu->mem,
647 addr, data, sizeof(data), MEM_READ, CACHE_DATA);
648
649 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
650 int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
651 }
652
653 return (data[0] << 8) + data[1];
654 }
655
656
657 /*
658 * store_64bit_word_in_host():
659 *
660 * Stores a 64-bit word in the _host's_ RAM. Emulated byte order is taken
661 * into account. This is useful when building structs in the host's RAM
662 * which will later be copied into emulated RAM.
663 */
664 void store_64bit_word_in_host(struct cpu *cpu,
665 unsigned char *data, uint64_t data64)
666 {
667 data[0] = (data64 >> 56) & 255;
668 data[1] = (data64 >> 48) & 255;
669 data[2] = (data64 >> 40) & 255;
670 data[3] = (data64 >> 32) & 255;
671 data[4] = (data64 >> 24) & 255;
672 data[5] = (data64 >> 16) & 255;
673 data[6] = (data64 >> 8) & 255;
674 data[7] = (data64) & 255;
675 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
676 int tmp = data[0]; data[0] = data[7]; data[7] = tmp;
677 tmp = data[1]; data[1] = data[6]; data[6] = tmp;
678 tmp = data[2]; data[2] = data[5]; data[5] = tmp;
679 tmp = data[3]; data[3] = data[4]; data[4] = tmp;
680 }
681 }
682
683
684 /*
685 * store_32bit_word_in_host():
686 *
687 * See comment for store_64bit_word_in_host().
688 *
689 * (Note: The data32 parameter is a uint64_t. This is done to suppress
690 * some warnings.)
691 */
692 void store_32bit_word_in_host(struct cpu *cpu,
693 unsigned char *data, uint64_t data32)
694 {
695 data[0] = (data32 >> 24) & 255;
696 data[1] = (data32 >> 16) & 255;
697 data[2] = (data32 >> 8) & 255;
698 data[3] = (data32) & 255;
699 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
700 int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
701 tmp = data[1]; data[1] = data[2]; data[2] = tmp;
702 }
703 }
704
705
706 /*
707 * store_16bit_word_in_host():
708 *
709 * See comment for store_64bit_word_in_host().
710 */
711 void store_16bit_word_in_host(struct cpu *cpu,
712 unsigned char *data, uint16_t data16)
713 {
714 data[0] = (data16 >> 8) & 255;
715 data[1] = (data16) & 255;
716 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
717 int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
718 }
719 }
720
721
722 /*
723 * machine_setup():
724 *
725 * This (rather large) function initializes memory, registers, and/or devices
726 * required by specific machine emulations.
727 */
728 void machine_setup(struct machine *machine)
729 {
730 struct memory *mem;
731 struct machine_entry *me;
732
733 /* Abreviation: :-) */
734 struct cpu *cpu = machine->cpus[machine->bootstrap_cpu];
735
736 machine->bootdev_id = diskimage_bootdev(machine,
737 &machine->bootdev_type);
738
739 mem = cpu->mem;
740 machine->machine_name = NULL;
741
742 /* TODO: Move this somewhere else? */
743 if (machine->boot_string_argument == NULL) {
744 switch (machine->machine_type) {
745 case MACHINE_ARC:
746 machine->boot_string_argument = "-aN";
747 break;
748 case MACHINE_CATS:
749 machine->boot_string_argument = "-A";
750 break;
751 case MACHINE_PMAX:
752 machine->boot_string_argument = "-a";
753 break;
754 default:
755 /* Important, because boot_string_argument should
756 not be set to NULL: */
757 machine->boot_string_argument = "";
758 }
759 }
760
761
762 /*
763 * If the machine has a setup function in src/machines/machine_*.c
764 * then use that one, otherwise use the old hardcoded stuff here:
765 */
766
767 me = first_machine_entry;
768 while (me != NULL) {
769 if (machine->machine_type == me->machine_type &&
770 me->setup != NULL) {
771 me->setup(machine, cpu);
772 break;
773 }
774 me = me->next;
775 }
776
777 if (me == NULL) {
778 fatal("Unknown emulation type %i\n", machine->machine_type);
779 exit(1);
780 }
781
782 if (machine->machine_name != NULL)
783 debug("machine: %s", machine->machine_name);
784
785 if (machine->emulated_hz > 0)
786 debug(" (%.2f MHz)", (float)machine->emulated_hz / 1000000);
787 debug("\n");
788
789 /* Default fake speed: 5 MHz */
790 if (machine->emulated_hz < 1)
791 machine->emulated_hz = 5000000;
792
793 if (machine->bootstr != NULL) {
794 debug("bootstring%s: %s", (machine->bootarg!=NULL &&
795 strlen(machine->bootarg) >= 1)? "(+bootarg)" : "",
796 machine->bootstr);
797 if (machine->bootarg != NULL && strlen(machine->bootarg) >= 1)
798 debug(" %s", machine->bootarg);
799 debug("\n");
800 }
801
802 if (verbose >= 2)
803 machine_dump_bus_info(machine);
804
805 if (!machine->stable)
806 fatal("!\n! NOTE: This machine type is not implemented well"
807 " enough yet to run\n! any real-world code!"
808 " (At least, it hasn't been verified to do so.)\n!\n"
809 "! Please read the GXemul documentation for information"
810 " about which\n! machine types that actually work.\n!\n");
811 }
812
813
814 /*
815 * machine_memsize_fix():
816 *
817 * Sets physical_ram_in_mb (if not already set), and memory_offset_in_mb,
818 * depending on machine type.
819 */
820 void machine_memsize_fix(struct machine *m)
821 {
822 if (m == NULL) {
823 fatal("machine_defaultmemsize(): m == NULL?\n");
824 exit(1);
825 }
826
827 if (m->physical_ram_in_mb == 0) {
828 struct machine_entry *me = first_machine_entry;
829 while (me != NULL) {
830 if (m->machine_type == me->machine_type &&
831 me->set_default_ram != NULL) {
832 me->set_default_ram(m);
833 break;
834 }
835 me = me->next;
836 }
837 }
838
839 /* Special hack for hpcmips machines: */
840 if (m->machine_type == MACHINE_HPCMIPS) {
841 m->dbe_on_nonexistant_memaccess = 0;
842 }
843
844 /* Special SGI memory offsets: (TODO: move this somewhere else) */
845 if (m->machine_type == MACHINE_SGI) {
846 switch (m->machine_subtype) {
847 case 20:
848 case 22:
849 case 24:
850 case 26:
851 m->memory_offset_in_mb = 128;
852 break;
853 case 28:
854 case 30:
855 m->memory_offset_in_mb = 512;
856 break;
857 }
858 }
859
860 if (m->physical_ram_in_mb == 0)
861 m->physical_ram_in_mb = DEFAULT_RAM_IN_MB;
862 }
863
864
865 /*
866 * machine_default_cputype():
867 *
868 * Sets m->cpu_name, if it isn't already set, depending on the machine type.
869 */
870 void machine_default_cputype(struct machine *m)
871 {
872 struct machine_entry *me;
873
874 if (m == NULL) {
875 fatal("machine_default_cputype(): m == NULL?\n");
876 exit(1);
877 }
878
879 /* Already set? Then return. */
880 if (m->cpu_name != NULL)
881 return;
882
883 me = first_machine_entry;
884 while (me != NULL) {
885 if (m->machine_type == me->machine_type &&
886 me->set_default_cpu != NULL) {
887 me->set_default_cpu(m);
888 break;
889 }
890 me = me->next;
891 }
892
893 if (m->cpu_name == NULL) {
894 fprintf(stderr, "machine_default_cputype(): no default"
895 " cpu for machine type %i subtype %i\n",
896 m->machine_type, m->machine_subtype);
897 exit(1);
898 }
899 }
900
901
902 /*
903 * machine_entry_new():
904 *
905 * This function creates a new machine_entry struct, and fills it with some
906 * valid data; it is up to the caller to add additional data that weren't
907 * passed as arguments to this function.
908 */
909 struct machine_entry *machine_entry_new(const char *name,
910 int arch, int oldstyle_type, int n_aliases, int n_subtypes)
911 {
912 struct machine_entry *me;
913
914 me = malloc(sizeof(struct machine_entry));
915 if (me == NULL) {
916 fprintf(stderr, "machine_entry_new(): out of memory (1)\n");
917 exit(1);
918 }
919
920 memset(me, 0, sizeof(struct machine_entry));
921
922 me->name = name;
923 me->arch = arch;
924 me->machine_type = oldstyle_type;
925 me->n_aliases = n_aliases;
926 me->aliases = malloc(sizeof(char *) * n_aliases);
927 if (me->aliases == NULL) {
928 fprintf(stderr, "machine_entry_new(): out of memory (2)\n");
929 exit(1);
930 }
931 me->n_subtypes = n_subtypes;
932 me->setup = NULL;
933
934 if (n_subtypes > 0) {
935 me->subtype = malloc(sizeof(struct machine_entry_subtype *) *
936 n_subtypes);
937 if (me->subtype == NULL) {
938 fprintf(stderr, "machine_entry_new(): out of "
939 "memory (3)\n");
940 exit(1);
941 }
942 }
943
944 return me;
945 }
946
947
948 /*
949 * machine_entry_subtype_new():
950 *
951 * This function creates a new machine_entry_subtype struct, and fills it with
952 * some valid data; it is up to the caller to add additional data that weren't
953 * passed as arguments to this function.
954 *
955 * For internal use.
956 */
957 struct machine_entry_subtype *machine_entry_subtype_new(
958 const char *name, int oldstyle_type, int n_aliases)
959 {
960 struct machine_entry_subtype *mes;
961
962 mes = malloc(sizeof(struct machine_entry_subtype));
963 if (mes == NULL) {
964 fprintf(stderr, "machine_entry_subtype_new(): out "
965 "of memory (1)\n");
966 exit(1);
967 }
968
969 memset(mes, 0, sizeof(struct machine_entry_subtype));
970 mes->name = name;
971 mes->machine_subtype = oldstyle_type;
972 mes->n_aliases = n_aliases;
973 mes->aliases = malloc(sizeof(char *) * n_aliases);
974 if (mes->aliases == NULL) {
975 fprintf(stderr, "machine_entry_subtype_new(): "
976 "out of memory (2)\n");
977 exit(1);
978 }
979
980 return mes;
981 }
982
983
984 /*
985 * machine_entry_add():
986 *
987 * Inserts a new machine_entry into the machine entries list.
988 */
989 void machine_entry_add(struct machine_entry *me, int arch)
990 {
991 struct machine_entry *prev, *next;
992
993 /* Only insert it if the architecture is implemented in this
994 emulator configuration: */
995 if (cpu_family_ptr_by_number(arch) == NULL)
996 return;
997
998 prev = NULL;
999 next = first_machine_entry;
1000
1001 for (;;) {
1002 if (next == NULL)
1003 break;
1004 if (strcasecmp(me->name, next->name) < 0)
1005 break;
1006
1007 prev = next;
1008 next = next->next;
1009 }
1010
1011 if (prev != NULL)
1012 prev->next = me;
1013 else
1014 first_machine_entry = me;
1015 me->next = next;
1016 }
1017
1018
1019 /*
1020 * machine_list_available_types_and_cpus():
1021 *
1022 * List all available machine types (for example when running the emulator
1023 * with just -H as command line argument).
1024 */
1025 void machine_list_available_types_and_cpus(void)
1026 {
1027 struct machine_entry *me;
1028 int iadd = DEBUG_INDENTATION * 2;
1029
1030 debug("Available CPU types:\n\n");
1031
1032 debug_indentation(iadd);
1033 cpu_list_available_types();
1034 debug_indentation(-iadd);
1035
1036 debug("\nMost of the CPU types are bogus, and not really implemented."
1037 " The main effect of\nselecting a specific CPU type is to choose "
1038 "what kind of 'id' it will have.\n\nAvailable machine types (with "
1039 "aliases) and their subtypes:\n\n");
1040
1041 debug_indentation(iadd);
1042 me = first_machine_entry;
1043
1044 if (me == NULL)
1045 fatal("No machines defined!\n");
1046
1047 while (me != NULL) {
1048 int i, j, iadd = DEBUG_INDENTATION;
1049
1050 debug("%s [%s] (", me->name,
1051 cpu_family_ptr_by_number(me->arch)->name);
1052 for (i=0; i<me->n_aliases; i++)
1053 debug("%s\"%s\"", i? ", " : "", me->aliases[i]);
1054 debug(")\n");
1055
1056 debug_indentation(iadd);
1057 for (i=0; i<me->n_subtypes; i++) {
1058 struct machine_entry_subtype *mes;
1059 mes = me->subtype[i];
1060 debug("- %s", mes->name);
1061 debug(" (");
1062 for (j=0; j<mes->n_aliases; j++)
1063 debug("%s\"%s\"", j? ", " : "",
1064 mes->aliases[j]);
1065 debug(")\n");
1066 }
1067 debug_indentation(-iadd);
1068
1069 me = me->next;
1070 }
1071 debug_indentation(-iadd);
1072
1073 debug("\nMost of the machine types are bogus too. Please read the "
1074 "GXemul documentation\nfor information about which machine types "
1075 "that actually work. Use the alias\nwhen selecting a machine type "
1076 "or subtype, not the real name.\n");
1077
1078 debug("\n");
1079
1080 useremul_list_emuls();
1081 debug("Userland emulation works for programs with the complexity"
1082 " of Hello World,\nbut not much more.\n");
1083 }
1084
1085
1086 /*
1087 * machine_init():
1088 *
1089 * This function should be called before any other machine_*() function
1090 * is used. automachine_init() registers all machines in src/machines/.
1091 */
1092 void machine_init(void)
1093 {
1094 if (first_machine_entry != NULL) {
1095 fatal("machine_init(): already called?\n");
1096 exit(1);
1097 }
1098
1099 automachine_init();
1100 }
1101

  ViewVC Help
Powered by ViewVC 1.1.26