/[gxemul]/upstream/0.3.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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26