/[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 12 - (hide annotations)
Mon Oct 8 16:18:38 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 16666 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.905 2005/08/16 09:16:24 debug Exp $
20050628	Continuing the work on the ARM translation engine. end_of_page
		works. Experimenting with load/store translation caches
		(virtual -> physical -> host).
20050629	More ARM stuff (memory access translation cache, mostly). This
		might break a lot of stuff elsewhere, probably some MIPS-
		related translation things.
20050630	Many load/stores are now automatically generated and included
		into cpu_arm_instr.c; 1024 functions in total (!).
		Fixes based on feedback from Alec Voropay: only print 8 hex
		digits instead of 16 in some cases when emulating 32-bit
		machines; similar 8 vs 16 digit fix for breakpoint addresses;
		4Kc has 16 TLB entries, not 48; the MIPS config select1
		register is now printed with "reg ,0".
		Also changing many other occurances of 16 vs 8 digit output.
		Adding cache associativity fields to mips_cpu_types.h; updating
		some other cache fields; making the output of
		mips_cpu_dumpinfo() look nicer.
		Generalizing the bintrans stuff for device accesses to also
		work with the new translation system. (This might also break
		some MIPS things.)
		Adding multi-load/store instructions to the ARM disassembler
		and the translator, and some optimizations of various kinds.
20050701	Adding a simple dev_disk (it can read/write sectors from
		disk images).
20050712	Adding dev_ether (a simple ethernet send/receive device).
		Debugger command "ninstrs" for toggling show_nr_of_instructions
		during runtime.
		Removing the framebuffer logo.
20050713	Continuing on dev_ether.
		Adding a dummy cpu_alpha (again).
20050714	More work on cpu_alpha.
20050715	More work on cpu_alpha. Many instructions work, enough to run
		a simple framebuffer fill test (similar to the ARM test).
20050716	More Alpha stuff.
20050717	Minor updates (Alpha stuff).
20050718	Minor updates (Alpha stuff).
20050719	Generalizing some Alpha instructions.
20050720	More Alpha-related updates.
20050721	Continuing on cpu_alpha. Importing rpb.h from NetBSD/alpha.
20050722	Alpha-related updates: userland stuff (Hello World using
		write() compiled statically for FreeBSD/Alpha runs fine), and
		more instructions are now implemented.
20050723	Fixing ldq_u and stq_u.
		Adding more instructions (conditional moves, masks, extracts,
		shifts).
20050724	More FreeBSD/Alpha userland stuff, and adding some more
		instructions (inserts).
20050725	Continuing on the Alpha stuff. (Adding dummy ldt/stt.)
		Adding a -A command line option to turn off alignment checks
		in some cases (for translated code).
		Trying to remove the old bintrans code which updated the pc
		and nr_of_executed_instructions for every instruction.
20050726	Making another attempt att removing the pc/nr of instructions
		code. This time it worked, huge performance increase for
		artificial test code, but performance loss for real-world
		code :-( so I'm scrapping that code for now.
		Tiny performance increase on Alpha (by using ret instead of
		jmp, to play nice with the Alpha's branch prediction) for the
		old MIPS bintrans backend.
20050727	Various minor fixes and cleanups.
20050728	Switching from a 2-level virtual to host/physical translation
		system for ARM emulation, to a 1-level translation.
		Trying to switch from 2-level to 1-level for the MIPS bintrans
		system as well (Alpha only, so far), but there is at least one
		problem: caches and/or how they work with device mappings.
20050730	Doing the 2-level to 1-level conversion for the i386 backend.
		The cache/device bug is still there for R2K/3K :(
		Various other minor updates (Malta etc).
		The mc146818 clock now updates the UIP bit in a way which works
		better with Linux for at least sgimips and Malta emulation.
		Beginning the work on refactoring the dyntrans system.
20050731	Continuing the dyntrans refactoring.
		Fixing a small but serious host alignment bug in memory_rw.
		Adding support for big-endian load/stores to the i386 bintrans
		backend.
		Another minor i386 bintrans backend update: stores from the
		zero register are now one (or two) loads shorter.
		The slt and sltu instructions were incorrectly implemented for
		the i386 backend; only using them for 32-bit mode for now.
20050801	Continuing the dyntrans refactoring.
		Cleanup of the ns16550 serial controller (removing unnecessary
		code).
		Bugfix (memory corruption bug) in dev_gt, and a patch/hack from
		Alec Voropay for Linux/Malta.
20050802	More cleanup/refactoring of the dyntrans subsystem: adding
		phys_page pointers to the lookup tables, for quick jumps
		between translated pages.
		Better fix for the ns16550 device (but still no real FIFO
		functionality).
		Converting cpu_ppc to the new dyntrans system. This means that
		I will have to start from scratch with implementing each
		instruction, and figure out how to implement dual 64/32-bit
		modes etc.
		Removing the URISC CPU family, because it was useless.
20050803	When selecting a machine type, the main type can now be omitted
		if the subtype name is unique. (I.e. -E can be omitted.)
		Fixing a dyntrans/device update bug. (Writes to offset 0 of
		a device could sometimes go unnoticed.)
		Adding an experimental "instruction combination" hack for
		ARM for memset-like byte fill loops.
20050804	Minor progress on cpu_alpha and related things.
		Finally fixing the MIPS dmult/dmultu bugs.
		Fixing some minor TODOs.
20050805	Generalizing the 8259 PIC. It now also works with Cobalt
		and evbmips emulation, in addition to the x86 hack.
		Finally converting the ns16550 device to use devinit.
		Continuing the work on the dyntrans system. Thinking about
		how to add breakpoints.
20050806	More dyntrans updates. Breakpoints seem to work now.
20050807	Minor updates: cpu_alpha and related things; removing
		dev_malta (as it isn't used any more).
		Dyntrans: working on general "show trace tree" support.
		The trace tree stuff now works with both the old MIPS code and
		with newer dyntrans modes. :)
		Continuing on Alpha-related stuff (trying to get *BSD to boot
		a bit further, adding more instructions, etc).
20050808	Adding a dummy IA64 cpu family, and continuing the refactoring
		of the dyntrans system.
		Removing the regression test stuff, because it was more or
		less useless.
		Adding loadlinked/storeconditional type instructions to the
		Alpha emulation. (Needed for Linux/alpha. Not very well tested
		yet.)
20050809	The function call trace tree now prints a per-function nr of
		arguments. (Semi-meaningless, since that data isn't read yet
		from the ELFs; some hardcoded symbols such as memcpy() and
		strlen() work fine, though.)
		More dyntrans refactoring; taking out more of the things that
		are common to all cpu families.
20050810	Working on adding support for "dual mode" for PPC dyntrans
		(i.e. both 64-bit and 32-bit modes).
		(Re)adding some simple PPC instructions.
20050811	Adding a dummy M68K cpu family. The dyntrans system isn't ready
		for variable-length ISAs yet, so it's completely bogus so far.
		Re-adding more PPC instructions.
		Adding a hack to src/file.c which allows OpenBSD/mac68k a.out
		kernels to be loaded.
		Beginning to add PPC loads/stores. So far they only work in
		32-bit mode.
20050812	The configure file option "add_remote" now accepts symbolic
		host names, in addition to numeric IPv4 addresses.
		Re-adding more PPC instructions.
20050814	Continuing to port back more PPC instructions.
		Found and fixed the cache/device write-update bug for 32-bit
		MIPS bintrans. :-)
		Triggered a really weird and annoying bug in Compaq's C
		compiler; ccc sometimes outputs code which loads from an
		address _before_ checking whether the pointer was NULL or not.
		(I'm not sure how to handle this problem.)
20050815	Removing all of the old x86 instruction execution code; adding
		a new (dummy) dyntrans module for x86.
		Taking the first steps to extend the dyntrans system to support
		variable-length instructions.
		Slowly preparing for the next release.
20050816	Adding a dummy SPARC cpu module.
		Minor updates (documentation etc) for the release.

==============  RELEASE 0.3.5  ==============


1 dpavlin 2 /*
2     * Copyright (C) 2005 Anders Gavare. All rights reserved.
3     *
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 12 * $Id: cpu.c,v 1.316 2005/08/16 05:37:09 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     #include <string.h>
37    
38     #include "cpu.h"
39     #include "machine.h"
40 dpavlin 12 #include "memory.h"
41 dpavlin 2 #include "misc.h"
42    
43    
44     extern int quiet_mode;
45     extern int show_opcode_statistics;
46    
47    
48     static struct cpu_family *first_cpu_family = NULL;
49    
50    
51     /*
52     * cpu_new():
53     *
54     * Create a new cpu object. Each family is tried in sequence until a
55     * CPU family recognizes the cpu_type_name.
56     */
57     struct cpu *cpu_new(struct memory *mem, struct machine *machine,
58     int cpu_id, char *name)
59     {
60 dpavlin 10 struct cpu *cpu;
61 dpavlin 2 struct cpu_family *fp;
62     char *cpu_type_name;
63    
64     if (name == NULL) {
65     fprintf(stderr, "cpu_new(): cpu name = NULL?\n");
66     exit(1);
67     }
68    
69     cpu_type_name = strdup(name);
70     if (cpu_type_name == NULL) {
71     fprintf(stderr, "cpu_new(): out of memory\n");
72     exit(1);
73     }
74    
75 dpavlin 12 cpu = zeroed_alloc(sizeof(struct cpu));
76 dpavlin 10
77     cpu->memory_rw = NULL;
78     cpu->name = cpu_type_name;
79     cpu->mem = mem;
80     cpu->machine = machine;
81     cpu->cpu_id = cpu_id;
82     cpu->byte_order = EMUL_LITTLE_ENDIAN;
83     cpu->bootstrap_cpu_flag = 0;
84     cpu->running = 0;
85    
86 dpavlin 12 cpu_create_or_reset_tc(cpu);
87    
88 dpavlin 2 fp = first_cpu_family;
89    
90     while (fp != NULL) {
91     if (fp->cpu_new != NULL) {
92 dpavlin 10 if (fp->cpu_new(cpu, mem, machine, cpu_id,
93     cpu_type_name)) {
94     /* Sanity check: */
95     if (cpu->memory_rw == NULL) {
96     fatal("\ncpu_new(): memory_rw == "
97     "NULL\n");
98 dpavlin 2 exit(1);
99     }
100 dpavlin 10 return cpu;
101 dpavlin 2 }
102     }
103    
104     fp = fp->next;
105     }
106    
107 dpavlin 6 fatal("\ncpu_new(): unknown cpu type '%s'\n", cpu_type_name);
108 dpavlin 2 exit(1);
109     }
110    
111    
112     /*
113     * cpu_show_full_statistics():
114     *
115     * Show detailed statistics on opcode usage on each cpu.
116     */
117     void cpu_show_full_statistics(struct machine *m)
118     {
119     if (m->cpu_family == NULL ||
120     m->cpu_family->show_full_statistics == NULL)
121     fatal("cpu_show_full_statistics(): NULL\n");
122     else
123     m->cpu_family->show_full_statistics(m);
124     }
125    
126    
127     /*
128     * cpu_tlbdump():
129     *
130     * Called from the debugger to dump the TLB in a readable format.
131     * x is the cpu number to dump, or -1 to dump all CPUs.
132     *
133     * If rawflag is nonzero, then the TLB contents isn't formated nicely,
134     * just dumped.
135     */
136     void cpu_tlbdump(struct machine *m, int x, int rawflag)
137     {
138     if (m->cpu_family == NULL || m->cpu_family->tlbdump == NULL)
139     fatal("cpu_tlbdump(): NULL\n");
140     else
141     m->cpu_family->tlbdump(m, x, rawflag);
142     }
143    
144    
145     /*
146     * cpu_register_match():
147     *
148     * Used by the debugger.
149     */
150     void cpu_register_match(struct machine *m, char *name,
151     int writeflag, uint64_t *valuep, int *match_register)
152     {
153     if (m->cpu_family == NULL || m->cpu_family->register_match == NULL)
154     fatal("cpu_register_match(): NULL\n");
155     else
156     m->cpu_family->register_match(m, name, writeflag,
157     valuep, match_register);
158     }
159    
160    
161     /*
162     * cpu_disassemble_instr():
163     *
164     * Convert an instruction word into human readable format, for instruction
165     * tracing.
166     */
167     int cpu_disassemble_instr(struct machine *m, struct cpu *cpu,
168     unsigned char *instr, int running, uint64_t addr, int bintrans)
169     {
170     if (m->cpu_family == NULL || m->cpu_family->disassemble_instr == NULL) {
171     fatal("cpu_disassemble_instr(): NULL\n");
172     return 0;
173     } else
174     return m->cpu_family->disassemble_instr(cpu, instr,
175     running, addr, bintrans);
176     }
177    
178    
179     /*
180     * cpu_register_dump():
181     *
182     * Dump cpu registers in a relatively readable format.
183     *
184     * gprs: set to non-zero to dump GPRs. (CPU dependant.)
185     * coprocs: set bit 0..x to dump registers in coproc 0..x. (CPU dependant.)
186     */
187     void cpu_register_dump(struct machine *m, struct cpu *cpu,
188     int gprs, int coprocs)
189     {
190     if (m->cpu_family == NULL || m->cpu_family->register_dump == NULL)
191     fatal("cpu_register_dump(): NULL\n");
192     else
193     m->cpu_family->register_dump(cpu, gprs, coprocs);
194     }
195    
196    
197     /*
198     * cpu_interrupt():
199     *
200     * Assert an interrupt.
201     * Return value is 1 if the interrupt was asserted, 0 otherwise.
202     */
203     int cpu_interrupt(struct cpu *cpu, uint64_t irq_nr)
204     {
205     if (cpu->machine->cpu_family == NULL ||
206     cpu->machine->cpu_family->interrupt == NULL) {
207     fatal("cpu_interrupt(): NULL\n");
208     return 0;
209     } else
210     return cpu->machine->cpu_family->interrupt(cpu, irq_nr);
211     }
212    
213    
214     /*
215     * cpu_interrupt_ack():
216     *
217     * Acknowledge an interrupt.
218     * Return value is 1 if the interrupt was deasserted, 0 otherwise.
219     */
220     int cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr)
221     {
222     if (cpu->machine->cpu_family == NULL ||
223     cpu->machine->cpu_family->interrupt_ack == NULL) {
224     /* debug("cpu_interrupt_ack(): NULL\n"); */
225     return 0;
226     } else
227     return cpu->machine->cpu_family->interrupt_ack(cpu, irq_nr);
228     }
229    
230    
231     /*
232 dpavlin 12 * cpu_functioncall_trace():
233     *
234     * This function should be called if machine->show_trace_tree is enabled, and
235     * a function call is being made. f contains the address of the function.
236     */
237     void cpu_functioncall_trace(struct cpu *cpu, uint64_t f)
238     {
239     int i, n_args = -1;
240     char *symbol;
241     uint64_t offset;
242    
243     if (cpu->machine->ncpus > 1)
244     fatal("cpu%i:\t", cpu->cpu_id);
245    
246     cpu->trace_tree_depth ++;
247     for (i=0; i<cpu->trace_tree_depth; i++)
248     fatal(" ");
249    
250     fatal("<");
251     symbol = get_symbol_name_and_n_args(&cpu->machine->symbol_context,
252     f, &offset, &n_args);
253     if (symbol != NULL)
254     fatal("%s", symbol);
255     else {
256     if (cpu->is_32bit)
257     fatal("0x%08x", (int)f);
258     else
259     fatal("0x%llx", (long long)f);
260     }
261     fatal("(");
262    
263     if (cpu->machine->cpu_family->functioncall_trace != NULL)
264     cpu->machine->cpu_family->functioncall_trace(cpu, f, n_args);
265    
266     fatal(")>\n");
267     }
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     if (cpu->translation_cache == NULL)
296     cpu->translation_cache = zeroed_alloc(DYNTRANS_CACHE_SIZE +
297     DYNTRANS_CACHE_MARGIN);
298    
299     /* Create an empty table at the beginning of the translation cache: */
300     memset(cpu->translation_cache, 0, sizeof(uint32_t)
301     * N_BASE_TABLE_ENTRIES);
302    
303     cpu->translation_cache_cur_ofs =
304     N_BASE_TABLE_ENTRIES * sizeof(uint32_t);
305    
306     /*
307     * There might be other translation pointers that still point to
308     * within the translation_cache region. Let's invalidate those too:
309     */
310     if (cpu->invalidate_code_translation_caches != NULL)
311     cpu->invalidate_code_translation_caches(cpu);
312     }
313    
314    
315     /*
316 dpavlin 2 * cpu_run():
317     *
318     * Run instructions on all CPUs in this machine, for a "medium duration"
319     * (or until all CPUs have halted).
320     *
321     * Return value is 1 if anything happened, 0 if all CPUs are stopped.
322     */
323     int cpu_run(struct emul *emul, struct machine *m)
324     {
325     if (m->cpu_family == NULL || m->cpu_family->run == NULL) {
326     fatal("cpu_run(): NULL\n");
327     return 0;
328     } else
329     return m->cpu_family->run(emul, m);
330     }
331    
332    
333     /*
334     * cpu_dumpinfo():
335     *
336     * Dumps info about a CPU using debug(). "cpu0: CPUNAME, running" (or similar)
337     * is outputed, and it is up to CPU dependant code to complete the line.
338     */
339     void cpu_dumpinfo(struct machine *m, struct cpu *cpu)
340     {
341     debug("cpu%i: %s, %s", cpu->cpu_id, cpu->name,
342     cpu->running? "running" : "stopped");
343    
344     if (m->cpu_family == NULL || m->cpu_family->dumpinfo == NULL)
345     fatal("cpu_dumpinfo(): NULL\n");
346     else
347     m->cpu_family->dumpinfo(cpu);
348     }
349    
350    
351     /*
352     * cpu_list_available_types():
353     *
354     * Print a list of available CPU types for each cpu family.
355     */
356     void cpu_list_available_types(void)
357     {
358     struct cpu_family *fp;
359     int iadd = 4;
360    
361     fp = first_cpu_family;
362    
363     if (fp == NULL) {
364     debug("No CPUs defined!\n");
365     return;
366     }
367    
368     while (fp != NULL) {
369     debug("%s:\n", fp->name);
370     debug_indentation(iadd);
371     if (fp->list_available_types != NULL)
372     fp->list_available_types();
373     else
374     debug("(internal error: list_available_types"
375     " = NULL)\n");
376     debug_indentation(-iadd);
377    
378     fp = fp->next;
379     }
380     }
381    
382    
383     /*
384     * cpu_run_deinit():
385     *
386     * Shuts down all CPUs in a machine when ending a simulation. (This function
387     * should only need to be called once for each machine.)
388     */
389 dpavlin 12 void cpu_run_deinit(struct machine *machine)
390 dpavlin 2 {
391     int te;
392    
393     /*
394     * Two last ticks of every hardware device. This will allow
395     * framebuffers to draw the last updates to the screen before
396     * halting.
397     */
398     for (te=0; te<machine->n_tick_entries; te++) {
399     machine->tick_func[te](machine->cpus[0],
400     machine->tick_extra[te]);
401     machine->tick_func[te](machine->cpus[0],
402     machine->tick_extra[te]);
403     }
404    
405     debug("cpu_run_deinit(): All CPUs halted.\n");
406    
407     if (machine->show_nr_of_instructions || !quiet_mode)
408 dpavlin 10 cpu_show_cycles(machine, 1);
409 dpavlin 2
410     if (show_opcode_statistics)
411     cpu_show_full_statistics(machine);
412    
413     fflush(stdout);
414     }
415    
416    
417     /*
418     * cpu_show_cycles():
419     *
420     * If automatic adjustment of clock interrupts is turned on, then recalculate
421     * emulated_hz. Also, if show_nr_of_instructions is on, then print a
422     * line to stdout about how many instructions/cycles have been executed so
423     * far.
424     */
425 dpavlin 10 void cpu_show_cycles(struct machine *machine, int forced)
426 dpavlin 2 {
427     uint64_t offset, pc;
428     char *symbol;
429 dpavlin 12 int64_t mseconds, ninstrs, is, avg;
430 dpavlin 2 struct timeval tv;
431 dpavlin 12 int h, m, s, ms, d, instrs_per_cycle = 1;
432 dpavlin 2
433     static int64_t mseconds_last = 0;
434     static int64_t ninstrs_last = -1;
435    
436 dpavlin 10 switch (machine->arch) {
437     case ARCH_MIPS:
438     instrs_per_cycle = machine->cpus[machine->bootstrap_cpu]->
439     cd.mips.cpu_type.instrs_per_cycle;
440     break;
441 dpavlin 2 }
442    
443     pc = machine->cpus[machine->bootstrap_cpu]->pc;
444    
445     gettimeofday(&tv, NULL);
446 dpavlin 10 mseconds = (tv.tv_sec - machine->starttime.tv_sec) * 1000
447     + (tv.tv_usec - machine->starttime.tv_usec) / 1000;
448 dpavlin 2
449     if (mseconds == 0)
450     mseconds = 1;
451    
452     if (mseconds - mseconds_last == 0)
453     mseconds ++;
454    
455 dpavlin 10 ninstrs = machine->ncycles_since_gettimeofday * instrs_per_cycle;
456 dpavlin 2
457     if (machine->automatic_clock_adjustment) {
458     static int first_adjustment = 1;
459    
460     /* Current nr of cycles per second: */
461     int64_t cur_cycles_per_second = 1000 *
462     (ninstrs-ninstrs_last) / (mseconds-mseconds_last)
463     / instrs_per_cycle;
464    
465     if (cur_cycles_per_second < 1000000)
466     cur_cycles_per_second = 1000000;
467    
468     if (first_adjustment) {
469     machine->emulated_hz = cur_cycles_per_second;
470     first_adjustment = 0;
471     } else {
472     machine->emulated_hz = (15 * machine->emulated_hz +
473     cur_cycles_per_second) / 16;
474     }
475    
476 dpavlin 12 /* debug("[ updating emulated_hz to %lli Hz ]\n",
477     (long long)machine->emulated_hz); */
478 dpavlin 2 }
479    
480    
481     /* RETURN here, unless show_nr_of_instructions (-N) is turned on: */
482     if (!machine->show_nr_of_instructions && !forced)
483     goto do_return;
484    
485 dpavlin 10 printf("[ %lli instrs",
486     (long long)(machine->ncycles * instrs_per_cycle));
487 dpavlin 2
488     if (!machine->automatic_clock_adjustment) {
489     d = machine->emulated_hz / 1000;
490     if (d < 1)
491     d = 1;
492 dpavlin 10 ms = machine->ncycles / d;
493 dpavlin 2 h = ms / 3600000;
494     ms -= 3600000 * h;
495     m = ms / 60000;
496     ms -= 60000 * m;
497     s = ms / 1000;
498     ms -= 1000 * s;
499    
500     printf("emulated time = %02i:%02i:%02i.%03i; ", h, m, s, ms);
501     }
502    
503     /* Instructions per second, and average so far: */
504 dpavlin 12 is = 1000 * (ninstrs-ninstrs_last) / (mseconds-mseconds_last);
505     avg = (long long)1000 * ninstrs / mseconds;
506     if (is < 0)
507     is = 0;
508     if (avg < 0)
509     avg = 0;
510     printf("; i/s=%lli avg=%lli", (long long)is, (long long)avg);
511 dpavlin 2
512     symbol = get_symbol_name(&machine->symbol_context, pc, &offset);
513    
514 dpavlin 12 if (machine->ncpus == 1) {
515     if (machine->cpus[machine->bootstrap_cpu]->is_32bit)
516     printf("; pc=0x%08x", (int)pc);
517     else
518     printf("; pc=0x%016llx", (long long)pc);
519     }
520 dpavlin 2
521 dpavlin 10 if (symbol != NULL)
522     printf(" <%s>", symbol);
523     printf(" ]\n");
524 dpavlin 2
525     do_return:
526     ninstrs_last = ninstrs;
527     mseconds_last = mseconds;
528     }
529    
530    
531     /*
532     * cpu_run_init():
533     *
534     * Prepare to run instructions on all CPUs in this machine. (This function
535     * should only need to be called once for each machine.)
536     */
537 dpavlin 12 void cpu_run_init(struct machine *machine)
538 dpavlin 2 {
539     int ncpus = machine->ncpus;
540     int te;
541    
542     machine->a_few_cycles = 1048576;
543     machine->ncycles_flush = 0;
544     machine->ncycles = 0;
545     machine->ncycles_show = 0;
546    
547     /*
548     * Instead of doing { one cycle, check hardware ticks }, we
549     * can do { n cycles, check hardware ticks }, as long as
550     * n is at most as much as the lowest number of cycles/tick
551     * for any hardware device.
552     */
553     for (te=0; te<machine->n_tick_entries; te++) {
554     if (machine->ticks_reset_value[te] < machine->a_few_cycles)
555     machine->a_few_cycles = machine->ticks_reset_value[te];
556     }
557    
558     machine->a_few_cycles >>= 1;
559     if (machine->a_few_cycles < 1)
560     machine->a_few_cycles = 1;
561    
562     if (ncpus > 1 && machine->max_random_cycles_per_chunk == 0)
563     machine->a_few_cycles = 1;
564    
565     /* debug("cpu_run_init(): a_few_cycles = %i\n",
566     machine->a_few_cycles); */
567    
568     /* For performance measurement: */
569     gettimeofday(&machine->starttime, NULL);
570 dpavlin 10 machine->ncycles_since_gettimeofday = 0;
571 dpavlin 2 }
572    
573    
574     /*
575     * add_cpu_family():
576     *
577     * Allocates a cpu_family struct and calls an init function for the
578     * family to fill in reasonable data and pointers.
579     */
580     static void add_cpu_family(int (*family_init)(struct cpu_family *), int arch)
581     {
582     struct cpu_family *fp, *tmp;
583     int res;
584    
585     fp = malloc(sizeof(struct cpu_family));
586     if (fp == NULL) {
587     fprintf(stderr, "add_cpu_family(): out of memory\n");
588     exit(1);
589     }
590     memset(fp, 0, sizeof(struct cpu_family));
591    
592     /*
593     * family_init() returns 1 if the struct has been filled with
594     * valid data, 0 if suppor for the cpu family isn't compiled
595     * into the emulator.
596     */
597     res = family_init(fp);
598     if (!res) {
599     free(fp);
600     return;
601     }
602     fp->arch = arch;
603     fp->next = NULL;
604    
605     /* Add last in family chain: */
606     tmp = first_cpu_family;
607     if (tmp == NULL) {
608     first_cpu_family = fp;
609     } else {
610     while (tmp->next != NULL)
611     tmp = tmp->next;
612     tmp->next = fp;
613     }
614     }
615    
616    
617     /*
618     * cpu_family_ptr_by_number():
619     *
620     * Returns a pointer to a CPU family based on the ARCH_* integers.
621     */
622     struct cpu_family *cpu_family_ptr_by_number(int arch)
623     {
624     struct cpu_family *fp;
625     fp = first_cpu_family;
626    
627     /* YUCK! This is too hardcoded! TODO */
628    
629     while (fp != NULL) {
630     if (arch == fp->arch)
631     return fp;
632     fp = fp->next;
633     }
634    
635     return NULL;
636     }
637    
638    
639     /*
640     * cpu_init():
641     *
642     * Should be called before any other cpu_*() function.
643     */
644     void cpu_init(void)
645     {
646     /* Note: These are registered in alphabetic order. */
647 dpavlin 12
648     #ifdef ENABLE_ALPHA
649     add_cpu_family(alpha_cpu_family_init, ARCH_ALPHA);
650     #endif
651    
652     #ifdef ENABLE_ARM
653 dpavlin 6 add_cpu_family(arm_cpu_family_init, ARCH_ARM);
654 dpavlin 12 #endif
655    
656     #ifdef ENABLE_IA64
657     add_cpu_family(ia64_cpu_family_init, ARCH_IA64);
658     #endif
659    
660     #ifdef ENABLE_M68K
661     add_cpu_family(m68k_cpu_family_init, ARCH_M68K);
662     #endif
663    
664     #ifdef ENABLE_MIPS
665 dpavlin 2 add_cpu_family(mips_cpu_family_init, ARCH_MIPS);
666 dpavlin 12 #endif
667    
668     #ifdef ENABLE_PPC
669 dpavlin 2 add_cpu_family(ppc_cpu_family_init, ARCH_PPC);
670 dpavlin 12 #endif
671    
672     #ifdef ENABLE_SPARC
673     add_cpu_family(sparc_cpu_family_init, ARCH_SPARC);
674     #endif
675    
676     #ifdef ENABLE_X86
677 dpavlin 4 add_cpu_family(x86_cpu_family_init, ARCH_X86);
678 dpavlin 12 #endif
679 dpavlin 2 }
680    

  ViewVC Help
Powered by ViewVC 1.1.26