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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26