/[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

Contents of /trunk/src/cpus/cpu_dyntrans.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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


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

  ViewVC Help
Powered by ViewVC 1.1.26