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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26