/[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 22 - (hide annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 44737 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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 22 * $Id: cpu_dyntrans.c,v 1.54 2006/02/09 22:55:20 debug Exp $
29 dpavlin 14 *
30     * Common dyntrans routines. Included from cpu_*.c.
31     */
32    
33    
34     #ifdef DYNTRANS_CPU_RUN_INSTR
35 dpavlin 22 #if 1 /* IC statistics: */
36 dpavlin 18 static void gather_statistics(struct cpu *cpu)
37     {
38 dpavlin 22 struct DYNTRANS_IC *ic = cpu->cd.DYNTRANS_ARCH.next_ic;
39     static long long n = 0;
40     static FILE *f = NULL;
41    
42     n++;
43     if (n < 100000000)
44     return;
45    
46     if (f == NULL) {
47     f = fopen("instruction_call_statistics.raw", "w");
48     if (f == NULL) {
49     fatal("Unable to open statistics file for output.\n");
50     exit(1);
51     }
52     }
53     fwrite(&ic->f, 1, sizeof(void *), f);
54     }
55     #else /* PC statistics: */
56     static void gather_statistics(struct cpu *cpu)
57     {
58 dpavlin 18 uint64_t a;
59     int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t)
60     cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC);
61     if (low_pc < 0 || low_pc >= DYNTRANS_IC_ENTRIES_PER_PAGE)
62     return;
63    
64 dpavlin 20 #if 0
65 dpavlin 18 /* Use the physical address: */
66     cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
67     cpu->cd.DYNTRANS_ARCH.cur_ic_page;
68     a = cpu->cd.DYNTRANS_ARCH.cur_physpage->physaddr;
69     #else
70     /* Use the PC (virtual address): */
71     a = cpu->pc;
72     #endif
73    
74     a &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
75     DYNTRANS_INSTR_ALIGNMENT_SHIFT);
76     a += low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT;
77    
78     /*
79     * TODO: Everything below this line should be cleaned up :-)
80     */
81     a &= 0x03ffffff;
82     {
83     static long long *array = NULL;
84     static char *array_16kpage_in_use = NULL;
85     static int n = 0;
86     a >>= DYNTRANS_INSTR_ALIGNMENT_SHIFT;
87     if (array == NULL)
88     array = zeroed_alloc(sizeof(long long) * 16384*1024);
89     if (array_16kpage_in_use == NULL)
90     array_16kpage_in_use = zeroed_alloc(sizeof(char) * 1024);
91     a &= (16384*1024-1);
92     array[a] ++;
93     array_16kpage_in_use[a / 16384] = 1;
94     n++;
95     if ((n & 0x3fffffff) == 0) {
96     FILE *f = fopen("statistics.out", "w");
97     int i, j;
98     printf("Saving statistics... "); fflush(stdout);
99     for (i=0; i<1024; i++)
100     if (array_16kpage_in_use[i]) {
101     for (j=0; j<16384; j++)
102     if (array[i*16384 + j] > 0)
103     fprintf(f, "%lli\t0x%016llx\n",
104     (long long)array[i*16384+j],
105     (long long)((i*16384+j) <<
106     DYNTRANS_INSTR_ALIGNMENT_SHIFT));
107     }
108     fclose(f);
109     printf("n=0x%08x\n", n);
110     }
111     }
112     }
113 dpavlin 22 #endif /* PC statistics */
114 dpavlin 18
115     #define S gather_statistics(cpu)
116    
117     #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
118 dpavlin 20 #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic; \
119 dpavlin 22 cpu->cd.DYNTRANS_ARCH.next_ic += ic->arg[0]; \
120 dpavlin 20 ic->f(cpu, ic);
121 dpavlin 18 #else
122     #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic);
123     #endif
124    
125    
126 dpavlin 14 /*
127     * XXX_cpu_run_instr():
128     *
129     * Execute one or more instructions on a specific CPU, using dyntrans.
130     *
131     * Return value is the number of instructions executed during this call,
132     * 0 if no instructions were executed.
133     */
134     int DYNTRANS_CPU_RUN_INSTR(struct emul *emul, struct cpu *cpu)
135     {
136     #ifdef MODE32
137     uint32_t cached_pc;
138     #else
139     uint64_t cached_pc;
140     #endif
141     int low_pc, n_instrs;
142    
143     #ifdef DYNTRANS_DUALMODE_32
144     if (cpu->is_32bit)
145     DYNTRANS_PC_TO_POINTERS32(cpu);
146     else
147     #endif
148     DYNTRANS_PC_TO_POINTERS(cpu);
149    
150     /*
151     * Interrupt assertion? (This is _below_ the initial PC to pointer
152     * conversion; if the conversion caused an exception of some kind
153     * then interrupts are probably disabled, and the exception will get
154     * priority over device interrupts.)
155     */
156     #ifdef DYNTRANS_ARM
157     if (cpu->cd.arm.irq_asserted && !(cpu->cd.arm.cpsr & ARM_FLAG_I))
158     arm_exception(cpu, ARM_EXCEPTION_IRQ);
159     #endif
160 dpavlin 20 #ifdef DYNTRANS_PPC
161     if (cpu->cd.ppc.dec_intr_pending && cpu->cd.ppc.msr & PPC_MSR_EE) {
162     ppc_exception(cpu, PPC_EXCEPTION_DEC);
163     cpu->cd.ppc.dec_intr_pending = 0;
164     }
165     if (cpu->cd.ppc.irq_asserted && cpu->cd.ppc.msr & PPC_MSR_EE)
166     ppc_exception(cpu, PPC_EXCEPTION_EI);
167     #endif
168 dpavlin 14
169     cached_pc = cpu->pc;
170    
171     cpu->n_translated_instrs = 0;
172     cpu->running_translated = 1;
173    
174 dpavlin 18 cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
175     cpu->cd.DYNTRANS_ARCH.cur_ic_page;
176    
177 dpavlin 14 if (single_step || cpu->machine->instruction_trace) {
178     /*
179     * Single-step:
180     */
181     struct DYNTRANS_IC *ic = cpu->cd.DYNTRANS_ARCH.next_ic
182     #ifndef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
183     ++
184     #endif
185     ;
186     if (cpu->machine->instruction_trace) {
187     #ifdef DYNTRANS_X86
188     unsigned char instr[17];
189     cpu->cd.x86.cursegment = X86_S_CS;
190     cpu->cd.x86.seg_override = 0;
191     #else
192     #ifdef DYNTRANS_M68K
193     unsigned char instr[16]; /* TODO: 16? */
194     #else
195     unsigned char instr[4]; /* General case... */
196     #endif
197     #endif
198     if (!cpu->memory_rw(cpu, cpu->mem, cached_pc, &instr[0],
199     sizeof(instr), MEM_READ, CACHE_INSTRUCTION)) {
200     fatal("XXX_cpu_run_instr(): could not read "
201     "the instruction\n");
202 dpavlin 22 } else {
203 dpavlin 14 cpu_disassemble_instr(cpu->machine, cpu,
204     instr, 1, 0, 0);
205 dpavlin 22 #ifdef DYNTRANS_MIPS
206     /* TODO: generalize, not just MIPS */
207     /* Show the instruction in the delay slot,
208     if any: */
209     fatal("TODO: check for delay slot!\n");
210     #endif
211     }
212 dpavlin 14 }
213    
214     /* When single-stepping, multiple instruction calls cannot
215     be combined into one. This clears all translations: */
216     if (cpu->cd.DYNTRANS_ARCH.cur_physpage->flags & COMBINATIONS) {
217     int i;
218     for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
219     cpu->cd.DYNTRANS_ARCH.cur_physpage->ics[i].f =
220     #ifdef DYNTRANS_DUALMODE_32
221     cpu->is_32bit?
222     instr32(to_be_translated) :
223     #endif
224     instr(to_be_translated);
225     fatal("[ Note: The translation of physical page 0x%llx"
226     " contained combinations of instructions; these "
227     "are now flushed because we are single-stepping."
228     " ]\n", (long long)cpu->cd.DYNTRANS_ARCH.
229     cur_physpage->physaddr);
230     cpu->cd.DYNTRANS_ARCH.cur_physpage->flags &=
231     ~(COMBINATIONS | TRANSLATIONS);
232     }
233    
234 dpavlin 18 if (show_opcode_statistics)
235     S;
236    
237 dpavlin 14 /* Execute just one instruction: */
238     ic->f(cpu, ic);
239     n_instrs = 1;
240 dpavlin 18 } else if (show_opcode_statistics) {
241     /* Gather statistics while executing multiple instructions: */
242     n_instrs = 0;
243     for (;;) {
244     struct DYNTRANS_IC *ic;
245    
246     S; I; S; I; S; I; S; I; S; I; S; I;
247     S; I; S; I; S; I; S; I; S; I; S; I;
248     S; I; S; I; S; I; S; I; S; I; S; I;
249     S; I; S; I; S; I; S; I; S; I; S; I;
250    
251     n_instrs += 24;
252    
253     if (!cpu->running_translated ||
254     n_instrs + cpu->n_translated_instrs >= 16384)
255     break;
256     }
257 dpavlin 14 } else {
258     /* Execute multiple instructions: */
259     n_instrs = 0;
260     for (;;) {
261     struct DYNTRANS_IC *ic;
262    
263     I; I; I; I; I; I; I; I; I; I;
264     I; I; I; I; I; I; I; I; I; I;
265     I; I; I; I; I; I; I; I; I; I;
266     I; I; I; I; I; I; I; I; I; I;
267     I; I; I; I; I; I; I; I; I; I;
268    
269     I; I; I; I; I; I; I; I; I; I;
270    
271 dpavlin 18 n_instrs += 60;
272 dpavlin 14
273     if (!cpu->running_translated ||
274     n_instrs + cpu->n_translated_instrs >= 16384)
275     break;
276     }
277     }
278    
279 dpavlin 20 n_instrs += cpu->n_translated_instrs;
280 dpavlin 14
281 dpavlin 20 /* Synchronize the program counter: */
282 dpavlin 14 low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t)
283     cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC);
284     if (low_pc >= 0 && low_pc < DYNTRANS_IC_ENTRIES_PER_PAGE) {
285     cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
286     DYNTRANS_INSTR_ALIGNMENT_SHIFT);
287     cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT);
288     } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE) {
289     /* Switch to next page: */
290     cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
291     DYNTRANS_INSTR_ALIGNMENT_SHIFT);
292     cpu->pc += (DYNTRANS_IC_ENTRIES_PER_PAGE <<
293     DYNTRANS_INSTR_ALIGNMENT_SHIFT);
294 dpavlin 22 } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE + 1) {
295     /* Switch to next page and skip an instruction which was
296     already executed (in a delay slot): */
297     cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
298     DYNTRANS_INSTR_ALIGNMENT_SHIFT);
299     cpu->pc += ((DYNTRANS_IC_ENTRIES_PER_PAGE + 1) <<
300     DYNTRANS_INSTR_ALIGNMENT_SHIFT);
301 dpavlin 14 }
302    
303 dpavlin 20 #ifdef DYNTRANS_PPC
304     /* Update the Decrementer and Time base registers: */
305     {
306     uint32_t old = cpu->cd.ppc.spr[SPR_DEC];
307     cpu->cd.ppc.spr[SPR_DEC] = (uint32_t) (old - n_instrs);
308 dpavlin 22 if ((old >> 31) == 0 && (cpu->cd.ppc.spr[SPR_DEC] >> 31) == 1
309     && !(cpu->cd.ppc.cpu_type.flags & PPC_NO_DEC))
310 dpavlin 20 cpu->cd.ppc.dec_intr_pending = 1;
311     old = cpu->cd.ppc.spr[SPR_TBL];
312     cpu->cd.ppc.spr[SPR_TBL] += n_instrs;
313     if ((old >> 31) == 1 && (cpu->cd.ppc.spr[SPR_TBL] >> 31) == 0)
314     cpu->cd.ppc.spr[SPR_TBU] ++;
315     }
316     #endif
317    
318     /* Return the nr of instructions executed: */
319     return n_instrs;
320 dpavlin 14 }
321     #endif /* DYNTRANS_CPU_RUN_INSTR */
322    
323    
324    
325     #ifdef DYNTRANS_FUNCTION_TRACE
326     /*
327     * XXX_cpu_functioncall_trace():
328     *
329     * Without this function, the main trace tree function prints something
330     * like <f()> or <0x1234()> on a function call. It is up to this
331     * function to print the arguments passed.
332     */
333     void DYNTRANS_FUNCTION_TRACE(struct cpu *cpu, uint64_t f, int n_args)
334     {
335     char strbuf[50];
336     char *symbol;
337     uint64_t ot;
338     int x, print_dots = 1, n_args_to_print =
339     #ifdef DYNTRANS_ALPHA
340     6
341     #else
342     #ifdef DYNTRANS_SH
343     8
344     #else
345     4 /* Default value for most archs */
346     #endif
347     #endif
348     ;
349    
350     if (n_args >= 0 && n_args <= n_args_to_print) {
351     print_dots = 0;
352     n_args_to_print = n_args;
353     }
354    
355     /*
356     * TODO: The type of each argument should be taken from the symbol
357     * table, in some way.
358     *
359     * The code here does a kind of "heuristic guess" regarding what the
360     * argument values might mean. Sometimes the output looks weird, but
361     * usually it looks good enough.
362     *
363     * Print ".." afterwards to show that there might be more arguments
364     * than were passed in register.
365     */
366     for (x=0; x<n_args_to_print; x++) {
367     int64_t d;
368     #ifdef DYNTRANS_X86
369     d = 0; /* TODO */
370     #else
371     /* Args in registers: */
372     d = cpu->cd.DYNTRANS_ARCH.
373     #ifdef DYNTRANS_ALPHA
374     r[ALPHA_A0
375     #endif
376     #ifdef DYNTRANS_ARM
377     r[0
378     #endif
379     #ifdef DYNTRANS_AVR
380     /* TODO: 24,25 = first register, but then
381     they go downwards, ie. 22,23 and so on */
382     r[24
383     #endif
384     #ifdef DYNTRANS_HPPA
385     r[0 /* TODO */
386     #endif
387     #ifdef DYNTRANS_I960
388     r[0 /* TODO */
389     #endif
390     #ifdef DYNTRANS_IA64
391     r[0 /* TODO */
392     #endif
393     #ifdef DYNTRANS_M68K
394     d[0 /* TODO */
395     #endif
396     #ifdef DYNTRANS_MIPS
397     gpr[MIPS_GPR_A0
398     #endif
399     #ifdef DYNTRANS_PPC
400     gpr[3
401     #endif
402     #ifdef DYNTRANS_SH
403     r[2
404     #endif
405     #ifdef DYNTRANS_SPARC
406 dpavlin 22 r[24
407 dpavlin 14 #endif
408     + x];
409     #endif
410     symbol = get_symbol_name(&cpu->machine->symbol_context, d, &ot);
411    
412     if (d > -256 && d < 256)
413     fatal("%i", (int)d);
414     else if (memory_points_to_string(cpu, cpu->mem, d, 1))
415     fatal("\"%s\"", memory_conv_to_string(cpu,
416     cpu->mem, d, strbuf, sizeof(strbuf)));
417     else if (symbol != NULL && ot == 0)
418     fatal("&%s", symbol);
419     else {
420     if (cpu->is_32bit)
421     fatal("0x%x", (int)d);
422     else
423     fatal("0x%llx", (long long)d);
424     }
425    
426     if (x < n_args_to_print - 1)
427     fatal(",");
428     }
429    
430     if (print_dots)
431     fatal(",..");
432     }
433     #endif
434    
435    
436    
437     #ifdef DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE
438 dpavlin 22
439 dpavlin 14 /* forward declaration of to_be_translated and end_of_page: */
440     static void instr(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
441     static void instr(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
442     #ifdef DYNTRANS_DUALMODE_32
443     static void instr32(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
444     static void instr32(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
445     #endif
446 dpavlin 22
447     #ifdef DYNTRANS_DELAYSLOT
448     static void instr(end_of_page2)(struct cpu *,struct DYNTRANS_IC *);
449     #ifdef DYNTRANS_DUALMODE_32
450     static void instr32(end_of_page2)(struct cpu *,struct DYNTRANS_IC *);
451     #endif
452     #endif
453    
454 dpavlin 14 /*
455     * XXX_tc_allocate_default_page():
456     *
457     * Create a default page (with just pointers to instr(to_be_translated)
458     * at cpu->translation_cache_cur_ofs.
459     */
460     static void DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE(struct cpu *cpu,
461     uint64_t physaddr)
462     {
463     struct DYNTRANS_TC_PHYSPAGE *ppp;
464     int i;
465    
466     /* Create the physpage header: */
467     ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
468     + cpu->translation_cache_cur_ofs);
469     ppp->next_ofs = 0;
470     ppp->physaddr = physaddr;
471    
472     /* TODO: Is this faster than copying an entire template page? */
473     for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
474     ppp->ics[i].f =
475     #ifdef DYNTRANS_DUALMODE_32
476     cpu->is_32bit? instr32(to_be_translated) :
477     #endif
478     instr(to_be_translated);
479    
480 dpavlin 22 ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 0].f =
481 dpavlin 14 #ifdef DYNTRANS_DUALMODE_32
482     cpu->is_32bit? instr32(end_of_page) :
483     #endif
484     instr(end_of_page);
485    
486 dpavlin 22 #ifdef DYNTRANS_DELAYSLOT
487     ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 1].f =
488     #ifdef DYNTRANS_DUALMODE_32
489     cpu->is_32bit? instr32(end_of_page2) :
490     #endif
491     instr(end_of_page2);
492     #endif
493    
494 dpavlin 14 cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE);
495 dpavlin 18
496     cpu->translation_cache_cur_ofs --;
497     cpu->translation_cache_cur_ofs |= 63;
498     cpu->translation_cache_cur_ofs ++;
499 dpavlin 14 }
500     #endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE */
501    
502    
503    
504     #ifdef DYNTRANS_PC_TO_POINTERS_FUNC
505     /*
506     * XXX_pc_to_pointers_generic():
507     *
508     * Generic case. See DYNTRANS_PC_TO_POINTERS_FUNC below.
509     */
510     void DYNTRANS_PC_TO_POINTERS_GENERIC(struct cpu *cpu)
511     {
512     #ifdef MODE32
513     uint32_t
514     #else
515     uint64_t
516     #endif
517 dpavlin 20 cached_pc, physaddr = 0;
518 dpavlin 14 uint32_t physpage_ofs;
519     int ok, pagenr, table_index;
520     uint32_t *physpage_entryp;
521     struct DYNTRANS_TC_PHYSPAGE *ppp;
522    
523     #ifdef MODE32
524     int index;
525     cached_pc = cpu->pc;
526 dpavlin 18 index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
527 dpavlin 14 #else
528     #ifdef DYNTRANS_ALPHA
529     uint32_t a, b;
530     int kernel = 0;
531     struct alpha_vph_page *vph_p;
532     cached_pc = cpu->pc;
533     a = (cached_pc >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
534     b = (cached_pc >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
535     if ((cached_pc >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
536     vph_p = cpu->cd.alpha.vph_table0_kernel[a];
537     kernel = 1;
538     } else
539     vph_p = cpu->cd.alpha.vph_table0[a];
540     #else
541 dpavlin 22 fatal("Neither alpha nor 32-bit? 3\n");
542 dpavlin 14 exit(1);
543     #endif
544     #endif
545    
546     /* Virtual to physical address translation: */
547     ok = 0;
548     #ifdef MODE32
549     if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL) {
550     physaddr = cpu->cd.DYNTRANS_ARCH.phys_addr[index];
551     ok = 1;
552     }
553     #else
554     #ifdef DYNTRANS_ALPHA
555     if (vph_p->host_load[b] != NULL) {
556     physaddr = vph_p->phys_addr[b];
557     ok = 1;
558     }
559     #else
560 dpavlin 22 fatal("Neither alpha nor 32-bit? 4\n");
561 dpavlin 14 exit(1);
562     #endif
563     #endif
564    
565     if (!ok) {
566     uint64_t paddr;
567     if (cpu->translate_address != NULL)
568     ok = cpu->translate_address(cpu, cached_pc,
569     &paddr, FLAG_INSTR);
570     else {
571     paddr = cached_pc;
572     ok = 1;
573     }
574     if (!ok) {
575 dpavlin 20 /* fatal("TODO: instruction vaddr=>paddr translation"
576 dpavlin 14 " failed. vaddr=0x%llx\n", (long long)cached_pc);
577 dpavlin 20 fatal("!! cpu->pc=0x%llx\n", (long long)cpu->pc); */
578    
579 dpavlin 14 ok = cpu->translate_address(cpu, cpu->pc, &paddr,
580     FLAG_INSTR);
581 dpavlin 20
582     /* printf("EXCEPTION HANDLER: vaddr = 0x%x ==> "
583     "paddr = 0x%x\n", (int)cpu->pc, (int)paddr);
584     fatal("!? cpu->pc=0x%llx\n", (long long)cpu->pc); */
585    
586 dpavlin 14 if (!ok) {
587     fatal("FATAL: could not find physical"
588     " address of the exception handler?");
589     exit(1);
590     }
591     }
592     cached_pc = cpu->pc;
593 dpavlin 18 #ifdef MODE32
594     index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
595     #endif
596 dpavlin 14 physaddr = paddr;
597     }
598    
599 dpavlin 18 #ifdef MODE32
600     if (cpu->cd.DYNTRANS_ARCH.host_load[index] == NULL) {
601     unsigned char *host_page = memory_paddr_to_hostaddr(cpu->mem,
602     physaddr, MEM_READ);
603     if (host_page != NULL) {
604     int q = DYNTRANS_PAGESIZE - 1;
605     host_page += (physaddr &
606     ((1 << BITS_PER_MEMBLOCK) - 1) & ~q);
607     cpu->update_translation_table(cpu, cached_pc & ~q,
608     host_page, TLB_CODE, physaddr & ~q);
609     }
610     }
611     #endif
612    
613     if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE) {
614 dpavlin 20 debug("[ dyntrans: resetting the translation cache ]\n");
615 dpavlin 14 cpu_create_or_reset_tc(cpu);
616 dpavlin 18 }
617 dpavlin 14
618     pagenr = DYNTRANS_ADDR_TO_PAGENR(physaddr);
619     table_index = PAGENR_TO_TABLE_INDEX(pagenr);
620    
621     physpage_entryp = &(((uint32_t *)cpu->translation_cache)[table_index]);
622     physpage_ofs = *physpage_entryp;
623     ppp = NULL;
624    
625     /* Traverse the physical page chain: */
626     while (physpage_ofs != 0) {
627     ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
628     + physpage_ofs);
629     /* If we found the page in the cache, then we're done: */
630     if (ppp->physaddr == physaddr)
631     break;
632     /* Try the next page in the chain: */
633     physpage_ofs = ppp->next_ofs;
634     }
635    
636     /* If the offset is 0 (or ppp is NULL), then we need to create a
637     new "default" empty translation page. */
638    
639     if (ppp == NULL) {
640     /* fatal("CREATING page %lli (physaddr 0x%llx), table index "
641     "%i\n", (long long)pagenr, (long long)physaddr,
642     (int)table_index); */
643     *physpage_entryp = physpage_ofs =
644     cpu->translation_cache_cur_ofs;
645    
646     /* Allocate a default page, with to_be_translated entries: */
647     DYNTRANS_TC_ALLOCATE(cpu, physaddr);
648    
649     ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
650     + physpage_ofs);
651     }
652    
653     #ifdef MODE32
654     if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL)
655     cpu->cd.DYNTRANS_ARCH.phys_page[index] = ppp;
656     #endif
657    
658     #ifdef DYNTRANS_ALPHA
659     if (vph_p->host_load[b] != NULL)
660     vph_p->phys_page[b] = ppp;
661     #endif
662    
663 dpavlin 20 #ifdef MODE32
664     /* Small optimization: only mark the physical page as non-writable
665     if it did not contain translations. (Because if it does contain
666     translations, it is already non-writable.) */
667     if (!cpu->cd.DYNTRANS_ARCH.phystranslation[pagenr >> 5] &
668     (1 << (pagenr & 31)))
669     #endif
670 dpavlin 18 cpu->invalidate_translation_caches(cpu, physaddr,
671     JUST_MARK_AS_NON_WRITABLE | INVALIDATE_PADDR);
672 dpavlin 14
673     cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
674 dpavlin 18
675 dpavlin 14 cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
676     DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
677    
678     /* printf("cached_pc=0x%016llx pagenr=%lli table_index=%lli, "
679     "physpage_ofs=0x%016llx\n", (long long)cached_pc, (long long)pagenr,
680     (long long)table_index, (long long)physpage_ofs); */
681     }
682    
683    
684     /*
685     * XXX_pc_to_pointers():
686     *
687     * This function uses the current program counter (a virtual address) to
688     * find out which physical translation page to use, and then sets the current
689     * translation page pointers to that page.
690     *
691     * If there was no translation page for that physical page, then an empty
692     * one is created.
693     *
694     * NOTE: This is the quick lookup version. See
695     * DYNTRANS_PC_TO_POINTERS_GENERIC above for the generic case.
696     */
697     void DYNTRANS_PC_TO_POINTERS_FUNC(struct cpu *cpu)
698     {
699     #ifdef MODE32
700     uint32_t
701     #else
702     uint64_t
703     #endif
704 dpavlin 22 cached_pc = cpu->pc;
705 dpavlin 14 struct DYNTRANS_TC_PHYSPAGE *ppp;
706    
707     #ifdef MODE32
708     int index;
709 dpavlin 18 index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
710 dpavlin 14 ppp = cpu->cd.DYNTRANS_ARCH.phys_page[index];
711     if (ppp != NULL)
712     goto have_it;
713     #else
714     #ifdef DYNTRANS_ALPHA
715     uint32_t a, b;
716     int kernel = 0;
717     struct alpha_vph_page *vph_p;
718     a = (cached_pc >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
719     b = (cached_pc >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
720     if ((cached_pc >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
721     vph_p = cpu->cd.alpha.vph_table0_kernel[a];
722     kernel = 1;
723     } else
724     vph_p = cpu->cd.alpha.vph_table0[a];
725     if (vph_p != cpu->cd.alpha.vph_default_page) {
726     ppp = vph_p->phys_page[b];
727     if (ppp != NULL)
728     goto have_it;
729     }
730     #else
731 dpavlin 22 fatal("X1: cached_pc=%016llx\n", (long long)cached_pc);
732 dpavlin 20 /* Temporary, to avoid a compiler warning: */
733     ppp = NULL;
734 dpavlin 22 fatal("Neither alpha nor 32-bit? 1\n");
735 dpavlin 14 exit(1);
736     #endif
737     #endif
738    
739     DYNTRANS_PC_TO_POINTERS_GENERIC(cpu);
740     return;
741    
742     /* Quick return path: */
743 dpavlin 20 #if defined(MODE32) || defined(DYNTRANS_ALPHA)
744 dpavlin 14 have_it:
745     cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
746     cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
747     DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
748    
749     /* printf("cached_pc=0x%016llx pagenr=%lli table_index=%lli, "
750     "physpage_ofs=0x%016llx\n", (long long)cached_pc, (long long)pagenr,
751     (long long)table_index, (long long)physpage_ofs); */
752 dpavlin 20 #endif
753 dpavlin 14 }
754     #endif /* DYNTRANS_PC_TO_POINTERS_FUNC */
755    
756    
757    
758     #ifdef DYNTRANS_INVAL_ENTRY
759     /*
760     * XXX_invalidate_tlb_entry():
761     *
762     * Invalidate one translation entry (based on virtual address).
763     *
764     * If the JUST_MARK_AS_NON_WRITABLE flag is set, then the translation entry
765     * is just downgraded to non-writable (ie the host store page is set to
766     * NULL). Otherwise, the entire translation is removed.
767     */
768 dpavlin 18 static void DYNTRANS_INVALIDATE_TLB_ENTRY(struct cpu *cpu,
769 dpavlin 14 #ifdef MODE32
770     uint32_t
771     #else
772     uint64_t
773     #endif
774     vaddr_page, int flags)
775     {
776     #ifdef MODE32
777 dpavlin 18 uint32_t index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
778 dpavlin 14
779 dpavlin 18 #ifdef DYNTRANS_ARM
780 dpavlin 20 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5] &= ~(1 << (index & 31));
781 dpavlin 18 #endif
782    
783 dpavlin 14 if (flags & JUST_MARK_AS_NON_WRITABLE) {
784     /* printf("JUST MARKING NON-W: vaddr 0x%08x\n",
785     (int)vaddr_page); */
786     cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
787     } else {
788     cpu->cd.DYNTRANS_ARCH.host_load[index] = NULL;
789     cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
790     cpu->cd.DYNTRANS_ARCH.phys_addr[index] = 0;
791     cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
792 dpavlin 18 cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = 0;
793 dpavlin 14 }
794     #else
795     /* 2-level: */
796     #ifdef DYNTRANS_ALPHA
797     struct alpha_vph_page *vph_p;
798     uint32_t a, b;
799     int kernel = 0;
800    
801     a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
802     b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
803     if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
804     vph_p = cpu->cd.alpha.vph_table0_kernel[a];
805     kernel = 1;
806     } else
807     vph_p = cpu->cd.alpha.vph_table0[a];
808    
809     if (vph_p == cpu->cd.alpha.vph_default_page) {
810     fatal("alpha_invalidate_tlb_entry(): huh? Problem 1.\n");
811     exit(1);
812     }
813    
814     if (flags & JUST_MARK_AS_NON_WRITABLE) {
815     vph_p->host_store[b] = NULL;
816     return;
817     }
818     vph_p->host_load[b] = NULL;
819     vph_p->host_store[b] = NULL;
820     vph_p->phys_addr[b] = 0;
821     vph_p->phys_page[b] = NULL;
822     vph_p->refcount --;
823     if (vph_p->refcount < 0) {
824     fatal("alpha_invalidate_tlb_entry(): huh? Problem 2.\n");
825     exit(1);
826     }
827     if (vph_p->refcount == 0) {
828     vph_p->next = cpu->cd.alpha.vph_next_free_page;
829     cpu->cd.alpha.vph_next_free_page = vph_p;
830     if (kernel)
831     cpu->cd.alpha.vph_table0_kernel[a] =
832     cpu->cd.alpha.vph_default_page;
833     else
834     cpu->cd.alpha.vph_table0[a] =
835     cpu->cd.alpha.vph_default_page;
836     }
837     #else /* !DYNTRANS_ALPHA */
838 dpavlin 22 fatal("Not yet for non-1-level, non-Alpha\n");
839 dpavlin 14 #endif /* !DYNTRANS_ALPHA */
840     #endif
841     }
842     #endif
843    
844    
845 dpavlin 18 #ifdef DYNTRANS_INVALIDATE_TC
846 dpavlin 14 /*
847 dpavlin 18 * XXX_invalidate_translation_caches():
848 dpavlin 14 *
849     * Invalidate all entries matching a specific physical address, a specific
850     * virtual address, or ALL entries.
851     *
852     * flags should be one of
853     * INVALIDATE_PADDR INVALIDATE_VADDR or INVALIDATE_ALL
854     *
855 dpavlin 22 * In addition, for INVALIDATE_ALL, INVALIDATE_VADDR_UPPER4 may be set and
856     * bit 31..28 of addr are used to select the virtual addresses to invalidate.
857     * (This is useful for PowerPC emulation, when segment registers are updated.)
858     *
859 dpavlin 14 * In the case when all translations are invalidated, paddr doesn't need
860     * to be supplied.
861     *
862 dpavlin 18 * NOTE/TODO: When invalidating a virtual address, it is only cleared from
863     * the quick translation array, not from the linear
864     * vph_tlb_entry[] array. Hopefully this is enough anyway.
865 dpavlin 14 */
866 dpavlin 22 void DYNTRANS_INVALIDATE_TC(struct cpu *cpu, uint64_t addr, int flags)
867 dpavlin 14 {
868     int r;
869     #ifdef MODE32
870     uint32_t
871     #else
872     uint64_t
873     #endif
874 dpavlin 22 addr_page = addr & ~(DYNTRANS_PAGESIZE - 1);
875 dpavlin 14
876 dpavlin 20 /* fatal("invalidate(): "); */
877    
878 dpavlin 22 /* Quick case for _one_ virtual addresses: see note above. */
879 dpavlin 18 if (flags & INVALIDATE_VADDR) {
880 dpavlin 20 /* fatal("vaddr 0x%08x\n", (int)addr_page); */
881 dpavlin 18 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, addr_page, flags);
882     return;
883     }
884    
885 dpavlin 22 /* Invalidate everything: */
886     #ifdef DYNTRANS_PPC
887     if (flags & INVALIDATE_ALL && flags & INVALIDATE_VADDR_UPPER4) {
888     /* fatal("all, upper4 (PowerPC segment)\n"); */
889     for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
890     if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid &&
891     (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page
892     & 0xf0000000) == addr_page) {
893     DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, cpu->cd.
894     DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
895     0);
896     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid=0;
897     }
898     }
899     return;
900     }
901     #endif
902 dpavlin 20 if (flags & INVALIDATE_ALL) {
903     /* fatal("all\n"); */
904     for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
905     if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
906     DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, cpu->cd.
907     DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
908     0);
909     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid=0;
910     }
911     }
912     return;
913     }
914    
915 dpavlin 22 /* Invalidate a physical page: */
916 dpavlin 20
917 dpavlin 22 if (!(flags & INVALIDATE_PADDR))
918     fatal("HUH? Invalidate: Not vaddr, all, or paddr?\n");
919    
920     /* fatal("addr 0x%08x\n", (int)addr_page); */
921    
922 dpavlin 14 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
923 dpavlin 22 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && addr_page
924     == cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page) {
925 dpavlin 14 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
926     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
927     flags);
928     if (flags & JUST_MARK_AS_NON_WRITABLE)
929     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
930     .writeflag = 0;
931     else
932     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
933     .valid = 0;
934     }
935     }
936     }
937 dpavlin 18 #endif /* DYNTRANS_INVALIDATE_TC */
938 dpavlin 14
939    
940    
941     #ifdef DYNTRANS_INVALIDATE_TC_CODE
942     /*
943     * XXX_invalidate_code_translation():
944     *
945     * Invalidate code translations for a specific physical address, a specific
946     * virtual address, or for all entries in the cache.
947     */
948     void DYNTRANS_INVALIDATE_TC_CODE(struct cpu *cpu, uint64_t addr, int flags)
949     {
950     int r;
951 dpavlin 18 #ifdef MODE32
952 dpavlin 14 uint32_t
953     #else
954     uint64_t
955     #endif
956     vaddr_page, paddr_page;
957    
958     addr &= ~(DYNTRANS_PAGESIZE-1);
959    
960     /* printf("DYNTRANS_INVALIDATE_TC_CODE addr=0x%08x flags=%i\n",
961     (int)addr, flags); */
962    
963     if (flags & INVALIDATE_PADDR) {
964     int pagenr, table_index;
965     uint32_t physpage_ofs, *physpage_entryp;
966 dpavlin 18 struct DYNTRANS_TC_PHYSPAGE *ppp, *prev_ppp;
967 dpavlin 14
968     pagenr = DYNTRANS_ADDR_TO_PAGENR(addr);
969 dpavlin 18
970     #ifdef MODE32
971     /* If this page isn't marked as having any translations,
972     then return immediately. */
973     if (!(cpu->cd.DYNTRANS_ARCH.phystranslation[pagenr >> 5]
974     & 1 << (pagenr & 31)))
975     return;
976     /* Remove the mark: */
977     cpu->cd.DYNTRANS_ARCH.phystranslation[pagenr >> 5] &=
978     ~ (1 << (pagenr & 31));
979     #endif
980    
981 dpavlin 14 table_index = PAGENR_TO_TABLE_INDEX(pagenr);
982    
983     physpage_entryp = &(((uint32_t *)cpu->
984     translation_cache)[table_index]);
985     physpage_ofs = *physpage_entryp;
986 dpavlin 18 prev_ppp = ppp = NULL;
987 dpavlin 14
988     /* Traverse the physical page chain: */
989     while (physpage_ofs != 0) {
990 dpavlin 18 prev_ppp = ppp;
991 dpavlin 14 ppp = (struct DYNTRANS_TC_PHYSPAGE *)
992     (cpu->translation_cache + physpage_ofs);
993     /* If we found the page in the cache,
994     then we're done: */
995     if (ppp->physaddr == addr)
996     break;
997     /* Try the next page in the chain: */
998     physpage_ofs = ppp->next_ofs;
999     }
1000    
1001 dpavlin 18 if (physpage_ofs == 0)
1002     ppp = NULL;
1003    
1004     #if 1
1005     /*
1006     * "Bypass" the page, removing it from the code cache.
1007     *
1008     * NOTE/TODO: This gives _TERRIBLE_ performance with self-
1009     * modifying code, or when a single page is used for both
1010     * code and (writable) data.
1011     */
1012 dpavlin 14 if (ppp != NULL) {
1013 dpavlin 18 if (prev_ppp != NULL)
1014     prev_ppp->next_ofs = ppp->next_ofs;
1015     else
1016     *physpage_entryp = ppp->next_ofs;
1017     }
1018     #else
1019     /*
1020     * Instead of removing the page from the code cache, each
1021     * entry can be set to "to_be_translated". This is slow in
1022     * the general case, but in the case of self-modifying code,
1023     * it might be faster since we don't risk wasting cache
1024     * memory as quickly (which would force unnecessary Restarts).
1025     */
1026     if (ppp != NULL) {
1027 dpavlin 14 /* TODO: Is this faster than copying an entire
1028     template page? */
1029     int i;
1030     for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
1031     ppp->ics[i].f =
1032     #ifdef DYNTRANS_DUALMODE_32
1033     cpu->is_32bit? instr32(to_be_translated) :
1034     #endif
1035     instr(to_be_translated);
1036     }
1037 dpavlin 18 #endif
1038 dpavlin 14 }
1039    
1040 dpavlin 18 /* Invalidate entries (NOTE: only code entries) in the VPH table: */
1041     for (r = DYNTRANS_MAX_VPH_TLB_ENTRIES/2;
1042     r < DYNTRANS_MAX_VPH_TLB_ENTRIES; r ++) {
1043 dpavlin 14 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
1044     vaddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
1045     .vaddr_page & ~(DYNTRANS_PAGESIZE-1);
1046     paddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
1047     .paddr_page & ~(DYNTRANS_PAGESIZE-1);
1048    
1049     if (flags & INVALIDATE_ALL ||
1050     (flags & INVALIDATE_PADDR && paddr_page == addr) ||
1051     (flags & INVALIDATE_VADDR && vaddr_page == addr)) {
1052     #ifdef MODE32
1053 dpavlin 18 uint32_t index =
1054     DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1055 dpavlin 14 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1056 dpavlin 18 /* Remove the mark: */
1057     index = DYNTRANS_ADDR_TO_PAGENR(paddr_page);
1058     cpu->cd.DYNTRANS_ARCH.phystranslation[
1059     index >> 5] &= ~ (1 << (index & 31));
1060 dpavlin 14 #else
1061     /* 2-level: */
1062     #ifdef DYNTRANS_ALPHA
1063     struct alpha_vph_page *vph_p;
1064     uint32_t a, b;
1065     int kernel = 0;
1066    
1067     a = (vaddr_page >> ALPHA_LEVEL0_SHIFT)
1068     & (ALPHA_LEVEL0 - 1);
1069     b = (vaddr_page >> ALPHA_LEVEL1_SHIFT)
1070     & (ALPHA_LEVEL1 - 1);
1071     if ((vaddr_page >> ALPHA_TOPSHIFT) ==
1072     ALPHA_TOP_KERNEL) {
1073     vph_p = cpu->cd.alpha.
1074     vph_table0_kernel[a];
1075     kernel = 1;
1076     } else
1077     vph_p = cpu->cd.alpha.vph_table0[a];
1078     vph_p->phys_page[b] = NULL;
1079     #else /* !DYNTRANS_ALPHA */
1080 dpavlin 22 fatal("Not yet for non-1-level, non-Alpha\n");
1081 dpavlin 14 #endif /* !DYNTRANS_ALPHA */
1082     #endif
1083     }
1084     }
1085     }
1086     }
1087     #endif /* DYNTRANS_INVALIDATE_TC_CODE */
1088    
1089    
1090    
1091     #ifdef DYNTRANS_UPDATE_TRANSLATION_TABLE
1092     /*
1093     * XXX_update_translation_table():
1094     *
1095     * Update the virtual memory translation tables.
1096     */
1097     void DYNTRANS_UPDATE_TRANSLATION_TABLE(struct cpu *cpu, uint64_t vaddr_page,
1098     unsigned char *host_page, int writeflag, uint64_t paddr_page)
1099     {
1100 dpavlin 20 #ifndef MODE32
1101 dpavlin 14 int64_t lowest, highest = -1;
1102 dpavlin 20 #endif
1103 dpavlin 18 int found, r, lowest_index, start, end, useraccess = 0;
1104 dpavlin 14
1105     #ifdef DYNTRANS_ALPHA
1106     uint32_t a, b;
1107     struct alpha_vph_page *vph_p;
1108     int kernel = 0;
1109     /* fatal("update_translation_table(): v=0x%llx, h=%p w=%i"
1110     " p=0x%llx\n", (long long)vaddr_page, host_page, writeflag,
1111     (long long)paddr_page); */
1112     #else
1113     #ifdef MODE32
1114     uint32_t index;
1115     vaddr_page &= 0xffffffffULL;
1116     paddr_page &= 0xffffffffULL;
1117     /* fatal("update_translation_table(): v=0x%x, h=%p w=%i"
1118     " p=0x%x\n", (int)vaddr_page, host_page, writeflag,
1119     (int)paddr_page); */
1120     #else /* !MODE32 */
1121 dpavlin 22 fatal("Neither 32-bit nor Alpha? 2\n");
1122 dpavlin 14 exit(1);
1123     #endif
1124     #endif
1125    
1126 dpavlin 18 if (writeflag & MEMORY_USER_ACCESS) {
1127     writeflag &= ~MEMORY_USER_ACCESS;
1128     useraccess = 1;
1129     }
1130    
1131     start = 0; end = DYNTRANS_MAX_VPH_TLB_ENTRIES / 2;
1132     #if 1
1133     /* Half of the TLB used for data, half for code: */
1134     if (writeflag & TLB_CODE) {
1135     writeflag &= ~TLB_CODE;
1136     start = end; end = DYNTRANS_MAX_VPH_TLB_ENTRIES;
1137     }
1138     #else
1139     /* Data and code entries are mixed. */
1140     end = DYNTRANS_MAX_VPH_TLB_ENTRIES;
1141     #endif
1142    
1143 dpavlin 14 /* Scan the current TLB entries: */
1144 dpavlin 20 lowest_index = start;
1145 dpavlin 18
1146     #ifdef MODE32
1147 dpavlin 20 /*
1148     * NOTE 1: vaddr_to_tlbindex is one more than the index, so that
1149     * 0 becomes -1, which means a miss.
1150     *
1151     * NOTE 2: When a miss occurs, instead of scanning the entire tlb
1152     * for the entry with the lowest time stamp, just choosing
1153     * one at random will work as well.
1154     */
1155     found = (int)cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[
1156 dpavlin 18 DYNTRANS_ADDR_TO_PAGENR(vaddr_page)] - 1;
1157 dpavlin 20 if (found < 0) {
1158     static unsigned int x = 0;
1159     lowest_index = (x % (end-start)) + start;
1160     x ++;
1161     }
1162     #else
1163     lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp;
1164     found = -1;
1165 dpavlin 18 for (r=start; r<end; r++) {
1166 dpavlin 14 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp < lowest) {
1167     lowest = cpu->cd.DYNTRANS_ARCH.
1168     vph_tlb_entry[r].timestamp;
1169     lowest_index = r;
1170     }
1171     if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp > highest)
1172     highest = cpu->cd.DYNTRANS_ARCH.
1173     vph_tlb_entry[r].timestamp;
1174     if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid &&
1175     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page ==
1176     vaddr_page) {
1177     found = r;
1178     break;
1179     }
1180     }
1181 dpavlin 20 #endif
1182 dpavlin 14
1183     if (found < 0) {
1184     /* Create the new TLB entry, overwriting the oldest one: */
1185     r = lowest_index;
1186     if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
1187     /* This one has to be invalidated first: */
1188     DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
1189     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
1190     0);
1191     }
1192    
1193     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid = 1;
1194     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].host_page = host_page;
1195     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page = paddr_page;
1196     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page = vaddr_page;
1197 dpavlin 20 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag =
1198     writeflag & MEM_WRITE;
1199     #ifndef MODE32
1200 dpavlin 14 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1;
1201 dpavlin 20 #endif
1202 dpavlin 14
1203     /* Add the new translation to the table: */
1204     #ifdef DYNTRANS_ALPHA
1205     a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
1206     b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
1207     if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
1208     vph_p = cpu->cd.alpha.vph_table0_kernel[a];
1209     kernel = 1;
1210     } else
1211     vph_p = cpu->cd.alpha.vph_table0[a];
1212     if (vph_p == cpu->cd.alpha.vph_default_page) {
1213     if (cpu->cd.alpha.vph_next_free_page != NULL) {
1214     if (kernel)
1215     vph_p = cpu->cd.alpha.vph_table0_kernel
1216     [a] = cpu->cd.alpha.
1217     vph_next_free_page;
1218     else
1219     vph_p = cpu->cd.alpha.vph_table0[a] =
1220     cpu->cd.alpha.vph_next_free_page;
1221     cpu->cd.alpha.vph_next_free_page = vph_p->next;
1222     } else {
1223     if (kernel)
1224     vph_p = cpu->cd.alpha.vph_table0_kernel
1225     [a] = malloc(sizeof(struct
1226     alpha_vph_page));
1227     else
1228     vph_p = cpu->cd.alpha.vph_table0[a] =
1229     malloc(sizeof(struct
1230     alpha_vph_page));
1231     memset(vph_p, 0, sizeof(struct alpha_vph_page));
1232     }
1233     }
1234     vph_p->refcount ++;
1235     vph_p->host_load[b] = host_page;
1236     vph_p->host_store[b] = writeflag? host_page : NULL;
1237     vph_p->phys_addr[b] = paddr_page;
1238     vph_p->phys_page[b] = NULL;
1239     #else
1240     #ifdef MODE32
1241 dpavlin 18 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1242 dpavlin 14 cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
1243     cpu->cd.DYNTRANS_ARCH.host_store[index] =
1244     writeflag? host_page : NULL;
1245     cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
1246     cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1247 dpavlin 18 cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = r + 1;
1248     #ifdef DYNTRANS_ARM
1249     if (useraccess)
1250 dpavlin 20 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5]
1251     |= 1 << (index & 31);
1252 dpavlin 18 #endif
1253 dpavlin 14 #endif /* 32 */
1254     #endif /* !ALPHA */
1255     } else {
1256     /*
1257     * The translation was already in the TLB.
1258     * Writeflag = 0: Do nothing.
1259     * Writeflag = 1: Make sure the page is writable.
1260 dpavlin 20 * Writeflag = MEM_DOWNGRADE: Downgrade to readonly.
1261 dpavlin 14 */
1262 dpavlin 18 r = found;
1263 dpavlin 20 #ifndef MODE32
1264 dpavlin 18 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1;
1265 dpavlin 20 #endif
1266     if (writeflag & MEM_WRITE)
1267 dpavlin 14 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1;
1268 dpavlin 20 if (writeflag & MEM_DOWNGRADE)
1269 dpavlin 14 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 0;
1270     #ifdef DYNTRANS_ALPHA
1271     a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
1272     b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
1273     if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
1274     vph_p = cpu->cd.alpha.vph_table0_kernel[a];
1275     kernel = 1;
1276     } else
1277     vph_p = cpu->cd.alpha.vph_table0[a];
1278     vph_p->phys_page[b] = NULL;
1279     if (vph_p->phys_addr[b] == paddr_page) {
1280 dpavlin 20 if (writeflag & MEM_WRITE)
1281 dpavlin 14 vph_p->host_store[b] = host_page;
1282 dpavlin 20 if (writeflag & MEM_DOWNGRADE)
1283 dpavlin 14 vph_p->host_store[b] = NULL;
1284     } else {
1285     /* Change the entire physical/host mapping: */
1286     vph_p->host_load[b] = host_page;
1287     vph_p->host_store[b] = writeflag? host_page : NULL;
1288     vph_p->phys_addr[b] = paddr_page;
1289     }
1290     #else
1291     #ifdef MODE32
1292 dpavlin 18 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1293 dpavlin 14 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1294 dpavlin 18 #ifdef DYNTRANS_ARM
1295 dpavlin 20 cpu->cd.DYNTRANS_ARCH.is_userpage[index>>5] &= ~(1<<(index&31));
1296 dpavlin 18 if (useraccess)
1297 dpavlin 20 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5]
1298     |= 1 << (index & 31);
1299 dpavlin 18 #endif
1300 dpavlin 14 if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) {
1301 dpavlin 20 if (writeflag & MEM_WRITE)
1302 dpavlin 14 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1303     host_page;
1304 dpavlin 20 if (writeflag & MEM_DOWNGRADE)
1305 dpavlin 14 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
1306     } else {
1307     /* Change the entire physical/host mapping: */
1308     cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
1309     cpu->cd.DYNTRANS_ARCH.host_store[index] =
1310     writeflag? host_page : NULL;
1311     cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
1312     }
1313     #endif /* 32 */
1314     #endif /* !ALPHA */
1315     }
1316     }
1317     #endif /* DYNTRANS_UPDATE_TRANSLATION_TABLE */
1318    
1319    
1320     /*****************************************************************************/
1321    
1322    
1323     #ifdef DYNTRANS_TO_BE_TRANSLATED_HEAD
1324     /*
1325     * Check for breakpoints.
1326     */
1327     if (!single_step_breakpoint) {
1328     #ifdef MODE32
1329     uint32_t curpc = cpu->pc;
1330     #else
1331     uint64_t curpc = cpu->pc;
1332     #endif
1333     int i;
1334     for (i=0; i<cpu->machine->n_breakpoints; i++)
1335     if (curpc ==
1336     #ifdef MODE32
1337     (uint32_t)
1338     #endif
1339     cpu->machine->breakpoint_addr[i]) {
1340     if (!cpu->machine->instruction_trace) {
1341     int old_quiet_mode = quiet_mode;
1342     quiet_mode = 0;
1343     DISASSEMBLE(cpu, ib, 1, 0, 0);
1344     quiet_mode = old_quiet_mode;
1345     }
1346     fatal("BREAKPOINT: pc = 0x%llx\n(The "
1347     "instruction has not yet executed.)\n",
1348     (long long)cpu->pc);
1349 dpavlin 22 #ifdef DYNTRANS_DELAYSLOT
1350     if (cpu->cd.DYNTRANS_ARCH.delay_slot !=
1351     NOT_DELAYED)
1352     fatal("ERROR! Breakpoint in a delay"
1353     " slot! Not yet supported.\n");
1354     #endif
1355 dpavlin 14 single_step_breakpoint = 1;
1356     single_step = 1;
1357     goto stop_running_translated;
1358     }
1359     }
1360     #endif /* DYNTRANS_TO_BE_TRANSLATED_HEAD */
1361    
1362    
1363     /*****************************************************************************/
1364    
1365    
1366     #ifdef DYNTRANS_TO_BE_TRANSLATED_TAIL
1367     /*
1368     * If we end up here, then an instruction was translated.
1369 dpavlin 18 * Mark the page as containing a translation.
1370     *
1371     * (Special case for 32-bit mode: set the corresponding bit in the
1372     * phystranslation[] array.)
1373 dpavlin 14 */
1374 dpavlin 18 #ifdef MODE32
1375     if (!(cpu->cd.DYNTRANS_ARCH.cur_physpage->flags & TRANSLATIONS)) {
1376 dpavlin 22 uint32_t index = DYNTRANS_ADDR_TO_PAGENR((uint32_t)addr);
1377 dpavlin 18 cpu->cd.DYNTRANS_ARCH.phystranslation[index >> 5] |=
1378     (1 << (index & 31));
1379     }
1380     #endif
1381     cpu->cd.DYNTRANS_ARCH.cur_physpage->flags |= TRANSLATIONS;
1382 dpavlin 14
1383 dpavlin 18
1384 dpavlin 22 #ifdef DYNTRANS_BACKEND
1385 dpavlin 14 /*
1386 dpavlin 22 * "Empty"/simple native dyntrans backend stuff:
1387     *
1388     * 1) If no translation is currently being done, but the translated
1389     * instruction was simple enough, then let's start making a new
1390     * native translation block.
1391     *
1392     * 2) If a native translation block is currently being constructed,
1393     * but this instruction wasn't simple enough, then end the block
1394     * (without including this instruction).
1395     *
1396     * 3) If a native translation block is currently being constructed,
1397     * and this is a simple instruction, then add it.
1398     */
1399     if (simple && cpu->translation_context.p == NULL &&
1400     dyntrans_backend_enable) {
1401     size_t s = 0;
1402    
1403     if (cpu->translation_context.translation_buffer == NULL) {
1404     cpu->translation_context.translation_buffer =
1405     zeroed_alloc(DTB_TRANSLATION_SIZE_MAX +
1406     DTB_TRANSLATION_SIZE_MARGIN);
1407     }
1408    
1409     cpu->translation_context.p =
1410     cpu->translation_context.translation_buffer;
1411    
1412     cpu->translation_context.ic_page =
1413     cpu->cd.DYNTRANS_ARCH.cur_ic_page;
1414     cpu->translation_context.start_instr_call_index =
1415     ((size_t)ic - (size_t)cpu->cd.DYNTRANS_ARCH.cur_ic_page)
1416     / (sizeof(*ic));
1417    
1418     dtb_function_prologue(&cpu->translation_context, &s);
1419     cpu->translation_context.p += s;
1420     cpu->translation_context.n_simple = 0;
1421     }
1422    
1423     /* If this is not a continuation of a simple translation, then
1424     stop now! */
1425     if (cpu->translation_context.ic_page != cpu->cd.DYNTRANS_ARCH.
1426     cur_ic_page || ic != &cpu->cd.DYNTRANS_ARCH.cur_ic_page[
1427     cpu->translation_context.start_instr_call_index +
1428     cpu->translation_context.n_simple])
1429     simple = 0;
1430    
1431     if (cpu->translation_context.p != NULL && !simple) {
1432     size_t s = 0, total;
1433    
1434     if (cpu->translation_context.n_simple > 1) {
1435     dtb_generate_ptr_inc(cpu, &cpu->translation_context,
1436     &s, &cpu->cd.DYNTRANS_ARCH.next_ic,
1437     (cpu->translation_context.n_simple - 1) *
1438     sizeof(*(cpu->cd.DYNTRANS_ARCH.next_ic)));
1439     cpu->translation_context.p += s;
1440     }
1441    
1442     dtb_function_epilogue(&cpu->translation_context, &s);
1443     cpu->translation_context.p += s;
1444    
1445     cpu_dtb_do_fixups(cpu);
1446     #if 0
1447     {
1448     int i;
1449     unsigned char *addr = cpu->translation_context.translation_buffer;
1450     printf("index = %i\n", cpu->translation_context.start_instr_call_index);
1451     quiet_mode = 0;
1452     for (i=0; i<4*32; i+=4)
1453     alpha_cpu_disassemble_instr(cpu, (unsigned char *)addr + i,
1454     0, i, 0);
1455     }
1456     #endif
1457     total = (size_t)cpu->translation_context.p -
1458     (size_t)cpu->translation_context.translation_buffer;
1459    
1460     /* Copy the translated block to the translation cache: */
1461     /* Align first: */
1462     cpu->translation_cache_cur_ofs --;
1463     cpu->translation_cache_cur_ofs |= 31;
1464     cpu->translation_cache_cur_ofs ++;
1465    
1466     memcpy(cpu->translation_cache + cpu->translation_cache_cur_ofs,
1467     cpu->translation_context.translation_buffer, total);
1468    
1469     /* Set the ic pointer: */
1470     ((struct DYNTRANS_IC *)cpu->translation_context.ic_page)
1471     [cpu->translation_context.start_instr_call_index].f =
1472     (void *)
1473     (cpu->translation_cache + cpu->translation_cache_cur_ofs);
1474    
1475     /* Align cur_ofs afterwards as well, just to be safe. */
1476     cpu->translation_cache_cur_ofs += total;
1477     cpu->translation_cache_cur_ofs --;
1478     cpu->translation_cache_cur_ofs |= 31;
1479     cpu->translation_cache_cur_ofs ++;
1480    
1481     /* Set the "combined instruction" flag for this page: */
1482     cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
1483     cpu->cd.DYNTRANS_ARCH.cur_ic_page;
1484     cpu->cd.DYNTRANS_ARCH.cur_physpage->flags |= COMBINATIONS;
1485    
1486     dtb_host_cacheinvalidate(0,0); /* p , size ... ); */
1487    
1488     cpu->translation_context.p = NULL;
1489     }
1490     if (cpu->translation_context.p != NULL) {
1491     size_t s = 0;
1492     dtb_generate_fcall(cpu, &cpu->translation_context,
1493     &s, (size_t)ic->f, (size_t)ic);
1494     cpu->translation_context.p += s;
1495     cpu->translation_context.n_simple ++;
1496     }
1497     #endif /* DYNTRANS_BACKEND */
1498    
1499    
1500     /*
1501 dpavlin 14 * Now it is time to check for combinations of instructions that can
1502     * be converted into a single function call.
1503     *
1504     * Note: Single-stepping or instruction tracing doesn't work with
1505     * instruction combination.
1506     */
1507 dpavlin 18 if (!single_step && !cpu->machine->instruction_trace) {
1508 dpavlin 20 if (cpu->cd.DYNTRANS_ARCH.combination_check != NULL &&
1509 dpavlin 18 cpu->machine->speed_tricks)
1510 dpavlin 20 cpu->cd.DYNTRANS_ARCH.combination_check(cpu, ic,
1511 dpavlin 18 addr & (DYNTRANS_PAGESIZE - 1));
1512 dpavlin 20 cpu->cd.DYNTRANS_ARCH.combination_check = NULL;
1513 dpavlin 18 }
1514 dpavlin 14
1515     /* ... and finally execute the translated instruction: */
1516     if (single_step_breakpoint) {
1517     /*
1518     * Special case when single-stepping: Execute the translated
1519     * instruction, but then replace it with a "to be translated"
1520     * directly afterwards.
1521     */
1522     single_step_breakpoint = 0;
1523     ic->f(cpu, ic);
1524     ic->f =
1525     #ifdef DYNTRANS_DUALMODE_32
1526     cpu->is_32bit? instr32(to_be_translated) :
1527     #endif
1528     instr(to_be_translated);
1529     } else
1530     ic->f(cpu, ic);
1531    
1532     return;
1533    
1534    
1535     bad: /*
1536     * Nothing was translated. (Unimplemented or illegal instruction.)
1537     */
1538    
1539     quiet_mode = 0;
1540     fatal("to_be_translated(): TODO: unimplemented instruction");
1541    
1542     if (cpu->machine->instruction_trace)
1543     #ifdef MODE32
1544     fatal(" at 0x%x\n", (int)cpu->pc);
1545     #else
1546     fatal(" at 0x%llx\n", (long long)cpu->pc);
1547     #endif
1548     else {
1549     fatal(":\n");
1550     DISASSEMBLE(cpu, ib, 1, 0, 0);
1551     }
1552    
1553     cpu->running = 0;
1554     cpu->dead = 1;
1555     stop_running_translated:
1556     debugger_n_steps_left_before_interaction = 0;
1557     cpu->running_translated = 0;
1558     ic = cpu->cd.DYNTRANS_ARCH.next_ic = &nothing_call;
1559     cpu->cd.DYNTRANS_ARCH.next_ic ++;
1560    
1561     /* Execute the "nothing" instruction: */
1562     ic->f(cpu, ic);
1563     #endif /* DYNTRANS_TO_BE_TRANSLATED_TAIL */
1564    

  ViewVC Help
Powered by ViewVC 1.1.26