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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26