/[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

Annotation of /upstream/0.3.4/src/cpu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 11 - (hide 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 dpavlin 2 /*
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 dpavlin 10 * $Id: cpu.c,v 1.298 2005/06/27 10:43:16 debug Exp $
29 dpavlin 2 *
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 dpavlin 10 struct cpu *cpu;
60 dpavlin 2 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 dpavlin 10 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 dpavlin 2 fp = first_cpu_family;
91    
92     while (fp != NULL) {
93     if (fp->cpu_new != NULL) {
94 dpavlin 10 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 dpavlin 2 exit(1);
101     }
102 dpavlin 10 return cpu;
103 dpavlin 2 }
104     }
105    
106     fp = fp->next;
107     }
108    
109 dpavlin 6 fatal("\ncpu_new(): unknown cpu type '%s'\n", cpu_type_name);
110 dpavlin 2 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 dpavlin 10 cpu_show_cycles(machine, 1);
327 dpavlin 2
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 dpavlin 10 void cpu_show_cycles(struct machine *machine, int forced)
344 dpavlin 2 {
345     uint64_t offset, pc;
346 dpavlin 10 int is_32bit = 0, instrs_per_cycle = 1;
347 dpavlin 2 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 dpavlin 10 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 dpavlin 2 }
368    
369     pc = machine->cpus[machine->bootstrap_cpu]->pc;
370    
371     gettimeofday(&tv, NULL);
372 dpavlin 10 mseconds = (tv.tv_sec - machine->starttime.tv_sec) * 1000
373     + (tv.tv_usec - machine->starttime.tv_usec) / 1000;
374 dpavlin 2
375     if (mseconds == 0)
376     mseconds = 1;
377    
378     if (mseconds - mseconds_last == 0)
379     mseconds ++;
380    
381 dpavlin 10 ninstrs = machine->ncycles_since_gettimeofday * instrs_per_cycle;
382 dpavlin 2
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 dpavlin 10 printf("[ %lli instrs",
412     (long long)(machine->ncycles * instrs_per_cycle));
413 dpavlin 2
414     if (!machine->automatic_clock_adjustment) {
415     d = machine->emulated_hz / 1000;
416     if (d < 1)
417     d = 1;
418 dpavlin 10 ms = machine->ncycles / d;
419 dpavlin 2 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 dpavlin 10 printf("; i/s=%lli avg=%lli; ",
431 dpavlin 2 (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 dpavlin 10 printf("pc=0x%08x", (int)pc);
439 dpavlin 2 else
440 dpavlin 10 printf("pc=0x%016llx", (long long)pc);
441 dpavlin 2
442 dpavlin 10 if (symbol != NULL)
443     printf(" <%s>", symbol);
444     printf(" ]\n");
445 dpavlin 2
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 dpavlin 10 machine->ncycles_since_gettimeofday = 0;
492 dpavlin 2 }
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 dpavlin 6 add_cpu_family(arm_cpu_family_init, ARCH_ARM);
569 dpavlin 2 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 dpavlin 4 add_cpu_family(x86_cpu_family_init, ARCH_X86);
573 dpavlin 2 }
574    

  ViewVC Help
Powered by ViewVC 1.1.26