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

Annotation of /trunk/src/cpu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (hide annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 16110 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

==============  RELEASE 0.4.1  ==============


1 dpavlin 2 /*
2 dpavlin 22 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 dpavlin 2 *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 28 * $Id: cpu.c,v 1.348 2006/07/20 21:52:59 debug Exp $
29 dpavlin 2 *
30     * Common routines for CPU emulation. (Not specific to any CPU type.)
31     */
32    
33     #include <stdio.h>
34     #include <stdlib.h>
35     #include <sys/types.h>
36 dpavlin 22 #include <sys/mman.h>
37 dpavlin 2 #include <string.h>
38    
39     #include "cpu.h"
40     #include "machine.h"
41 dpavlin 12 #include "memory.h"
42 dpavlin 2 #include "misc.h"
43    
44    
45     static struct cpu_family *first_cpu_family = NULL;
46    
47    
48     /*
49     * cpu_new():
50     *
51     * Create a new cpu object. Each family is tried in sequence until a
52     * CPU family recognizes the cpu_type_name.
53     */
54     struct cpu *cpu_new(struct memory *mem, struct machine *machine,
55     int cpu_id, char *name)
56     {
57 dpavlin 10 struct cpu *cpu;
58 dpavlin 2 struct cpu_family *fp;
59     char *cpu_type_name;
60    
61     if (name == NULL) {
62     fprintf(stderr, "cpu_new(): cpu name = NULL?\n");
63     exit(1);
64     }
65    
66     cpu_type_name = strdup(name);
67     if (cpu_type_name == NULL) {
68     fprintf(stderr, "cpu_new(): out of memory\n");
69     exit(1);
70     }
71    
72 dpavlin 12 cpu = zeroed_alloc(sizeof(struct cpu));
73 dpavlin 10
74     cpu->memory_rw = NULL;
75     cpu->name = cpu_type_name;
76     cpu->mem = mem;
77     cpu->machine = machine;
78     cpu->cpu_id = cpu_id;
79     cpu->byte_order = EMUL_LITTLE_ENDIAN;
80     cpu->bootstrap_cpu_flag = 0;
81     cpu->running = 0;
82    
83 dpavlin 12 cpu_create_or_reset_tc(cpu);
84    
85 dpavlin 2 fp = first_cpu_family;
86    
87     while (fp != NULL) {
88     if (fp->cpu_new != NULL) {
89 dpavlin 10 if (fp->cpu_new(cpu, mem, machine, cpu_id,
90     cpu_type_name)) {
91     /* Sanity check: */
92     if (cpu->memory_rw == NULL) {
93     fatal("\ncpu_new(): memory_rw == "
94     "NULL\n");
95 dpavlin 2 exit(1);
96     }
97 dpavlin 26 break;
98 dpavlin 2 }
99     }
100    
101     fp = fp->next;
102     }
103    
104 dpavlin 26 if (fp == NULL) {
105     fatal("\ncpu_new(): unknown cpu type '%s'\n", cpu_type_name);
106     return NULL;
107     }
108    
109     fp->init_tables(cpu);
110    
111     return cpu;
112 dpavlin 2 }
113    
114    
115     /*
116     * cpu_tlbdump():
117     *
118     * Called from the debugger to dump the TLB in a readable format.
119     * x is the cpu number to dump, or -1 to dump all CPUs.
120     *
121     * If rawflag is nonzero, then the TLB contents isn't formated nicely,
122     * just dumped.
123     */
124     void cpu_tlbdump(struct machine *m, int x, int rawflag)
125     {
126     if (m->cpu_family == NULL || m->cpu_family->tlbdump == NULL)
127     fatal("cpu_tlbdump(): NULL\n");
128     else
129     m->cpu_family->tlbdump(m, x, rawflag);
130     }
131    
132    
133     /*
134     * cpu_register_match():
135     *
136     * Used by the debugger.
137     */
138     void cpu_register_match(struct machine *m, char *name,
139     int writeflag, uint64_t *valuep, int *match_register)
140     {
141     if (m->cpu_family == NULL || m->cpu_family->register_match == NULL)
142     fatal("cpu_register_match(): NULL\n");
143     else
144     m->cpu_family->register_match(m, name, writeflag,
145     valuep, match_register);
146     }
147    
148    
149     /*
150     * cpu_disassemble_instr():
151     *
152     * Convert an instruction word into human readable format, for instruction
153     * tracing.
154     */
155     int cpu_disassemble_instr(struct machine *m, struct cpu *cpu,
156 dpavlin 24 unsigned char *instr, int running, uint64_t addr)
157 dpavlin 2 {
158     if (m->cpu_family == NULL || m->cpu_family->disassemble_instr == NULL) {
159     fatal("cpu_disassemble_instr(): NULL\n");
160     return 0;
161     } else
162     return m->cpu_family->disassemble_instr(cpu, instr,
163 dpavlin 24 running, addr);
164 dpavlin 2 }
165    
166    
167     /*
168     * cpu_register_dump():
169     *
170     * Dump cpu registers in a relatively readable format.
171     *
172 dpavlin 18 * gprs: set to non-zero to dump GPRs. (CPU dependent.)
173     * coprocs: set bit 0..x to dump registers in coproc 0..x. (CPU dependent.)
174 dpavlin 2 */
175     void cpu_register_dump(struct machine *m, struct cpu *cpu,
176     int gprs, int coprocs)
177     {
178     if (m->cpu_family == NULL || m->cpu_family->register_dump == NULL)
179     fatal("cpu_register_dump(): NULL\n");
180     else
181     m->cpu_family->register_dump(cpu, gprs, coprocs);
182     }
183    
184    
185     /*
186 dpavlin 24 * cpu_gdb_stub():
187     *
188     * Execute a "remote GDB" command. Return value is a pointer to a newly
189     * allocated response string, if the command was successfully executed. If
190     * there was an error, NULL is returned.
191     */
192     char *cpu_gdb_stub(struct cpu *cpu, char *cmd)
193     {
194     if (cpu->machine->cpu_family == NULL ||
195     cpu->machine->cpu_family->gdb_stub == NULL) {
196     fatal("cpu_gdb_stub(): NULL\n");
197     return NULL;
198     } else
199     return cpu->machine->cpu_family->gdb_stub(cpu, cmd);
200     }
201    
202    
203     /*
204 dpavlin 2 * cpu_interrupt():
205     *
206     * Assert an interrupt.
207     * Return value is 1 if the interrupt was asserted, 0 otherwise.
208     */
209     int cpu_interrupt(struct cpu *cpu, uint64_t irq_nr)
210     {
211     if (cpu->machine->cpu_family == NULL ||
212     cpu->machine->cpu_family->interrupt == NULL) {
213     fatal("cpu_interrupt(): NULL\n");
214     return 0;
215     } else
216     return cpu->machine->cpu_family->interrupt(cpu, irq_nr);
217     }
218    
219    
220     /*
221     * cpu_interrupt_ack():
222     *
223     * Acknowledge an interrupt.
224     * Return value is 1 if the interrupt was deasserted, 0 otherwise.
225     */
226     int cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr)
227     {
228     if (cpu->machine->cpu_family == NULL ||
229     cpu->machine->cpu_family->interrupt_ack == NULL) {
230     /* debug("cpu_interrupt_ack(): NULL\n"); */
231     return 0;
232     } else
233     return cpu->machine->cpu_family->interrupt_ack(cpu, irq_nr);
234     }
235    
236    
237     /*
238 dpavlin 12 * cpu_functioncall_trace():
239     *
240     * This function should be called if machine->show_trace_tree is enabled, and
241     * a function call is being made. f contains the address of the function.
242     */
243     void cpu_functioncall_trace(struct cpu *cpu, uint64_t f)
244     {
245     int i, n_args = -1;
246     char *symbol;
247     uint64_t offset;
248    
249     if (cpu->machine->ncpus > 1)
250     fatal("cpu%i:\t", cpu->cpu_id);
251    
252     cpu->trace_tree_depth ++;
253 dpavlin 14 if (cpu->trace_tree_depth > 100)
254     cpu->trace_tree_depth = 100;
255 dpavlin 12 for (i=0; i<cpu->trace_tree_depth; i++)
256     fatal(" ");
257    
258     fatal("<");
259     symbol = get_symbol_name_and_n_args(&cpu->machine->symbol_context,
260     f, &offset, &n_args);
261     if (symbol != NULL)
262     fatal("%s", symbol);
263     else {
264     if (cpu->is_32bit)
265 dpavlin 24 fatal("0x%"PRIx32, (uint32_t) f);
266 dpavlin 12 else
267 dpavlin 24 fatal("0x%"PRIx64, (uint64_t) f);
268 dpavlin 12 }
269     fatal("(");
270    
271     if (cpu->machine->cpu_family->functioncall_trace != NULL)
272     cpu->machine->cpu_family->functioncall_trace(cpu, f, n_args);
273    
274     fatal(")>\n");
275 dpavlin 24
276     #ifdef PRINT_MEMORY_CHECKSUM
277     /* Temporary hack for finding bugs: */
278     fatal("call chksum=%016"PRIx64"\n", memory_checksum(cpu->mem));
279     #endif
280 dpavlin 12 }
281    
282    
283     /*
284     * cpu_functioncall_trace_return():
285     *
286     * This function should be called if machine->show_trace_tree is enabled, and
287     * a function is being returned from.
288     *
289     * TODO: Print return value? This could be implemented similar to the
290     * cpu->functioncall_trace function call above.
291     */
292     void cpu_functioncall_trace_return(struct cpu *cpu)
293     {
294     cpu->trace_tree_depth --;
295     if (cpu->trace_tree_depth < 0)
296     cpu->trace_tree_depth = 0;
297     }
298    
299    
300     /*
301     * cpu_create_or_reset_tc():
302     *
303     * Create the translation cache in memory (ie allocate memory for it), if
304     * necessary, and then reset it to an initial state.
305     */
306     void cpu_create_or_reset_tc(struct cpu *cpu)
307     {
308 dpavlin 22 size_t s = DYNTRANS_CACHE_SIZE + DYNTRANS_CACHE_MARGIN;
309 dpavlin 12
310 dpavlin 24 if (cpu->translation_cache == NULL)
311     cpu->translation_cache = zeroed_alloc(s);
312 dpavlin 22
313 dpavlin 12 /* Create an empty table at the beginning of the translation cache: */
314     memset(cpu->translation_cache, 0, sizeof(uint32_t)
315     * N_BASE_TABLE_ENTRIES);
316    
317     cpu->translation_cache_cur_ofs =
318     N_BASE_TABLE_ENTRIES * sizeof(uint32_t);
319    
320     /*
321     * There might be other translation pointers that still point to
322     * within the translation_cache region. Let's invalidate those too:
323     */
324 dpavlin 14 if (cpu->invalidate_code_translation != NULL)
325     cpu->invalidate_code_translation(cpu, 0, INVALIDATE_ALL);
326 dpavlin 12 }
327    
328    
329     /*
330 dpavlin 2 * cpu_dumpinfo():
331     *
332     * Dumps info about a CPU using debug(). "cpu0: CPUNAME, running" (or similar)
333 dpavlin 18 * is outputed, and it is up to CPU dependent code to complete the line.
334 dpavlin 2 */
335     void cpu_dumpinfo(struct machine *m, struct cpu *cpu)
336     {
337     debug("cpu%i: %s, %s", cpu->cpu_id, cpu->name,
338     cpu->running? "running" : "stopped");
339    
340     if (m->cpu_family == NULL || m->cpu_family->dumpinfo == NULL)
341     fatal("cpu_dumpinfo(): NULL\n");
342     else
343     m->cpu_family->dumpinfo(cpu);
344     }
345    
346    
347     /*
348     * cpu_list_available_types():
349     *
350     * Print a list of available CPU types for each cpu family.
351     */
352     void cpu_list_available_types(void)
353     {
354     struct cpu_family *fp;
355 dpavlin 22 int iadd = DEBUG_INDENTATION;
356 dpavlin 2
357     fp = first_cpu_family;
358    
359     if (fp == NULL) {
360     debug("No CPUs defined!\n");
361     return;
362     }
363    
364     while (fp != NULL) {
365     debug("%s:\n", fp->name);
366     debug_indentation(iadd);
367     if (fp->list_available_types != NULL)
368     fp->list_available_types();
369     else
370     debug("(internal error: list_available_types"
371     " = NULL)\n");
372     debug_indentation(-iadd);
373    
374     fp = fp->next;
375     }
376     }
377    
378    
379     /*
380     * cpu_run_deinit():
381     *
382     * Shuts down all CPUs in a machine when ending a simulation. (This function
383     * should only need to be called once for each machine.)
384     */
385 dpavlin 12 void cpu_run_deinit(struct machine *machine)
386 dpavlin 2 {
387     int te;
388    
389     /*
390 dpavlin 28 * Two last ticks of every hardware device. This will allow e.g.
391     * framebuffers to draw the last updates to the screen before halting.
392     *
393     * TODO: This should be refactored when redesigning the mainbus
394     * concepts!
395 dpavlin 2 */
396     for (te=0; te<machine->n_tick_entries; te++) {
397     machine->tick_func[te](machine->cpus[0],
398     machine->tick_extra[te]);
399     machine->tick_func[te](machine->cpus[0],
400     machine->tick_extra[te]);
401     }
402    
403 dpavlin 28 if (machine->show_nr_of_instructions)
404 dpavlin 10 cpu_show_cycles(machine, 1);
405 dpavlin 2
406     fflush(stdout);
407     }
408    
409    
410     /*
411     * cpu_show_cycles():
412     *
413     * If automatic adjustment of clock interrupts is turned on, then recalculate
414     * emulated_hz. Also, if show_nr_of_instructions is on, then print a
415     * line to stdout about how many instructions/cycles have been executed so
416     * far.
417     */
418 dpavlin 10 void cpu_show_cycles(struct machine *machine, int forced)
419 dpavlin 2 {
420     uint64_t offset, pc;
421     char *symbol;
422 dpavlin 12 int64_t mseconds, ninstrs, is, avg;
423 dpavlin 2 struct timeval tv;
424 dpavlin 24 int h, m, s, ms, d;
425 dpavlin 2
426     static int64_t mseconds_last = 0;
427     static int64_t ninstrs_last = -1;
428    
429     pc = machine->cpus[machine->bootstrap_cpu]->pc;
430    
431     gettimeofday(&tv, NULL);
432 dpavlin 10 mseconds = (tv.tv_sec - machine->starttime.tv_sec) * 1000
433     + (tv.tv_usec - machine->starttime.tv_usec) / 1000;
434 dpavlin 2
435     if (mseconds == 0)
436     mseconds = 1;
437    
438     if (mseconds - mseconds_last == 0)
439     mseconds ++;
440    
441 dpavlin 28 ninstrs = machine->ninstrs_since_gettimeofday;
442 dpavlin 2
443     if (machine->automatic_clock_adjustment) {
444     static int first_adjustment = 1;
445    
446     /* Current nr of cycles per second: */
447     int64_t cur_cycles_per_second = 1000 *
448 dpavlin 24 (ninstrs-ninstrs_last) / (mseconds-mseconds_last);
449 dpavlin 2
450 dpavlin 24 /* fatal("[ CYCLES PER SECOND = %"PRIi64" ]\n",
451     cur_cycles_per_second); */
452    
453 dpavlin 2 if (cur_cycles_per_second < 1000000)
454     cur_cycles_per_second = 1000000;
455    
456     if (first_adjustment) {
457     machine->emulated_hz = cur_cycles_per_second;
458     first_adjustment = 0;
459     } else {
460     machine->emulated_hz = (15 * machine->emulated_hz +
461     cur_cycles_per_second) / 16;
462     }
463    
464 dpavlin 24 /* fatal("[ updating emulated_hz to %"PRIi64" Hz ]\n",
465     machine->emulated_hz); */
466 dpavlin 2 }
467    
468    
469     /* RETURN here, unless show_nr_of_instructions (-N) is turned on: */
470     if (!machine->show_nr_of_instructions && !forced)
471     goto do_return;
472    
473 dpavlin 28 printf("[ %"PRIi64" instrs", (int64_t)machine->ninstrs);
474 dpavlin 2
475     if (!machine->automatic_clock_adjustment) {
476     d = machine->emulated_hz / 1000;
477     if (d < 1)
478     d = 1;
479 dpavlin 28 ms = machine->ninstrs / d;
480 dpavlin 2 h = ms / 3600000;
481     ms -= 3600000 * h;
482     m = ms / 60000;
483     ms -= 60000 * m;
484     s = ms / 1000;
485     ms -= 1000 * s;
486    
487 dpavlin 22 printf(", emulated time = %02i:%02i:%02i.%03i; ", h, m, s, ms);
488 dpavlin 2 }
489    
490     /* Instructions per second, and average so far: */
491 dpavlin 12 is = 1000 * (ninstrs-ninstrs_last) / (mseconds-mseconds_last);
492     avg = (long long)1000 * ninstrs / mseconds;
493     if (is < 0)
494     is = 0;
495     if (avg < 0)
496     avg = 0;
497 dpavlin 24 printf("; i/s=%"PRIi64" avg=%"PRIi64, is, avg);
498 dpavlin 2
499     symbol = get_symbol_name(&machine->symbol_context, pc, &offset);
500    
501 dpavlin 12 if (machine->ncpus == 1) {
502     if (machine->cpus[machine->bootstrap_cpu]->is_32bit)
503 dpavlin 24 printf("; pc=0x%08"PRIx32, (uint32_t) pc);
504 dpavlin 12 else
505 dpavlin 24 printf("; pc=0x%016"PRIx64, (uint64_t) pc);
506 dpavlin 12 }
507 dpavlin 2
508 dpavlin 10 if (symbol != NULL)
509     printf(" <%s>", symbol);
510     printf(" ]\n");
511 dpavlin 2
512     do_return:
513     ninstrs_last = ninstrs;
514     mseconds_last = mseconds;
515     }
516    
517    
518     /*
519     * cpu_run_init():
520     *
521     * Prepare to run instructions on all CPUs in this machine. (This function
522     * should only need to be called once for each machine.)
523     */
524 dpavlin 12 void cpu_run_init(struct machine *machine)
525 dpavlin 2 {
526 dpavlin 28 machine->ninstrs_flush = 0;
527     machine->ninstrs = 0;
528     machine->ninstrs_show = 0;
529 dpavlin 2
530     /* For performance measurement: */
531     gettimeofday(&machine->starttime, NULL);
532 dpavlin 28 machine->ninstrs_since_gettimeofday = 0;
533 dpavlin 2 }
534    
535    
536     /*
537     * add_cpu_family():
538     *
539     * Allocates a cpu_family struct and calls an init function for the
540     * family to fill in reasonable data and pointers.
541     */
542     static void add_cpu_family(int (*family_init)(struct cpu_family *), int arch)
543     {
544     struct cpu_family *fp, *tmp;
545     int res;
546    
547     fp = malloc(sizeof(struct cpu_family));
548     if (fp == NULL) {
549     fprintf(stderr, "add_cpu_family(): out of memory\n");
550     exit(1);
551     }
552     memset(fp, 0, sizeof(struct cpu_family));
553    
554     /*
555     * family_init() returns 1 if the struct has been filled with
556     * valid data, 0 if suppor for the cpu family isn't compiled
557     * into the emulator.
558     */
559     res = family_init(fp);
560     if (!res) {
561     free(fp);
562     return;
563     }
564     fp->arch = arch;
565     fp->next = NULL;
566    
567     /* Add last in family chain: */
568     tmp = first_cpu_family;
569     if (tmp == NULL) {
570     first_cpu_family = fp;
571     } else {
572     while (tmp->next != NULL)
573     tmp = tmp->next;
574     tmp->next = fp;
575     }
576     }
577    
578    
579     /*
580     * cpu_family_ptr_by_number():
581     *
582     * Returns a pointer to a CPU family based on the ARCH_* integers.
583     */
584     struct cpu_family *cpu_family_ptr_by_number(int arch)
585     {
586     struct cpu_family *fp;
587     fp = first_cpu_family;
588    
589     /* YUCK! This is too hardcoded! TODO */
590    
591     while (fp != NULL) {
592     if (arch == fp->arch)
593     return fp;
594     fp = fp->next;
595     }
596    
597     return NULL;
598     }
599    
600    
601     /*
602     * cpu_init():
603     *
604     * Should be called before any other cpu_*() function.
605     */
606     void cpu_init(void)
607     {
608     /* Note: These are registered in alphabetic order. */
609 dpavlin 12
610     #ifdef ENABLE_ALPHA
611     add_cpu_family(alpha_cpu_family_init, ARCH_ALPHA);
612     #endif
613    
614     #ifdef ENABLE_ARM
615 dpavlin 6 add_cpu_family(arm_cpu_family_init, ARCH_ARM);
616 dpavlin 12 #endif
617    
618 dpavlin 14 #ifdef ENABLE_AVR
619     add_cpu_family(avr_cpu_family_init, ARCH_AVR);
620     #endif
621    
622     #ifdef ENABLE_HPPA
623     add_cpu_family(hppa_cpu_family_init, ARCH_HPPA);
624     #endif
625    
626     #ifdef ENABLE_I960
627     add_cpu_family(i960_cpu_family_init, ARCH_I960);
628     #endif
629    
630 dpavlin 12 #ifdef ENABLE_IA64
631     add_cpu_family(ia64_cpu_family_init, ARCH_IA64);
632     #endif
633    
634     #ifdef ENABLE_M68K
635     add_cpu_family(m68k_cpu_family_init, ARCH_M68K);
636     #endif
637    
638     #ifdef ENABLE_MIPS
639 dpavlin 2 add_cpu_family(mips_cpu_family_init, ARCH_MIPS);
640 dpavlin 12 #endif
641    
642     #ifdef ENABLE_PPC
643 dpavlin 2 add_cpu_family(ppc_cpu_family_init, ARCH_PPC);
644 dpavlin 12 #endif
645    
646 dpavlin 14 #ifdef ENABLE_SH
647     add_cpu_family(sh_cpu_family_init, ARCH_SH);
648     #endif
649    
650 dpavlin 12 #ifdef ENABLE_SPARC
651     add_cpu_family(sparc_cpu_family_init, ARCH_SPARC);
652     #endif
653    
654 dpavlin 28 #ifdef ENABLE_TRANSPUTER
655     add_cpu_family(transputer_cpu_family_init, ARCH_TRANSPUTER);
656     #endif
657    
658 dpavlin 12 #ifdef ENABLE_X86
659 dpavlin 4 add_cpu_family(x86_cpu_family_init, ARCH_X86);
660 dpavlin 12 #endif
661 dpavlin 2 }
662    

  ViewVC Help
Powered by ViewVC 1.1.26