/[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 42 - (hide annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 53401 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26