/[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 32 - (hide 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 dpavlin 14 /*
2 dpavlin 22 * Copyright (C) 2005-2006 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 32 * $Id: cpu_dyntrans.c,v 1.132 2006/10/27 13:12:20 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 #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 dpavlin 28 fatal("XXX_run_instr(): could not read "
275 dpavlin 14 "the instruction\n");
276 dpavlin 22 } else {
277 dpavlin 24 #ifdef DYNTRANS_DELAYSLOT
278 dpavlin 32 int len =
279     #endif
280     cpu_disassemble_instr(
281     cpu->machine, cpu, instr, 1, 0);
282     #ifdef DYNTRANS_DELAYSLOT
283 dpavlin 22 /* Show the instruction in the delay slot,
284     if any: */
285 dpavlin 24 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 dpavlin 32 + len, &instr[0],
293 dpavlin 24 sizeof(instr), MEM_READ,
294     CACHE_INSTRUCTION);
295     cpu->delay_slot = DELAYED;
296 dpavlin 32 cpu->pc += len;
297 dpavlin 24 cpu_disassemble_instr(cpu->machine,
298     cpu, instr, 1, 0);
299     cpu->delay_slot = saved_delayslot;
300 dpavlin 32 cpu->pc -= len;
301 dpavlin 24 }
302 dpavlin 22 #endif
303     }
304 dpavlin 14 }
305    
306 dpavlin 28 if (cpu->machine->statistics_enabled)
307 dpavlin 18 S;
308    
309 dpavlin 14 /* Execute just one instruction: */
310 dpavlin 24 I;
311    
312 dpavlin 14 n_instrs = 1;
313 dpavlin 24 } 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 dpavlin 30 if (n_instrs + cpu->n_translated_instrs >=
331 dpavlin 26 N_SAFE_DYNTRANS_LIMIT)
332 dpavlin 24 break;
333     }
334 dpavlin 28 } else if (cpu->machine->statistics_enabled) {
335 dpavlin 18 /* 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 dpavlin 30 if (n_instrs + cpu->n_translated_instrs >=
348 dpavlin 26 N_SAFE_DYNTRANS_LIMIT)
349 dpavlin 18 break;
350     }
351 dpavlin 14 } else {
352     /* Execute multiple instructions: */
353 dpavlin 30 int n = 0;
354 dpavlin 14 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 dpavlin 30 n += 60;
366 dpavlin 14
367 dpavlin 30 if (n + cpu->n_translated_instrs >=
368 dpavlin 26 N_SAFE_DYNTRANS_LIMIT)
369 dpavlin 14 break;
370     }
371 dpavlin 30 n_instrs = n;
372 dpavlin 14 }
373    
374 dpavlin 20 n_instrs += cpu->n_translated_instrs;
375 dpavlin 14
376 dpavlin 20 /* Synchronize the program counter: */
377 dpavlin 14 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 dpavlin 22 } 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 dpavlin 14 }
397    
398 dpavlin 24 #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 dpavlin 32
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 dpavlin 24 }
423     #endif
424 dpavlin 20 #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 dpavlin 22 if ((old >> 31) == 0 && (cpu->cd.ppc.spr[SPR_DEC] >> 31) == 1
430     && !(cpu->cd.ppc.cpu_type.flags & PPC_NO_DEC))
431 dpavlin 20 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 dpavlin 14 }
442 dpavlin 28 #endif /* DYNTRANS_RUN_INSTR */
443 dpavlin 14
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 dpavlin 24 #if defined(DYNTRANS_ALPHA) || defined(DYNTRANS_SPARC)
461 dpavlin 14 6
462     #else
463     #ifdef DYNTRANS_SH
464 dpavlin 32 8 /* Both for 32-bit and 64-bit SuperH */
465 dpavlin 14 #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 dpavlin 28 #if defined(DYNTRANS_X86) || defined(DYNTRANS_TRANSPUTER)
490 dpavlin 14 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 dpavlin 32 #ifdef DYNTRANS_AVR32
506     r[0 /* TODO */
507     #endif
508 dpavlin 14 #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 dpavlin 32 #ifdef DYNTRANS_RCA180X
527     r[0 /* TODO */
528     #endif
529 dpavlin 14 #ifdef DYNTRANS_SH
530 dpavlin 32 r[4 /* NetBSD seems to use 4? But 2 seems
531     to be used by other code? TODO */
532 dpavlin 14 #endif
533     #ifdef DYNTRANS_SPARC
534 dpavlin 32 r[8 /* o0..o5 */
535 dpavlin 14 #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 dpavlin 24 fatal("0x%"PRIx32, (uint32_t)d);
550 dpavlin 14 else
551 dpavlin 24 fatal("0x%"PRIx64, (uint64_t)d);
552 dpavlin 14 }
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 dpavlin 26 /* Copy the entire template page first: */
581     memcpy(ppp, cpu->cd.DYNTRANS_ARCH.physpage_template, sizeof(
582     struct DYNTRANS_TC_PHYSPAGE));
583 dpavlin 14
584 dpavlin 26 ppp->physaddr = physaddr & ~(DYNTRANS_PAGESIZE - 1);
585 dpavlin 14
586     cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE);
587 dpavlin 18
588     cpu->translation_cache_cur_ofs --;
589 dpavlin 26 cpu->translation_cache_cur_ofs |= 127;
590 dpavlin 18 cpu->translation_cache_cur_ofs ++;
591 dpavlin 14 }
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 dpavlin 24 cached_pc = cpu->pc, physaddr = 0;
610 dpavlin 14 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 dpavlin 24 int index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
617 dpavlin 14 #else
618 dpavlin 24 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 dpavlin 14 #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 dpavlin 24 if (l3->host_load[x3] != NULL) {
645     physaddr = l3->phys_addr[x3];
646 dpavlin 14 ok = 1;
647     }
648     #endif
649    
650     if (!ok) {
651     uint64_t paddr;
652 dpavlin 26 if (cpu->translate_v2p != NULL) {
653 dpavlin 30 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 dpavlin 26 ok = cpu->translate_v2p(
660 dpavlin 30 cpu, vaddr, &paddr, FLAG_INSTR);
661 dpavlin 26 } else {
662 dpavlin 14 paddr = cached_pc;
663     ok = 1;
664     }
665     if (!ok) {
666 dpavlin 28 /*
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 dpavlin 24 /* 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 dpavlin 20
676 dpavlin 28 /* If there was an exception, the PC has changed.
677     Update cached_pc: */
678     cached_pc = cpu->pc;
679 dpavlin 20
680 dpavlin 28 #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 dpavlin 20 /* printf("EXCEPTION HANDLER: vaddr = 0x%x ==> "
705     "paddr = 0x%x\n", (int)cpu->pc, (int)paddr);
706 dpavlin 24 fatal("!? cpu->pc=0x%"PRIx64"\n", (uint64_t)cpu->pc); */
707 dpavlin 20
708 dpavlin 14 if (!ok) {
709     fatal("FATAL: could not find physical"
710     " address of the exception handler?");
711     exit(1);
712     }
713     }
714 dpavlin 24
715 dpavlin 14 physaddr = paddr;
716     }
717    
718 dpavlin 28 physaddr &= ~(DYNTRANS_PAGESIZE - 1);
719    
720 dpavlin 18 #ifdef MODE32
721     if (cpu->cd.DYNTRANS_ARCH.host_load[index] == NULL) {
722 dpavlin 24 #else
723     if (l3->host_load[x3] == NULL) {
724     #endif
725 dpavlin 28 int q = DYNTRANS_PAGESIZE - 1;
726 dpavlin 18 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 dpavlin 28 host_page, 0, physaddr);
731 dpavlin 18 }
732     }
733    
734     if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE) {
735 dpavlin 26 #ifdef UNSTABLE_DEVEL
736     fatal("[ dyntrans: resetting the translation cache ]\n");
737     #endif
738 dpavlin 14 cpu_create_or_reset_tc(cpu);
739 dpavlin 18 }
740 dpavlin 14
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 dpavlin 26
753 dpavlin 14 /* If we found the page in the cache, then we're done: */
754 dpavlin 26 if (ppp->physaddr == physaddr)
755 dpavlin 14 break;
756 dpavlin 26
757 dpavlin 14 /* 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 dpavlin 24 /* fatal("CREATING page %lli (physaddr 0x%"PRIx64"), table "
766     "index %i\n", (long long)pagenr, (uint64_t)physaddr,
767 dpavlin 14 (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 dpavlin 24 #else
782     if (l3->host_load[x3] != NULL)
783     l3->phys_page[x3] = ppp;
784 dpavlin 14 #endif
785    
786 dpavlin 28 /*
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 dpavlin 14
796     cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
797 dpavlin 18
798 dpavlin 14 cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
799     DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
800    
801 dpavlin 24 /* 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 dpavlin 14 }
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 dpavlin 22 cached_pc = cpu->pc;
828 dpavlin 14 struct DYNTRANS_TC_PHYSPAGE *ppp;
829    
830     #ifdef MODE32
831     int index;
832 dpavlin 18 index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
833 dpavlin 14 ppp = cpu->cd.DYNTRANS_ARCH.phys_page[index];
834     if (ppp != NULL)
835     goto have_it;
836     #else
837 dpavlin 24 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 dpavlin 14 #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 dpavlin 24 /* 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 dpavlin 14 }
867     #endif /* DYNTRANS_PC_TO_POINTERS_FUNC */
868    
869    
870    
871 dpavlin 26 #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 dpavlin 24 /*
889 dpavlin 26 * XXX_init_tables():
890 dpavlin 24 *
891 dpavlin 26 * 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 dpavlin 24 */
894 dpavlin 26 void DYNTRANS_INIT_TABLES(struct cpu *cpu)
895 dpavlin 24 {
896 dpavlin 26 #ifndef MODE32
897 dpavlin 24 struct DYNTRANS_L2_64_TABLE *dummy_l2;
898     struct DYNTRANS_L3_64_TABLE *dummy_l3;
899     int x1, x2;
900 dpavlin 26 #endif
901     int i;
902     struct DYNTRANS_TC_PHYSPAGE *ppp = malloc(sizeof(
903     struct DYNTRANS_TC_PHYSPAGE));
904 dpavlin 24
905 dpavlin 26 if (ppp == NULL) {
906     fprintf(stderr, "out of memory\n");
907     exit(1);
908     }
909    
910     ppp->next_ofs = 0;
911 dpavlin 28 ppp->translations = 0;
912 dpavlin 26 /* 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 dpavlin 24 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 dpavlin 26 #endif
965 dpavlin 24 }
966 dpavlin 26 #endif /* DYNTRANS_INIT_TABLES */
967 dpavlin 24
968    
969    
970 dpavlin 14 #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 dpavlin 18 static void DYNTRANS_INVALIDATE_TLB_ENTRY(struct cpu *cpu,
981 dpavlin 14 #ifdef MODE32
982     uint32_t
983     #else
984     uint64_t
985     #endif
986     vaddr_page, int flags)
987     {
988     #ifdef MODE32
989 dpavlin 18 uint32_t index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
990 dpavlin 14
991 dpavlin 18 #ifdef DYNTRANS_ARM
992 dpavlin 20 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5] &= ~(1 << (index & 31));
993 dpavlin 18 #endif
994    
995 dpavlin 14 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 dpavlin 24 int tlbi = cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index];
1001 dpavlin 14 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 dpavlin 24 if (tlbi > 0)
1006     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[tlbi-1].valid = 0;
1007 dpavlin 18 cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = 0;
1008 dpavlin 14 }
1009     #else
1010 dpavlin 24 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 dpavlin 14
1017 dpavlin 24 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 dpavlin 14
1021 dpavlin 24 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1022     if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy)
1023     return;
1024 dpavlin 14
1025 dpavlin 24 l3 = l2->l3[x2];
1026     if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy)
1027     return;
1028    
1029 dpavlin 14 if (flags & JUST_MARK_AS_NON_WRITABLE) {
1030 dpavlin 24 l3->host_store[x3] = NULL;
1031 dpavlin 14 return;
1032     }
1033 dpavlin 28
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 dpavlin 24 l3->host_load[x3] = NULL;
1079     l3->host_store[x3] = NULL;
1080     l3->phys_addr[x3] = 0;
1081     l3->phys_page[x3] = NULL;
1082 dpavlin 28 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 dpavlin 24 if (l3->refcount < 0) {
1090     fatal("xxx_invalidate_tlb_entry(): huh? Refcount bug.\n");
1091 dpavlin 14 exit(1);
1092     }
1093 dpavlin 28
1094 dpavlin 24 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 dpavlin 28 #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 dpavlin 24 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 dpavlin 14 }
1123     #endif
1124     }
1125     #endif
1126    
1127    
1128 dpavlin 18 #ifdef DYNTRANS_INVALIDATE_TC
1129 dpavlin 14 /*
1130 dpavlin 18 * XXX_invalidate_translation_caches():
1131 dpavlin 14 *
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 dpavlin 22 * 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 dpavlin 14 * In the case when all translations are invalidated, paddr doesn't need
1143     * to be supplied.
1144     *
1145 dpavlin 18 * 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 dpavlin 14 */
1149 dpavlin 22 void DYNTRANS_INVALIDATE_TC(struct cpu *cpu, uint64_t addr, int flags)
1150 dpavlin 14 {
1151     int r;
1152     #ifdef MODE32
1153     uint32_t
1154     #else
1155     uint64_t
1156     #endif
1157 dpavlin 22 addr_page = addr & ~(DYNTRANS_PAGESIZE - 1);
1158 dpavlin 14
1159 dpavlin 20 /* fatal("invalidate(): "); */
1160    
1161 dpavlin 22 /* Quick case for _one_ virtual addresses: see note above. */
1162 dpavlin 18 if (flags & INVALIDATE_VADDR) {
1163 dpavlin 20 /* fatal("vaddr 0x%08x\n", (int)addr_page); */
1164 dpavlin 18 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, addr_page, flags);
1165     return;
1166     }
1167    
1168 dpavlin 22 /* 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 dpavlin 20 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 dpavlin 22 /* Invalidate a physical page: */
1199 dpavlin 20
1200 dpavlin 22 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 dpavlin 14 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
1206 dpavlin 22 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && addr_page
1207     == cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page) {
1208 dpavlin 14 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 dpavlin 18 #endif /* DYNTRANS_INVALIDATE_TC */
1221 dpavlin 14
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 dpavlin 18 #ifdef MODE32
1235 dpavlin 14 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 dpavlin 18 struct DYNTRANS_TC_PHYSPAGE *ppp, *prev_ppp;
1250 dpavlin 14
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 dpavlin 18 prev_ppp = ppp = NULL;
1258 dpavlin 14
1259     /* Traverse the physical page chain: */
1260     while (physpage_ofs != 0) {
1261 dpavlin 18 prev_ppp = ppp;
1262 dpavlin 14 ppp = (struct DYNTRANS_TC_PHYSPAGE *)
1263     (cpu->translation_cache + physpage_ofs);
1264 dpavlin 26
1265 dpavlin 14 /* If we found the page in the cache,
1266     then we're done: */
1267     if (ppp->physaddr == addr)
1268     break;
1269 dpavlin 26
1270 dpavlin 14 /* Try the next page in the chain: */
1271     physpage_ofs = ppp->next_ofs;
1272     }
1273    
1274 dpavlin 18 if (physpage_ofs == 0)
1275     ppp = NULL;
1276    
1277 dpavlin 28 #if 0
1278 dpavlin 18 /*
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 dpavlin 14 if (ppp != NULL) {
1286 dpavlin 18 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 dpavlin 28 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 dpavlin 14 #ifdef DYNTRANS_DUALMODE_32
1311 dpavlin 28 cpu->is_32bit?
1312     instr32(to_be_translated) :
1313 dpavlin 14 #endif
1314 dpavlin 28 instr(to_be_translated);
1315     }
1316    
1317     x >>= 1;
1318     }
1319    
1320     ppp->translations = 0;
1321 dpavlin 14 }
1322 dpavlin 18 #endif
1323 dpavlin 14 }
1324    
1325 dpavlin 26 /* Invalidate entries in the VPH table: */
1326     for (r = 0; r < DYNTRANS_MAX_VPH_TLB_ENTRIES; r ++) {
1327 dpavlin 14 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 dpavlin 18 uint32_t index =
1338     DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1339 dpavlin 14 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1340     #else
1341 dpavlin 24 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 dpavlin 14
1348 dpavlin 24 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 dpavlin 14 #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 dpavlin 32 int found, r, useraccess = 0;
1375 dpavlin 14
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 dpavlin 24 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 dpavlin 28
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 dpavlin 24 (uint64_t)paddr_page); */
1394 dpavlin 14 #endif
1395    
1396 dpavlin 26 assert((vaddr_page & (DYNTRANS_PAGESIZE-1)) == 0);
1397     assert((paddr_page & (DYNTRANS_PAGESIZE-1)) == 0);
1398    
1399 dpavlin 18 if (writeflag & MEMORY_USER_ACCESS) {
1400     writeflag &= ~MEMORY_USER_ACCESS;
1401     useraccess = 1;
1402     }
1403    
1404 dpavlin 14 /* Scan the current TLB entries: */
1405 dpavlin 18
1406     #ifdef MODE32
1407 dpavlin 20 /*
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 dpavlin 18 DYNTRANS_ADDR_TO_PAGENR(vaddr_page)] - 1;
1417 dpavlin 30 #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 dpavlin 20 if (found < 0) {
1436 dpavlin 32 /* Create the new TLB entry, overwriting a "random" entry: */
1437 dpavlin 20 static unsigned int x = 0;
1438 dpavlin 32 r = (x++) % DYNTRANS_MAX_VPH_TLB_ENTRIES;
1439 dpavlin 14
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 dpavlin 20 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag =
1452     writeflag & MEM_WRITE;
1453 dpavlin 14
1454     /* Add the new translation to the table: */
1455     #ifdef MODE32
1456 dpavlin 18 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1457 dpavlin 14 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 dpavlin 18 cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = r + 1;
1463     #ifdef DYNTRANS_ARM
1464     if (useraccess)
1465 dpavlin 20 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5]
1466     |= 1 << (index & 31);
1467 dpavlin 18 #endif
1468 dpavlin 24 #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 dpavlin 28 l2->refcount = 0;
1480 dpavlin 24 for (i=0; i<(1 << DYNTRANS_L2N); i++)
1481     l2->l3[i] = cpu->cd.DYNTRANS_ARCH.
1482     l3_64_dummy;
1483     }
1484 dpavlin 28 if (l2->refcount != 0) {
1485     fatal("Huh? l2 Refcount problem.\n");
1486     exit(1);
1487     }
1488 dpavlin 24 }
1489 dpavlin 28 if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) {
1490     fatal("INTERNAL ERROR L2 reuse\n");
1491     exit(1);
1492     }
1493 dpavlin 24 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 dpavlin 28 if (l3->refcount != 0) {
1504     fatal("Huh? l3 Refcount problem.\n");
1505     exit(1);
1506     }
1507 dpavlin 24 l2->refcount ++;
1508     }
1509 dpavlin 28 if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy) {
1510     fatal("INTERNAL ERROR L3 reuse\n");
1511     exit(1);
1512     }
1513    
1514 dpavlin 24 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 dpavlin 28
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 dpavlin 24 #endif /* !MODE32 */
1545 dpavlin 14 } 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 dpavlin 20 * Writeflag = MEM_DOWNGRADE: Downgrade to readonly.
1551 dpavlin 14 */
1552 dpavlin 18 r = found;
1553 dpavlin 20 if (writeflag & MEM_WRITE)
1554 dpavlin 14 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1;
1555 dpavlin 20 if (writeflag & MEM_DOWNGRADE)
1556 dpavlin 14 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 0;
1557     #ifdef MODE32
1558 dpavlin 18 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1559 dpavlin 14 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1560 dpavlin 18 #ifdef DYNTRANS_ARM
1561 dpavlin 20 cpu->cd.DYNTRANS_ARCH.is_userpage[index>>5] &= ~(1<<(index&31));
1562 dpavlin 18 if (useraccess)
1563 dpavlin 20 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5]
1564     |= 1 << (index & 31);
1565 dpavlin 18 #endif
1566 dpavlin 14 if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) {
1567 dpavlin 20 if (writeflag & MEM_WRITE)
1568 dpavlin 14 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1569     host_page;
1570 dpavlin 20 if (writeflag & MEM_DOWNGRADE)
1571 dpavlin 14 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 dpavlin 24 #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 dpavlin 28 printf("HOST LOAD 2 set to %p\n", host_page);
1594 dpavlin 24 l3->host_load[x3] = host_page;
1595     l3->host_store[x3] = writeflag? host_page : NULL;
1596     l3->phys_addr[x3] = paddr_page;
1597     }
1598 dpavlin 28
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 dpavlin 24 #endif /* !MODE32 */
1626 dpavlin 14 }
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 dpavlin 24 MODE_uint_t curpc = cpu->pc;
1640 dpavlin 14 int i;
1641     for (i=0; i<cpu->machine->n_breakpoints; i++)
1642 dpavlin 24 if (curpc == (MODE_uint_t)
1643 dpavlin 14 cpu->machine->breakpoint_addr[i]) {
1644     if (!cpu->machine->instruction_trace) {
1645     int old_quiet_mode = quiet_mode;
1646     quiet_mode = 0;
1647 dpavlin 24 DISASSEMBLE(cpu, ib, 1, 0);
1648 dpavlin 14 quiet_mode = old_quiet_mode;
1649     }
1650 dpavlin 24 fatal("BREAKPOINT: pc = 0x%"PRIx64"\n(The "
1651 dpavlin 14 "instruction has not yet executed.)\n",
1652 dpavlin 24 (uint64_t)cpu->pc);
1653 dpavlin 22 #ifdef DYNTRANS_DELAYSLOT
1654 dpavlin 24 if (cpu->delay_slot != NOT_DELAYED)
1655 dpavlin 22 fatal("ERROR! Breakpoint in a delay"
1656     " slot! Not yet supported.\n");
1657     #endif
1658 dpavlin 14 single_step_breakpoint = 1;
1659 dpavlin 26 single_step = ENTER_SINGLE_STEPPING;
1660 dpavlin 14 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 dpavlin 28 * 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 dpavlin 14 */
1674 dpavlin 28
1675 dpavlin 24 /* Make sure cur_physpage is in synch: */
1676     cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
1677     cpu->cd.DYNTRANS_ARCH.cur_ic_page;
1678 dpavlin 28
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 dpavlin 18 }
1687 dpavlin 14
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 dpavlin 24 * instruction combination. For architectures with delay slots,
1694     * we also ignore combinations if the delay slot is across a page
1695     * boundary.
1696 dpavlin 14 */
1697 dpavlin 24 if (!single_step && !cpu->machine->instruction_trace
1698     #ifdef DYNTRANS_DELAYSLOT
1699     && !in_crosspage_delayslot
1700     #endif
1701 dpavlin 30 && 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 dpavlin 18 }
1706 dpavlin 14
1707 dpavlin 24 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 dpavlin 14 /* ... and finally execute the translated instruction: */
1724 dpavlin 24 if ((single_step_breakpoint && cpu->delay_slot == NOT_DELAYED)
1725     #ifdef DYNTRANS_DELAYSLOT
1726     || in_crosspage_delayslot
1727     #endif
1728     ) {
1729 dpavlin 14 /*
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 dpavlin 24 #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
1736     cpu->cd.DYNTRANS_ARCH.next_ic = ic + ic->arg[0];
1737     #endif
1738 dpavlin 14 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 dpavlin 24 #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 dpavlin 14 ic->f(cpu, ic);
1760 dpavlin 24 }
1761 dpavlin 14
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 dpavlin 24 fatal(" at 0x%"PRIx32"\n", (uint32_t)cpu->pc);
1775 dpavlin 14 #else
1776 dpavlin 24 fatal(" at 0x%"PRIx64"\n", (uint64_t)cpu->pc);
1777 dpavlin 14 #endif
1778     else {
1779     fatal(":\n");
1780 dpavlin 24 DISASSEMBLE(cpu, ib, 1, 0);
1781 dpavlin 14 }
1782    
1783     cpu->running = 0;
1784 dpavlin 30
1785     /* Note: Single-stepping can jump here. */
1786 dpavlin 14 stop_running_translated:
1787 dpavlin 30
1788 dpavlin 14 debugger_n_steps_left_before_interaction = 0;
1789 dpavlin 30
1790 dpavlin 14 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 dpavlin 30
1796 dpavlin 14 #endif /* DYNTRANS_TO_BE_TRANSLATED_TAIL */
1797    

  ViewVC Help
Powered by ViewVC 1.1.26