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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26