/[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 26 - (show annotations)
Mon Oct 8 16:20:10 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 16702 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1264 2006/06/25 11:08:04 debug Exp $
20060624	Replacing the error-prone machine type initialization stuff
		with something more reasonable.
		Finally removing the old "cpu_run" kludge; moving around stuff
		in machine.c and emul.c to better suit the dyntrans system.
		Various minor dyntrans cleanups (renaming translate_address to
		translate_v2p, and experimenting with template physpages).
20060625	Removing the speed hack which separated the vph entries into
		two halves (code vs data); things seem a lot more stable now.
		Minor performance hack: R2000/R3000 cache isolation now only
		clears address translations when going into isolation, not
		when going out of it.
		Fixing the MIPS interrupt problems by letting mtc0 immediately
		cause interrupts.

==============  RELEASE 0.4.0.1  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26