/[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 32 - (show annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 50435 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1421 2006/11/06 05:32:37 debug Exp $
20060816	Adding a framework for emulated/virtual timers (src/timer.c),
		using only setitimer().
		Rewriting the mc146818 to use the new timer framework.
20060817	Adding a call to gettimeofday() every now and then (once every
		second, at the moment) to resynch the timer if it drifts.
		Beginning to convert the ISA timer interrupt mechanism (8253
		and 8259) to use the new timer framework.
		Removing the -I command line option.
20060819	Adding the -I command line option again, with new semantics.
		Working on Footbridge timer interrupts; NetBSD/NetWinder and
		NetBSD/CATS now run at correct speed, but unfortunately with
		HUGE delays during bootup.
20060821	Some minor m68k updates. Adding the first instruction: nop. :)
		Minor Alpha emulation updates.
20060822	Adding a FreeBSD development specific YAMON environment
		variable ("khz") (as suggested by Bruce M. Simpson).
		Moving YAMON environment variable initialization from
		machine_evbmips.c into promemul/yamon.c, and adding some more
		variables.
		Continuing on the LCA PCI bus controller (for Alpha machines).
20060823	Continuing on the timer stuff: experimenting with MIPS count/
		compare interrupts connected to the timer framework.
20060825	Adding bogus SCSI commands 0x51 (SCSICDROM_READ_DISCINFO) and
		0x52 (SCSICDROM_READ_TRACKINFO) to the SCSI emulation layer,
		to allow NetBSD/pmax 4.0_BETA to be installed from CDROM.
		Minor updates to the LCA PCI controller.
20060827	Implementing a CHIP8 cpu mode, and a corresponding CHIP8
		machine, for fun. Disassembly support for all instructions,
		and most of the common instructions have been implemented: mvi,
		mov_imm, add_imm, jmp, rand, cls, sprite, skeq_imm, jsr,
		skne_imm, bcd, rts, ldr, str, mov, or, and, xor, add, sub,
		font, ssound, sdelay, gdelay, bogus skup/skpr, skeq, skne.
20060828	Beginning to convert the CHIP8 cpu in the CHIP8 machine to a
		(more correct) RCA 180x cpu. (Disassembly for all 1802
		instructions has been implemented, but no execution yet, and
		no 1805 extended instructions.)
20060829	Minor Alpha emulation updates.
20060830	Beginning to experiment a little with PCI IDE for SGI O2.
		Fixing the cursor key mappings for MobilePro 770 emulation.
		Fixing the LK201 warning caused by recent NetBSD/pmax.
		The MIPS R41xx standby, suspend, and hibernate instructions now
		behave like the RM52xx/MIPS32/MIPS64 wait instruction.
		Fixing dev_wdc so it calculates correct (64-bit) offsets before
		giving them to diskimage_access().
20060831	Continuing on Alpha emulation (OSF1 PALcode).
20060901	Minor Alpha updates; beginning on virtual memory pagetables.
		Removed the limit for max nr of devices (in preparation for
		allowing devices' base addresses to be changed during runtime).
		Adding a hack for MIPS [d]mfc0 select 0 (except the count
		register), so that the coproc register is simply copied.
		The MIPS suspend instruction now exits the emulator, instead
		of being treated as a wait instruction (this causes NetBSD/
		hpcmips to get correct 'halt' behavior).
		The VR41xx RTC now returns correct time.
		Connecting the VR41xx timer to the timer framework (fixed at
		128 Hz, for now).
		Continuing on SPARC emulation, adding more instructions:
		restore, ba_xcc, ble. The rectangle drawing demo works :)
		Removing the last traces of the old ENABLE_CACHE_EMULATION
		MIPS stuff (not usable with dyntrans anyway).
20060902	Splitting up src/net.c into several smaller files in its own
		subdirectory (src/net/).
20060903	Cleanup of the files in src/net/, to make them less ugly.
20060904	Continuing on the 'settings' subsystem.
		Minor progress on the SPARC emulation mode.
20060905	Cleanup of various things, and connecting the settings
		infrastructure to various subsystems (emul, machine, cpu, etc).
		Changing the lk201 mouse update routine to not rely on any
		emulated hardware framebuffer cursor coordinates, but instead
		always do (semi-usable) relative movements.
20060906	Continuing on the lk201 mouse stuff. Mouse behaviour with
		multiple framebuffers (which was working in Ultrix) is now
		semi-broken (but it still works, in a way).
		Moving the documentation about networking into its own file
		(networking.html), and refreshing it a bit. Adding an example
		of how to use ethernet frame direct-access (udp_snoop).
20060907	Continuing on the settings infrastructure.
20060908	Minor updates to SH emulation: for 32-bit emulation: delay
		slots and the 'jsr @Rn' instruction. I'm putting 64-bit SH5 on
		ice, for now.
20060909-10	Implementing some more 32-bit SH instructions. Removing the
		64-bit mode completely. Enough has now been implemented to run
		the rectangle drawing demo. :-)
20060912	Adding more SH instructions.
20060916	Continuing on SH emulation (some more instructions: div0u,
		div1, rotcl/rotcr, more mov instructions, dt, braf, sets, sett,
		tst_imm, dmuls.l, subc, ldc_rm_vbr, movt, clrt, clrs, clrmac).
		Continuing on the settings subsystem (beginning on reading/
		writing settings, removing bugs, and connecting more cpus to
		the framework).
20060919	More work on SH emulation; adding an ldc banked instruction,
		and attaching a 640x480 framebuffer to the Dreamcast machine
		mode (NetBSD/dreamcast prints the NetBSD copyright banner :-),
		and then panics).
20060920	Continuing on the settings subsystem.
20060921	Fixing the Footbridge timer stuff so that NetBSD/cats and
		NetBSD/netwinder boot up without the delays.
20060922	Temporarily hardcoding MIPS timer interrupt to 100 Hz. With
		'wait' support disabled, NetBSD/malta and Linux/malta run at
		correct speed.
20060923	Connecting dev_gt to the timer framework, so that NetBSD/cobalt
		runs at correct speed.
		Moving SH4-specific memory mapped registers into its own
		device (dev_sh4.c).
		Running with -N now prints "idling" instead of bogus nr of
		instrs/second (which isn't valid anyway) while idling.
20060924	Algor emulation should now run at correct speed.
		Adding disassembly support for some MIPS64 revision 2
		instructions: ext, dext, dextm, dextu.
20060926	The timer framework now works also when the MIPS wait
		instruction is used.
20060928	Re-implementing checks for coprocessor availability for MIPS
		cop0 instructions. (Thanks to Carl van Schaik for noticing the
		lack of cop0 availability checks.)
20060929	Implementing an instruction combination hack which treats
		NetBSD/pmax' idle loop as a wait-like instruction.
20060930	The ENTRYHI_R_MASK was missing in (at least) memory_mips_v2p.c,
		causing TLB lookups to sometimes succeed when they should have
		failed. (A big thank you to Juli Mallett for noticing the
		problem.)
		Adding disassembly support for more MIPS64 revision 2 opcodes
		(seb, seh, wsbh, jalr.hb, jr.hb, synci, ins, dins, dinsu,
		dinsm, dsbh, dshd, ror, dror, rorv, drorv, dror32). Also
		implementing seb, seh, dsbh, dshd, and wsbh.
		Implementing an instruction combination hack for Linux/pmax'
		idle loop, similar to the NetBSD/pmax case.
20061001	Changing the NetBSD/sgimips install instructions to extract
		files from an iso image, instead of downloading them via ftp.
20061002	More-than-31-bit userland addresses in memory_mips_v2p.c were
		not actually working; applying a fix from Carl van Schaik to
		enable them to work + making some other updates (adding kuseg
		support).
		Fixing hpcmips (vr41xx) timer initialization.
		Experimenting with O(n)->O(1) reduction in the MIPS TLB lookup
		loop. Seems to work both for R3000 and non-R3000.
20061003	Continuing a little on SH emulation (adding more control
		registers; mini-cleanup of memory_sh.c).
20061004	Beginning on a dev_rtc, a clock/timer device for the test
		machines; also adding a demo, and some documentation.
		Fixing a bug in SH "mov.w @(disp,pc),Rn" (the result wasn't
		sign-extended), and adding the addc and ldtlb instructions.
20061005	Contining on SH emulation: virtual to physical address
		translation, and a skeleton exception mechanism.
20061006	Adding more SH instructions (various loads and stores, rte,
		negc, muls.w, various privileged register-move instructions).
20061007	More SH instructions: various move instructions, trapa, div0s,
		float, fdiv, ftrc.
		Continuing on dev_rtc; removing the rtc demo.
20061008	Adding a dummy Dreamcast PROM module. (Homebrew Dreamcast
		programs using KOS libs need this.)
		Adding more SH instructions: "stc vbr,rn", rotl, rotr, fsca,
		fmul, fadd, various floating-point moves, etc. A 256-byte
		demo for Dreamcast runs :-)
20061012	Adding the SH "lds Rm,pr" and bsr instructions.
20061013	More SH instructions: "sts fpscr,rn", tas.b, and some more
		floating point instructions, cmp/str, and more moves.
		Adding a dummy dev_pvr (Dreamcast graphics controller).
20061014	Generalizing the expression evaluator (used in the built-in
		debugger) to support parentheses and +-*/%^&|.
20061015	Removing the experimental tlb index hint code in
		mips_memory_v2p.c, since it didn't really have any effect.
20061017	Minor SH updates; adding the "sts pr,Rn", fcmp/gt, fneg,
		frchg, and some other instructions. Fixing missing sign-
		extension in an 8-bit load instruction.
20061019	Adding a simple dev_dreamcast_rtc.
		Implementing memory-mapped access to the SH ITLB/UTLB arrays.
20061021	Continuing on various SH and Dreamcast things: sh4 timers,
		debug messages for dev_pvr, fixing some virtual address
		translation bugs, adding the bsrf instruction.
		The NetBSD/dreamcast GENERIC_MD kernel now reaches userland :)
		Adding a dummy dev_dreamcast_asic.c (not really useful yet).
		Implementing simple support for Store Queues.
		Beginning on the PVR Tile Accelerator.
20061022	Generalizing the PVR framebuffer to support off-screen drawing,
		multiple bit-depths, etc. (A small speed penalty, but most
		likely worth it.)
		Adding more SH instructions (mulu.w, fcmp/eq, fsub, fmac,
		fschg, and some more); correcting bugs in "fsca" and "float".
20061024	Adding the SH ftrv (matrix * vector) instruction. Marcus
		Comstedt's "tatest" example runs :) (wireframe only).
		Correcting disassembly for SH floating point instructions that
		use the xd* registers.
		Adding the SH fsts instruction.
		In memory_device_dyntrans_access(), only the currently used
		range is now invalidated, and not the entire device range.
20061025	Adding a dummy AVR32 cpu mode skeleton.
20061026	Various Dreamcast updates; beginning on a Maple bus controller.
20061027	Continuing on the Maple bus. A bogus Controller, Keyboard, and
		Mouse can now be detected by NetBSD and KOS homebrew programs.
		Cleaning up the SH4 Timer Management Unit, and beginning on
		SH4 interrupts.
		Implementing the Dreamcast SYSASIC.
20061028	Continuing on the SYSASIC.
		Adding the SH fsqrt instruction.
		memory_sh.c now actually scans the ITLB.
		Fixing a bug in dev_sh4.c, related to associative writes into
		the memory-mapped UTLB array. NetBSD/dreamcast now reaches
		userland stably, and prints the "Terminal type?" message :-]
		Implementing enough of the Dreamcast keyboard to make NetBSD
		accept it for input.
		Enabling SuperH for stable (non-development) builds.
		Adding NetBSD/dreamcast to the documentation, although it
		doesn't support root-on-nfs yet.
20061029	Changing usleep(1) calls in the debugger to to usleep(10000)
		(according to Brian Foley, this makes GXemul run better on
		MacOS X).
		Making the Maple "Controller" do something (enough to barely
		interact with dcircus.elf).
20061030-31	Some progress on the PVR. More test programs start running (but
		with strange output).
		Various other SH4-related updates.
20061102	Various Dreamcast and SH4 updates; more KOS demos run now.
20061104	Adding a skeleton dev_mb8696x.c (the Dreamcast's LAN adapter).
20061105	Continuing on the MB8696x; NetBSD/dreamcast detects it as mbe0.
		Testing for the release.

==============  RELEASE 0.4.3  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26