/[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 26 - (hide annotations)
Mon Oct 8 16:20:10 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 48545 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1264 2006/06/25 11:08:04 debug Exp $
20060624	Replacing the error-prone machine type initialization stuff
		with something more reasonable.
		Finally removing the old "cpu_run" kludge; moving around stuff
		in machine.c and emul.c to better suit the dyntrans system.
		Various minor dyntrans cleanups (renaming translate_address to
		translate_v2p, and experimenting with template physpages).
20060625	Removing the speed hack which separated the vph entries into
		two halves (code vs data); things seem a lot more stable now.
		Minor performance hack: R2000/R3000 cache isolation now only
		clears address translations when going into isolation, not
		when going out of it.
		Fixing the MIPS interrupt problems by letting mtc0 immediately
		cause interrupts.

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

  ViewVC Help
Powered by ViewVC 1.1.26