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

Annotation of /trunk/src/cpu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (hide annotations)
Mon Oct 8 16:18:00 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 14050 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.707 2005/04/27 16:37:33 debug Exp $
20050408	Some minor updates to the wdc. Linux now doesn't complain
		anymore if a disk is non-present.
20050409	Various minor fixes (a bintrans bug, and some other things).
		The wdc seems to work with Playstation2 emulation, but there
		is a _long_ annoying delay when disks are detected.
		Fixing a really important bintrans bug (when devices and RAM
		are mixed within 4KB pages), which was triggered with
		NetBSD/playstation2 kernels.
20050410	Adding a dummy dev_ps2_ether (just so that NetBSD doesn't
		complain as much during bootup).
		Symbols starting with '$' are now ignored.
		Renaming dev_ps2_ohci.c to dev_ohci.c, etc.
20050411	Moving the bintrans-cache-isolation check from cpu_mips.c to
		cpu_mips_coproc.c. (I thought this would give a speedup, but
		it's not noticable.)
		Better playstation2 sbus interrupt code.
		Skip ahead many ticks if the count register is read manually.
		(This increases the speed of delay-loops that simply read
		the count register.)
20050412	Updates to the playstation2 timer/interrupt code.
		Some other minor updates.
20050413	NetBSD/cobalt runs from a disk image :-) including userland;
		updating the documentation on how to install NetBSD/cobalt
		using NetBSD/pmax (!).
		Some minor bintrans updates (no real speed improvement) and
		other minor updates (playstation2 now uses the -o options).
20050414	Adding a dummy x86 (and AMD64) mode.
20050415	Adding some (32-bit and 16-bit) x86 instructions.
		Adding some initial support for non-SCSI, non-IDE floppy
		images. (The x86 mode can boot from these, more or less.)
		Moving the devices/ and include/ directories to src/devices/
		and src/include/, respectively.
20050416	Continuing on the x86 stuff. (Adding pc_bios.c and some simple
		support for software interrupts in 16-bit mode.)
20050417	Ripping out most of the x86 instruction decoding stuff, trying
		to rewrite it in a cleaner way.
		Disabling some of the least working CPU families in the
		configure script (sparc, x86, alpha, hppa), so that they are
		not enabled by default.
20050418	Trying to fix the bug which caused problems when turning on
		and off bintrans interactively, by flushing the bintrans cache
		whenever bintrans is manually (re)enabled.
20050419	Adding the 'lswi' ppc instruction.
		Minor updates to the x86 instruction decoding.
20050420	Renaming x86 register name indices from R_xx to X86_R_xx (this
		makes building on Tru64 nicer).
20050422	Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi.
20050427	Adding screenshots to guestoses.html.
		Some minor fixes and testing for the next release.

==============  RELEASE 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