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

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


1 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