/[gxemul]/upstream/0.3.8/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 /upstream/0.3.8/src/cpu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (hide annotations)
Mon Oct 8 16:19:43 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 20022 byte(s)
0.3.8
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 22 * $Id: cpu.c,v 1.329 2006/01/16 04:48:08 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     extern int quiet_mode;
46     extern int show_opcode_statistics;
47 dpavlin 22 extern int dyntrans_backend_enable;
48 dpavlin 2
49     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     */
58     struct cpu *cpu_new(struct memory *mem, struct machine *machine,
59     int cpu_id, char *name)
60     {
61 dpavlin 10 struct cpu *cpu;
62 dpavlin 2 struct cpu_family *fp;
63     char *cpu_type_name;
64    
65     if (name == NULL) {
66     fprintf(stderr, "cpu_new(): cpu name = NULL?\n");
67     exit(1);
68     }
69    
70     cpu_type_name = strdup(name);
71     if (cpu_type_name == NULL) {
72     fprintf(stderr, "cpu_new(): out of memory\n");
73     exit(1);
74     }
75    
76 dpavlin 12 cpu = zeroed_alloc(sizeof(struct cpu));
77 dpavlin 10
78     cpu->memory_rw = NULL;
79     cpu->name = cpu_type_name;
80     cpu->mem = mem;
81     cpu->machine = machine;
82     cpu->cpu_id = cpu_id;
83     cpu->byte_order = EMUL_LITTLE_ENDIAN;
84     cpu->bootstrap_cpu_flag = 0;
85     cpu->running = 0;
86    
87 dpavlin 12 cpu_create_or_reset_tc(cpu);
88    
89 dpavlin 2 fp = first_cpu_family;
90    
91     while (fp != NULL) {
92     if (fp->cpu_new != NULL) {
93 dpavlin 10 if (fp->cpu_new(cpu, mem, machine, cpu_id,
94     cpu_type_name)) {
95     /* Sanity check: */
96     if (cpu->memory_rw == NULL) {
97     fatal("\ncpu_new(): memory_rw == "
98     "NULL\n");
99 dpavlin 2 exit(1);
100     }
101 dpavlin 10 return cpu;
102 dpavlin 2 }
103     }
104    
105     fp = fp->next;
106     }
107    
108 dpavlin 6 fatal("\ncpu_new(): unknown cpu type '%s'\n", cpu_type_name);
109 dpavlin 2 exit(1);
110     }
111    
112    
113     /*
114     * cpu_show_full_statistics():
115     *
116     * Show detailed statistics on opcode usage on each cpu.
117     */
118     void cpu_show_full_statistics(struct machine *m)
119     {
120     if (m->cpu_family == NULL ||
121     m->cpu_family->show_full_statistics == NULL)
122     fatal("cpu_show_full_statistics(): NULL\n");
123     else
124     m->cpu_family->show_full_statistics(m);
125     }
126    
127    
128     /*
129     * cpu_tlbdump():
130     *
131     * Called from the debugger to dump the TLB in a readable format.
132     * x is the cpu number to dump, or -1 to dump all CPUs.
133     *
134     * If rawflag is nonzero, then the TLB contents isn't formated nicely,
135     * just dumped.
136     */
137     void cpu_tlbdump(struct machine *m, int x, int rawflag)
138     {
139     if (m->cpu_family == NULL || m->cpu_family->tlbdump == NULL)
140     fatal("cpu_tlbdump(): NULL\n");
141     else
142     m->cpu_family->tlbdump(m, x, rawflag);
143     }
144    
145    
146     /*
147     * cpu_register_match():
148     *
149     * Used by the debugger.
150     */
151     void cpu_register_match(struct machine *m, char *name,
152     int writeflag, uint64_t *valuep, int *match_register)
153     {
154     if (m->cpu_family == NULL || m->cpu_family->register_match == NULL)
155     fatal("cpu_register_match(): NULL\n");
156     else
157     m->cpu_family->register_match(m, name, writeflag,
158     valuep, match_register);
159     }
160    
161    
162     /*
163     * cpu_disassemble_instr():
164     *
165     * Convert an instruction word into human readable format, for instruction
166     * tracing.
167     */
168     int cpu_disassemble_instr(struct machine *m, struct cpu *cpu,
169     unsigned char *instr, int running, uint64_t addr, int bintrans)
170     {
171     if (m->cpu_family == NULL || m->cpu_family->disassemble_instr == NULL) {
172     fatal("cpu_disassemble_instr(): NULL\n");
173     return 0;
174     } else
175     return m->cpu_family->disassemble_instr(cpu, instr,
176     running, addr, bintrans);
177     }
178    
179    
180     /*
181     * cpu_register_dump():
182     *
183     * Dump cpu registers in a relatively readable format.
184     *
185 dpavlin 18 * gprs: set to non-zero to dump GPRs. (CPU dependent.)
186     * coprocs: set bit 0..x to dump registers in coproc 0..x. (CPU dependent.)
187 dpavlin 2 */
188     void cpu_register_dump(struct machine *m, struct cpu *cpu,
189     int gprs, int coprocs)
190     {
191     if (m->cpu_family == NULL || m->cpu_family->register_dump == NULL)
192     fatal("cpu_register_dump(): NULL\n");
193     else
194     m->cpu_family->register_dump(cpu, gprs, coprocs);
195     }
196    
197    
198     /*
199     * cpu_interrupt():
200     *
201     * Assert an interrupt.
202     * Return value is 1 if the interrupt was asserted, 0 otherwise.
203     */
204     int cpu_interrupt(struct cpu *cpu, uint64_t irq_nr)
205     {
206     if (cpu->machine->cpu_family == NULL ||
207     cpu->machine->cpu_family->interrupt == NULL) {
208     fatal("cpu_interrupt(): NULL\n");
209     return 0;
210     } else
211     return cpu->machine->cpu_family->interrupt(cpu, irq_nr);
212     }
213    
214    
215     /*
216     * cpu_interrupt_ack():
217     *
218     * Acknowledge an interrupt.
219     * Return value is 1 if the interrupt was deasserted, 0 otherwise.
220     */
221     int cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr)
222     {
223     if (cpu->machine->cpu_family == NULL ||
224     cpu->machine->cpu_family->interrupt_ack == NULL) {
225     /* debug("cpu_interrupt_ack(): NULL\n"); */
226     return 0;
227     } else
228     return cpu->machine->cpu_family->interrupt_ack(cpu, irq_nr);
229     }
230    
231    
232     /*
233 dpavlin 12 * cpu_functioncall_trace():
234     *
235     * This function should be called if machine->show_trace_tree is enabled, and
236     * a function call is being made. f contains the address of the function.
237     */
238     void cpu_functioncall_trace(struct cpu *cpu, uint64_t f)
239     {
240     int i, n_args = -1;
241     char *symbol;
242     uint64_t offset;
243    
244     if (cpu->machine->ncpus > 1)
245     fatal("cpu%i:\t", cpu->cpu_id);
246    
247     cpu->trace_tree_depth ++;
248 dpavlin 14 if (cpu->trace_tree_depth > 100)
249     cpu->trace_tree_depth = 100;
250 dpavlin 12 for (i=0; i<cpu->trace_tree_depth; i++)
251     fatal(" ");
252    
253     fatal("<");
254     symbol = get_symbol_name_and_n_args(&cpu->machine->symbol_context,
255     f, &offset, &n_args);
256     if (symbol != NULL)
257     fatal("%s", symbol);
258     else {
259     if (cpu->is_32bit)
260     fatal("0x%08x", (int)f);
261     else
262     fatal("0x%llx", (long long)f);
263     }
264     fatal("(");
265    
266     if (cpu->machine->cpu_family->functioncall_trace != NULL)
267     cpu->machine->cpu_family->functioncall_trace(cpu, f, n_args);
268    
269     fatal(")>\n");
270     }
271    
272    
273     /*
274     * cpu_functioncall_trace_return():
275     *
276     * This function should be called if machine->show_trace_tree is enabled, and
277     * a function is being returned from.
278     *
279     * TODO: Print return value? This could be implemented similar to the
280     * cpu->functioncall_trace function call above.
281     */
282     void cpu_functioncall_trace_return(struct cpu *cpu)
283     {
284     cpu->trace_tree_depth --;
285     if (cpu->trace_tree_depth < 0)
286     cpu->trace_tree_depth = 0;
287     }
288    
289    
290     /*
291     * cpu_create_or_reset_tc():
292     *
293     * Create the translation cache in memory (ie allocate memory for it), if
294     * necessary, and then reset it to an initial state.
295     */
296     void cpu_create_or_reset_tc(struct cpu *cpu)
297     {
298 dpavlin 22 size_t s = DYNTRANS_CACHE_SIZE + DYNTRANS_CACHE_MARGIN;
299 dpavlin 12
300 dpavlin 22 if (cpu->translation_cache == NULL) {
301     #ifdef DYNTRANS_BACKEND
302     if (dyntrans_backend_enable) {
303     cpu->translation_cache = (unsigned char *) mmap(NULL,
304     s, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON |
305     MAP_PRIVATE, -1, 0);
306     if (cpu->translation_cache == NULL) {
307     dyntrans_backend_enable = 0;
308     fatal("%\n% WARNING! Dyntrans backend disabled"
309     ", because mmap() failed.\n%\n");
310     }
311     }
312     #endif
313     if (cpu->translation_cache == NULL)
314     cpu->translation_cache = zeroed_alloc(s);
315     }
316    
317 dpavlin 12 /* Create an empty table at the beginning of the translation cache: */
318     memset(cpu->translation_cache, 0, sizeof(uint32_t)
319     * N_BASE_TABLE_ENTRIES);
320    
321     cpu->translation_cache_cur_ofs =
322     N_BASE_TABLE_ENTRIES * sizeof(uint32_t);
323    
324     /*
325     * There might be other translation pointers that still point to
326     * within the translation_cache region. Let's invalidate those too:
327     */
328 dpavlin 14 if (cpu->invalidate_code_translation != NULL)
329     cpu->invalidate_code_translation(cpu, 0, INVALIDATE_ALL);
330 dpavlin 12 }
331    
332    
333     /*
334 dpavlin 2 * cpu_run():
335     *
336     * Run instructions on all CPUs in this machine, for a "medium duration"
337     * (or until all CPUs have halted).
338     *
339     * Return value is 1 if anything happened, 0 if all CPUs are stopped.
340     */
341     int cpu_run(struct emul *emul, struct machine *m)
342     {
343     if (m->cpu_family == NULL || m->cpu_family->run == NULL) {
344     fatal("cpu_run(): NULL\n");
345     return 0;
346     } else
347     return m->cpu_family->run(emul, m);
348     }
349    
350    
351     /*
352     * cpu_dumpinfo():
353     *
354     * Dumps info about a CPU using debug(). "cpu0: CPUNAME, running" (or similar)
355 dpavlin 18 * is outputed, and it is up to CPU dependent code to complete the line.
356 dpavlin 2 */
357     void cpu_dumpinfo(struct machine *m, struct cpu *cpu)
358     {
359     debug("cpu%i: %s, %s", cpu->cpu_id, cpu->name,
360     cpu->running? "running" : "stopped");
361    
362     if (m->cpu_family == NULL || m->cpu_family->dumpinfo == NULL)
363     fatal("cpu_dumpinfo(): NULL\n");
364     else
365     m->cpu_family->dumpinfo(cpu);
366     }
367    
368    
369     /*
370     * cpu_list_available_types():
371     *
372     * Print a list of available CPU types for each cpu family.
373     */
374     void cpu_list_available_types(void)
375     {
376     struct cpu_family *fp;
377 dpavlin 22 int iadd = DEBUG_INDENTATION;
378 dpavlin 2
379     fp = first_cpu_family;
380    
381     if (fp == NULL) {
382     debug("No CPUs defined!\n");
383     return;
384     }
385    
386     while (fp != NULL) {
387     debug("%s:\n", fp->name);
388     debug_indentation(iadd);
389     if (fp->list_available_types != NULL)
390     fp->list_available_types();
391     else
392     debug("(internal error: list_available_types"
393     " = NULL)\n");
394     debug_indentation(-iadd);
395    
396     fp = fp->next;
397     }
398     }
399    
400    
401     /*
402     * cpu_run_deinit():
403     *
404     * Shuts down all CPUs in a machine when ending a simulation. (This function
405     * should only need to be called once for each machine.)
406     */
407 dpavlin 12 void cpu_run_deinit(struct machine *machine)
408 dpavlin 2 {
409     int te;
410    
411     /*
412     * Two last ticks of every hardware device. This will allow
413     * framebuffers to draw the last updates to the screen before
414     * halting.
415     */
416     for (te=0; te<machine->n_tick_entries; te++) {
417     machine->tick_func[te](machine->cpus[0],
418     machine->tick_extra[te]);
419     machine->tick_func[te](machine->cpus[0],
420     machine->tick_extra[te]);
421     }
422    
423     debug("cpu_run_deinit(): All CPUs halted.\n");
424    
425     if (machine->show_nr_of_instructions || !quiet_mode)
426 dpavlin 10 cpu_show_cycles(machine, 1);
427 dpavlin 2
428     if (show_opcode_statistics)
429     cpu_show_full_statistics(machine);
430    
431     fflush(stdout);
432     }
433    
434    
435     /*
436     * cpu_show_cycles():
437     *
438     * If automatic adjustment of clock interrupts is turned on, then recalculate
439     * emulated_hz. Also, if show_nr_of_instructions is on, then print a
440     * line to stdout about how many instructions/cycles have been executed so
441     * far.
442     */
443 dpavlin 10 void cpu_show_cycles(struct machine *machine, int forced)
444 dpavlin 2 {
445     uint64_t offset, pc;
446     char *symbol;
447 dpavlin 12 int64_t mseconds, ninstrs, is, avg;
448 dpavlin 2 struct timeval tv;
449 dpavlin 12 int h, m, s, ms, d, instrs_per_cycle = 1;
450 dpavlin 2
451     static int64_t mseconds_last = 0;
452     static int64_t ninstrs_last = -1;
453    
454 dpavlin 10 switch (machine->arch) {
455     case ARCH_MIPS:
456     instrs_per_cycle = machine->cpus[machine->bootstrap_cpu]->
457     cd.mips.cpu_type.instrs_per_cycle;
458     break;
459 dpavlin 2 }
460    
461     pc = machine->cpus[machine->bootstrap_cpu]->pc;
462    
463     gettimeofday(&tv, NULL);
464 dpavlin 10 mseconds = (tv.tv_sec - machine->starttime.tv_sec) * 1000
465     + (tv.tv_usec - machine->starttime.tv_usec) / 1000;
466 dpavlin 2
467     if (mseconds == 0)
468     mseconds = 1;
469    
470     if (mseconds - mseconds_last == 0)
471     mseconds ++;
472    
473 dpavlin 10 ninstrs = machine->ncycles_since_gettimeofday * instrs_per_cycle;
474 dpavlin 2
475     if (machine->automatic_clock_adjustment) {
476     static int first_adjustment = 1;
477    
478     /* Current nr of cycles per second: */
479     int64_t cur_cycles_per_second = 1000 *
480     (ninstrs-ninstrs_last) / (mseconds-mseconds_last)
481     / instrs_per_cycle;
482    
483     if (cur_cycles_per_second < 1000000)
484     cur_cycles_per_second = 1000000;
485    
486     if (first_adjustment) {
487     machine->emulated_hz = cur_cycles_per_second;
488     first_adjustment = 0;
489     } else {
490     machine->emulated_hz = (15 * machine->emulated_hz +
491     cur_cycles_per_second) / 16;
492     }
493    
494 dpavlin 12 /* debug("[ updating emulated_hz to %lli Hz ]\n",
495     (long long)machine->emulated_hz); */
496 dpavlin 2 }
497    
498    
499     /* RETURN here, unless show_nr_of_instructions (-N) is turned on: */
500     if (!machine->show_nr_of_instructions && !forced)
501     goto do_return;
502    
503 dpavlin 10 printf("[ %lli instrs",
504     (long long)(machine->ncycles * instrs_per_cycle));
505 dpavlin 2
506     if (!machine->automatic_clock_adjustment) {
507     d = machine->emulated_hz / 1000;
508     if (d < 1)
509     d = 1;
510 dpavlin 10 ms = machine->ncycles / d;
511 dpavlin 2 h = ms / 3600000;
512     ms -= 3600000 * h;
513     m = ms / 60000;
514     ms -= 60000 * m;
515     s = ms / 1000;
516     ms -= 1000 * s;
517    
518 dpavlin 22 printf(", emulated time = %02i:%02i:%02i.%03i; ", h, m, s, ms);
519 dpavlin 2 }
520    
521     /* Instructions per second, and average so far: */
522 dpavlin 12 is = 1000 * (ninstrs-ninstrs_last) / (mseconds-mseconds_last);
523     avg = (long long)1000 * ninstrs / mseconds;
524     if (is < 0)
525     is = 0;
526     if (avg < 0)
527     avg = 0;
528     printf("; i/s=%lli avg=%lli", (long long)is, (long long)avg);
529 dpavlin 2
530     symbol = get_symbol_name(&machine->symbol_context, pc, &offset);
531    
532 dpavlin 12 if (machine->ncpus == 1) {
533     if (machine->cpus[machine->bootstrap_cpu]->is_32bit)
534     printf("; pc=0x%08x", (int)pc);
535     else
536     printf("; pc=0x%016llx", (long long)pc);
537     }
538 dpavlin 2
539 dpavlin 10 if (symbol != NULL)
540     printf(" <%s>", symbol);
541     printf(" ]\n");
542 dpavlin 2
543     do_return:
544     ninstrs_last = ninstrs;
545     mseconds_last = mseconds;
546     }
547    
548    
549     /*
550     * cpu_run_init():
551     *
552     * Prepare to run instructions on all CPUs in this machine. (This function
553     * should only need to be called once for each machine.)
554     */
555 dpavlin 12 void cpu_run_init(struct machine *machine)
556 dpavlin 2 {
557     int ncpus = machine->ncpus;
558     int te;
559    
560     machine->a_few_cycles = 1048576;
561     machine->ncycles_flush = 0;
562     machine->ncycles = 0;
563     machine->ncycles_show = 0;
564    
565     /*
566     * Instead of doing { one cycle, check hardware ticks }, we
567     * can do { n cycles, check hardware ticks }, as long as
568     * n is at most as much as the lowest number of cycles/tick
569     * for any hardware device.
570     */
571     for (te=0; te<machine->n_tick_entries; te++) {
572     if (machine->ticks_reset_value[te] < machine->a_few_cycles)
573     machine->a_few_cycles = machine->ticks_reset_value[te];
574     }
575    
576     machine->a_few_cycles >>= 1;
577     if (machine->a_few_cycles < 1)
578     machine->a_few_cycles = 1;
579    
580     if (ncpus > 1 && machine->max_random_cycles_per_chunk == 0)
581     machine->a_few_cycles = 1;
582    
583     /* debug("cpu_run_init(): a_few_cycles = %i\n",
584     machine->a_few_cycles); */
585    
586     /* For performance measurement: */
587     gettimeofday(&machine->starttime, NULL);
588 dpavlin 10 machine->ncycles_since_gettimeofday = 0;
589 dpavlin 2 }
590    
591    
592     /*
593     * add_cpu_family():
594     *
595     * Allocates a cpu_family struct and calls an init function for the
596     * family to fill in reasonable data and pointers.
597     */
598     static void add_cpu_family(int (*family_init)(struct cpu_family *), int arch)
599     {
600     struct cpu_family *fp, *tmp;
601     int res;
602    
603     fp = malloc(sizeof(struct cpu_family));
604     if (fp == NULL) {
605     fprintf(stderr, "add_cpu_family(): out of memory\n");
606     exit(1);
607     }
608     memset(fp, 0, sizeof(struct cpu_family));
609    
610     /*
611     * family_init() returns 1 if the struct has been filled with
612     * valid data, 0 if suppor for the cpu family isn't compiled
613     * into the emulator.
614     */
615     res = family_init(fp);
616     if (!res) {
617     free(fp);
618     return;
619     }
620     fp->arch = arch;
621     fp->next = NULL;
622    
623     /* Add last in family chain: */
624     tmp = first_cpu_family;
625     if (tmp == NULL) {
626     first_cpu_family = fp;
627     } else {
628     while (tmp->next != NULL)
629     tmp = tmp->next;
630     tmp->next = fp;
631     }
632     }
633    
634    
635     /*
636     * cpu_family_ptr_by_number():
637     *
638     * Returns a pointer to a CPU family based on the ARCH_* integers.
639     */
640     struct cpu_family *cpu_family_ptr_by_number(int arch)
641     {
642     struct cpu_family *fp;
643     fp = first_cpu_family;
644    
645     /* YUCK! This is too hardcoded! TODO */
646    
647     while (fp != NULL) {
648     if (arch == fp->arch)
649     return fp;
650     fp = fp->next;
651     }
652    
653     return NULL;
654     }
655    
656    
657 dpavlin 22 #ifdef DYNTRANS_BACKEND
658 dpavlin 2 /*
659 dpavlin 22 * cpu_dtb_add_fixup():
660     *
661     * Add a fixup entry to a currently ongoing dyntrans backend translation.
662     */
663     void cpu_dtb_add_fixup(struct cpu *cpu, int type, void *addr, size_t data)
664     {
665     struct dtb_fixup *fixup = malloc(sizeof (struct dtb_fixup));
666     if (fixup == NULL) {
667     fprintf(stderr, "out of memory\n"),
668     exit(1);
669     }
670    
671     /* memset(fixup, 0, sizeof(struct dtb_fixup)); */
672    
673     fixup->next = cpu->translation_context.fixups;
674     cpu->translation_context.fixups = fixup;
675    
676     fixup->type = type;
677     fixup->addr = addr;
678     fixup->data = data;
679    
680     /* printf("{ fixup added: host addr %p, data=%p }\n", addr,
681     (void *)data); */
682     }
683    
684    
685     /*
686     * cpu_dtb_do_fixups():
687     *
688     * This function should be called when a chunk of code has been translated,
689     * and post-fixup is to be applied (i.e. add data which for some reason was
690     * not included in the generated code).
691     *
692     * If no fixup is necessary for a specific host platform, then it still needs
693     * an empty do_fixups routine here (just set done = 1).
694     */
695     void cpu_dtb_do_fixups(struct cpu *cpu)
696     {
697     for (;;) {
698     int done = 0;
699     size_t omit_addr;
700    
701     struct dtb_fixup *fixup = cpu->translation_context.fixups;
702     if (fixup == NULL)
703     break;
704    
705     cpu->translation_context.fixups = fixup->next;
706    
707     #ifdef DYNTRANS_BACKEND_ALPHA
708     /* Add the data at the end of the new translation: */
709     /*printf("%p %p\n", fixup->addr, fixup->data);*/
710     omit_addr = (size_t)cpu->translation_context.p -
711     (size_t)cpu->translation_context.translation_buffer;
712     /*printf("omit_addr = %016llx\n", (long long)omit_addr);*/
713     omit_addr = ((omit_addr - 1) | (sizeof(uint64_t) - 1)) + 1;
714     /*printf("omit_addr = %016llx\n", (long long)omit_addr);*/
715     {
716     uint64_t *x = (void *)(omit_addr + (size_t)cpu->
717     translation_context.translation_buffer);
718     uint32_t *fixup_instr = (void *)fixup->addr;
719     size_t ofs = omit_addr;
720     if (ofs > 0x7fff) {
721     fatal("Alpha fixup > 0x7fff!\n");
722     exit(1);
723     }
724     *x = fixup->data;
725     /*printf("orig instr = 0x%08x\n", *fixup_instr);*/
726     (*fixup_instr) &= ~0xffff;
727     (*fixup_instr) |= ofs;
728     /*printf("new instr = 0x%08x\n", *fixup_instr);*/
729     }
730     omit_addr += sizeof(uint64_t);
731     cpu->translation_context.p = (void *)
732     ((size_t)cpu->translation_context.translation_buffer
733     + omit_addr);
734     done = 1;
735     #endif /* DYNTRANS_BACKEND_ALPHA */
736    
737     if (!done)
738     fatal("!!! cpu_dtb_do_fixups() not implemented yet"
739     " for this host architecture!\n");
740     }
741     }
742    
743     #endif /* DYNTRANS_BACKEND */
744    
745    
746     /*
747 dpavlin 2 * cpu_init():
748     *
749     * Should be called before any other cpu_*() function.
750     */
751     void cpu_init(void)
752     {
753     /* Note: These are registered in alphabetic order. */
754 dpavlin 12
755     #ifdef ENABLE_ALPHA
756     add_cpu_family(alpha_cpu_family_init, ARCH_ALPHA);
757     #endif
758    
759     #ifdef ENABLE_ARM
760 dpavlin 6 add_cpu_family(arm_cpu_family_init, ARCH_ARM);
761 dpavlin 12 #endif
762    
763 dpavlin 14 #ifdef ENABLE_AVR
764     add_cpu_family(avr_cpu_family_init, ARCH_AVR);
765     #endif
766    
767     #ifdef ENABLE_HPPA
768     add_cpu_family(hppa_cpu_family_init, ARCH_HPPA);
769     #endif
770    
771     #ifdef ENABLE_I960
772     add_cpu_family(i960_cpu_family_init, ARCH_I960);
773     #endif
774    
775 dpavlin 12 #ifdef ENABLE_IA64
776     add_cpu_family(ia64_cpu_family_init, ARCH_IA64);
777     #endif
778    
779     #ifdef ENABLE_M68K
780     add_cpu_family(m68k_cpu_family_init, ARCH_M68K);
781     #endif
782    
783     #ifdef ENABLE_MIPS
784 dpavlin 2 add_cpu_family(mips_cpu_family_init, ARCH_MIPS);
785 dpavlin 12 #endif
786    
787     #ifdef ENABLE_PPC
788 dpavlin 2 add_cpu_family(ppc_cpu_family_init, ARCH_PPC);
789 dpavlin 12 #endif
790    
791 dpavlin 14 #ifdef ENABLE_SH
792     add_cpu_family(sh_cpu_family_init, ARCH_SH);
793     #endif
794    
795 dpavlin 12 #ifdef ENABLE_SPARC
796     add_cpu_family(sparc_cpu_family_init, ARCH_SPARC);
797     #endif
798    
799     #ifdef ENABLE_X86
800 dpavlin 4 add_cpu_family(x86_cpu_family_init, ARCH_X86);
801 dpavlin 12 #endif
802 dpavlin 2 }
803    

  ViewVC Help
Powered by ViewVC 1.1.26