/[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 44 - (hide annotations)
Mon Oct 8 16:22:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 52126 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1632 2007/09/11 21:46:35 debug Exp $
20070616	Implementing the MIPS32/64 revision 2 "ror" instruction.
20070617	Adding a struct for each physpage which keeps track of which
		ranges within that page (base offset, length) that are
		continuously translatable. When running with native code
		generation enabled (-b), a range is added after each read-
		ahead loop.
		Experimenting with using the physical program counter sample
		data (implemented 20070608) together with the "translatable
		range" information, to figure out which physical address ranges
		would be worth translating to native code (if the number of
		samples falling within a range is above a certain threshold).
20070618	Adding automagic building of .index comment files for
		src/file/, src/promemul/, src src/useremul/ as well.
		Adding a "has been translated" bit to the ranges, so that only
		not-yet-translated ranges will be sampled.
20070619	Moving src/cpu.c and src/memory_rw.c into src/cpus/,
		src/device.c into src/devices/, and src/machine.c into
		src/machines/.
		Creating a skeleton cc/ld native backend module; beginning on
		the function which will detect cc command line, etc.
20070620	Continuing on the native code generation infrastructure.
20070621	Moving src/x11.c and src/console.c into a new src/console/
		subdir (for everything that is console or framebuffer related).
		Moving src/symbol*.c into a new src/symbol/, which should
		contain anything that is symbol handling related.
20070624	Making the program counter sampling threshold a "settings
		variable" (sampling_threshold), i.e. it can now be changed
		during runtime.
		Switching the RELEASE notes format from plain text to HTML.
		If the TMPDIR environment variable is set, it is used instead
		of "/tmp" for temporary files.
		Continuing on the cc/ld backend: simple .c code is generated,
		the compiler and linker are called, etc.
		Adding detection of host architecture to the configure script
		(again), and adding icache invalidation support (only
		implemented for Alpha hosts so far).
20070625	Simplifying the program counter sampling mechanism.
20070626	Removing the cc/ld native code generation stuff, program
		counter sampling, etc; it would not have worked well in the
		general case.
20070627	Removing everything related to native code generation.
20070629	Removing the (practically unusable) support for multiple
		emulations. (The single emulation allowed now still supports
		multiple simultaneous machines, as before.)
		Beginning on PCCTWO and M88K interrupts.
20070723	Adding a dummy skeleton for emulation of M32R processors.
20070901	Fixing a warning found by "gcc version 4.3.0 20070817
		(experimental)" on amd64.
20070905	Removing some more traces of the old "multiple emulations"
		code.
		Also looking in /usr/local/include and /usr/local/lib for
		X11 libs, when running configure.
20070909	Minor updates to the guest OS install instructions, in
		preparation for the NetBSD 4.0 release.
20070918	More testing of NetBSD 4.0 RC1.

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

  ViewVC Help
Powered by ViewVC 1.1.26