/[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 40 - (hide annotations)
Mon Oct 8 16:22:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 15000 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1539 2007/05/01 04:03:51 debug Exp $
20070415	Landisk PCLOCK should be 33.33 MHz, not 50 MHz. (This makes
		the clock run at correct speed.)
		FINALLY found and fixed the bug which caused OpenBSD/landisk
		to randomly bug out: an &-sign was missing in the special case
		handling of FPSCR in the 'LDS.L @Rm+,FPSCR' instruction.
		Adding similar special case handling for 'LDC.L @Rm+,SR'
		(calling sh_update_sr() instead of just loading).
		Implementing the 'FCNVSD FPUL,DRn' and 'FCNVDS DRm,FPUL'
		SuperH instructions.
		The 'LDC Rm,SR' instruction now immediately breaks out of the
		dyntrans loop if an interrupt is to be triggered.
20070416	In memory_rw.c, if mapping a page as writable, make sure to
		invalidate code translations even if the data access was a
		read.
		Minor SuperH updates.
20070418	Removing the dummy M68K emulation mode.
		Minor SH update (turning unnecessary sts_mach_rn, sts_macl_rn,
		and sts_pr_rn instruction handlers into mov_rm_rn).
20070419	Beginning to add a skeleton for an M88K mode: Adding a hack to
		allow OpenBSD/m88k a.out binaries to be loaded, and disassembly
		of a few simple 88K instructions.
		Commenting out the 'LDC Rm,SR' fix from a few days ago, because
		it made Linux/dreamcast bug out.
		Adding a hack to dev_sh4.c (an extra translation cache
		invalidation), which allows OpenBSD/landisk to boot ok after
		an install. Upgrading the Landisk machine mode to stable,
		updating documentation, etc.
20070420	Experimenting with adding a PCI controller (pcic) to dev_sh4.
		Adding a dummy Realtek 8139C+ skeleton device (dev_rtl8139c).
		Implementing the first M88K instructions (br, or[.u] imm), and
		adding disassembly of some more instructions.
20070421	Continuing a little on dev_rtl8139c.
20070422	Implementing the 9346 EEPROM "read" command for dev_rtl8139c.
		Finally found and fixed an old bug in the log n symbol search
		(it sometimes missed symbols). Debug trace (-i, -t etc) should
		now show more symbols. :-)
20070423	Continuing a little on M88K disassembly.
20070428	Fixing a memset arg order bug in src/net/net.c (thanks to
		Nigel Horne for noticing the bug).
		Applying parts of a patch from Carl van Schaik to clear out
		bottom bits of MIPS addresses more correctly, when using large
		page sizes, and doing some other minor cleanup/refactoring.
		Fixing a couple of warnings given by gcc with the -W option (a
		few more warnings than just plain -Wall).
		Reducing SuperH dyntrans physical address space from 64-bit to
		32-bit (since SH5/SH64 isn't imlemented yet anyway).
		Adding address-to-symbol annotation to a few more instructions
		in the SuperH instruction trace output.
		Beginning regression testing for the next release.
		Reverting the value of SCIF_DELAYED_TX_VALUE from 1 to 2,
		because OpenBSD/landisk may otherwise hang randomly.
20070429	The ugly hack/workaround to get OpenBSD/landisk booting without
		crashing does NOT work anymore (with the April 21 snapshot
		of OpenBSD/landisk). Strangely enough, removing the hack
		completely causes OpenBSD/landisk to work (!).
		More regression testing (re-testing everything SuperH-related,
		and some other things).
		Cobalt interrupts were actually broken; fixing by commenting
		out the DEC21143s in the Cobalt machine.
20070430	More regression testing.
20070501	Updating the OpenBSD/landisk install instructions to use
		4.1 instead of the current snapshot.
		GAAAH! OpenBSD/landisk 4.1 _needs_ the ugly hack/workaround;
		reintroducing it again. (The 4.1 kernel is actually from
		2007-03-11.)
		Simplifying the NetBSD/evbarm install instructions a bit.
		More regression testing.

==============  RELEASE 0.4.5.1  ==============


1 dpavlin 2 /*
2 dpavlin 34 * Copyright (C) 2005-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 40 * $Id: cpu.c,v 1.376 2007/04/19 15:18:15 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 dpavlin 32 #include "settings.h"
44 dpavlin 2
45    
46 dpavlin 34 extern size_t dyntrans_cache_size;
47     extern int native_code_translation_enabled;
48    
49 dpavlin 2 static struct cpu_family *first_cpu_family = NULL;
50    
51    
52     /*
53     * cpu_new():
54     *
55     * Create a new cpu object. Each family is tried in sequence until a
56     * CPU family recognizes the cpu_type_name.
57 dpavlin 32 *
58     * If there was no match, NULL is returned. Otherwise, a pointer to an
59     * initialized cpu struct is returned.
60 dpavlin 2 */
61     struct cpu *cpu_new(struct memory *mem, struct machine *machine,
62     int cpu_id, char *name)
63     {
64 dpavlin 10 struct cpu *cpu;
65 dpavlin 2 struct cpu_family *fp;
66     char *cpu_type_name;
67 dpavlin 32 char tmpstr[30];
68 dpavlin 2
69     if (name == NULL) {
70     fprintf(stderr, "cpu_new(): cpu name = NULL?\n");
71     exit(1);
72     }
73    
74     cpu_type_name = strdup(name);
75     if (cpu_type_name == NULL) {
76     fprintf(stderr, "cpu_new(): out of memory\n");
77     exit(1);
78     }
79    
80 dpavlin 12 cpu = zeroed_alloc(sizeof(struct cpu));
81 dpavlin 10
82 dpavlin 34 cpu->path = malloc(strlen(machine->path) + 15);
83     if (cpu->path == NULL) {
84     fprintf(stderr, "cpu_new(): out of memory\n");
85     exit(1);
86     }
87     snprintf(cpu->path, strlen(machine->path) + 15,
88     "%s.cpu[%i]", machine->path, cpu_id);
89    
90 dpavlin 32 cpu->memory_rw = NULL;
91     cpu->name = cpu_type_name;
92     cpu->mem = mem;
93     cpu->machine = machine;
94     cpu->cpu_id = cpu_id;
95     cpu->byte_order = EMUL_UNDEFINED_ENDIAN;
96     cpu->running = 0;
97 dpavlin 10
98 dpavlin 32 /* Create settings, and attach to the machine: */
99     cpu->settings = settings_new();
100     snprintf(tmpstr, sizeof(tmpstr), "cpu[%i]", cpu_id);
101     settings_add(machine->settings, tmpstr, 1,
102     SETTINGS_TYPE_SUBSETTINGS, 0, cpu->settings);
103    
104     settings_add(cpu->settings, "name", 0, SETTINGS_TYPE_STRING,
105     SETTINGS_FORMAT_STRING, (void *) &cpu->name);
106     settings_add(cpu->settings, "running", 0, SETTINGS_TYPE_INT,
107     SETTINGS_FORMAT_YESNO, (void *) &cpu->running);
108    
109 dpavlin 12 cpu_create_or_reset_tc(cpu);
110    
111 dpavlin 2 fp = first_cpu_family;
112    
113     while (fp != NULL) {
114     if (fp->cpu_new != NULL) {
115 dpavlin 10 if (fp->cpu_new(cpu, mem, machine, cpu_id,
116     cpu_type_name)) {
117     /* Sanity check: */
118     if (cpu->memory_rw == NULL) {
119     fatal("\ncpu_new(): memory_rw == "
120     "NULL\n");
121 dpavlin 2 exit(1);
122     }
123 dpavlin 26 break;
124 dpavlin 2 }
125     }
126    
127     fp = fp->next;
128     }
129    
130 dpavlin 26 if (fp == NULL) {
131     fatal("\ncpu_new(): unknown cpu type '%s'\n", cpu_type_name);
132     return NULL;
133     }
134    
135     fp->init_tables(cpu);
136    
137 dpavlin 32 if (cpu->byte_order == EMUL_UNDEFINED_ENDIAN) {
138     fatal("\ncpu_new(): Internal bug: Endianness not set.\n");
139     exit(1);
140     }
141    
142 dpavlin 26 return cpu;
143 dpavlin 2 }
144    
145    
146     /*
147 dpavlin 32 * cpu_destroy():
148     *
149     * Destroy a cpu object.
150     */
151     void cpu_destroy(struct cpu *cpu)
152     {
153     settings_remove(cpu->settings, "name");
154     settings_remove(cpu->settings, "running");
155    
156     /* Remove any remaining level-1 settings: */
157     settings_remove_all(cpu->settings);
158    
159     settings_destroy(cpu->settings);
160    
161 dpavlin 34 if (cpu->path != NULL)
162     free(cpu->path);
163    
164 dpavlin 32 /* TODO: This assumes that zeroed_alloc() actually succeeded
165     with using mmap(), and not malloc()! */
166     munmap((void *)cpu, sizeof(struct cpu));
167     }
168    
169    
170     /*
171 dpavlin 2 * cpu_tlbdump():
172     *
173     * Called from the debugger to dump the TLB in a readable format.
174     * x is the cpu number to dump, or -1 to dump all CPUs.
175     *
176     * If rawflag is nonzero, then the TLB contents isn't formated nicely,
177     * just dumped.
178     */
179     void cpu_tlbdump(struct machine *m, int x, int rawflag)
180     {
181     if (m->cpu_family == NULL || m->cpu_family->tlbdump == NULL)
182     fatal("cpu_tlbdump(): NULL\n");
183     else
184     m->cpu_family->tlbdump(m, x, rawflag);
185     }
186    
187    
188     /*
189     * cpu_disassemble_instr():
190     *
191     * Convert an instruction word into human readable format, for instruction
192     * tracing.
193     */
194     int cpu_disassemble_instr(struct machine *m, struct cpu *cpu,
195 dpavlin 24 unsigned char *instr, int running, uint64_t addr)
196 dpavlin 2 {
197     if (m->cpu_family == NULL || m->cpu_family->disassemble_instr == NULL) {
198     fatal("cpu_disassemble_instr(): NULL\n");
199     return 0;
200     } else
201     return m->cpu_family->disassemble_instr(cpu, instr,
202 dpavlin 24 running, addr);
203 dpavlin 2 }
204    
205    
206     /*
207     * cpu_register_dump():
208     *
209     * Dump cpu registers in a relatively readable format.
210     *
211 dpavlin 18 * gprs: set to non-zero to dump GPRs. (CPU dependent.)
212     * coprocs: set bit 0..x to dump registers in coproc 0..x. (CPU dependent.)
213 dpavlin 2 */
214     void cpu_register_dump(struct machine *m, struct cpu *cpu,
215     int gprs, int coprocs)
216     {
217     if (m->cpu_family == NULL || m->cpu_family->register_dump == NULL)
218     fatal("cpu_register_dump(): NULL\n");
219     else
220     m->cpu_family->register_dump(cpu, gprs, coprocs);
221     }
222    
223    
224     /*
225 dpavlin 12 * cpu_functioncall_trace():
226     *
227     * This function should be called if machine->show_trace_tree is enabled, and
228     * a function call is being made. f contains the address of the function.
229     */
230     void cpu_functioncall_trace(struct cpu *cpu, uint64_t f)
231     {
232     int i, n_args = -1;
233     char *symbol;
234     uint64_t offset;
235    
236     if (cpu->machine->ncpus > 1)
237     fatal("cpu%i:\t", cpu->cpu_id);
238    
239     cpu->trace_tree_depth ++;
240 dpavlin 14 if (cpu->trace_tree_depth > 100)
241     cpu->trace_tree_depth = 100;
242 dpavlin 12 for (i=0; i<cpu->trace_tree_depth; i++)
243     fatal(" ");
244    
245     fatal("<");
246     symbol = get_symbol_name_and_n_args(&cpu->machine->symbol_context,
247     f, &offset, &n_args);
248     if (symbol != NULL)
249     fatal("%s", symbol);
250     else {
251     if (cpu->is_32bit)
252 dpavlin 24 fatal("0x%"PRIx32, (uint32_t) f);
253 dpavlin 12 else
254 dpavlin 24 fatal("0x%"PRIx64, (uint64_t) f);
255 dpavlin 12 }
256     fatal("(");
257    
258     if (cpu->machine->cpu_family->functioncall_trace != NULL)
259     cpu->machine->cpu_family->functioncall_trace(cpu, f, n_args);
260    
261     fatal(")>\n");
262 dpavlin 24
263     #ifdef PRINT_MEMORY_CHECKSUM
264     /* Temporary hack for finding bugs: */
265     fatal("call chksum=%016"PRIx64"\n", memory_checksum(cpu->mem));
266     #endif
267 dpavlin 12 }
268    
269    
270     /*
271     * cpu_functioncall_trace_return():
272     *
273     * This function should be called if machine->show_trace_tree is enabled, and
274     * a function is being returned from.
275     *
276     * TODO: Print return value? This could be implemented similar to the
277     * cpu->functioncall_trace function call above.
278     */
279     void cpu_functioncall_trace_return(struct cpu *cpu)
280     {
281     cpu->trace_tree_depth --;
282     if (cpu->trace_tree_depth < 0)
283     cpu->trace_tree_depth = 0;
284     }
285    
286    
287     /*
288     * cpu_create_or_reset_tc():
289     *
290     * Create the translation cache in memory (ie allocate memory for it), if
291     * necessary, and then reset it to an initial state.
292     */
293     void cpu_create_or_reset_tc(struct cpu *cpu)
294     {
295 dpavlin 34 size_t s = dyntrans_cache_size + DYNTRANS_CACHE_MARGIN;
296 dpavlin 12
297 dpavlin 34 if (cpu->translation_cache == NULL) {
298 dpavlin 24 cpu->translation_cache = zeroed_alloc(s);
299 dpavlin 22
300 dpavlin 34 #ifdef NATIVE_CODE_GENERATION
301     if (native_code_translation_enabled) {
302     mprotect(cpu->translation_cache, s,
303     PROT_READ | PROT_WRITE | PROT_EXEC);
304     }
305     #endif
306     }
307    
308 dpavlin 38 #ifdef NATIVE_CODE_GENERATION
309     if (native_code_translation_enabled && cpu->inr.inr_entries == NULL)
310     cpu->inr.inr_entries = zeroed_alloc(
311     sizeof(struct inr_entry) * INR_MAX_ENTRIES);
312 dpavlin 34
313 dpavlin 38 cpu->inr.nr_inr_entries_used = 0;
314     #endif
315    
316 dpavlin 12 /* Create an empty table at the beginning of the translation cache: */
317     memset(cpu->translation_cache, 0, sizeof(uint32_t)
318     * N_BASE_TABLE_ENTRIES);
319    
320     cpu->translation_cache_cur_ofs =
321     N_BASE_TABLE_ENTRIES * sizeof(uint32_t);
322    
323     /*
324     * There might be other translation pointers that still point to
325     * within the translation_cache region. Let's invalidate those too:
326     */
327 dpavlin 14 if (cpu->invalidate_code_translation != NULL)
328     cpu->invalidate_code_translation(cpu, 0, INVALIDATE_ALL);
329 dpavlin 12 }
330    
331    
332     /*
333 dpavlin 2 * cpu_dumpinfo():
334     *
335     * Dumps info about a CPU using debug(). "cpu0: CPUNAME, running" (or similar)
336 dpavlin 18 * is outputed, and it is up to CPU dependent code to complete the line.
337 dpavlin 2 */
338     void cpu_dumpinfo(struct machine *m, struct cpu *cpu)
339     {
340     debug("cpu%i: %s, %s", cpu->cpu_id, cpu->name,
341     cpu->running? "running" : "stopped");
342    
343     if (m->cpu_family == NULL || m->cpu_family->dumpinfo == NULL)
344     fatal("cpu_dumpinfo(): NULL\n");
345     else
346     m->cpu_family->dumpinfo(cpu);
347     }
348    
349    
350     /*
351     * cpu_list_available_types():
352     *
353     * Print a list of available CPU types for each cpu family.
354     */
355     void cpu_list_available_types(void)
356     {
357     struct cpu_family *fp;
358 dpavlin 22 int iadd = DEBUG_INDENTATION;
359 dpavlin 2
360     fp = first_cpu_family;
361    
362     if (fp == NULL) {
363     debug("No CPUs defined!\n");
364     return;
365     }
366    
367     while (fp != NULL) {
368     debug("%s:\n", fp->name);
369     debug_indentation(iadd);
370     if (fp->list_available_types != NULL)
371     fp->list_available_types();
372     else
373     debug("(internal error: list_available_types"
374     " = NULL)\n");
375     debug_indentation(-iadd);
376    
377     fp = fp->next;
378     }
379     }
380    
381    
382     /*
383     * cpu_run_deinit():
384     *
385     * Shuts down all CPUs in a machine when ending a simulation. (This function
386     * should only need to be called once for each machine.)
387     */
388 dpavlin 12 void cpu_run_deinit(struct machine *machine)
389 dpavlin 2 {
390     int te;
391    
392     /*
393 dpavlin 28 * Two last ticks of every hardware device. This will allow e.g.
394     * framebuffers to draw the last updates to the screen before halting.
395     *
396     * TODO: This should be refactored when redesigning the mainbus
397     * concepts!
398 dpavlin 2 */
399     for (te=0; te<machine->n_tick_entries; te++) {
400     machine->tick_func[te](machine->cpus[0],
401     machine->tick_extra[te]);
402     machine->tick_func[te](machine->cpus[0],
403     machine->tick_extra[te]);
404     }
405    
406 dpavlin 28 if (machine->show_nr_of_instructions)
407 dpavlin 10 cpu_show_cycles(machine, 1);
408 dpavlin 2
409     fflush(stdout);
410     }
411    
412    
413     /*
414     * cpu_show_cycles():
415     *
416 dpavlin 32 * If show_nr_of_instructions is on, then print a line to stdout about how
417     * many instructions/cycles have been executed so far.
418 dpavlin 2 */
419 dpavlin 10 void cpu_show_cycles(struct machine *machine, int forced)
420 dpavlin 2 {
421     uint64_t offset, pc;
422     char *symbol;
423 dpavlin 12 int64_t mseconds, ninstrs, is, avg;
424 dpavlin 2 struct timeval tv;
425 dpavlin 32 struct cpu *cpu = machine->cpus[machine->bootstrap_cpu];
426 dpavlin 2
427     static int64_t mseconds_last = 0;
428     static int64_t ninstrs_last = -1;
429    
430 dpavlin 32 pc = cpu->pc;
431 dpavlin 2
432     gettimeofday(&tv, NULL);
433 dpavlin 10 mseconds = (tv.tv_sec - machine->starttime.tv_sec) * 1000
434     + (tv.tv_usec - machine->starttime.tv_usec) / 1000;
435 dpavlin 2
436     if (mseconds == 0)
437     mseconds = 1;
438    
439     if (mseconds - mseconds_last == 0)
440     mseconds ++;
441    
442 dpavlin 28 ninstrs = machine->ninstrs_since_gettimeofday;
443 dpavlin 2
444     /* RETURN here, unless show_nr_of_instructions (-N) is turned on: */
445     if (!machine->show_nr_of_instructions && !forced)
446     goto do_return;
447    
448 dpavlin 28 printf("[ %"PRIi64" instrs", (int64_t)machine->ninstrs);
449 dpavlin 2
450     /* Instructions per second, and average so far: */
451 dpavlin 12 is = 1000 * (ninstrs-ninstrs_last) / (mseconds-mseconds_last);
452     avg = (long long)1000 * ninstrs / mseconds;
453     if (is < 0)
454     is = 0;
455     if (avg < 0)
456     avg = 0;
457 dpavlin 2
458 dpavlin 32 if (cpu->has_been_idling) {
459     printf("; idling");
460     cpu->has_been_idling = 0;
461     } else
462     printf("; i/s=%"PRIi64" avg=%"PRIi64, is, avg);
463    
464 dpavlin 2 symbol = get_symbol_name(&machine->symbol_context, pc, &offset);
465    
466 dpavlin 12 if (machine->ncpus == 1) {
467 dpavlin 32 if (cpu->is_32bit)
468 dpavlin 24 printf("; pc=0x%08"PRIx32, (uint32_t) pc);
469 dpavlin 12 else
470 dpavlin 24 printf("; pc=0x%016"PRIx64, (uint64_t) pc);
471 dpavlin 12 }
472 dpavlin 2
473 dpavlin 10 if (symbol != NULL)
474     printf(" <%s>", symbol);
475     printf(" ]\n");
476 dpavlin 2
477     do_return:
478     ninstrs_last = ninstrs;
479     mseconds_last = mseconds;
480     }
481    
482    
483     /*
484     * cpu_run_init():
485     *
486     * Prepare to run instructions on all CPUs in this machine. (This function
487     * should only need to be called once for each machine.)
488     */
489 dpavlin 12 void cpu_run_init(struct machine *machine)
490 dpavlin 2 {
491 dpavlin 28 machine->ninstrs_flush = 0;
492     machine->ninstrs = 0;
493     machine->ninstrs_show = 0;
494 dpavlin 2
495     /* For performance measurement: */
496     gettimeofday(&machine->starttime, NULL);
497 dpavlin 28 machine->ninstrs_since_gettimeofday = 0;
498 dpavlin 2 }
499    
500    
501     /*
502     * add_cpu_family():
503     *
504     * Allocates a cpu_family struct and calls an init function for the
505     * family to fill in reasonable data and pointers.
506     */
507     static void add_cpu_family(int (*family_init)(struct cpu_family *), int arch)
508     {
509     struct cpu_family *fp, *tmp;
510     int res;
511    
512     fp = malloc(sizeof(struct cpu_family));
513     if (fp == NULL) {
514     fprintf(stderr, "add_cpu_family(): out of memory\n");
515     exit(1);
516     }
517     memset(fp, 0, sizeof(struct cpu_family));
518    
519     /*
520     * family_init() returns 1 if the struct has been filled with
521     * valid data, 0 if suppor for the cpu family isn't compiled
522     * into the emulator.
523     */
524     res = family_init(fp);
525     if (!res) {
526     free(fp);
527     return;
528     }
529     fp->arch = arch;
530     fp->next = NULL;
531    
532     /* Add last in family chain: */
533     tmp = first_cpu_family;
534     if (tmp == NULL) {
535     first_cpu_family = fp;
536     } else {
537     while (tmp->next != NULL)
538     tmp = tmp->next;
539     tmp->next = fp;
540     }
541     }
542    
543    
544     /*
545     * cpu_family_ptr_by_number():
546     *
547     * Returns a pointer to a CPU family based on the ARCH_* integers.
548     */
549     struct cpu_family *cpu_family_ptr_by_number(int arch)
550     {
551     struct cpu_family *fp;
552     fp = first_cpu_family;
553    
554     /* YUCK! This is too hardcoded! TODO */
555    
556     while (fp != NULL) {
557     if (arch == fp->arch)
558     return fp;
559     fp = fp->next;
560     }
561    
562     return NULL;
563     }
564    
565    
566     /*
567     * cpu_init():
568     *
569     * Should be called before any other cpu_*() function.
570 dpavlin 32 *
571     * TODO: Make this nicer by moving out the conditional stuff to
572     * an automagically generated file? Or a define in config.h?
573 dpavlin 2 */
574     void cpu_init(void)
575     {
576     /* Note: These are registered in alphabetic order. */
577 dpavlin 12
578     #ifdef ENABLE_ALPHA
579     add_cpu_family(alpha_cpu_family_init, ARCH_ALPHA);
580     #endif
581    
582     #ifdef ENABLE_ARM
583 dpavlin 6 add_cpu_family(arm_cpu_family_init, ARCH_ARM);
584 dpavlin 12 #endif
585    
586 dpavlin 14 #ifdef ENABLE_AVR
587     add_cpu_family(avr_cpu_family_init, ARCH_AVR);
588     #endif
589    
590 dpavlin 40 #ifdef ENABLE_M88K
591     add_cpu_family(m88k_cpu_family_init, ARCH_M88K);
592 dpavlin 12 #endif
593    
594     #ifdef ENABLE_MIPS
595 dpavlin 2 add_cpu_family(mips_cpu_family_init, ARCH_MIPS);
596 dpavlin 12 #endif
597    
598     #ifdef ENABLE_PPC
599 dpavlin 2 add_cpu_family(ppc_cpu_family_init, ARCH_PPC);
600 dpavlin 12 #endif
601    
602 dpavlin 14 #ifdef ENABLE_SH
603     add_cpu_family(sh_cpu_family_init, ARCH_SH);
604     #endif
605    
606 dpavlin 12 #ifdef ENABLE_SPARC
607     add_cpu_family(sparc_cpu_family_init, ARCH_SPARC);
608     #endif
609 dpavlin 2 }
610    

  ViewVC Help
Powered by ViewVC 1.1.26