/[gxemul]/upstream/0.3.6.1/src/cpus/cpu_run.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.6.1/src/cpus/cpu_run.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 17 - (hide annotations)
Mon Oct 8 16:19:05 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 7639 byte(s)
0.3.6.1
1 dpavlin 14 /*
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     * $Id: cpu_run.c,v 1.2 2005/09/18 19:54:14 debug Exp $
29     *
30     * Included from cpu_mips.c, cpu_ppc.c etc. (The reason for this is that
31     * the call to a specific cpu's routine that runs one instruction will
32     * be inlined from here.)
33     *
34     * TODO: Rewrite/cleanup. This is too ugly.
35     */
36    
37     #include "console.h"
38     #include "debugger.h"
39    
40    
41     static int instrs_per_cycle(struct cpu *cpu) {
42     #ifdef CPU_RUN_MIPS
43     return cpu->cd.mips.cpu_type.instrs_per_cycle;
44     #else
45     return 1;
46     #endif
47     }
48    
49    
50     /*
51     * CPU_RUN():
52     *
53     * Run instructions on all CPUs in this machine, for a "medium duration"
54     * (or until all CPUs have halted).
55     *
56     * Return value is 1 if anything happened, 0 if all CPUs are stopped.
57     */
58     int CPU_RUN(struct emul *emul, struct machine *machine)
59     {
60     struct cpu **cpus = machine->cpus;
61     int ncpus = machine->ncpus;
62     int64_t max_instructions_cached = machine->max_instructions;
63     int64_t max_random_cycles_per_chunk_cached =
64     machine->max_random_cycles_per_chunk;
65     int64_t ncycles_chunk_end;
66     int running, rounds;
67    
68     /* The main loop: */
69     running = 1;
70     rounds = 0;
71     while (running || single_step) {
72     ncycles_chunk_end = machine->ncycles + (1 << 17);
73    
74     machine->a_few_instrs = machine->a_few_cycles *
75     instrs_per_cycle(cpus[0]);
76    
77     /* Do a chunk of cycles: */
78     do {
79     int i, j, te, cpu0instrs, a_few_instrs2;
80    
81     running = 0;
82     cpu0instrs = 0;
83    
84     /*
85     * Run instructions from each CPU:
86     */
87    
88     /* Is any cpu alive? */
89     for (i=0; i<ncpus; i++)
90     if (cpus[i]->running)
91     running = 1;
92    
93     if (single_step) {
94     if (single_step == 1) {
95     /*
96     * TODO: (Important!)
97     *
98     * If these are enabled, and focus is
99     * shifted to another machine in the
100     * debugger, then the wrong machine
101     * gets its variables restored!
102     */
103     old_instruction_trace =
104     machine->instruction_trace;
105     old_quiet_mode = quiet_mode;
106     old_show_trace_tree =
107     machine->show_trace_tree;
108     machine->instruction_trace = 1;
109     machine->show_trace_tree = 1;
110     quiet_mode = 0;
111     single_step = 2;
112     }
113    
114     for (j=0; j<instrs_per_cycle(cpus[0]); j++) {
115     if (single_step)
116     debugger();
117     for (i=0; i<ncpus; i++)
118     if (cpus[i]->running) {
119     int instrs_run =
120     CPU_RINSTR(emul,
121     cpus[i]);
122     if (i == 0)
123     cpu0instrs +=
124     instrs_run;
125     }
126     }
127     } else if (max_random_cycles_per_chunk_cached > 0) {
128     for (i=0; i<ncpus; i++)
129     if (cpus[i]->running && !single_step) {
130     a_few_instrs2 = machine->
131     a_few_cycles;
132     if (a_few_instrs2 >=
133     max_random_cycles_per_chunk_cached)
134     a_few_instrs2 = max_random_cycles_per_chunk_cached;
135     j = (random() % a_few_instrs2) + 1;
136     j *= instrs_per_cycle(cpus[i]);
137     while (j-- >= 1 && cpus[i]->running) {
138     int instrs_run = CPU_RINSTR(emul, cpus[i]);
139     if (i == 0)
140     cpu0instrs += instrs_run;
141     if (single_step)
142     break;
143     }
144     }
145     } else {
146     /* CPU 0 is special, cpu0instr must be updated. */
147     for (j=0; j<machine->a_few_instrs; ) {
148     int instrs_run;
149     if (!cpus[0]->running || single_step)
150     break;
151     do {
152     instrs_run =
153     CPU_RINSTR(emul, cpus[0]);
154     if (instrs_run == 0 ||
155     single_step) {
156     j = machine->a_few_instrs;
157     break;
158     }
159     } while (instrs_run == 0);
160     j += instrs_run;
161     cpu0instrs += instrs_run;
162     }
163    
164     /* CPU 1 and up: */
165     for (i=1; i<ncpus; i++) {
166     a_few_instrs2 = machine->a_few_cycles *
167     instrs_per_cycle(cpus[i]);
168     for (j=0; j<a_few_instrs2; )
169     if (cpus[i]->running) {
170     int instrs_run = 0;
171     while (!instrs_run) {
172     instrs_run = CPU_RINSTR(emul, cpus[i]);
173     if (instrs_run == 0 ||
174     single_step) {
175     j = a_few_instrs2;
176     break;
177     }
178     }
179     j += instrs_run;
180     } else
181     break;
182     }
183     }
184    
185     /*
186     * Hardware 'ticks': (clocks, interrupt sources...)
187     *
188     * Here, cpu0instrs is the number of instructions
189     * executed on cpu0. (TODO: don't use cpu 0 for this,
190     * use some kind of "mainbus" instead.) Hardware
191     * ticks are not per instruction, but per cycle,
192     * so we divide by the number of
193     * instructions_per_cycle for cpu0.
194     *
195     * TODO: This doesn't work in a machine with, say,
196     * a mixture of R3000, R4000, and R10000 CPUs, if
197     * there ever was such a thing.
198     *
199     * TODO 2: A small bug occurs if cpu0instrs isn't
200     * evenly divisible by instrs_per_cycle. We then
201     * cause hardware ticks a fraction of a cycle too
202     * often.
203     */
204     i = instrs_per_cycle(cpus[0]);
205     switch (i) {
206     case 1: break;
207     case 2: cpu0instrs >>= 1; break;
208     case 4: cpu0instrs >>= 2; break;
209     default:
210     cpu0instrs /= i;
211     }
212    
213     for (te=0; te<machine->n_tick_entries; te++) {
214     machine->ticks_till_next[te] -= cpu0instrs;
215    
216     if (machine->ticks_till_next[te] <= 0) {
217     while (machine->ticks_till_next[te]
218     <= 0)
219     machine->ticks_till_next[te] +=
220     machine->
221     ticks_reset_value[te];
222     machine->tick_func[te](cpus[0],
223     machine->tick_extra[te]);
224     }
225     }
226    
227     /* Any CPU dead? */
228     for (i=0; i<ncpus; i++) {
229     if (cpus[i]->dead && machine->
230     exit_without_entering_debugger == 0)
231     single_step = 1;
232     }
233    
234     machine->ncycles += cpu0instrs;
235     } while (running && (machine->ncycles < ncycles_chunk_end));
236    
237     /* If we've done buffered console output,
238     the flush stdout every now and then: */
239     if (machine->ncycles > machine->ncycles_flush + (1<<17)) {
240     console_flush();
241     machine->ncycles_flush = machine->ncycles;
242     }
243    
244     if (machine->ncycles > machine->ncycles_show + (1<<25)) {
245     machine->ncycles_since_gettimeofday +=
246     (machine->ncycles - machine->ncycles_show);
247     cpu_show_cycles(machine, 0);
248     machine->ncycles_show = machine->ncycles;
249     }
250    
251     if (max_instructions_cached != 0 &&
252     machine->ncycles >= max_instructions_cached)
253     running = 0;
254    
255     /* Let's allow other machines to run. */
256     rounds ++;
257     if (rounds > 2)
258     break;
259     }
260    
261     return running;
262     }
263    

  ViewVC Help
Powered by ViewVC 1.1.26