/[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 30 - (hide annotations)
Mon Oct 8 16:20:40 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 49688 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1325 2006/08/15 15:38:37 debug Exp $
20060723	More Transputer instructions (pfix, nfix, opr, mint, ldl, ldlp,
		eqc, rev, ajw, stl, stlf, sthf, sub, ldnl, ldnlp, ldpi, move,
		wcnt, add, bcnt).
		Adding more SPARC instructions (andcc, addcc, bl, rdpr).
		Progress on the igsfb framebuffer used by NetBSD/netwinder.
		Enabling 8-bit fills in dev_fb.
		NetBSD/netwinder 3.0.1 can now run from a disk image :-)
20060724	Cleanup/performance fix for 64-bit virtual translation table
		updates (by removing the "timestamp" stuff). A full NetBSD/pmax
		3.0.1 install for R4400 has dropped from 667 seconds to 584 :)
		Fixing the igsfb "almost vga" color (it is 24-bit, not 18-bit).
		Adding some MIPS instruction combinations (3*lw, and 3*addu).
		The 8048 keyboard now turns off interrupt enable between the
		KBR_ACK and the KBR_RSTDONE, to work better with Linux 2.6.
		Not causing PPC DEC interrupts if PPC_NO_DEC is set for a
		specific CPU; NetBSD/bebox gets slightly further than before.
		Adding some more SPARC instructions: branches, udiv.
20060725	Refreshing dev_pckbc.c a little.
		Cleanups for the SH emulation mode, and adding the first
		"compact" (16-bit) instructions: various simple movs, nop,
		shll, stc, or, ldc.
20060726	Adding dummy "pcn" (AMD PCnet NIC) PCI glue.
20060727	Various cleanups; removing stuff from cpu.h, such as
		running_translated (not really meaningful anymore), and
		page flags (breaking into the debugger clears all translations
		anyway).
		Minor MIPS instruction combination updates.
20060807	Expanding the 3*sw and 3*lw MIPS instruction combinations to
		work with 2* and 4* too, resulting in a minor performance gain.
		Implementing a usleep hack for the RM52xx/MIPS32/MIPS64 "wait"
		instruction (when emulating 1 cpu).
20060808	Experimenting with some more MIPS instruction combinations.
		Implementing support for showing a (hardcoded 12x22) text
		cursor in igsfb.
20060809	Simplifying the NetBSD/evbmips (Malta) install instructions
		somewhat (by using a NetBSD/pmax ramdisk install kernel).
20060812	Experimenting more with the MIPS 'wait' instruction.
		PCI configuration register writes can now be handled, which
		allow PCI IDE controllers to work with NetBSD/Malta 3.0.1 and
		NetBSD/cobalt 3.0.1. (Previously only NetBSD 2.1 worked.)
20060813	Updating dev_gt.c based on numbers from Alec Voropay, to enable
		Linux 2.6 to use PCI on Malta.
		Continuing on Algor interrupt stuff.
20060814	Adding support for routing ISA interrupts to two different
		interrupts, making it possible to run NetBSD/algor :-)
20060814-15	Testing for the release.

==============  RELEASE 0.4.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26