/[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 34 - (hide 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 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 34 * $Id: cpu_dyntrans.c,v 1.142 2007/02/11 10:47:31 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 28 buf[0] = '\0';
55 dpavlin 18
56 dpavlin 28 while ((ch = cpu->machine->statistics_fields[i]) != '\0') {
57     if (i != 0)
58     strlcat(buf, " ", sizeof(buf));
59 dpavlin 18
60 dpavlin 28 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 dpavlin 18 }
104 dpavlin 28
105     fprintf(cpu->machine->statistics_file, "%s\n", buf);
106 dpavlin 18 }
107    
108 dpavlin 24
109 dpavlin 18 #define S gather_statistics(cpu)
110    
111 dpavlin 24
112 dpavlin 18 #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
113 dpavlin 20 #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic; \
114 dpavlin 22 cpu->cd.DYNTRANS_ARCH.next_ic += ic->arg[0]; \
115 dpavlin 20 ic->f(cpu, ic);
116 dpavlin 18 #else
117 dpavlin 24
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 dpavlin 18 #endif
165 dpavlin 28 #endif /* STATIC STUFF */
166 dpavlin 18
167    
168 dpavlin 28
169     #ifdef DYNTRANS_RUN_INSTR
170 dpavlin 14 /*
171 dpavlin 28 * XXX_run_instr():
172 dpavlin 14 *
173     * Execute one or more instructions on a specific CPU, using dyntrans.
174 dpavlin 28 * (For dualmode archs, this function is included twice.)
175 dpavlin 14 *
176     * Return value is the number of instructions executed during this call,
177     * 0 if no instructions were executed.
178     */
179 dpavlin 28 int DYNTRANS_RUN_INSTR(struct cpu *cpu)
180 dpavlin 14 {
181 dpavlin 28 MODE_uint_t cached_pc;
182     int low_pc, n_instrs;
183 dpavlin 24
184 dpavlin 28 /* Ugly... fix this some day. */
185     #ifdef DYNTRANS_DUALMODE_32
186 dpavlin 26 #ifdef MODE32
187 dpavlin 28 DYNTRANS_PC_TO_POINTERS32(cpu);
188 dpavlin 26 #else
189 dpavlin 28 DYNTRANS_PC_TO_POINTERS(cpu);
190 dpavlin 14 #endif
191 dpavlin 28 #else
192     DYNTRANS_PC_TO_POINTERS(cpu);
193 dpavlin 14 #endif
194    
195     /*
196     * Interrupt assertion? (This is _below_ the initial PC to pointer
197     * conversion; if the conversion caused an exception of some kind
198     * then interrupts are probably disabled, and the exception will get
199     * priority over device interrupts.)
200 dpavlin 24 *
201     * TODO: Turn this into a family-specific function somewhere...
202 dpavlin 14 */
203     #ifdef DYNTRANS_ARM
204     if (cpu->cd.arm.irq_asserted && !(cpu->cd.arm.cpsr & ARM_FLAG_I))
205     arm_exception(cpu, ARM_EXCEPTION_IRQ);
206     #endif
207 dpavlin 24 #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 dpavlin 20 #ifdef DYNTRANS_PPC
231     if (cpu->cd.ppc.dec_intr_pending && cpu->cd.ppc.msr & PPC_MSR_EE) {
232 dpavlin 30 if (!(cpu->cd.ppc.cpu_type.flags & PPC_NO_DEC))
233     ppc_exception(cpu, PPC_EXCEPTION_DEC);
234 dpavlin 20 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 dpavlin 32 #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 dpavlin 14
246     cached_pc = cpu->pc;
247    
248     cpu->n_translated_instrs = 0;
249    
250 dpavlin 18 cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
251     cpu->cd.DYNTRANS_ARCH.cur_ic_page;
252    
253 dpavlin 24 if (single_step || cpu->machine->instruction_trace
254     || cpu->machine->register_dump) {
255 dpavlin 14 /*
256     * Single-step:
257     */
258 dpavlin 24 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 dpavlin 14 if (cpu->machine->instruction_trace) {
264 dpavlin 32 /* 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 dpavlin 14 if (!cpu->memory_rw(cpu, cpu->mem, cached_pc, &instr[0],
269     sizeof(instr), MEM_READ, CACHE_INSTRUCTION)) {
270 dpavlin 28 fatal("XXX_run_instr(): could not read "
271 dpavlin 14 "the instruction\n");
272 dpavlin 22 } else {
273 dpavlin 24 #ifdef DYNTRANS_DELAYSLOT
274 dpavlin 32 int len =
275     #endif
276     cpu_disassemble_instr(
277     cpu->machine, cpu, instr, 1, 0);
278     #ifdef DYNTRANS_DELAYSLOT
279 dpavlin 22 /* Show the instruction in the delay slot,
280     if any: */
281 dpavlin 24 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 dpavlin 32 + len, &instr[0],
289 dpavlin 24 sizeof(instr), MEM_READ,
290     CACHE_INSTRUCTION);
291     cpu->delay_slot = DELAYED;
292 dpavlin 32 cpu->pc += len;
293 dpavlin 24 cpu_disassemble_instr(cpu->machine,
294     cpu, instr, 1, 0);
295     cpu->delay_slot = saved_delayslot;
296 dpavlin 32 cpu->pc -= len;
297 dpavlin 24 }
298 dpavlin 22 #endif
299     }
300 dpavlin 14 }
301    
302 dpavlin 28 if (cpu->machine->statistics_enabled)
303 dpavlin 18 S;
304    
305 dpavlin 14 /* Execute just one instruction: */
306 dpavlin 24 I;
307    
308 dpavlin 14 n_instrs = 1;
309 dpavlin 24 } 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 dpavlin 30 if (n_instrs + cpu->n_translated_instrs >=
327 dpavlin 26 N_SAFE_DYNTRANS_LIMIT)
328 dpavlin 24 break;
329     }
330 dpavlin 28 } else if (cpu->machine->statistics_enabled) {
331 dpavlin 18 /* 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 dpavlin 30 if (n_instrs + cpu->n_translated_instrs >=
344 dpavlin 26 N_SAFE_DYNTRANS_LIMIT)
345 dpavlin 18 break;
346     }
347 dpavlin 14 } else {
348     /* Execute multiple instructions: */
349 dpavlin 34 n_instrs = 0;
350 dpavlin 14 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 dpavlin 34 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 dpavlin 14
367 dpavlin 34 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 dpavlin 14 break;
372     }
373     }
374    
375 dpavlin 20 n_instrs += cpu->n_translated_instrs;
376 dpavlin 14
377 dpavlin 20 /* Synchronize the program counter: */
378 dpavlin 14 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 dpavlin 22 } 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 dpavlin 14 }
398    
399 dpavlin 24 #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 dpavlin 32
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 dpavlin 34 INTERRUPT_ASSERT(
416     cpu->cd.mips.irq_compare);
417 dpavlin 32 } else
418     #endif
419     {
420     if (diff1 > 0 && diff2 <= 0)
421 dpavlin 34 INTERRUPT_ASSERT(
422     cpu->cd.mips.irq_compare);
423 dpavlin 32 }
424     }
425 dpavlin 24 }
426     #endif
427 dpavlin 20 #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 dpavlin 22 if ((old >> 31) == 0 && (cpu->cd.ppc.spr[SPR_DEC] >> 31) == 1
433     && !(cpu->cd.ppc.cpu_type.flags & PPC_NO_DEC))
434 dpavlin 20 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 dpavlin 14 }
445 dpavlin 28 #endif /* DYNTRANS_RUN_INSTR */
446 dpavlin 14
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 dpavlin 24 #if defined(DYNTRANS_ALPHA) || defined(DYNTRANS_SPARC)
464 dpavlin 14 6
465     #else
466     #ifdef DYNTRANS_SH
467 dpavlin 32 8 /* Both for 32-bit and 64-bit SuperH */
468 dpavlin 14 #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 dpavlin 34 #if defined(DYNTRANS_TRANSPUTER)
493 dpavlin 14 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 dpavlin 32 #ifdef DYNTRANS_RCA180X
518     r[0 /* TODO */
519     #endif
520 dpavlin 14 #ifdef DYNTRANS_SH
521 dpavlin 32 r[4 /* NetBSD seems to use 4? But 2 seems
522     to be used by other code? TODO */
523 dpavlin 14 #endif
524     #ifdef DYNTRANS_SPARC
525 dpavlin 32 r[8 /* o0..o5 */
526 dpavlin 14 #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 dpavlin 24 fatal("0x%"PRIx32, (uint32_t)d);
541 dpavlin 14 else
542 dpavlin 24 fatal("0x%"PRIx64, (uint64_t)d);
543 dpavlin 14 }
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 dpavlin 34 native_commit(cpu);
569    
570 dpavlin 14 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
571     + cpu->translation_cache_cur_ofs);
572    
573 dpavlin 26 /* Copy the entire template page first: */
574     memcpy(ppp, cpu->cd.DYNTRANS_ARCH.physpage_template, sizeof(
575     struct DYNTRANS_TC_PHYSPAGE));
576 dpavlin 14
577 dpavlin 26 ppp->physaddr = physaddr & ~(DYNTRANS_PAGESIZE - 1);
578 dpavlin 14
579     cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE);
580 dpavlin 18
581     cpu->translation_cache_cur_ofs --;
582 dpavlin 26 cpu->translation_cache_cur_ofs |= 127;
583 dpavlin 18 cpu->translation_cache_cur_ofs ++;
584 dpavlin 14 }
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 dpavlin 24 cached_pc = cpu->pc, physaddr = 0;
603 dpavlin 14 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 dpavlin 24 int index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
610 dpavlin 14 #else
611 dpavlin 24 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 dpavlin 14 #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 dpavlin 24 if (l3->host_load[x3] != NULL) {
638     physaddr = l3->phys_addr[x3];
639 dpavlin 14 ok = 1;
640     }
641     #endif
642    
643     if (!ok) {
644     uint64_t paddr;
645 dpavlin 26 if (cpu->translate_v2p != NULL) {
646 dpavlin 30 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 dpavlin 26 ok = cpu->translate_v2p(
653 dpavlin 30 cpu, vaddr, &paddr, FLAG_INSTR);
654 dpavlin 26 } else {
655 dpavlin 14 paddr = cached_pc;
656     ok = 1;
657     }
658     if (!ok) {
659 dpavlin 28 /*
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 dpavlin 24 /* 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 dpavlin 20
669 dpavlin 28 /* If there was an exception, the PC has changed.
670     Update cached_pc: */
671     cached_pc = cpu->pc;
672 dpavlin 20
673 dpavlin 28 #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 dpavlin 34 x2 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N))
682     & mask2;
683     x3 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N
684     - DYNTRANS_L3N)) & mask3;
685 dpavlin 28 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 dpavlin 20 /* printf("EXCEPTION HANDLER: vaddr = 0x%x ==> "
699     "paddr = 0x%x\n", (int)cpu->pc, (int)paddr);
700 dpavlin 24 fatal("!? cpu->pc=0x%"PRIx64"\n", (uint64_t)cpu->pc); */
701 dpavlin 20
702 dpavlin 14 if (!ok) {
703     fatal("FATAL: could not find physical"
704     " address of the exception handler?");
705     exit(1);
706     }
707     }
708 dpavlin 24
709 dpavlin 14 physaddr = paddr;
710     }
711    
712 dpavlin 28 physaddr &= ~(DYNTRANS_PAGESIZE - 1);
713    
714 dpavlin 18 #ifdef MODE32
715     if (cpu->cd.DYNTRANS_ARCH.host_load[index] == NULL) {
716 dpavlin 24 #else
717     if (l3->host_load[x3] == NULL) {
718     #endif
719 dpavlin 28 int q = DYNTRANS_PAGESIZE - 1;
720 dpavlin 18 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 dpavlin 28 host_page, 0, physaddr);
725 dpavlin 18 }
726     }
727    
728 dpavlin 34 if (cpu->translation_cache_cur_ofs >= dyntrans_cache_size) {
729 dpavlin 26 #ifdef UNSTABLE_DEVEL
730     fatal("[ dyntrans: resetting the translation cache ]\n");
731     #endif
732 dpavlin 14 cpu_create_or_reset_tc(cpu);
733 dpavlin 18 }
734 dpavlin 14
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 dpavlin 26
747 dpavlin 14 /* If we found the page in the cache, then we're done: */
748 dpavlin 26 if (ppp->physaddr == physaddr)
749 dpavlin 14 break;
750 dpavlin 26
751 dpavlin 14 /* 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 dpavlin 24 /* fatal("CREATING page %lli (physaddr 0x%"PRIx64"), table "
760     "index %i\n", (long long)pagenr, (uint64_t)physaddr,
761 dpavlin 14 (int)table_index); */
762 dpavlin 34 native_commit(cpu);
763 dpavlin 14 *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 dpavlin 24 #else
777     if (l3->host_load[x3] != NULL)
778     l3->phys_page[x3] = ppp;
779 dpavlin 14 #endif
780    
781 dpavlin 28 /*
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 dpavlin 14
791     cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
792 dpavlin 18
793 dpavlin 14 cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
794     DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
795    
796 dpavlin 24 /* 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 dpavlin 14 }
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 dpavlin 22 cached_pc = cpu->pc;
823 dpavlin 14 struct DYNTRANS_TC_PHYSPAGE *ppp;
824    
825     #ifdef MODE32
826     int index;
827 dpavlin 18 index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
828 dpavlin 14 ppp = cpu->cd.DYNTRANS_ARCH.phys_page[index];
829     if (ppp != NULL)
830     goto have_it;
831     #else
832 dpavlin 24 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 dpavlin 14 #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 dpavlin 24 /* 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 dpavlin 14 }
862     #endif /* DYNTRANS_PC_TO_POINTERS_FUNC */
863    
864    
865    
866 dpavlin 26 #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 dpavlin 24 /*
884 dpavlin 26 * XXX_init_tables():
885 dpavlin 24 *
886 dpavlin 26 * 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 dpavlin 24 */
889 dpavlin 26 void DYNTRANS_INIT_TABLES(struct cpu *cpu)
890 dpavlin 24 {
891 dpavlin 26 #ifndef MODE32
892 dpavlin 24 struct DYNTRANS_L2_64_TABLE *dummy_l2;
893     struct DYNTRANS_L3_64_TABLE *dummy_l3;
894     int x1, x2;
895 dpavlin 26 #endif
896     int i;
897     struct DYNTRANS_TC_PHYSPAGE *ppp = malloc(sizeof(
898     struct DYNTRANS_TC_PHYSPAGE));
899 dpavlin 24
900 dpavlin 26 if (ppp == NULL) {
901     fprintf(stderr, "out of memory\n");
902     exit(1);
903     }
904    
905     ppp->next_ofs = 0;
906 dpavlin 28 ppp->translations = 0;
907 dpavlin 26 /* 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 dpavlin 24 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 dpavlin 26 #endif
960 dpavlin 24 }
961 dpavlin 26 #endif /* DYNTRANS_INIT_TABLES */
962 dpavlin 24
963    
964    
965 dpavlin 14 #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 dpavlin 18 static void DYNTRANS_INVALIDATE_TLB_ENTRY(struct cpu *cpu,
976 dpavlin 14 #ifdef MODE32
977     uint32_t
978     #else
979     uint64_t
980     #endif
981     vaddr_page, int flags)
982     {
983     #ifdef MODE32
984 dpavlin 18 uint32_t index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
985 dpavlin 14
986 dpavlin 18 #ifdef DYNTRANS_ARM
987 dpavlin 20 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5] &= ~(1 << (index & 31));
988 dpavlin 18 #endif
989    
990 dpavlin 14 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 dpavlin 24 int tlbi = cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index];
996 dpavlin 14 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 dpavlin 24 if (tlbi > 0)
1001     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[tlbi-1].valid = 0;
1002 dpavlin 18 cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = 0;
1003 dpavlin 14 }
1004     #else
1005 dpavlin 24 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 dpavlin 14
1012 dpavlin 24 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 dpavlin 14
1016 dpavlin 24 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1017     if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy)
1018     return;
1019 dpavlin 14
1020 dpavlin 24 l3 = l2->l3[x2];
1021     if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy)
1022     return;
1023    
1024 dpavlin 14 if (flags & JUST_MARK_AS_NON_WRITABLE) {
1025 dpavlin 24 l3->host_store[x3] = NULL;
1026 dpavlin 14 return;
1027     }
1028 dpavlin 28
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 dpavlin 24 l3->host_load[x3] = NULL;
1074     l3->host_store[x3] = NULL;
1075     l3->phys_addr[x3] = 0;
1076     l3->phys_page[x3] = NULL;
1077 dpavlin 28 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 dpavlin 24 if (l3->refcount < 0) {
1085     fatal("xxx_invalidate_tlb_entry(): huh? Refcount bug.\n");
1086 dpavlin 14 exit(1);
1087     }
1088 dpavlin 28
1089 dpavlin 24 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 dpavlin 28 #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 dpavlin 24 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 dpavlin 14 }
1118     #endif
1119     }
1120     #endif
1121    
1122    
1123 dpavlin 18 #ifdef DYNTRANS_INVALIDATE_TC
1124 dpavlin 14 /*
1125 dpavlin 18 * XXX_invalidate_translation_caches():
1126 dpavlin 14 *
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 dpavlin 22 * 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 dpavlin 14 * In the case when all translations are invalidated, paddr doesn't need
1138     * to be supplied.
1139     *
1140 dpavlin 18 * 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 dpavlin 14 */
1144 dpavlin 22 void DYNTRANS_INVALIDATE_TC(struct cpu *cpu, uint64_t addr, int flags)
1145 dpavlin 14 {
1146     int r;
1147     #ifdef MODE32
1148     uint32_t
1149     #else
1150     uint64_t
1151     #endif
1152 dpavlin 22 addr_page = addr & ~(DYNTRANS_PAGESIZE - 1);
1153 dpavlin 14
1154 dpavlin 20 /* fatal("invalidate(): "); */
1155    
1156 dpavlin 22 /* Quick case for _one_ virtual addresses: see note above. */
1157 dpavlin 18 if (flags & INVALIDATE_VADDR) {
1158 dpavlin 20 /* fatal("vaddr 0x%08x\n", (int)addr_page); */
1159 dpavlin 18 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, addr_page, flags);
1160     return;
1161     }
1162    
1163 dpavlin 22 /* 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 dpavlin 20 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 dpavlin 22 /* Invalidate a physical page: */
1194 dpavlin 20
1195 dpavlin 22 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 dpavlin 14 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
1201 dpavlin 22 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && addr_page
1202     == cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page) {
1203 dpavlin 14 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 dpavlin 18 #endif /* DYNTRANS_INVALIDATE_TC */
1216 dpavlin 14
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 dpavlin 18 #ifdef MODE32
1230 dpavlin 14 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 dpavlin 18 struct DYNTRANS_TC_PHYSPAGE *ppp, *prev_ppp;
1245 dpavlin 14
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 dpavlin 34
1253     /* Return immediately if there is no code translation
1254     for this page. */
1255     if (physpage_ofs == 0)
1256     return;
1257    
1258 dpavlin 18 prev_ppp = ppp = NULL;
1259 dpavlin 14
1260     /* Traverse the physical page chain: */
1261     while (physpage_ofs != 0) {
1262 dpavlin 18 prev_ppp = ppp;
1263 dpavlin 14 ppp = (struct DYNTRANS_TC_PHYSPAGE *)
1264     (cpu->translation_cache + physpage_ofs);
1265 dpavlin 26
1266 dpavlin 14 /* If we found the page in the cache,
1267     then we're done: */
1268     if (ppp->physaddr == addr)
1269     break;
1270 dpavlin 26
1271 dpavlin 14 /* Try the next page in the chain: */
1272     physpage_ofs = ppp->next_ofs;
1273     }
1274    
1275 dpavlin 34 /* 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 dpavlin 18
1280 dpavlin 28 #if 0
1281 dpavlin 18 /*
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 dpavlin 14 if (ppp != NULL) {
1289 dpavlin 18 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 dpavlin 28 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 dpavlin 14 #ifdef DYNTRANS_DUALMODE_32
1314 dpavlin 28 cpu->is_32bit?
1315     instr32(to_be_translated) :
1316 dpavlin 14 #endif
1317 dpavlin 28 instr(to_be_translated);
1318     }
1319    
1320     x >>= 1;
1321     }
1322    
1323     ppp->translations = 0;
1324 dpavlin 14 }
1325 dpavlin 18 #endif
1326 dpavlin 14 }
1327    
1328 dpavlin 26 /* Invalidate entries in the VPH table: */
1329     for (r = 0; r < DYNTRANS_MAX_VPH_TLB_ENTRIES; r ++) {
1330 dpavlin 14 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 dpavlin 18 uint32_t index =
1341     DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1342 dpavlin 14 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1343     #else
1344 dpavlin 24 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 dpavlin 14
1351 dpavlin 24 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 dpavlin 14 #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 dpavlin 32 int found, r, useraccess = 0;
1378 dpavlin 14
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 dpavlin 24 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 dpavlin 28
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 dpavlin 24 (uint64_t)paddr_page); */
1397 dpavlin 14 #endif
1398    
1399 dpavlin 26 assert((vaddr_page & (DYNTRANS_PAGESIZE-1)) == 0);
1400     assert((paddr_page & (DYNTRANS_PAGESIZE-1)) == 0);
1401    
1402 dpavlin 18 if (writeflag & MEMORY_USER_ACCESS) {
1403     writeflag &= ~MEMORY_USER_ACCESS;
1404     useraccess = 1;
1405     }
1406    
1407 dpavlin 14 /* Scan the current TLB entries: */
1408 dpavlin 18
1409     #ifdef MODE32
1410 dpavlin 20 /*
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 dpavlin 18 DYNTRANS_ADDR_TO_PAGENR(vaddr_page)] - 1;
1420 dpavlin 30 #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 dpavlin 20 if (found < 0) {
1439 dpavlin 32 /* Create the new TLB entry, overwriting a "random" entry: */
1440 dpavlin 20 static unsigned int x = 0;
1441 dpavlin 32 r = (x++) % DYNTRANS_MAX_VPH_TLB_ENTRIES;
1442 dpavlin 14
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 dpavlin 20 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag =
1455     writeflag & MEM_WRITE;
1456 dpavlin 14
1457     /* Add the new translation to the table: */
1458     #ifdef MODE32
1459 dpavlin 18 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1460 dpavlin 14 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 dpavlin 18 cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = r + 1;
1466     #ifdef DYNTRANS_ARM
1467     if (useraccess)
1468 dpavlin 20 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5]
1469     |= 1 << (index & 31);
1470 dpavlin 18 #endif
1471 dpavlin 24 #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 dpavlin 28 l2->refcount = 0;
1483 dpavlin 24 for (i=0; i<(1 << DYNTRANS_L2N); i++)
1484     l2->l3[i] = cpu->cd.DYNTRANS_ARCH.
1485     l3_64_dummy;
1486     }
1487 dpavlin 28 if (l2->refcount != 0) {
1488     fatal("Huh? l2 Refcount problem.\n");
1489     exit(1);
1490     }
1491 dpavlin 24 }
1492 dpavlin 28 if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) {
1493     fatal("INTERNAL ERROR L2 reuse\n");
1494     exit(1);
1495     }
1496 dpavlin 24 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 dpavlin 28 if (l3->refcount != 0) {
1507     fatal("Huh? l3 Refcount problem.\n");
1508     exit(1);
1509     }
1510 dpavlin 24 l2->refcount ++;
1511     }
1512 dpavlin 28 if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy) {
1513     fatal("INTERNAL ERROR L3 reuse\n");
1514     exit(1);
1515     }
1516    
1517 dpavlin 24 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 dpavlin 28
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 dpavlin 24 #endif /* !MODE32 */
1548 dpavlin 14 } 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 dpavlin 20 * Writeflag = MEM_DOWNGRADE: Downgrade to readonly.
1554 dpavlin 14 */
1555 dpavlin 18 r = found;
1556 dpavlin 20 if (writeflag & MEM_WRITE)
1557 dpavlin 14 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1;
1558 dpavlin 20 if (writeflag & MEM_DOWNGRADE)
1559 dpavlin 14 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 0;
1560     #ifdef MODE32
1561 dpavlin 18 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1562 dpavlin 14 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1563 dpavlin 18 #ifdef DYNTRANS_ARM
1564 dpavlin 20 cpu->cd.DYNTRANS_ARCH.is_userpage[index>>5] &= ~(1<<(index&31));
1565 dpavlin 18 if (useraccess)
1566 dpavlin 20 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5]
1567     |= 1 << (index & 31);
1568 dpavlin 18 #endif
1569 dpavlin 14 if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) {
1570 dpavlin 20 if (writeflag & MEM_WRITE)
1571 dpavlin 14 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1572     host_page;
1573 dpavlin 20 if (writeflag & MEM_DOWNGRADE)
1574 dpavlin 14 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 dpavlin 24 #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 dpavlin 28 printf("HOST LOAD 2 set to %p\n", host_page);
1597 dpavlin 24 l3->host_load[x3] = host_page;
1598     l3->host_store[x3] = writeflag? host_page : NULL;
1599     l3->phys_addr[x3] = paddr_page;
1600     }
1601 dpavlin 28
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 dpavlin 24 #endif /* !MODE32 */
1629 dpavlin 14 }
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 dpavlin 24 MODE_uint_t curpc = cpu->pc;
1643 dpavlin 14 int i;
1644     for (i=0; i<cpu->machine->n_breakpoints; i++)
1645 dpavlin 24 if (curpc == (MODE_uint_t)
1646 dpavlin 14 cpu->machine->breakpoint_addr[i]) {
1647     if (!cpu->machine->instruction_trace) {
1648     int old_quiet_mode = quiet_mode;
1649     quiet_mode = 0;
1650 dpavlin 24 DISASSEMBLE(cpu, ib, 1, 0);
1651 dpavlin 14 quiet_mode = old_quiet_mode;
1652     }
1653 dpavlin 24 fatal("BREAKPOINT: pc = 0x%"PRIx64"\n(The "
1654 dpavlin 14 "instruction has not yet executed.)\n",
1655 dpavlin 24 (uint64_t)cpu->pc);
1656 dpavlin 22 #ifdef DYNTRANS_DELAYSLOT
1657 dpavlin 24 if (cpu->delay_slot != NOT_DELAYED)
1658 dpavlin 22 fatal("ERROR! Breakpoint in a delay"
1659     " slot! Not yet supported.\n");
1660     #endif
1661 dpavlin 14 single_step_breakpoint = 1;
1662 dpavlin 26 single_step = ENTER_SINGLE_STEPPING;
1663 dpavlin 14 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 dpavlin 28 * 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 dpavlin 14 */
1677 dpavlin 28
1678 dpavlin 24 /* Make sure cur_physpage is in synch: */
1679     cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
1680     cpu->cd.DYNTRANS_ARCH.cur_ic_page;
1681 dpavlin 28
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 dpavlin 18 }
1690 dpavlin 14
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 dpavlin 24 * instruction combination. For architectures with delay slots,
1697     * we also ignore combinations if the delay slot is across a page
1698     * boundary.
1699 dpavlin 14 */
1700 dpavlin 24 if (!single_step && !cpu->machine->instruction_trace
1701     #ifdef DYNTRANS_DELAYSLOT
1702     && !in_crosspage_delayslot
1703     #endif
1704 dpavlin 30 && 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 dpavlin 18 }
1709 dpavlin 14
1710 dpavlin 24 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 dpavlin 14 /* ... and finally execute the translated instruction: */
1727 dpavlin 24 if ((single_step_breakpoint && cpu->delay_slot == NOT_DELAYED)
1728     #ifdef DYNTRANS_DELAYSLOT
1729     || in_crosspage_delayslot
1730     #endif
1731     ) {
1732 dpavlin 14 /*
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 dpavlin 24 #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
1739     cpu->cd.DYNTRANS_ARCH.next_ic = ic + ic->arg[0];
1740     #endif
1741 dpavlin 14 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 dpavlin 24 #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 dpavlin 14 ic->f(cpu, ic);
1763 dpavlin 24 }
1764 dpavlin 14
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 dpavlin 24 fatal(" at 0x%"PRIx32"\n", (uint32_t)cpu->pc);
1778 dpavlin 14 #else
1779 dpavlin 24 fatal(" at 0x%"PRIx64"\n", (uint64_t)cpu->pc);
1780 dpavlin 14 #endif
1781     else {
1782     fatal(":\n");
1783 dpavlin 24 DISASSEMBLE(cpu, ib, 1, 0);
1784 dpavlin 14 }
1785    
1786     cpu->running = 0;
1787 dpavlin 30
1788     /* Note: Single-stepping can jump here. */
1789 dpavlin 14 stop_running_translated:
1790 dpavlin 30
1791 dpavlin 14 debugger_n_steps_left_before_interaction = 0;
1792 dpavlin 30
1793 dpavlin 14 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 dpavlin 30
1799 dpavlin 14 #endif /* DYNTRANS_TO_BE_TRANSLATED_TAIL */
1800    

  ViewVC Help
Powered by ViewVC 1.1.26