/[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

Contents of /trunk/src/cpu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (show annotations)
Mon Oct 8 16:18:38 2007 UTC (12 years, 1 month 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 /*
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 * $Id: cpu.c,v 1.316 2005/08/16 05:37:09 debug Exp $
29 *
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 #include "memory.h"
41 #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 struct cpu *cpu;
61 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 cpu = zeroed_alloc(sizeof(struct cpu));
76
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 cpu_create_or_reset_tc(cpu);
87
88 fp = first_cpu_family;
89
90 while (fp != NULL) {
91 if (fp->cpu_new != NULL) {
92 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 exit(1);
99 }
100 return cpu;
101 }
102 }
103
104 fp = fp->next;
105 }
106
107 fatal("\ncpu_new(): unknown cpu type '%s'\n", cpu_type_name);
108 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 * 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 * 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 void cpu_run_deinit(struct machine *machine)
390 {
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 cpu_show_cycles(machine, 1);
409
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 void cpu_show_cycles(struct machine *machine, int forced)
426 {
427 uint64_t offset, pc;
428 char *symbol;
429 int64_t mseconds, ninstrs, is, avg;
430 struct timeval tv;
431 int h, m, s, ms, d, instrs_per_cycle = 1;
432
433 static int64_t mseconds_last = 0;
434 static int64_t ninstrs_last = -1;
435
436 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 }
442
443 pc = machine->cpus[machine->bootstrap_cpu]->pc;
444
445 gettimeofday(&tv, NULL);
446 mseconds = (tv.tv_sec - machine->starttime.tv_sec) * 1000
447 + (tv.tv_usec - machine->starttime.tv_usec) / 1000;
448
449 if (mseconds == 0)
450 mseconds = 1;
451
452 if (mseconds - mseconds_last == 0)
453 mseconds ++;
454
455 ninstrs = machine->ncycles_since_gettimeofday * instrs_per_cycle;
456
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 /* debug("[ updating emulated_hz to %lli Hz ]\n",
477 (long long)machine->emulated_hz); */
478 }
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 printf("[ %lli instrs",
486 (long long)(machine->ncycles * instrs_per_cycle));
487
488 if (!machine->automatic_clock_adjustment) {
489 d = machine->emulated_hz / 1000;
490 if (d < 1)
491 d = 1;
492 ms = machine->ncycles / d;
493 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 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
512 symbol = get_symbol_name(&machine->symbol_context, pc, &offset);
513
514 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
521 if (symbol != NULL)
522 printf(" <%s>", symbol);
523 printf(" ]\n");
524
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 void cpu_run_init(struct machine *machine)
538 {
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 machine->ncycles_since_gettimeofday = 0;
571 }
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
648 #ifdef ENABLE_ALPHA
649 add_cpu_family(alpha_cpu_family_init, ARCH_ALPHA);
650 #endif
651
652 #ifdef ENABLE_ARM
653 add_cpu_family(arm_cpu_family_init, ARCH_ARM);
654 #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 add_cpu_family(mips_cpu_family_init, ARCH_MIPS);
666 #endif
667
668 #ifdef ENABLE_PPC
669 add_cpu_family(ppc_cpu_family_init, ARCH_PPC);
670 #endif
671
672 #ifdef ENABLE_SPARC
673 add_cpu_family(sparc_cpu_family_init, ARCH_SPARC);
674 #endif
675
676 #ifdef ENABLE_X86
677 add_cpu_family(x86_cpu_family_init, ARCH_X86);
678 #endif
679 }
680

  ViewVC Help
Powered by ViewVC 1.1.26