/[gxemul]/trunk/src/cpus/cpu_dyntrans.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/cpus/cpu_dyntrans.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (hide annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 51197 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

==============  RELEASE 0.4.1  ==============


1 dpavlin 14 /*
2 dpavlin 22 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 dpavlin 14 *
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 28 * $Id: cpu_dyntrans.c,v 1.113 2006/07/21 20:09:15 debug Exp $
29 dpavlin 14 *
30     * Common dyntrans routines. Included from cpu_*.c.
31     */
32    
33    
34 dpavlin 28 #ifndef STATIC_STUFF
35     #define STATIC_STUFF
36     /*
37     * gather_statistics():
38     */
39 dpavlin 18 static void gather_statistics(struct cpu *cpu)
40     {
41 dpavlin 28 char ch, buf[60];
42 dpavlin 22 struct DYNTRANS_IC *ic = cpu->cd.DYNTRANS_ARCH.next_ic;
43 dpavlin 28 int i = 0;
44 dpavlin 18 uint64_t a;
45     int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t)
46     cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC);
47    
48 dpavlin 28 buf[0] = '\0';
49 dpavlin 18
50 dpavlin 28 while ((ch = cpu->machine->statistics_fields[i]) != '\0') {
51     if (i != 0)
52     strlcat(buf, " ", sizeof(buf));
53 dpavlin 18
54 dpavlin 28 switch (ch) {
55     case 'i':
56     snprintf(buf + strlen(buf), sizeof(buf),
57     "%p", (void *)ic->f);
58     break;
59     case 'p':
60     /* Physical program counter address: */
61     /* (low_pc must be within the page!) */
62     if (low_pc < 0 ||
63     low_pc >= DYNTRANS_IC_ENTRIES_PER_PAGE)
64     strlcat(buf, "-", sizeof(buf));
65     cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
66     cpu->cd.DYNTRANS_ARCH.cur_ic_page;
67     a = cpu->cd.DYNTRANS_ARCH.cur_physpage->physaddr;
68     a &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
69     DYNTRANS_INSTR_ALIGNMENT_SHIFT);
70     a += low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT;
71     if (cpu->is_32bit)
72     snprintf(buf + strlen(buf), sizeof(buf),
73     "0x%016"PRIx32, (uint32_t)a);
74     else
75     snprintf(buf + strlen(buf), sizeof(buf),
76     "0x%016"PRIx64, (uint64_t)a);
77     break;
78     case 'v':
79     /* Virtual program counter address: */
80     /* (low_pc inside the page, or in a delay slot) */
81     if (low_pc < 0 ||
82     low_pc >= DYNTRANS_IC_ENTRIES_PER_PAGE + 2)
83     strlcat(buf, "-", sizeof(buf));
84     a = cpu->pc;
85     a &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
86     DYNTRANS_INSTR_ALIGNMENT_SHIFT);
87     a += low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT;
88     if (cpu->is_32bit)
89     snprintf(buf + strlen(buf), sizeof(buf),
90     "0x%016"PRIx32, (uint32_t)a);
91     else
92     snprintf(buf + strlen(buf), sizeof(buf),
93     "0x%016"PRIx64, (uint64_t)a);
94     break;
95     }
96     i++;
97 dpavlin 18 }
98 dpavlin 28
99     fprintf(cpu->machine->statistics_file, "%s\n", buf);
100 dpavlin 18 }
101    
102 dpavlin 24
103 dpavlin 18 #define S gather_statistics(cpu)
104    
105 dpavlin 24
106 dpavlin 18 #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
107 dpavlin 20 #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic; \
108 dpavlin 22 cpu->cd.DYNTRANS_ARCH.next_ic += ic->arg[0]; \
109 dpavlin 20 ic->f(cpu, ic);
110 dpavlin 18 #else
111 dpavlin 24
112     /* The normal instruction execution core: */
113     #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic);
114    
115     /* For heavy debugging: */
116     /* #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; \
117     { \
118     int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - \
119     (size_t)cpu->cd.DYNTRANS_ARCH.cur_ic_page) / \
120     sizeof(struct DYNTRANS_IC); \
121     printf("cur_ic_page=%p ic=%p (low_pc=0x%x)\n", \
122     cpu->cd.DYNTRANS_ARCH.cur_ic_page, \
123     ic, low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT); \
124     } \
125     ic->f(cpu, ic); */
126    
127     /* static long long nr_of_I_calls = 0; */
128    
129     /* Temporary hack for finding NULL bugs: */
130     /* #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; \
131     nr_of_I_calls ++; \
132     if (ic->f == NULL) { \
133     int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - \
134     (size_t)cpu->cd.DYNTRANS_ARCH.cur_ic_page) / \
135     sizeof(struct DYNTRANS_IC); \
136     cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << \
137     DYNTRANS_INSTR_ALIGNMENT_SHIFT); \
138     cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT);\
139     printf("Crash at %016"PRIx64"\n", cpu->pc); \
140     printf("nr of I calls: %lli\n", nr_of_I_calls); \
141     printf("Next ic = %p\n", cpu->cd. \
142     DYNTRANS_ARCH.next_ic); \
143     printf("cur ic page = %p\n", cpu->cd. \
144     DYNTRANS_ARCH.cur_ic_page); \
145     cpu->running = 0; \
146     return 0; \
147     } \
148     ic->f(cpu, ic); */
149    
150     /* Temporary hack for MIPS, to hunt for 32-bit/64-bit sign-extension bugs: */
151     /* #define I { int k; for (k=1; k<=31; k++) \
152     cpu->cd.mips.gpr[k] = (int32_t)cpu->cd.mips.gpr[k];\
153     if (cpu->cd.mips.gpr[0] != 0) { \
154     fatal("NOOOOOO\n"); exit(1); \
155     } \
156     ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic); }
157     */
158 dpavlin 18 #endif
159 dpavlin 28 #endif /* STATIC STUFF */
160 dpavlin 18
161    
162 dpavlin 28
163     #ifdef DYNTRANS_RUN_INSTR
164 dpavlin 14 /*
165 dpavlin 28 * XXX_run_instr():
166 dpavlin 14 *
167     * Execute one or more instructions on a specific CPU, using dyntrans.
168 dpavlin 28 * (For dualmode archs, this function is included twice.)
169 dpavlin 14 *
170     * Return value is the number of instructions executed during this call,
171     * 0 if no instructions were executed.
172     */
173 dpavlin 28 int DYNTRANS_RUN_INSTR(struct cpu *cpu)
174 dpavlin 14 {
175 dpavlin 28 MODE_uint_t cached_pc;
176     int low_pc, n_instrs;
177 dpavlin 24
178 dpavlin 28 /* Ugly... fix this some day. */
179     #ifdef DYNTRANS_DUALMODE_32
180 dpavlin 26 #ifdef MODE32
181 dpavlin 28 DYNTRANS_PC_TO_POINTERS32(cpu);
182 dpavlin 26 #else
183 dpavlin 28 DYNTRANS_PC_TO_POINTERS(cpu);
184 dpavlin 14 #endif
185 dpavlin 28 #else
186     DYNTRANS_PC_TO_POINTERS(cpu);
187 dpavlin 14 #endif
188    
189     /*
190     * Interrupt assertion? (This is _below_ the initial PC to pointer
191     * conversion; if the conversion caused an exception of some kind
192     * then interrupts are probably disabled, and the exception will get
193     * priority over device interrupts.)
194 dpavlin 24 *
195     * TODO: Turn this into a family-specific function somewhere...
196 dpavlin 14 */
197     #ifdef DYNTRANS_ARM
198     if (cpu->cd.arm.irq_asserted && !(cpu->cd.arm.cpsr & ARM_FLAG_I))
199     arm_exception(cpu, ARM_EXCEPTION_IRQ);
200     #endif
201 dpavlin 24 #ifdef DYNTRANS_MIPS
202     {
203     int enabled, mask;
204     int status = cpu->cd.mips.coproc[0]->reg[COP0_STATUS];
205     if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
206     /* R3000: */
207     enabled = status & MIPS_SR_INT_IE;
208     } else {
209     /* R4000 and others: */
210     enabled = (status & STATUS_IE)
211     && !(status & STATUS_EXL) && !(status & STATUS_ERL);
212     /* Special case for R5900/C790/TX79: */
213     if (cpu->cd.mips.cpu_type.rev == MIPS_R5900 &&
214     !(status & R5900_STATUS_EIE))
215     enabled = 0;
216     }
217     mask = status & cpu->cd.mips.coproc[0]->reg[COP0_CAUSE]
218     & STATUS_IM_MASK;
219    
220     if (enabled && mask)
221     mips_cpu_exception(cpu, EXCEPTION_INT, 0, 0, 0, 0, 0,0);
222     }
223     #endif
224 dpavlin 20 #ifdef DYNTRANS_PPC
225     if (cpu->cd.ppc.dec_intr_pending && cpu->cd.ppc.msr & PPC_MSR_EE) {
226     ppc_exception(cpu, PPC_EXCEPTION_DEC);
227     cpu->cd.ppc.dec_intr_pending = 0;
228     }
229     if (cpu->cd.ppc.irq_asserted && cpu->cd.ppc.msr & PPC_MSR_EE)
230     ppc_exception(cpu, PPC_EXCEPTION_EI);
231     #endif
232 dpavlin 14
233     cached_pc = cpu->pc;
234    
235     cpu->n_translated_instrs = 0;
236     cpu->running_translated = 1;
237    
238 dpavlin 18 cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
239     cpu->cd.DYNTRANS_ARCH.cur_ic_page;
240    
241 dpavlin 24 if (single_step || cpu->machine->instruction_trace
242     || cpu->machine->register_dump) {
243 dpavlin 14 /*
244     * Single-step:
245     */
246 dpavlin 24 struct DYNTRANS_IC *ic = cpu->cd.DYNTRANS_ARCH.next_ic;
247     if (cpu->machine->register_dump) {
248     debug("\n");
249     cpu_register_dump(cpu->machine, cpu, 1, 0x1);
250     }
251 dpavlin 14 if (cpu->machine->instruction_trace) {
252     #ifdef DYNTRANS_X86
253     unsigned char instr[17];
254     cpu->cd.x86.cursegment = X86_S_CS;
255     cpu->cd.x86.seg_override = 0;
256     #else
257     #ifdef DYNTRANS_M68K
258     unsigned char instr[16]; /* TODO: 16? */
259     #else
260     unsigned char instr[4]; /* General case... */
261     #endif
262     #endif
263 dpavlin 24
264 dpavlin 14 if (!cpu->memory_rw(cpu, cpu->mem, cached_pc, &instr[0],
265     sizeof(instr), MEM_READ, CACHE_INSTRUCTION)) {
266 dpavlin 28 fatal("XXX_run_instr(): could not read "
267 dpavlin 14 "the instruction\n");
268 dpavlin 22 } else {
269 dpavlin 14 cpu_disassemble_instr(cpu->machine, cpu,
270 dpavlin 24 instr, 1, 0);
271     #ifdef DYNTRANS_DELAYSLOT
272 dpavlin 22 /* Show the instruction in the delay slot,
273     if any: */
274 dpavlin 24 if (cpu->instruction_has_delayslot == NULL)
275     fatal("WARNING: ihd func not yet"
276     " implemented?\n");
277     else if (cpu->instruction_has_delayslot(cpu,
278     instr)) {
279     int saved_delayslot = cpu->delay_slot;
280     cpu->memory_rw(cpu, cpu->mem, cached_pc
281     + sizeof(instr), &instr[0],
282     sizeof(instr), MEM_READ,
283     CACHE_INSTRUCTION);
284     cpu->delay_slot = DELAYED;
285     cpu->pc += sizeof(instr);
286     cpu_disassemble_instr(cpu->machine,
287     cpu, instr, 1, 0);
288     cpu->delay_slot = saved_delayslot;
289     cpu->pc -= sizeof(instr);
290     }
291 dpavlin 22 #endif
292     }
293 dpavlin 14 }
294    
295     /* When single-stepping, multiple instruction calls cannot
296     be combined into one. This clears all translations: */
297     if (cpu->cd.DYNTRANS_ARCH.cur_physpage->flags & COMBINATIONS) {
298     int i;
299 dpavlin 24 for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++) {
300 dpavlin 14 cpu->cd.DYNTRANS_ARCH.cur_physpage->ics[i].f =
301     #ifdef DYNTRANS_DUALMODE_32
302     cpu->is_32bit?
303     instr32(to_be_translated) :
304     #endif
305     instr(to_be_translated);
306 dpavlin 24 #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
307     cpu->cd.DYNTRANS_ARCH.cur_physpage->ics[i].
308     arg[0] = 0;
309     #endif
310     }
311 dpavlin 28
312 dpavlin 24 fatal("[ Note: The translation of physical page 0x%"
313     PRIx64" contained combinations of instructions; "
314     "these are now flushed because we are single-"
315     "stepping. ]\n", (long long)cpu->cd.DYNTRANS_ARCH.
316 dpavlin 14 cur_physpage->physaddr);
317 dpavlin 28
318 dpavlin 14 cpu->cd.DYNTRANS_ARCH.cur_physpage->flags &=
319 dpavlin 28 ~COMBINATIONS;
320     cpu->cd.DYNTRANS_ARCH.cur_physpage->translations = 0;
321 dpavlin 14 }
322    
323 dpavlin 28 if (cpu->machine->statistics_enabled)
324 dpavlin 18 S;
325    
326 dpavlin 14 /* Execute just one instruction: */
327 dpavlin 24 I;
328    
329 dpavlin 14 n_instrs = 1;
330 dpavlin 24 } else if (cpu->machine->cycle_accurate) {
331     /* Executing multiple instructions, and call devices'
332     tick functions: */
333     n_instrs = 0;
334     for (;;) {
335     struct DYNTRANS_IC *ic;
336     /* TODO: continue here */
337     int64_t cycles = cpu->cd.avr.extra_cycles;
338     I;
339     n_instrs += 1;
340     cycles = cpu->cd.avr.extra_cycles - cycles + 1;
341     /* The instruction took 'cycles' cycles. */
342     /* printf("A\n"); */
343     while (cycles-- > 0)
344     cpu->machine->tick_func[1](cpu, cpu->machine->tick_extra[1]);
345     /* printf("B\n"); */
346    
347     if (!cpu->running_translated ||
348     n_instrs + cpu->n_translated_instrs >=
349 dpavlin 26 N_SAFE_DYNTRANS_LIMIT)
350 dpavlin 24 break;
351     }
352 dpavlin 28 } else if (cpu->machine->statistics_enabled) {
353 dpavlin 18 /* Gather statistics while executing multiple instructions: */
354     n_instrs = 0;
355     for (;;) {
356     struct DYNTRANS_IC *ic;
357    
358     S; I; S; I; S; I; S; I; S; I; S; I;
359     S; I; S; I; S; I; S; I; S; I; S; I;
360     S; I; S; I; S; I; S; I; S; I; S; I;
361     S; I; S; I; S; I; S; I; S; I; S; I;
362    
363     n_instrs += 24;
364    
365     if (!cpu->running_translated ||
366 dpavlin 24 n_instrs + cpu->n_translated_instrs >=
367 dpavlin 26 N_SAFE_DYNTRANS_LIMIT)
368 dpavlin 18 break;
369     }
370 dpavlin 14 } else {
371     /* Execute multiple instructions: */
372     n_instrs = 0;
373     for (;;) {
374     struct DYNTRANS_IC *ic;
375    
376     I; I; I; I; I; I; I; I; I; I;
377     I; I; I; I; I; I; I; I; I; I;
378     I; I; I; I; I; I; I; I; I; I;
379     I; I; I; I; I; I; I; I; I; I;
380     I; I; I; I; I; I; I; I; I; I;
381    
382     I; I; I; I; I; I; I; I; I; I;
383    
384 dpavlin 18 n_instrs += 60;
385 dpavlin 14
386     if (!cpu->running_translated ||
387 dpavlin 24 n_instrs + cpu->n_translated_instrs >=
388 dpavlin 26 N_SAFE_DYNTRANS_LIMIT)
389 dpavlin 14 break;
390     }
391     }
392    
393 dpavlin 20 n_instrs += cpu->n_translated_instrs;
394 dpavlin 14
395 dpavlin 20 /* Synchronize the program counter: */
396 dpavlin 14 low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t)
397     cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC);
398     if (low_pc >= 0 && low_pc < DYNTRANS_IC_ENTRIES_PER_PAGE) {
399     cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
400     DYNTRANS_INSTR_ALIGNMENT_SHIFT);
401     cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT);
402     } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE) {
403     /* Switch to next page: */
404     cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
405     DYNTRANS_INSTR_ALIGNMENT_SHIFT);
406     cpu->pc += (DYNTRANS_IC_ENTRIES_PER_PAGE <<
407     DYNTRANS_INSTR_ALIGNMENT_SHIFT);
408 dpavlin 22 } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE + 1) {
409     /* Switch to next page and skip an instruction which was
410     already executed (in a delay slot): */
411     cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
412     DYNTRANS_INSTR_ALIGNMENT_SHIFT);
413     cpu->pc += ((DYNTRANS_IC_ENTRIES_PER_PAGE + 1) <<
414     DYNTRANS_INSTR_ALIGNMENT_SHIFT);
415 dpavlin 14 }
416    
417 dpavlin 24 #ifdef DYNTRANS_MIPS
418     /* Update the count register (on everything except EXC3K): */
419     if (cpu->cd.mips.cpu_type.exc_model != EXC3K) {
420     uint32_t old = cpu->cd.mips.coproc[0]->reg[COP0_COUNT];
421     int32_t diff1 = cpu->cd.mips.coproc[0]->reg[COP0_COMPARE] - old;
422     int32_t diff2;
423     cpu->cd.mips.coproc[0]->reg[COP0_COUNT] =
424     (int32_t) (old + n_instrs);
425     diff2 = cpu->cd.mips.coproc[0]->reg[COP0_COMPARE] -
426     cpu->cd.mips.coproc[0]->reg[COP0_COUNT];
427     if (cpu->cd.mips.compare_register_set && diff1>0 && diff2<=0)
428     cpu_interrupt(cpu, 7);
429     }
430     #endif
431 dpavlin 20 #ifdef DYNTRANS_PPC
432     /* Update the Decrementer and Time base registers: */
433     {
434     uint32_t old = cpu->cd.ppc.spr[SPR_DEC];
435     cpu->cd.ppc.spr[SPR_DEC] = (uint32_t) (old - n_instrs);
436 dpavlin 22 if ((old >> 31) == 0 && (cpu->cd.ppc.spr[SPR_DEC] >> 31) == 1
437     && !(cpu->cd.ppc.cpu_type.flags & PPC_NO_DEC))
438 dpavlin 20 cpu->cd.ppc.dec_intr_pending = 1;
439     old = cpu->cd.ppc.spr[SPR_TBL];
440     cpu->cd.ppc.spr[SPR_TBL] += n_instrs;
441     if ((old >> 31) == 1 && (cpu->cd.ppc.spr[SPR_TBL] >> 31) == 0)
442     cpu->cd.ppc.spr[SPR_TBU] ++;
443     }
444     #endif
445    
446     /* Return the nr of instructions executed: */
447     return n_instrs;
448 dpavlin 14 }
449 dpavlin 28 #endif /* DYNTRANS_RUN_INSTR */
450 dpavlin 14
451    
452    
453     #ifdef DYNTRANS_FUNCTION_TRACE
454     /*
455     * XXX_cpu_functioncall_trace():
456     *
457     * Without this function, the main trace tree function prints something
458     * like <f()> or <0x1234()> on a function call. It is up to this
459     * function to print the arguments passed.
460     */
461     void DYNTRANS_FUNCTION_TRACE(struct cpu *cpu, uint64_t f, int n_args)
462     {
463     char strbuf[50];
464     char *symbol;
465     uint64_t ot;
466     int x, print_dots = 1, n_args_to_print =
467 dpavlin 24 #if defined(DYNTRANS_ALPHA) || defined(DYNTRANS_SPARC)
468 dpavlin 14 6
469     #else
470     #ifdef DYNTRANS_SH
471     8
472     #else
473     4 /* Default value for most archs */
474     #endif
475     #endif
476     ;
477    
478     if (n_args >= 0 && n_args <= n_args_to_print) {
479     print_dots = 0;
480     n_args_to_print = n_args;
481     }
482    
483     /*
484     * TODO: The type of each argument should be taken from the symbol
485     * table, in some way.
486     *
487     * The code here does a kind of "heuristic guess" regarding what the
488     * argument values might mean. Sometimes the output looks weird, but
489     * usually it looks good enough.
490     *
491     * Print ".." afterwards to show that there might be more arguments
492     * than were passed in register.
493     */
494     for (x=0; x<n_args_to_print; x++) {
495     int64_t d;
496 dpavlin 28 #if defined(DYNTRANS_X86) || defined(DYNTRANS_TRANSPUTER)
497 dpavlin 14 d = 0; /* TODO */
498     #else
499     /* Args in registers: */
500     d = cpu->cd.DYNTRANS_ARCH.
501     #ifdef DYNTRANS_ALPHA
502     r[ALPHA_A0
503     #endif
504     #ifdef DYNTRANS_ARM
505     r[0
506     #endif
507     #ifdef DYNTRANS_AVR
508     /* TODO: 24,25 = first register, but then
509     they go downwards, ie. 22,23 and so on */
510     r[24
511     #endif
512     #ifdef DYNTRANS_HPPA
513     r[0 /* TODO */
514     #endif
515     #ifdef DYNTRANS_I960
516     r[0 /* TODO */
517     #endif
518     #ifdef DYNTRANS_IA64
519     r[0 /* TODO */
520     #endif
521     #ifdef DYNTRANS_M68K
522     d[0 /* TODO */
523     #endif
524     #ifdef DYNTRANS_MIPS
525     gpr[MIPS_GPR_A0
526     #endif
527     #ifdef DYNTRANS_PPC
528     gpr[3
529     #endif
530     #ifdef DYNTRANS_SH
531     r[2
532     #endif
533     #ifdef DYNTRANS_SPARC
534 dpavlin 22 r[24
535 dpavlin 14 #endif
536     + x];
537     #endif
538     symbol = get_symbol_name(&cpu->machine->symbol_context, d, &ot);
539    
540     if (d > -256 && d < 256)
541     fatal("%i", (int)d);
542     else if (memory_points_to_string(cpu, cpu->mem, d, 1))
543     fatal("\"%s\"", memory_conv_to_string(cpu,
544     cpu->mem, d, strbuf, sizeof(strbuf)));
545     else if (symbol != NULL && ot == 0)
546     fatal("&%s", symbol);
547     else {
548     if (cpu->is_32bit)
549 dpavlin 24 fatal("0x%"PRIx32, (uint32_t)d);
550 dpavlin 14 else
551 dpavlin 24 fatal("0x%"PRIx64, (uint64_t)d);
552 dpavlin 14 }
553    
554     if (x < n_args_to_print - 1)
555     fatal(",");
556     }
557    
558     if (print_dots)
559     fatal(",..");
560     }
561     #endif
562    
563    
564    
565     #ifdef DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE
566     /*
567     * XXX_tc_allocate_default_page():
568     *
569     * Create a default page (with just pointers to instr(to_be_translated)
570     * at cpu->translation_cache_cur_ofs.
571     */
572     static void DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE(struct cpu *cpu,
573     uint64_t physaddr)
574     {
575     struct DYNTRANS_TC_PHYSPAGE *ppp;
576    
577     ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
578     + cpu->translation_cache_cur_ofs);
579    
580 dpavlin 26 /* Copy the entire template page first: */
581     memcpy(ppp, cpu->cd.DYNTRANS_ARCH.physpage_template, sizeof(
582     struct DYNTRANS_TC_PHYSPAGE));
583 dpavlin 14
584 dpavlin 26 ppp->physaddr = physaddr & ~(DYNTRANS_PAGESIZE - 1);
585 dpavlin 14
586     cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE);
587 dpavlin 18
588     cpu->translation_cache_cur_ofs --;
589 dpavlin 26 cpu->translation_cache_cur_ofs |= 127;
590 dpavlin 18 cpu->translation_cache_cur_ofs ++;
591 dpavlin 14 }
592     #endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE */
593    
594    
595    
596     #ifdef DYNTRANS_PC_TO_POINTERS_FUNC
597     /*
598     * XXX_pc_to_pointers_generic():
599     *
600     * Generic case. See DYNTRANS_PC_TO_POINTERS_FUNC below.
601     */
602     void DYNTRANS_PC_TO_POINTERS_GENERIC(struct cpu *cpu)
603     {
604     #ifdef MODE32
605     uint32_t
606     #else
607     uint64_t
608     #endif
609 dpavlin 24 cached_pc = cpu->pc, physaddr = 0;
610 dpavlin 14 uint32_t physpage_ofs;
611     int ok, pagenr, table_index;
612     uint32_t *physpage_entryp;
613     struct DYNTRANS_TC_PHYSPAGE *ppp;
614    
615     #ifdef MODE32
616 dpavlin 24 int index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
617 dpavlin 14 #else
618 dpavlin 24 const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1;
619     const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1;
620     const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1;
621     uint32_t x1, x2, x3;
622     struct DYNTRANS_L2_64_TABLE *l2;
623     struct DYNTRANS_L3_64_TABLE *l3;
624    
625     x1 = (cached_pc >> (64-DYNTRANS_L1N)) & mask1;
626     x2 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
627     x3 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N)) & mask3;
628     /* fatal("X3: cached_pc=%016"PRIx64" x1=%x x2=%x x3=%x\n",
629     (uint64_t)cached_pc, (int)x1, (int)x2, (int)x3); */
630     l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
631     /* fatal(" l2 = %p\n", l2); */
632     l3 = l2->l3[x2];
633     /* fatal(" l3 = %p\n", l3); */
634 dpavlin 14 #endif
635    
636     /* Virtual to physical address translation: */
637     ok = 0;
638     #ifdef MODE32
639     if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL) {
640     physaddr = cpu->cd.DYNTRANS_ARCH.phys_addr[index];
641     ok = 1;
642     }
643     #else
644 dpavlin 24 if (l3->host_load[x3] != NULL) {
645     physaddr = l3->phys_addr[x3];
646 dpavlin 14 ok = 1;
647     }
648     #endif
649    
650     if (!ok) {
651     uint64_t paddr;
652 dpavlin 26 if (cpu->translate_v2p != NULL) {
653     ok = cpu->translate_v2p(
654     cpu, cached_pc, &paddr, FLAG_INSTR);
655     } else {
656 dpavlin 14 paddr = cached_pc;
657     ok = 1;
658     }
659     if (!ok) {
660 dpavlin 28 /*
661     * The PC is now set to the exception handler.
662     * Try to find the paddr in the translation arrays,
663     * or if that fails, call translate_v2p for the
664     * exception handler.
665     */
666 dpavlin 24 /* fatal("TODO: instruction vaddr=>paddr translation "
667     "failed. vaddr=0x%"PRIx64"\n", (uint64_t)cached_pc);
668     fatal("!! cpu->pc=0x%"PRIx64"\n", (uint64_t)cpu->pc); */
669 dpavlin 20
670 dpavlin 28 /* If there was an exception, the PC has changed.
671     Update cached_pc: */
672     cached_pc = cpu->pc;
673 dpavlin 20
674 dpavlin 28 #ifdef MODE32
675     index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
676     if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL) {
677     paddr = cpu->cd.DYNTRANS_ARCH.phys_addr[index];
678     ok = 1;
679     }
680     #else
681     x1 = (cached_pc >> (64-DYNTRANS_L1N)) & mask1;
682     x2 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
683     x3 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N))
684     & mask3;
685     l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
686     l3 = l2->l3[x2];
687     if (l3->host_load[x3] != NULL) {
688     paddr = l3->phys_addr[x3];
689     ok = 1;
690     }
691     #endif
692    
693     if (!ok) {
694     ok = cpu->translate_v2p(cpu, cpu->pc, &paddr,
695     FLAG_INSTR);
696     }
697    
698 dpavlin 20 /* printf("EXCEPTION HANDLER: vaddr = 0x%x ==> "
699     "paddr = 0x%x\n", (int)cpu->pc, (int)paddr);
700 dpavlin 24 fatal("!? cpu->pc=0x%"PRIx64"\n", (uint64_t)cpu->pc); */
701 dpavlin 20
702 dpavlin 14 if (!ok) {
703     fatal("FATAL: could not find physical"
704     " address of the exception handler?");
705     exit(1);
706     }
707     }
708 dpavlin 24
709 dpavlin 14 physaddr = paddr;
710     }
711    
712 dpavlin 28 physaddr &= ~(DYNTRANS_PAGESIZE - 1);
713    
714 dpavlin 18 #ifdef MODE32
715     if (cpu->cd.DYNTRANS_ARCH.host_load[index] == NULL) {
716 dpavlin 24 #else
717     if (l3->host_load[x3] == NULL) {
718     #endif
719 dpavlin 28 int q = DYNTRANS_PAGESIZE - 1;
720 dpavlin 18 unsigned char *host_page = memory_paddr_to_hostaddr(cpu->mem,
721     physaddr, MEM_READ);
722     if (host_page != NULL) {
723     cpu->update_translation_table(cpu, cached_pc & ~q,
724 dpavlin 28 host_page, 0, physaddr);
725 dpavlin 18 }
726     }
727    
728     if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE) {
729 dpavlin 26 #ifdef UNSTABLE_DEVEL
730     fatal("[ dyntrans: resetting the translation cache ]\n");
731     #endif
732 dpavlin 14 cpu_create_or_reset_tc(cpu);
733 dpavlin 18 }
734 dpavlin 14
735     pagenr = DYNTRANS_ADDR_TO_PAGENR(physaddr);
736     table_index = PAGENR_TO_TABLE_INDEX(pagenr);
737    
738     physpage_entryp = &(((uint32_t *)cpu->translation_cache)[table_index]);
739     physpage_ofs = *physpage_entryp;
740     ppp = NULL;
741    
742     /* Traverse the physical page chain: */
743     while (physpage_ofs != 0) {
744     ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
745     + physpage_ofs);
746 dpavlin 26
747 dpavlin 14 /* If we found the page in the cache, then we're done: */
748 dpavlin 26 if (ppp->physaddr == physaddr)
749 dpavlin 14 break;
750 dpavlin 26
751 dpavlin 14 /* Try the next page in the chain: */
752     physpage_ofs = ppp->next_ofs;
753     }
754    
755     /* If the offset is 0 (or ppp is NULL), then we need to create a
756     new "default" empty translation page. */
757    
758     if (ppp == NULL) {
759 dpavlin 24 /* fatal("CREATING page %lli (physaddr 0x%"PRIx64"), table "
760     "index %i\n", (long long)pagenr, (uint64_t)physaddr,
761 dpavlin 14 (int)table_index); */
762     *physpage_entryp = physpage_ofs =
763     cpu->translation_cache_cur_ofs;
764    
765     /* Allocate a default page, with to_be_translated entries: */
766     DYNTRANS_TC_ALLOCATE(cpu, physaddr);
767    
768     ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
769     + physpage_ofs);
770     }
771    
772     #ifdef MODE32
773     if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL)
774     cpu->cd.DYNTRANS_ARCH.phys_page[index] = ppp;
775 dpavlin 24 #else
776     if (l3->host_load[x3] != NULL)
777     l3->phys_page[x3] = ppp;
778 dpavlin 14 #endif
779    
780 dpavlin 28 /*
781     * If there are no translations yet on this page, then mark it
782     * as non-writable. If there are already translations, then it
783     * should already have been marked as non-writable.
784     */
785     if (ppp->translations == 0) {
786     cpu->invalidate_translation_caches(cpu, physaddr,
787     JUST_MARK_AS_NON_WRITABLE | INVALIDATE_PADDR);
788     }
789 dpavlin 14
790     cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
791 dpavlin 18
792 dpavlin 14 cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
793     DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
794    
795 dpavlin 24 /* printf("cached_pc=0x%016"PRIx64" pagenr=%lli table_index=%lli, "
796     "physpage_ofs=0x%016"PRIx64"\n", (uint64_t)cached_pc, (long long)
797     pagenr, (long long)table_index, (uint64_t)physpage_ofs); */
798 dpavlin 14 }
799    
800    
801     /*
802     * XXX_pc_to_pointers():
803     *
804     * This function uses the current program counter (a virtual address) to
805     * find out which physical translation page to use, and then sets the current
806     * translation page pointers to that page.
807     *
808     * If there was no translation page for that physical page, then an empty
809     * one is created.
810     *
811     * NOTE: This is the quick lookup version. See
812     * DYNTRANS_PC_TO_POINTERS_GENERIC above for the generic case.
813     */
814     void DYNTRANS_PC_TO_POINTERS_FUNC(struct cpu *cpu)
815     {
816     #ifdef MODE32
817     uint32_t
818     #else
819     uint64_t
820     #endif
821 dpavlin 22 cached_pc = cpu->pc;
822 dpavlin 14 struct DYNTRANS_TC_PHYSPAGE *ppp;
823    
824     #ifdef MODE32
825     int index;
826 dpavlin 18 index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
827 dpavlin 14 ppp = cpu->cd.DYNTRANS_ARCH.phys_page[index];
828     if (ppp != NULL)
829     goto have_it;
830     #else
831 dpavlin 24 const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1;
832     const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1;
833     const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1;
834     uint32_t x1, x2, x3;
835     struct DYNTRANS_L2_64_TABLE *l2;
836     struct DYNTRANS_L3_64_TABLE *l3;
837    
838     x1 = (cached_pc >> (64-DYNTRANS_L1N)) & mask1;
839     x2 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
840     x3 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N)) & mask3;
841     l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
842     l3 = l2->l3[x2];
843     ppp = l3->phys_page[x3];
844     if (ppp != NULL)
845     goto have_it;
846 dpavlin 14 #endif
847    
848     DYNTRANS_PC_TO_POINTERS_GENERIC(cpu);
849     return;
850    
851     /* Quick return path: */
852     have_it:
853     cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
854     cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
855     DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
856    
857 dpavlin 24 /* printf("cached_pc=0x%016"PRIx64" pagenr=%lli table_index=%lli, "
858     "physpage_ofs=0x%016"PRIx64"\n", (uint64_t)cached_pc, (long long)
859     pagenr, (long long)table_index, (uint64_t)physpage_ofs); */
860 dpavlin 14 }
861     #endif /* DYNTRANS_PC_TO_POINTERS_FUNC */
862    
863    
864    
865 dpavlin 26 #ifdef DYNTRANS_INIT_TABLES
866    
867     /* forward declaration of to_be_translated and end_of_page: */
868     static void instr(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
869     static void instr(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
870     #ifdef DYNTRANS_DUALMODE_32
871     static void instr32(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
872     static void instr32(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
873     #endif
874    
875     #ifdef DYNTRANS_DELAYSLOT
876     static void instr(end_of_page2)(struct cpu *,struct DYNTRANS_IC *);
877     #ifdef DYNTRANS_DUALMODE_32
878     static void instr32(end_of_page2)(struct cpu *,struct DYNTRANS_IC *);
879     #endif
880     #endif
881    
882 dpavlin 24 /*
883 dpavlin 26 * XXX_init_tables():
884 dpavlin 24 *
885 dpavlin 26 * Initializes the default translation page (for newly allocated pages), and
886     * for 64-bit emulation it also initializes 64-bit dummy tables and pointers.
887 dpavlin 24 */
888 dpavlin 26 void DYNTRANS_INIT_TABLES(struct cpu *cpu)
889 dpavlin 24 {
890 dpavlin 26 #ifndef MODE32
891 dpavlin 24 struct DYNTRANS_L2_64_TABLE *dummy_l2;
892     struct DYNTRANS_L3_64_TABLE *dummy_l3;
893     int x1, x2;
894 dpavlin 26 #endif
895     int i;
896     struct DYNTRANS_TC_PHYSPAGE *ppp = malloc(sizeof(
897     struct DYNTRANS_TC_PHYSPAGE));
898 dpavlin 24
899 dpavlin 26 if (ppp == NULL) {
900     fprintf(stderr, "out of memory\n");
901     exit(1);
902     }
903    
904     ppp->next_ofs = 0;
905 dpavlin 28 ppp->flags = 0;
906     ppp->translations = 0;
907 dpavlin 26 /* ppp->physaddr is filled in by the page allocator */
908    
909     for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++) {
910     ppp->ics[i].f =
911     #ifdef DYNTRANS_DUALMODE_32
912     cpu->is_32bit? instr32(to_be_translated) :
913     #endif
914     instr(to_be_translated);
915     #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
916     ppp->ics[i].arg[0] = 0;
917     #endif
918     }
919    
920     /* End-of-page: */
921     ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 0].f =
922     #ifdef DYNTRANS_DUALMODE_32
923     cpu->is_32bit? instr32(end_of_page) :
924     #endif
925     instr(end_of_page);
926    
927     #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
928     ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 0].arg[0] = 0;
929     #endif
930    
931     /* End-of-page-2, for delay-slot architectures: */
932     #ifdef DYNTRANS_DELAYSLOT
933     ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 1].f =
934     #ifdef DYNTRANS_DUALMODE_32
935     cpu->is_32bit? instr32(end_of_page2) :
936     #endif
937     instr(end_of_page2);
938     #endif
939    
940     cpu->cd.DYNTRANS_ARCH.physpage_template = ppp;
941    
942    
943     /* Prepare 64-bit virtual address translation tables: */
944     #ifndef MODE32
945 dpavlin 24 if (cpu->is_32bit)
946     return;
947    
948     dummy_l2 = zeroed_alloc(sizeof(struct DYNTRANS_L2_64_TABLE));
949     dummy_l3 = zeroed_alloc(sizeof(struct DYNTRANS_L3_64_TABLE));
950    
951     cpu->cd.DYNTRANS_ARCH.l2_64_dummy = dummy_l2;
952     cpu->cd.DYNTRANS_ARCH.l3_64_dummy = dummy_l3;
953    
954     for (x1 = 0; x1 < (1 << DYNTRANS_L1N); x1 ++)
955     cpu->cd.DYNTRANS_ARCH.l1_64[x1] = dummy_l2;
956    
957     for (x2 = 0; x2 < (1 << DYNTRANS_L2N); x2 ++)
958     dummy_l2->l3[x2] = dummy_l3;
959 dpavlin 26 #endif
960 dpavlin 24 }
961 dpavlin 26 #endif /* DYNTRANS_INIT_TABLES */
962 dpavlin 24
963    
964    
965 dpavlin 14 #ifdef DYNTRANS_INVAL_ENTRY
966     /*
967     * XXX_invalidate_tlb_entry():
968     *
969     * Invalidate one translation entry (based on virtual address).
970     *
971     * If the JUST_MARK_AS_NON_WRITABLE flag is set, then the translation entry
972     * is just downgraded to non-writable (ie the host store page is set to
973     * NULL). Otherwise, the entire translation is removed.
974     */
975 dpavlin 18 static void DYNTRANS_INVALIDATE_TLB_ENTRY(struct cpu *cpu,
976 dpavlin 14 #ifdef MODE32
977     uint32_t
978     #else
979     uint64_t
980     #endif
981     vaddr_page, int flags)
982     {
983     #ifdef MODE32
984 dpavlin 18 uint32_t index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
985 dpavlin 14
986 dpavlin 18 #ifdef DYNTRANS_ARM
987 dpavlin 20 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5] &= ~(1 << (index & 31));
988 dpavlin 18 #endif
989    
990 dpavlin 14 if (flags & JUST_MARK_AS_NON_WRITABLE) {
991     /* printf("JUST MARKING NON-W: vaddr 0x%08x\n",
992     (int)vaddr_page); */
993     cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
994     } else {
995 dpavlin 24 int tlbi = cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index];
996 dpavlin 14 cpu->cd.DYNTRANS_ARCH.host_load[index] = NULL;
997     cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
998     cpu->cd.DYNTRANS_ARCH.phys_addr[index] = 0;
999     cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1000 dpavlin 24 if (tlbi > 0)
1001     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[tlbi-1].valid = 0;
1002 dpavlin 18 cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = 0;
1003 dpavlin 14 }
1004     #else
1005 dpavlin 24 const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1;
1006     const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1;
1007     const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1;
1008     uint32_t x1, x2, x3;
1009     struct DYNTRANS_L2_64_TABLE *l2;
1010     struct DYNTRANS_L3_64_TABLE *l3;
1011 dpavlin 14
1012 dpavlin 24 x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1;
1013     x2 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
1014     x3 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N))& mask3;
1015 dpavlin 14
1016 dpavlin 24 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1017     if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy)
1018     return;
1019 dpavlin 14
1020 dpavlin 24 l3 = l2->l3[x2];
1021     if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy)
1022     return;
1023    
1024 dpavlin 14 if (flags & JUST_MARK_AS_NON_WRITABLE) {
1025 dpavlin 24 l3->host_store[x3] = NULL;
1026 dpavlin 14 return;
1027     }
1028 dpavlin 28
1029     #ifdef BUGHUNT
1030    
1031     {
1032     /* Consistency check, for debugging: */
1033     int x1, x1b; // x2, x3;
1034     struct DYNTRANS_L2_64_TABLE *l2;
1035     //struct DYNTRANS_L3_64_TABLE *l3;
1036    
1037     for (x1 = 0; x1 <= mask1; x1 ++) {
1038     l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1039     if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy)
1040     continue;
1041     /* Make sure that this l2 isn't used more than 1 time! */
1042     for (x1b = 0; x1b <= mask1; x1b ++)
1043     if (x1 != x1b &&
1044     l2 == cpu->cd.DYNTRANS_ARCH.l1_64[x1b]) {
1045     fatal("L2 reuse: %p\n", l2);
1046     exit(1);
1047     }
1048     }
1049     }
1050    
1051     /* Count how many pages are actually in use: */
1052     {
1053     int n=0, i;
1054     for (i=0; i<=mask3; i++)
1055     if (l3->vaddr_to_tlbindex[i])
1056     n++;
1057     if (n != l3->refcount) {
1058     printf("Z: %i in use, but refcount = %i!\n", n, l3->refcount);
1059     exit(1);
1060     }
1061    
1062     n = 0;
1063     for (i=0; i<=mask3; i++)
1064     if (l3->host_load[i] != NULL)
1065     n++;
1066     if (n != l3->refcount) {
1067     printf("ZHL: %i in use, but refcount = %i!\n", n, l3->refcount);
1068     exit(1);
1069     }
1070     }
1071     #endif
1072    
1073 dpavlin 24 l3->host_load[x3] = NULL;
1074     l3->host_store[x3] = NULL;
1075     l3->phys_addr[x3] = 0;
1076     l3->phys_page[x3] = NULL;
1077 dpavlin 28 if (l3->vaddr_to_tlbindex[x3] != 0) {
1078     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[
1079     l3->vaddr_to_tlbindex[x3] - 1].valid = 0;
1080     l3->refcount --;
1081     }
1082     l3->vaddr_to_tlbindex[x3] = 0;
1083    
1084 dpavlin 24 if (l3->refcount < 0) {
1085     fatal("xxx_invalidate_tlb_entry(): huh? Refcount bug.\n");
1086 dpavlin 14 exit(1);
1087     }
1088 dpavlin 28
1089 dpavlin 24 if (l3->refcount == 0) {
1090     l3->next = cpu->cd.DYNTRANS_ARCH.next_free_l3;
1091     cpu->cd.DYNTRANS_ARCH.next_free_l3 = l3;
1092     l2->l3[x2] = cpu->cd.DYNTRANS_ARCH.l3_64_dummy;
1093    
1094 dpavlin 28 #ifdef BUGHUNT
1095     /* Make sure that we're placing a CLEAN page on the
1096     freelist: */
1097     {
1098     int i;
1099     for (i=0; i<=mask3; i++)
1100     if (l3->host_load[i] != NULL) {
1101     fatal("TRYING TO RETURN A NON-CLEAN L3 PAGE!\n");
1102     exit(1);
1103     }
1104     }
1105     #endif
1106 dpavlin 24 l2->refcount --;
1107     if (l2->refcount < 0) {
1108     fatal("xxx_invalidate_tlb_entry(): Refcount bug L2.\n");
1109     exit(1);
1110     }
1111     if (l2->refcount == 0) {
1112     l2->next = cpu->cd.DYNTRANS_ARCH.next_free_l2;
1113     cpu->cd.DYNTRANS_ARCH.next_free_l2 = l2;
1114     cpu->cd.DYNTRANS_ARCH.l1_64[x1] =
1115     cpu->cd.DYNTRANS_ARCH.l2_64_dummy;
1116     }
1117 dpavlin 14 }
1118     #endif
1119     }
1120     #endif
1121    
1122    
1123 dpavlin 18 #ifdef DYNTRANS_INVALIDATE_TC
1124 dpavlin 14 /*
1125 dpavlin 18 * XXX_invalidate_translation_caches():
1126 dpavlin 14 *
1127     * Invalidate all entries matching a specific physical address, a specific
1128     * virtual address, or ALL entries.
1129     *
1130     * flags should be one of
1131     * INVALIDATE_PADDR INVALIDATE_VADDR or INVALIDATE_ALL
1132     *
1133 dpavlin 22 * In addition, for INVALIDATE_ALL, INVALIDATE_VADDR_UPPER4 may be set and
1134     * bit 31..28 of addr are used to select the virtual addresses to invalidate.
1135     * (This is useful for PowerPC emulation, when segment registers are updated.)
1136     *
1137 dpavlin 14 * In the case when all translations are invalidated, paddr doesn't need
1138     * to be supplied.
1139     *
1140 dpavlin 18 * NOTE/TODO: When invalidating a virtual address, it is only cleared from
1141     * the quick translation array, not from the linear
1142     * vph_tlb_entry[] array. Hopefully this is enough anyway.
1143 dpavlin 14 */
1144 dpavlin 22 void DYNTRANS_INVALIDATE_TC(struct cpu *cpu, uint64_t addr, int flags)
1145 dpavlin 14 {
1146     int r;
1147     #ifdef MODE32
1148     uint32_t
1149     #else
1150     uint64_t
1151     #endif
1152 dpavlin 22 addr_page = addr & ~(DYNTRANS_PAGESIZE - 1);
1153 dpavlin 14
1154 dpavlin 20 /* fatal("invalidate(): "); */
1155    
1156 dpavlin 22 /* Quick case for _one_ virtual addresses: see note above. */
1157 dpavlin 18 if (flags & INVALIDATE_VADDR) {
1158 dpavlin 20 /* fatal("vaddr 0x%08x\n", (int)addr_page); */
1159 dpavlin 18 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, addr_page, flags);
1160     return;
1161     }
1162    
1163 dpavlin 22 /* Invalidate everything: */
1164     #ifdef DYNTRANS_PPC
1165     if (flags & INVALIDATE_ALL && flags & INVALIDATE_VADDR_UPPER4) {
1166     /* fatal("all, upper4 (PowerPC segment)\n"); */
1167     for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
1168     if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid &&
1169     (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page
1170     & 0xf0000000) == addr_page) {
1171     DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, cpu->cd.
1172     DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
1173     0);
1174     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid=0;
1175     }
1176     }
1177     return;
1178     }
1179     #endif
1180 dpavlin 20 if (flags & INVALIDATE_ALL) {
1181     /* fatal("all\n"); */
1182     for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
1183     if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
1184     DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, cpu->cd.
1185     DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
1186     0);
1187     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid=0;
1188     }
1189     }
1190     return;
1191     }
1192    
1193 dpavlin 22 /* Invalidate a physical page: */
1194 dpavlin 20
1195 dpavlin 22 if (!(flags & INVALIDATE_PADDR))
1196     fatal("HUH? Invalidate: Not vaddr, all, or paddr?\n");
1197    
1198     /* fatal("addr 0x%08x\n", (int)addr_page); */
1199    
1200 dpavlin 14 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
1201 dpavlin 22 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && addr_page
1202     == cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page) {
1203 dpavlin 14 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
1204     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
1205     flags);
1206     if (flags & JUST_MARK_AS_NON_WRITABLE)
1207     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
1208     .writeflag = 0;
1209     else
1210     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
1211     .valid = 0;
1212     }
1213     }
1214     }
1215 dpavlin 18 #endif /* DYNTRANS_INVALIDATE_TC */
1216 dpavlin 14
1217    
1218    
1219     #ifdef DYNTRANS_INVALIDATE_TC_CODE
1220     /*
1221     * XXX_invalidate_code_translation():
1222     *
1223     * Invalidate code translations for a specific physical address, a specific
1224     * virtual address, or for all entries in the cache.
1225     */
1226     void DYNTRANS_INVALIDATE_TC_CODE(struct cpu *cpu, uint64_t addr, int flags)
1227     {
1228     int r;
1229 dpavlin 18 #ifdef MODE32
1230 dpavlin 14 uint32_t
1231     #else
1232     uint64_t
1233     #endif
1234     vaddr_page, paddr_page;
1235    
1236     addr &= ~(DYNTRANS_PAGESIZE-1);
1237    
1238     /* printf("DYNTRANS_INVALIDATE_TC_CODE addr=0x%08x flags=%i\n",
1239     (int)addr, flags); */
1240    
1241     if (flags & INVALIDATE_PADDR) {
1242     int pagenr, table_index;
1243     uint32_t physpage_ofs, *physpage_entryp;
1244 dpavlin 18 struct DYNTRANS_TC_PHYSPAGE *ppp, *prev_ppp;
1245 dpavlin 14
1246     pagenr = DYNTRANS_ADDR_TO_PAGENR(addr);
1247     table_index = PAGENR_TO_TABLE_INDEX(pagenr);
1248    
1249     physpage_entryp = &(((uint32_t *)cpu->
1250     translation_cache)[table_index]);
1251     physpage_ofs = *physpage_entryp;
1252 dpavlin 18 prev_ppp = ppp = NULL;
1253 dpavlin 14
1254     /* Traverse the physical page chain: */
1255     while (physpage_ofs != 0) {
1256 dpavlin 18 prev_ppp = ppp;
1257 dpavlin 14 ppp = (struct DYNTRANS_TC_PHYSPAGE *)
1258     (cpu->translation_cache + physpage_ofs);
1259 dpavlin 26
1260 dpavlin 14 /* If we found the page in the cache,
1261     then we're done: */
1262     if (ppp->physaddr == addr)
1263     break;
1264 dpavlin 26
1265 dpavlin 14 /* Try the next page in the chain: */
1266     physpage_ofs = ppp->next_ofs;
1267     }
1268    
1269 dpavlin 18 if (physpage_ofs == 0)
1270     ppp = NULL;
1271    
1272 dpavlin 28 #if 0
1273 dpavlin 18 /*
1274     * "Bypass" the page, removing it from the code cache.
1275     *
1276     * NOTE/TODO: This gives _TERRIBLE_ performance with self-
1277     * modifying code, or when a single page is used for both
1278     * code and (writable) data.
1279     */
1280 dpavlin 14 if (ppp != NULL) {
1281 dpavlin 18 if (prev_ppp != NULL)
1282     prev_ppp->next_ofs = ppp->next_ofs;
1283     else
1284     *physpage_entryp = ppp->next_ofs;
1285     }
1286     #else
1287     /*
1288     * Instead of removing the page from the code cache, each
1289     * entry can be set to "to_be_translated". This is slow in
1290     * the general case, but in the case of self-modifying code,
1291     * it might be faster since we don't risk wasting cache
1292     * memory as quickly (which would force unnecessary Restarts).
1293     */
1294 dpavlin 28 if (ppp != NULL && ppp->translations != 0) {
1295     uint32_t x = ppp->translations; /* TODO:
1296     urk Should be same type as ppp->translations */
1297     int i, j, n, m;
1298     n = 8 * sizeof(x);
1299     m = DYNTRANS_IC_ENTRIES_PER_PAGE / n;
1300    
1301     for (i=0; i<n; i++) {
1302     if (x & 1) {
1303     for (j=0; j<m; j++)
1304     ppp->ics[i*m + j].f =
1305 dpavlin 14 #ifdef DYNTRANS_DUALMODE_32
1306 dpavlin 28 cpu->is_32bit?
1307     instr32(to_be_translated) :
1308 dpavlin 14 #endif
1309 dpavlin 28 instr(to_be_translated);
1310     }
1311    
1312     x >>= 1;
1313     }
1314    
1315     ppp->flags &= ~COMBINATIONS;
1316     ppp->translations = 0;
1317 dpavlin 14 }
1318 dpavlin 18 #endif
1319 dpavlin 14 }
1320    
1321 dpavlin 26 /* Invalidate entries in the VPH table: */
1322     for (r = 0; r < DYNTRANS_MAX_VPH_TLB_ENTRIES; r ++) {
1323 dpavlin 14 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
1324     vaddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
1325     .vaddr_page & ~(DYNTRANS_PAGESIZE-1);
1326     paddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
1327     .paddr_page & ~(DYNTRANS_PAGESIZE-1);
1328    
1329     if (flags & INVALIDATE_ALL ||
1330     (flags & INVALIDATE_PADDR && paddr_page == addr) ||
1331     (flags & INVALIDATE_VADDR && vaddr_page == addr)) {
1332     #ifdef MODE32
1333 dpavlin 18 uint32_t index =
1334     DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1335 dpavlin 14 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1336     #else
1337 dpavlin 24 const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1;
1338     const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1;
1339     const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1;
1340     uint32_t x1, x2, x3;
1341     struct DYNTRANS_L2_64_TABLE *l2;
1342     struct DYNTRANS_L3_64_TABLE *l3;
1343 dpavlin 14
1344 dpavlin 24 x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1;
1345     x2 = (vaddr_page >> (64-DYNTRANS_L1N -
1346     DYNTRANS_L2N)) & mask2;
1347     x3 = (vaddr_page >> (64-DYNTRANS_L1N -
1348     DYNTRANS_L2N - DYNTRANS_L3N)) & mask3;
1349     l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1350     l3 = l2->l3[x2];
1351     l3->phys_page[x3] = NULL;
1352 dpavlin 14 #endif
1353     }
1354     }
1355     }
1356     }
1357     #endif /* DYNTRANS_INVALIDATE_TC_CODE */
1358    
1359    
1360    
1361     #ifdef DYNTRANS_UPDATE_TRANSLATION_TABLE
1362     /*
1363     * XXX_update_translation_table():
1364     *
1365     * Update the virtual memory translation tables.
1366     */
1367     void DYNTRANS_UPDATE_TRANSLATION_TABLE(struct cpu *cpu, uint64_t vaddr_page,
1368     unsigned char *host_page, int writeflag, uint64_t paddr_page)
1369     {
1370 dpavlin 20 #ifndef MODE32
1371 dpavlin 14 int64_t lowest, highest = -1;
1372 dpavlin 20 #endif
1373 dpavlin 26 int found, r, lowest_index, useraccess = 0;
1374 dpavlin 14
1375     #ifdef MODE32
1376     uint32_t index;
1377     vaddr_page &= 0xffffffffULL;
1378     paddr_page &= 0xffffffffULL;
1379     /* fatal("update_translation_table(): v=0x%x, h=%p w=%i"
1380     " p=0x%x\n", (int)vaddr_page, host_page, writeflag,
1381     (int)paddr_page); */
1382     #else /* !MODE32 */
1383 dpavlin 24 const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1;
1384     const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1;
1385     const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1;
1386     uint32_t x1, x2, x3;
1387     struct DYNTRANS_L2_64_TABLE *l2;
1388     struct DYNTRANS_L3_64_TABLE *l3;
1389 dpavlin 28
1390     /* fatal("update_translation_table(): v=0x%016"PRIx64", h=%p w=%i"
1391     " p=0x%016"PRIx64"\n", (uint64_t)vaddr_page, host_page, writeflag,
1392 dpavlin 24 (uint64_t)paddr_page); */
1393 dpavlin 14 #endif
1394    
1395 dpavlin 26 assert((vaddr_page & (DYNTRANS_PAGESIZE-1)) == 0);
1396     assert((paddr_page & (DYNTRANS_PAGESIZE-1)) == 0);
1397    
1398 dpavlin 18 if (writeflag & MEMORY_USER_ACCESS) {
1399     writeflag &= ~MEMORY_USER_ACCESS;
1400     useraccess = 1;
1401     }
1402    
1403 dpavlin 14 /* Scan the current TLB entries: */
1404 dpavlin 26 lowest_index = 0;
1405 dpavlin 18
1406     #ifdef MODE32
1407 dpavlin 20 /*
1408     * NOTE 1: vaddr_to_tlbindex is one more than the index, so that
1409     * 0 becomes -1, which means a miss.
1410     *
1411     * NOTE 2: When a miss occurs, instead of scanning the entire tlb
1412     * for the entry with the lowest time stamp, just choosing
1413     * one at random will work as well.
1414     */
1415     found = (int)cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[
1416 dpavlin 18 DYNTRANS_ADDR_TO_PAGENR(vaddr_page)] - 1;
1417 dpavlin 20 if (found < 0) {
1418     static unsigned int x = 0;
1419 dpavlin 26 lowest_index = (x++) % DYNTRANS_MAX_VPH_TLB_ENTRIES;
1420 dpavlin 20 }
1421     #else
1422     lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp;
1423     found = -1;
1424 dpavlin 26 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
1425 dpavlin 14 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp < lowest) {
1426     lowest = cpu->cd.DYNTRANS_ARCH.
1427     vph_tlb_entry[r].timestamp;
1428     lowest_index = r;
1429     }
1430     if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp > highest)
1431     highest = cpu->cd.DYNTRANS_ARCH.
1432     vph_tlb_entry[r].timestamp;
1433     if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid &&
1434     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page ==
1435     vaddr_page) {
1436     found = r;
1437     break;
1438     }
1439     }
1440 dpavlin 20 #endif
1441 dpavlin 14
1442     if (found < 0) {
1443     /* Create the new TLB entry, overwriting the oldest one: */
1444     r = lowest_index;
1445     if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
1446     /* This one has to be invalidated first: */
1447     DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
1448     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
1449     0);
1450     }
1451    
1452     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid = 1;
1453     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].host_page = host_page;
1454     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page = paddr_page;
1455     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page = vaddr_page;
1456 dpavlin 20 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag =
1457     writeflag & MEM_WRITE;
1458     #ifndef MODE32
1459 dpavlin 14 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1;
1460 dpavlin 20 #endif
1461 dpavlin 14
1462     /* Add the new translation to the table: */
1463     #ifdef MODE32
1464 dpavlin 18 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1465 dpavlin 14 cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
1466     cpu->cd.DYNTRANS_ARCH.host_store[index] =
1467     writeflag? host_page : NULL;
1468     cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
1469     cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1470 dpavlin 18 cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = r + 1;
1471     #ifdef DYNTRANS_ARM
1472     if (useraccess)
1473 dpavlin 20 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5]
1474     |= 1 << (index & 31);
1475 dpavlin 18 #endif
1476 dpavlin 24 #else /* !MODE32 */
1477     x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1;
1478     x2 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
1479     x3 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N))
1480     & mask3;
1481 dpavlin 28
1482 dpavlin 24 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1483     if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) {
1484     if (cpu->cd.DYNTRANS_ARCH.next_free_l2 != NULL) {
1485     l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1] =
1486     cpu->cd.DYNTRANS_ARCH.next_free_l2;
1487     cpu->cd.DYNTRANS_ARCH.next_free_l2 = l2->next;
1488     } else {
1489     int i;
1490     l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1] =
1491     malloc(sizeof(struct DYNTRANS_L2_64_TABLE));
1492 dpavlin 28 l2->refcount = 0;
1493 dpavlin 24 for (i=0; i<(1 << DYNTRANS_L2N); i++)
1494     l2->l3[i] = cpu->cd.DYNTRANS_ARCH.
1495     l3_64_dummy;
1496     }
1497 dpavlin 28 if (l2->refcount != 0) {
1498     fatal("Huh? l2 Refcount problem.\n");
1499     exit(1);
1500     }
1501 dpavlin 24 }
1502 dpavlin 28 if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) {
1503     fatal("INTERNAL ERROR L2 reuse\n");
1504     exit(1);
1505     }
1506 dpavlin 24 l3 = l2->l3[x2];
1507     if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy) {
1508     if (cpu->cd.DYNTRANS_ARCH.next_free_l3 != NULL) {
1509     l3 = l2->l3[x2] =
1510     cpu->cd.DYNTRANS_ARCH.next_free_l3;
1511     cpu->cd.DYNTRANS_ARCH.next_free_l3 = l3->next;
1512     } else {
1513     l3 = l2->l3[x2] = zeroed_alloc(sizeof(
1514     struct DYNTRANS_L3_64_TABLE));
1515     }
1516 dpavlin 28 if (l3->refcount != 0) {
1517     fatal("Huh? l3 Refcount problem.\n");
1518     exit(1);
1519     }
1520 dpavlin 24 l2->refcount ++;
1521     }
1522 dpavlin 28 if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy) {
1523     fatal("INTERNAL ERROR L3 reuse\n");
1524     exit(1);
1525     }
1526    
1527 dpavlin 24 l3->host_load[x3] = host_page;
1528     l3->host_store[x3] = writeflag? host_page : NULL;
1529     l3->phys_addr[x3] = paddr_page;
1530     l3->phys_page[x3] = NULL;
1531     l3->vaddr_to_tlbindex[x3] = r + 1;
1532     l3->refcount ++;
1533 dpavlin 28
1534     #ifdef BUGHUNT
1535     /* Count how many pages are actually in use: */
1536     {
1537     int n=0, i;
1538     for (i=0; i<=mask3; i++)
1539     if (l3->vaddr_to_tlbindex[i])
1540     n++;
1541     if (n != l3->refcount) {
1542     printf("X: %i in use, but refcount = %i!\n", n, l3->refcount);
1543     exit(1);
1544     }
1545    
1546     n = 0;
1547     for (i=0; i<=mask3; i++)
1548     if (l3->host_load[i] != NULL)
1549     n++;
1550     if (n != l3->refcount) {
1551     printf("XHL: %i in use, but refcount = %i!\n", n, l3->refcount);
1552     exit(1);
1553     }
1554     }
1555     #endif
1556    
1557 dpavlin 24 #endif /* !MODE32 */
1558 dpavlin 14 } else {
1559     /*
1560     * The translation was already in the TLB.
1561     * Writeflag = 0: Do nothing.
1562     * Writeflag = 1: Make sure the page is writable.
1563 dpavlin 20 * Writeflag = MEM_DOWNGRADE: Downgrade to readonly.
1564 dpavlin 14 */
1565 dpavlin 18 r = found;
1566 dpavlin 20 #ifndef MODE32
1567 dpavlin 18 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1;
1568 dpavlin 20 #endif
1569     if (writeflag & MEM_WRITE)
1570 dpavlin 14 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1;
1571 dpavlin 20 if (writeflag & MEM_DOWNGRADE)
1572 dpavlin 14 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 0;
1573     #ifdef MODE32
1574 dpavlin 18 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1575 dpavlin 14 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1576 dpavlin 18 #ifdef DYNTRANS_ARM
1577 dpavlin 20 cpu->cd.DYNTRANS_ARCH.is_userpage[index>>5] &= ~(1<<(index&31));
1578 dpavlin 18 if (useraccess)
1579 dpavlin 20 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5]
1580     |= 1 << (index & 31);
1581 dpavlin 18 #endif
1582 dpavlin 14 if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) {
1583 dpavlin 20 if (writeflag & MEM_WRITE)
1584 dpavlin 14 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1585     host_page;
1586 dpavlin 20 if (writeflag & MEM_DOWNGRADE)
1587 dpavlin 14 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
1588     } else {
1589     /* Change the entire physical/host mapping: */
1590     cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
1591     cpu->cd.DYNTRANS_ARCH.host_store[index] =
1592     writeflag? host_page : NULL;
1593     cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
1594     }
1595 dpavlin 24 #else /* !MODE32 */
1596     x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1;
1597     x2 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
1598     x3 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N))
1599     & mask3;
1600     l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1601     l3 = l2->l3[x2];
1602     if (l3->phys_addr[x3] == paddr_page) {
1603     if (writeflag & MEM_WRITE)
1604     l3->host_store[x3] = host_page;
1605     if (writeflag & MEM_DOWNGRADE)
1606     l3->host_store[x3] = NULL;
1607     } else {
1608     /* Change the entire physical/host mapping: */
1609 dpavlin 28 printf("HOST LOAD 2 set to %p\n", host_page);
1610 dpavlin 24 l3->host_load[x3] = host_page;
1611     l3->host_store[x3] = writeflag? host_page : NULL;
1612     l3->phys_addr[x3] = paddr_page;
1613     }
1614 dpavlin 28
1615     #ifdef BUGHUNT
1616     /* Count how many pages are actually in use: */
1617     {
1618     int n=0, i;
1619     for (i=0; i<=mask3; i++)
1620     if (l3->vaddr_to_tlbindex[i])
1621     n++;
1622     if (n != l3->refcount) {
1623     printf("Y: %i in use, but refcount = %i!\n", n, l3->refcount);
1624     exit(1);
1625     }
1626    
1627     n = 0;
1628     for (i=0; i<=mask3; i++)
1629     if (l3->host_load[i] != NULL)
1630     n++;
1631     if (n != l3->refcount) {
1632     printf("YHL: %i in use, but refcount = %i!\n", n, l3->refcount);
1633     printf("Entry r = %i\n", r);
1634     printf("Valid = %i\n",
1635     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid);
1636     exit(1);
1637     }
1638     }
1639     #endif
1640    
1641 dpavlin 24 #endif /* !MODE32 */
1642 dpavlin 14 }
1643     }
1644     #endif /* DYNTRANS_UPDATE_TRANSLATION_TABLE */
1645    
1646    
1647     /*****************************************************************************/
1648    
1649    
1650     #ifdef DYNTRANS_TO_BE_TRANSLATED_HEAD
1651     /*
1652     * Check for breakpoints.
1653     */
1654     if (!single_step_breakpoint) {
1655 dpavlin 24 MODE_uint_t curpc = cpu->pc;
1656 dpavlin 14 int i;
1657     for (i=0; i<cpu->machine->n_breakpoints; i++)
1658 dpavlin 24 if (curpc == (MODE_uint_t)
1659 dpavlin 14 cpu->machine->breakpoint_addr[i]) {
1660     if (!cpu->machine->instruction_trace) {
1661     int old_quiet_mode = quiet_mode;
1662     quiet_mode = 0;
1663 dpavlin 24 DISASSEMBLE(cpu, ib, 1, 0);
1664 dpavlin 14 quiet_mode = old_quiet_mode;
1665     }
1666 dpavlin 24 fatal("BREAKPOINT: pc = 0x%"PRIx64"\n(The "
1667 dpavlin 14 "instruction has not yet executed.)\n",
1668 dpavlin 24 (uint64_t)cpu->pc);
1669 dpavlin 22 #ifdef DYNTRANS_DELAYSLOT
1670 dpavlin 24 if (cpu->delay_slot != NOT_DELAYED)
1671 dpavlin 22 fatal("ERROR! Breakpoint in a delay"
1672     " slot! Not yet supported.\n");
1673     #endif
1674 dpavlin 14 single_step_breakpoint = 1;
1675 dpavlin 26 single_step = ENTER_SINGLE_STEPPING;
1676 dpavlin 14 goto stop_running_translated;
1677     }
1678     }
1679     #endif /* DYNTRANS_TO_BE_TRANSLATED_HEAD */
1680    
1681    
1682     /*****************************************************************************/
1683    
1684    
1685     #ifdef DYNTRANS_TO_BE_TRANSLATED_TAIL
1686     /*
1687 dpavlin 28 * If we end up here, then an instruction was translated. Let's mark
1688     * the page as containing a translation at this part of the page.
1689 dpavlin 14 */
1690 dpavlin 28
1691 dpavlin 24 /* Make sure cur_physpage is in synch: */
1692     cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
1693     cpu->cd.DYNTRANS_ARCH.cur_ic_page;
1694 dpavlin 28
1695     {
1696     int x = addr & (DYNTRANS_PAGESIZE - 1);
1697     int addr_per_translation_range = DYNTRANS_PAGESIZE / (8 *
1698     sizeof(cpu->cd.DYNTRANS_ARCH.cur_physpage->translations));
1699     x /= addr_per_translation_range;
1700    
1701     cpu->cd.DYNTRANS_ARCH.cur_physpage->translations |= (1 << x);
1702 dpavlin 18 }
1703 dpavlin 14
1704     /*
1705     * Now it is time to check for combinations of instructions that can
1706     * be converted into a single function call.
1707     *
1708     * Note: Single-stepping or instruction tracing doesn't work with
1709 dpavlin 24 * instruction combination. For architectures with delay slots,
1710     * we also ignore combinations if the delay slot is across a page
1711     * boundary.
1712 dpavlin 14 */
1713 dpavlin 24 if (!single_step && !cpu->machine->instruction_trace
1714     #ifdef DYNTRANS_DELAYSLOT
1715     && !in_crosspage_delayslot
1716     #endif
1717     ) {
1718 dpavlin 20 if (cpu->cd.DYNTRANS_ARCH.combination_check != NULL &&
1719 dpavlin 28 cpu->machine->allow_instruction_combinations)
1720 dpavlin 20 cpu->cd.DYNTRANS_ARCH.combination_check(cpu, ic,
1721 dpavlin 18 addr & (DYNTRANS_PAGESIZE - 1));
1722     }
1723 dpavlin 14
1724 dpavlin 24 cpu->cd.DYNTRANS_ARCH.combination_check = NULL;
1725    
1726     /* An additional check, to catch some bugs: */
1727     if (ic->f == (
1728     #ifdef DYNTRANS_DUALMODE_32
1729     cpu->is_32bit? instr32(to_be_translated) :
1730     #endif
1731     instr(to_be_translated))) {
1732     fatal("INTERNAL ERROR: ic->f not set!\n");
1733     goto bad;
1734     }
1735     if (ic->f == NULL) {
1736     fatal("INTERNAL ERROR: ic->f == NULL!\n");
1737     goto bad;
1738     }
1739    
1740 dpavlin 14 /* ... and finally execute the translated instruction: */
1741 dpavlin 24 if ((single_step_breakpoint && cpu->delay_slot == NOT_DELAYED)
1742     #ifdef DYNTRANS_DELAYSLOT
1743     || in_crosspage_delayslot
1744     #endif
1745     ) {
1746 dpavlin 14 /*
1747     * Special case when single-stepping: Execute the translated
1748     * instruction, but then replace it with a "to be translated"
1749     * directly afterwards.
1750     */
1751     single_step_breakpoint = 0;
1752 dpavlin 24 #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
1753     cpu->cd.DYNTRANS_ARCH.next_ic = ic + ic->arg[0];
1754     #endif
1755 dpavlin 14 ic->f(cpu, ic);
1756     ic->f =
1757     #ifdef DYNTRANS_DUALMODE_32
1758     cpu->is_32bit? instr32(to_be_translated) :
1759     #endif
1760     instr(to_be_translated);
1761 dpavlin 24 #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
1762     ic->arg[0] = 0;
1763     #endif
1764     } else {
1765     #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
1766     cpu->cd.DYNTRANS_ARCH.next_ic = ic + ic->arg[0];
1767    
1768     /* Additional check, for variable length ISAs: */
1769     if (ic->arg[0] == 0) {
1770     fatal("INTERNAL ERROR: instr len = 0!\n");
1771     goto bad;
1772     }
1773     #endif
1774    
1775     /* Finally finally :-), execute the instruction: */
1776 dpavlin 14 ic->f(cpu, ic);
1777 dpavlin 24 }
1778 dpavlin 14
1779     return;
1780    
1781    
1782     bad: /*
1783     * Nothing was translated. (Unimplemented or illegal instruction.)
1784     */
1785    
1786     quiet_mode = 0;
1787     fatal("to_be_translated(): TODO: unimplemented instruction");
1788    
1789     if (cpu->machine->instruction_trace)
1790     #ifdef MODE32
1791 dpavlin 24 fatal(" at 0x%"PRIx32"\n", (uint32_t)cpu->pc);
1792 dpavlin 14 #else
1793 dpavlin 24 fatal(" at 0x%"PRIx64"\n", (uint64_t)cpu->pc);
1794 dpavlin 14 #endif
1795     else {
1796     fatal(":\n");
1797 dpavlin 24 DISASSEMBLE(cpu, ib, 1, 0);
1798 dpavlin 14 }
1799    
1800     cpu->running = 0;
1801     cpu->dead = 1;
1802     stop_running_translated:
1803     debugger_n_steps_left_before_interaction = 0;
1804     cpu->running_translated = 0;
1805     ic = cpu->cd.DYNTRANS_ARCH.next_ic = &nothing_call;
1806     cpu->cd.DYNTRANS_ARCH.next_ic ++;
1807    
1808     /* Execute the "nothing" instruction: */
1809     ic->f(cpu, ic);
1810     #endif /* DYNTRANS_TO_BE_TRANSLATED_TAIL */
1811    

  ViewVC Help
Powered by ViewVC 1.1.26