/[gxemul]/trunk/src/cpus/cpu_dyntrans.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 34 - (show annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 50660 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1480 2007/02/19 01:34:42 debug Exp $
20061029	Changing usleep(1) calls in the debugger to usleep(10000)
20061107	Adding a new disk image option (-d o...) which sets the ISO9660
		filesystem base offset; also making some other hacks to allow
		NetBSD/dreamcast and homebrew demos/games to boot directly
		from a filesystem image.
		Moving Dreamcast-specific stuff in the documentation to its
		own page (dreamcast.html).
		Adding a border to the Dreamcast PVR framebuffer.
20061108	Adding a -T command line option (again?), for halting the
		emulator on unimplemented memory accesses.
20061109	Continuing on various SH4 and Dreamcast related things.
		The emulator should now halt on more unimplemented device
		accesses, instead of just printing a warning, forcing me to
		actually implement missing stuff :)
20061111	Continuing on SH4 and Dreamcast stuff.
		Adding a bogus Landisk (SH4) machine mode.
20061112	Implementing some parts of the Dreamcast GDROM device. With
		some ugly hacks, NetBSD can (barely) mount an ISO image.
20061113	NetBSD/dreamcast now starts booting from the Live CD image,
		but crashes randomly quite early on in the boot process.
20061122	Beginning on a skeleton interrupt.h and interrupt.c for the
		new interrupt subsystem.
20061124	Continuing on the new interrupt system; taking the first steps
		to attempt to connect CPUs (SuperH and MIPS) and devices
		(dev_cons and SH4 timer interrupts) to it. Many things will
		probably break from now on.
20061125	Converting dev_ns16550, dev_8253 to the new interrupt system.
		Attempting to begin to convert the ISA bus.
20061130	Incorporating a patch from Brian Foley for the configure
		script, which checks for X11 libs in /usr/X11R6/lib64 (which
		is used on some Linux systems).
20061227	Adding a note in the man page about booting from Dreamcast
		CDROM images (i.e. that no external kernel is needed).
20061229	Continuing on the interrupt system rewrite: beginning to
		convert more devices, adding abort() calls for legacy interrupt
		system calls so that everything now _has_ to be rewritten!
		Almost all machine modes are now completely broken.
20061230	More progress on removing old interrupt code, mostly related
		to the ISA bus + devices, the LCA bus (on AlphaBook1), and
		the Footbridge bus (for CATS). And some minor PCI stuff.
		Connecting the ARM cpu to the new interrupt system.
		The CATS, NetWinder, and QEMU_MIPS machine modes now work with
		the new interrupt system :)
20061231	Connecting PowerPC CPUs to the new interrupt system.
		Making PReP machines (IBM 6050) work again.
		Beginning to convert the GT PCI controller (for e.g. Malta
		and Cobalt emulation). Some things work, but not everything.
		Updating Copyright notices for 2007.
20070101	Converting dev_kn02 from legacy style to devinit; the 3max
		machine mode now works with the new interrupt system :-]
20070105	Beginning to convert the SGI O2 machine to the new interrupt
		system; finally converting O2 (IP32) devices to devinit, etc.
20070106	Continuing on the interrupt system redesign/rewrite; KN01
		(PMAX), KN230, and Dreamcast ASIC interrupts should work again,
		moving out stuff from machine.h and devices.h into the
		corresponding devices, beginning the rewrite of i80321
		interrupts, etc.
20070107	Beginning on the rewrite of Eagle interrupt stuff (PReP, etc).
20070117	Beginning the rewrite of Algor (V3) interrupts (finally
		changing dev_v3 into devinit style).
20070118	Removing the "bus" registry concept from machine.h, because
		it was practically meaningless.
		Continuing on the rewrite of Algor V3 ISA interrupts.
20070121	More work on Algor interrupts; they are now working again,
		well enough to run NetBSD/algor. :-)
20070122	Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips
		can be installed using the new interrupt system :-)
20070123	Making the testmips mode work with the new interrupt system.
20070127	Beginning to convert DEC5800 devices to devinit, and to the
		new interrupt system.
		Converting Playstation 2 devices to devinit, and converting
		the interrupt system. Also fixing a severe bug: the interrupt
		mask register on Playstation 2 is bitwise _toggled_ on writes.
20070128	Removing the dummy NetGear machine mode and the 8250 device
		(which was only used by the NetGear machine).
		Beginning to convert the MacPPC GC (Grand Central) interrupt
		controller to the new interrupt system.
		Converting Jazz interrupts (PICA61 etc.) to the new interrupt
		system. NetBSD/arc can be installed again :-)
		Fixing the JAZZ timer (hardcoding it at 100 Hz, works with
		NetBSD and it is better than a completely dummy timer as it
		was before).
		Converting dev_mp to the new interrupt system, although I
		haven't had time to actually test it yet.
		Completely removing src/machines/interrupts.c, cpu_interrupt
		and cpu_interrupt_ack in src/cpu.c, and
		src/include/machine_interrupts.h! Adding fatal error messages
		+ abort() in the few places that are left to fix.
		Converting dev_z8530 to the new interrupt system.
		FINALLY removing the md_int struct completely from the
		machine struct.
		SH4 fixes (adding a PADDR invalidation in the ITLB replacement
		code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs
		all the way to the login prompt, and can be interacted with :-)
		Converting the CPC700 controller (PCI and interrupt controller
		for PM/PPC) to the new interrupt system.
20070129	Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/
		sgimips' and OpenBSD/sgi's ramdisk kernels can now be
		interacted with again.
20070130	Moving out the MIPS multi_lw and _sw instruction combinations
		so that they are auto-generated at compile time instead.
20070131	Adding detection of amd64/x86_64 hosts in the configure script,
		for doing initial experiments (again :-) with native code
		generation.
		Adding a -k command line option to set the size of the dyntrans
		cache, and a -B command line option to disable native code
		generation, even if GXemul was compiled with support for
		native code generation for the specific host CPU architecture.
20070201	Experimenting with a skeleton for native code generation.
		Changing the default behaviour, so that native code generation
		is now disabled by default, and has to be enabled by using
		-b on the command line.
20070202	Continuing the native code generation experiments.
		Making PCI interrupts work for Footbridge again.
20070203	More native code generation experiments.
		Removing most of the native code generation experimental code,
		it does not make sense to include any quick hacks like this.
		Minor cleanup/removal of some more legacy MIPS interrupt code.
20070204	Making i80321 interrupts work again (for NetBSD/evbarm etc.),
		and fixing the timer at 100 Hz.
20070206	Experimenting with removing the wdc interrupt slowness hack.
20070207	Lowering the number of dyntrans TLB entries for MIPS from
		192 to 128, resulting in a minor speed improvement.
		Minor optimization to the code invalidation routine in
		cpu_dyntrans.c.
20070208	Increasing (experimentally) the nr of dyntrans instructions per
		loop from 60 to 120.
20070210	Commenting out (experimentally) the dyntrans_device_danger
		detection in memory_rw.c.
		Changing the testmips and baremips machines to use a revision 2
		MIPS64 CPU by default, instead of revision 1.
		Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC
		files, the PC bios emulation, and the Olivetti M700 (ARC) and
		db64360 emulation modes.
20070211	Adding an "mp" demo to the demos directory, which tests the
		SMP functionality of the testmips machine.
		Fixing PReP interrupts some more. NetBSD/prep now boots again.
20070216	Adding a "nop workaround" for booting Mach/PMAX to the
		documentation; thanks to Artur Bujdoso for the values.
		Converting more of the MacPPC interrupt stuff to the new
		system.
		Beginning to convert BeBox interrupts to the new system.
		PPC603e should NOT have the PPC_NO_DEC flag! Removing it.
		Correcting BeBox clock speed (it was set to 100 in the NetBSD
		bootinfo block, but should be 33000000/4), allowing NetBSD
		to start without using the (incorrect) PPC_NO_DEC hack.
20070217	Implementing (slow) AltiVec vector loads and stores, allowing
		NetBSD/macppc to finally boot using the GENERIC kernel :-)
		Updating the documentation with install instructions for
		NetBSD/macppc.
20070218-19	Regression testing for the release.

==============  RELEASE 0.4.4  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26