/[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 18 - (hide annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 37289 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26