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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5 - (show annotations)
Mon Oct 8 16:18:06 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 14050 byte(s)
0.3.2
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.292 2005/04/14 21:01:53 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 "misc.h"
41
42
43 extern int quiet_mode;
44 extern int show_opcode_statistics;
45
46
47 static struct cpu_family *first_cpu_family = NULL;
48
49
50 /*
51 * cpu_new():
52 *
53 * Create a new cpu object. Each family is tried in sequence until a
54 * CPU family recognizes the cpu_type_name.
55 */
56 struct cpu *cpu_new(struct memory *mem, struct machine *machine,
57 int cpu_id, char *name)
58 {
59 struct cpu *c;
60 struct cpu_family *fp;
61 char *cpu_type_name;
62
63 if (name == NULL) {
64 fprintf(stderr, "cpu_new(): cpu name = NULL?\n");
65 exit(1);
66 }
67
68 cpu_type_name = strdup(name);
69 if (cpu_type_name == NULL) {
70 fprintf(stderr, "cpu_new(): out of memory\n");
71 exit(1);
72 }
73
74 fp = first_cpu_family;
75
76 while (fp != NULL) {
77 if (fp->cpu_new != NULL) {
78 c = fp->cpu_new(mem, machine, cpu_id, cpu_type_name);
79 if (c != NULL) {
80 /* Some sanity-checks: */
81 if (c->memory_rw == NULL) {
82 fatal("No memory_rw?\n");
83 exit(1);
84 }
85
86 return c;
87 }
88 }
89
90 fp = fp->next;
91 }
92
93 fprintf(stderr, "cpu_new(): unknown cpu type '%s'\n", cpu_type_name);
94 exit(1);
95 }
96
97
98 /*
99 * cpu_show_full_statistics():
100 *
101 * Show detailed statistics on opcode usage on each cpu.
102 */
103 void cpu_show_full_statistics(struct machine *m)
104 {
105 if (m->cpu_family == NULL ||
106 m->cpu_family->show_full_statistics == NULL)
107 fatal("cpu_show_full_statistics(): NULL\n");
108 else
109 m->cpu_family->show_full_statistics(m);
110 }
111
112
113 /*
114 * cpu_tlbdump():
115 *
116 * Called from the debugger to dump the TLB in a readable format.
117 * x is the cpu number to dump, or -1 to dump all CPUs.
118 *
119 * If rawflag is nonzero, then the TLB contents isn't formated nicely,
120 * just dumped.
121 */
122 void cpu_tlbdump(struct machine *m, int x, int rawflag)
123 {
124 if (m->cpu_family == NULL || m->cpu_family->tlbdump == NULL)
125 fatal("cpu_tlbdump(): NULL\n");
126 else
127 m->cpu_family->tlbdump(m, x, rawflag);
128 }
129
130
131 /*
132 * cpu_register_match():
133 *
134 * Used by the debugger.
135 */
136 void cpu_register_match(struct machine *m, char *name,
137 int writeflag, uint64_t *valuep, int *match_register)
138 {
139 if (m->cpu_family == NULL || m->cpu_family->register_match == NULL)
140 fatal("cpu_register_match(): NULL\n");
141 else
142 m->cpu_family->register_match(m, name, writeflag,
143 valuep, match_register);
144 }
145
146
147 /*
148 * cpu_disassemble_instr():
149 *
150 * Convert an instruction word into human readable format, for instruction
151 * tracing.
152 */
153 int cpu_disassemble_instr(struct machine *m, struct cpu *cpu,
154 unsigned char *instr, int running, uint64_t addr, int bintrans)
155 {
156 if (m->cpu_family == NULL || m->cpu_family->disassemble_instr == NULL) {
157 fatal("cpu_disassemble_instr(): NULL\n");
158 return 0;
159 } else
160 return m->cpu_family->disassemble_instr(cpu, instr,
161 running, addr, bintrans);
162 }
163
164
165 /*
166 * cpu_register_dump():
167 *
168 * Dump cpu registers in a relatively readable format.
169 *
170 * gprs: set to non-zero to dump GPRs. (CPU dependant.)
171 * coprocs: set bit 0..x to dump registers in coproc 0..x. (CPU dependant.)
172 */
173 void cpu_register_dump(struct machine *m, struct cpu *cpu,
174 int gprs, int coprocs)
175 {
176 if (m->cpu_family == NULL || m->cpu_family->register_dump == NULL)
177 fatal("cpu_register_dump(): NULL\n");
178 else
179 m->cpu_family->register_dump(cpu, gprs, coprocs);
180 }
181
182
183 /*
184 * cpu_interrupt():
185 *
186 * Assert an interrupt.
187 * Return value is 1 if the interrupt was asserted, 0 otherwise.
188 */
189 int cpu_interrupt(struct cpu *cpu, uint64_t irq_nr)
190 {
191 if (cpu->machine->cpu_family == NULL ||
192 cpu->machine->cpu_family->interrupt == NULL) {
193 fatal("cpu_interrupt(): NULL\n");
194 return 0;
195 } else
196 return cpu->machine->cpu_family->interrupt(cpu, irq_nr);
197 }
198
199
200 /*
201 * cpu_interrupt_ack():
202 *
203 * Acknowledge an interrupt.
204 * Return value is 1 if the interrupt was deasserted, 0 otherwise.
205 */
206 int cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr)
207 {
208 if (cpu->machine->cpu_family == NULL ||
209 cpu->machine->cpu_family->interrupt_ack == NULL) {
210 /* debug("cpu_interrupt_ack(): NULL\n"); */
211 return 0;
212 } else
213 return cpu->machine->cpu_family->interrupt_ack(cpu, irq_nr);
214 }
215
216
217 /*
218 * cpu_run():
219 *
220 * Run instructions on all CPUs in this machine, for a "medium duration"
221 * (or until all CPUs have halted).
222 *
223 * Return value is 1 if anything happened, 0 if all CPUs are stopped.
224 */
225 int cpu_run(struct emul *emul, struct machine *m)
226 {
227 if (m->cpu_family == NULL || m->cpu_family->run == NULL) {
228 fatal("cpu_run(): NULL\n");
229 return 0;
230 } else
231 return m->cpu_family->run(emul, m);
232 }
233
234
235 /*
236 * cpu_dumpinfo():
237 *
238 * Dumps info about a CPU using debug(). "cpu0: CPUNAME, running" (or similar)
239 * is outputed, and it is up to CPU dependant code to complete the line.
240 */
241 void cpu_dumpinfo(struct machine *m, struct cpu *cpu)
242 {
243 debug("cpu%i: %s, %s", cpu->cpu_id, cpu->name,
244 cpu->running? "running" : "stopped");
245
246 if (m->cpu_family == NULL || m->cpu_family->dumpinfo == NULL)
247 fatal("cpu_dumpinfo(): NULL\n");
248 else
249 m->cpu_family->dumpinfo(cpu);
250 }
251
252
253 /*
254 * cpu_list_available_types():
255 *
256 * Print a list of available CPU types for each cpu family.
257 */
258 void cpu_list_available_types(void)
259 {
260 struct cpu_family *fp;
261 int iadd = 4;
262
263 fp = first_cpu_family;
264
265 if (fp == NULL) {
266 debug("No CPUs defined!\n");
267 return;
268 }
269
270 while (fp != NULL) {
271 debug("%s:\n", fp->name);
272 debug_indentation(iadd);
273 if (fp->list_available_types != NULL)
274 fp->list_available_types();
275 else
276 debug("(internal error: list_available_types"
277 " = NULL)\n");
278 debug_indentation(-iadd);
279
280 fp = fp->next;
281 }
282 }
283
284
285 /*
286 * cpu_run_deinit():
287 *
288 * Shuts down all CPUs in a machine when ending a simulation. (This function
289 * should only need to be called once for each machine.)
290 */
291 void cpu_run_deinit(struct emul *emul, struct machine *machine)
292 {
293 int te;
294
295 /*
296 * Two last ticks of every hardware device. This will allow
297 * framebuffers to draw the last updates to the screen before
298 * halting.
299 */
300 for (te=0; te<machine->n_tick_entries; te++) {
301 machine->tick_func[te](machine->cpus[0],
302 machine->tick_extra[te]);
303 machine->tick_func[te](machine->cpus[0],
304 machine->tick_extra[te]);
305 }
306
307 debug("cpu_run_deinit(): All CPUs halted.\n");
308
309 if (machine->show_nr_of_instructions || !quiet_mode)
310 cpu_show_cycles(machine, &machine->starttime,
311 machine->ncycles, 1);
312
313 if (show_opcode_statistics)
314 cpu_show_full_statistics(machine);
315
316 fflush(stdout);
317 }
318
319
320 /*
321 * cpu_show_cycles():
322 *
323 * If automatic adjustment of clock interrupts is turned on, then recalculate
324 * emulated_hz. Also, if show_nr_of_instructions is on, then print a
325 * line to stdout about how many instructions/cycles have been executed so
326 * far.
327 */
328 void cpu_show_cycles(struct machine *machine,
329 struct timeval *starttime, int64_t ncycles, int forced)
330 {
331 uint64_t offset, pc;
332 int is_32bit = 0, instrs_per_cycle;
333 char *symbol;
334 int64_t mseconds, ninstrs;
335 struct timeval tv;
336 int h, m, s, ms, d;
337
338 static int64_t mseconds_last = 0;
339 static int64_t ninstrs_last = -1;
340
341 if (machine->arch != ARCH_MIPS) {
342 fatal("cpu_show_cycles(): not yet for !MIPS\n");
343 return;
344 }
345
346 if (machine->cpus[machine->bootstrap_cpu]->cd.mips.cpu_type.isa_level
347 < 3 || machine->cpus[machine->bootstrap_cpu]->cd.mips.cpu_type.
348 isa_level == 32)
349 is_32bit = 1;
350 pc = machine->cpus[machine->bootstrap_cpu]->pc;
351 instrs_per_cycle = machine->cpus[machine->bootstrap_cpu]->
352 cd.mips.cpu_type.instrs_per_cycle;
353
354 gettimeofday(&tv, NULL);
355 mseconds = (tv.tv_sec - starttime->tv_sec) * 1000
356 + (tv.tv_usec - starttime->tv_usec) / 1000;
357
358 if (mseconds == 0)
359 mseconds = 1;
360
361 if (mseconds - mseconds_last == 0)
362 mseconds ++;
363
364 ninstrs = ncycles * instrs_per_cycle;
365
366 if (machine->automatic_clock_adjustment) {
367 static int first_adjustment = 1;
368
369 /* Current nr of cycles per second: */
370 int64_t cur_cycles_per_second = 1000 *
371 (ninstrs-ninstrs_last) / (mseconds-mseconds_last)
372 / instrs_per_cycle;
373
374 if (cur_cycles_per_second < 1000000)
375 cur_cycles_per_second = 1000000;
376
377 if (first_adjustment) {
378 machine->emulated_hz = cur_cycles_per_second;
379 first_adjustment = 0;
380 } else {
381 machine->emulated_hz = (15 * machine->emulated_hz +
382 cur_cycles_per_second) / 16;
383 }
384
385 debug("[ updating emulated_hz to %lli Hz ]\n",
386 (long long)machine->emulated_hz);
387 }
388
389
390 /* RETURN here, unless show_nr_of_instructions (-N) is turned on: */
391 if (!machine->show_nr_of_instructions && !forced)
392 goto do_return;
393
394
395 printf("[ ");
396
397 if (!machine->automatic_clock_adjustment) {
398 d = machine->emulated_hz / 1000;
399 if (d < 1)
400 d = 1;
401 ms = ncycles / d;
402 h = ms / 3600000;
403 ms -= 3600000 * h;
404 m = ms / 60000;
405 ms -= 60000 * m;
406 s = ms / 1000;
407 ms -= 1000 * s;
408
409 printf("emulated time = %02i:%02i:%02i.%03i; ", h, m, s, ms);
410 }
411
412 printf("cycles=%lli", (long long) ncycles);
413
414 if (instrs_per_cycle > 1)
415 printf(" (%lli instrs)", (long long) ninstrs);
416
417 /* Instructions per second, and average so far: */
418 printf("; i/s=%lli avg=%lli",
419 (long long) ((long long)1000 * (ninstrs-ninstrs_last)
420 / (mseconds-mseconds_last)),
421 (long long) ((long long)1000 * ninstrs / mseconds));
422
423 symbol = get_symbol_name(&machine->symbol_context, pc, &offset);
424
425 if (is_32bit)
426 printf("; pc=%08x", (int)pc);
427 else
428 printf("; pc=%016llx", (long long)pc);
429
430 printf(" <%s> ]\n", symbol? symbol : "no symbol");
431
432 do_return:
433 ninstrs_last = ninstrs;
434 mseconds_last = mseconds;
435 }
436
437
438 /*
439 * cpu_run_init():
440 *
441 * Prepare to run instructions on all CPUs in this machine. (This function
442 * should only need to be called once for each machine.)
443 */
444 void cpu_run_init(struct emul *emul, struct machine *machine)
445 {
446 int ncpus = machine->ncpus;
447 int te;
448
449 machine->a_few_cycles = 1048576;
450 machine->ncycles_flush = 0;
451 machine->ncycles = 0;
452 machine->ncycles_show = 0;
453
454 /*
455 * Instead of doing { one cycle, check hardware ticks }, we
456 * can do { n cycles, check hardware ticks }, as long as
457 * n is at most as much as the lowest number of cycles/tick
458 * for any hardware device.
459 */
460 for (te=0; te<machine->n_tick_entries; te++) {
461 if (machine->ticks_reset_value[te] < machine->a_few_cycles)
462 machine->a_few_cycles = machine->ticks_reset_value[te];
463 }
464
465 machine->a_few_cycles >>= 1;
466 if (machine->a_few_cycles < 1)
467 machine->a_few_cycles = 1;
468
469 if (ncpus > 1 && machine->max_random_cycles_per_chunk == 0)
470 machine->a_few_cycles = 1;
471
472 /* debug("cpu_run_init(): a_few_cycles = %i\n",
473 machine->a_few_cycles); */
474
475 /* For performance measurement: */
476 gettimeofday(&machine->starttime, NULL);
477 }
478
479
480 /*
481 * add_cpu_family():
482 *
483 * Allocates a cpu_family struct and calls an init function for the
484 * family to fill in reasonable data and pointers.
485 */
486 static void add_cpu_family(int (*family_init)(struct cpu_family *), int arch)
487 {
488 struct cpu_family *fp, *tmp;
489 int res;
490
491 fp = malloc(sizeof(struct cpu_family));
492 if (fp == NULL) {
493 fprintf(stderr, "add_cpu_family(): out of memory\n");
494 exit(1);
495 }
496 memset(fp, 0, sizeof(struct cpu_family));
497
498 /*
499 * family_init() returns 1 if the struct has been filled with
500 * valid data, 0 if suppor for the cpu family isn't compiled
501 * into the emulator.
502 */
503 res = family_init(fp);
504 if (!res) {
505 free(fp);
506 return;
507 }
508 fp->arch = arch;
509 fp->next = NULL;
510
511 /* Add last in family chain: */
512 tmp = first_cpu_family;
513 if (tmp == NULL) {
514 first_cpu_family = fp;
515 } else {
516 while (tmp->next != NULL)
517 tmp = tmp->next;
518 tmp->next = fp;
519 }
520 }
521
522
523 /*
524 * cpu_family_ptr_by_number():
525 *
526 * Returns a pointer to a CPU family based on the ARCH_* integers.
527 */
528 struct cpu_family *cpu_family_ptr_by_number(int arch)
529 {
530 struct cpu_family *fp;
531 fp = first_cpu_family;
532
533 /* YUCK! This is too hardcoded! TODO */
534
535 while (fp != NULL) {
536 if (arch == fp->arch)
537 return fp;
538 fp = fp->next;
539 }
540
541 return NULL;
542 }
543
544
545 /*
546 * cpu_init():
547 *
548 * Should be called before any other cpu_*() function.
549 */
550 void cpu_init(void)
551 {
552 /* Note: These are registered in alphabetic order. */
553 add_cpu_family(alpha_cpu_family_init, ARCH_ALPHA);
554 add_cpu_family(hppa_cpu_family_init, ARCH_HPPA);
555 add_cpu_family(mips_cpu_family_init, ARCH_MIPS);
556 add_cpu_family(ppc_cpu_family_init, ARCH_PPC);
557 add_cpu_family(sparc_cpu_family_init, ARCH_SPARC);
558 add_cpu_family(urisc_cpu_family_init, ARCH_URISC);
559 add_cpu_family(x86_cpu_family_init, ARCH_X86);
560 }
561

  ViewVC Help
Powered by ViewVC 1.1.26