/[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 14 - (show annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 31309 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

1 /*
2 * Copyright (C) 2005 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.19 2005/10/07 22:10:51 debug Exp $
29 *
30 * Common dyntrans routines. Included from cpu_*.c.
31 */
32
33
34 #ifdef DYNTRANS_CPU_RUN_INSTR
35 /*
36 * XXX_cpu_run_instr():
37 *
38 * Execute one or more instructions on a specific CPU, using dyntrans.
39 *
40 * Return value is the number of instructions executed during this call,
41 * 0 if no instructions were executed.
42 */
43 int DYNTRANS_CPU_RUN_INSTR(struct emul *emul, struct cpu *cpu)
44 {
45 #ifdef MODE32
46 uint32_t cached_pc;
47 #else
48 uint64_t cached_pc;
49 #endif
50 int low_pc, n_instrs;
51
52 #ifdef DYNTRANS_DUALMODE_32
53 if (cpu->is_32bit)
54 DYNTRANS_PC_TO_POINTERS32(cpu);
55 else
56 #endif
57 DYNTRANS_PC_TO_POINTERS(cpu);
58
59 /*
60 * Interrupt assertion? (This is _below_ the initial PC to pointer
61 * conversion; if the conversion caused an exception of some kind
62 * then interrupts are probably disabled, and the exception will get
63 * priority over device interrupts.)
64 */
65 #ifdef DYNTRANS_ARM
66 if (cpu->cd.arm.irq_asserted && !(cpu->cd.arm.cpsr & ARM_FLAG_I))
67 arm_exception(cpu, ARM_EXCEPTION_IRQ);
68 #endif
69
70 cached_pc = cpu->pc;
71
72 cpu->n_translated_instrs = 0;
73 cpu->running_translated = 1;
74
75 if (single_step || cpu->machine->instruction_trace) {
76 /*
77 * Single-step:
78 */
79 struct DYNTRANS_IC *ic = cpu->cd.DYNTRANS_ARCH.next_ic
80 #ifndef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
81 ++
82 #endif
83 ;
84 if (cpu->machine->instruction_trace) {
85 #ifdef DYNTRANS_X86
86 unsigned char instr[17];
87 cpu->cd.x86.cursegment = X86_S_CS;
88 cpu->cd.x86.seg_override = 0;
89 #else
90 #ifdef DYNTRANS_M68K
91 unsigned char instr[16]; /* TODO: 16? */
92 #else
93 unsigned char instr[4]; /* General case... */
94 #endif
95 #endif
96 if (!cpu->memory_rw(cpu, cpu->mem, cached_pc, &instr[0],
97 sizeof(instr), MEM_READ, CACHE_INSTRUCTION)) {
98 fatal("XXX_cpu_run_instr(): could not read "
99 "the instruction\n");
100 } else
101 cpu_disassemble_instr(cpu->machine, cpu,
102 instr, 1, 0, 0);
103 }
104
105 /* When single-stepping, multiple instruction calls cannot
106 be combined into one. This clears all translations: */
107 if (cpu->cd.DYNTRANS_ARCH.cur_physpage->flags & COMBINATIONS) {
108 int i;
109 for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
110 cpu->cd.DYNTRANS_ARCH.cur_physpage->ics[i].f =
111 #ifdef DYNTRANS_DUALMODE_32
112 cpu->is_32bit?
113 instr32(to_be_translated) :
114 #endif
115 instr(to_be_translated);
116 fatal("[ Note: The translation of physical page 0x%llx"
117 " contained combinations of instructions; these "
118 "are now flushed because we are single-stepping."
119 " ]\n", (long long)cpu->cd.DYNTRANS_ARCH.
120 cur_physpage->physaddr);
121 cpu->cd.DYNTRANS_ARCH.cur_physpage->flags &=
122 ~(COMBINATIONS | TRANSLATIONS);
123 }
124
125 /* Execute just one instruction: */
126 ic->f(cpu, ic);
127 n_instrs = 1;
128 } else {
129 /* Execute multiple instructions: */
130 n_instrs = 0;
131 for (;;) {
132 struct DYNTRANS_IC *ic;
133
134 #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
135 #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic; ic->f(cpu, ic);
136 #else
137 #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic);
138 #endif
139
140 I; I; I; I; I; I; I; I; I; I;
141 I; I; I; I; I; I; I; I; I; I;
142 I; I; I; I; I; I; I; I; I; I;
143 I; I; I; I; I; I; I; I; I; I;
144 I; I; I; I; I; I; I; I; I; I;
145
146 I; I; I; I; I; I; I; I; I; I;
147 I; I; I; I; I; I; I; I; I; I;
148 I; I; I; I; I; I; I; I; I; I;
149 I; I; I; I; I; I; I; I; I; I;
150 I; I; I; I; I; I; I; I; I; I;
151
152 I; I; I; I; I; I; I; I; I; I;
153 I; I; I; I; I; I; I; I; I; I;
154
155 n_instrs += 120;
156
157 if (!cpu->running_translated ||
158 n_instrs + cpu->n_translated_instrs >= 16384)
159 break;
160 }
161 }
162
163
164 /*
165 * Update the program counter and return the correct number of
166 * executed instructions:
167 */
168 low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t)
169 cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC);
170
171 if (low_pc >= 0 && low_pc < DYNTRANS_IC_ENTRIES_PER_PAGE) {
172 #ifdef DYNTRANS_ARM
173 cpu->cd.arm.r[ARM_PC] &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1)<<2);
174 cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
175 cpu->pc = cpu->cd.arm.r[ARM_PC];
176 #else
177 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
178 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
179 cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT);
180 #endif
181 } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE) {
182 /* Switch to next page: */
183 #ifdef DYNTRANS_ARM
184 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << 2);
185 cpu->cd.arm.r[ARM_PC] += (ARM_IC_ENTRIES_PER_PAGE << 2);
186 cpu->pc = cpu->cd.arm.r[ARM_PC];
187 #else
188 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
189 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
190 cpu->pc += (DYNTRANS_IC_ENTRIES_PER_PAGE <<
191 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
192 #endif
193 } else {
194 /* debug("debug: Outside a page (This is actually ok)\n"); */
195 }
196
197 return n_instrs + cpu->n_translated_instrs;
198 }
199 #endif /* DYNTRANS_CPU_RUN_INSTR */
200
201
202
203 #ifdef DYNTRANS_FUNCTION_TRACE
204 /*
205 * XXX_cpu_functioncall_trace():
206 *
207 * Without this function, the main trace tree function prints something
208 * like <f()> or <0x1234()> on a function call. It is up to this
209 * function to print the arguments passed.
210 */
211 void DYNTRANS_FUNCTION_TRACE(struct cpu *cpu, uint64_t f, int n_args)
212 {
213 char strbuf[50];
214 char *symbol;
215 uint64_t ot;
216 int x, print_dots = 1, n_args_to_print =
217 #ifdef DYNTRANS_ALPHA
218 6
219 #else
220 #ifdef DYNTRANS_SH
221 8
222 #else
223 4 /* Default value for most archs */
224 #endif
225 #endif
226 ;
227
228 if (n_args >= 0 && n_args <= n_args_to_print) {
229 print_dots = 0;
230 n_args_to_print = n_args;
231 }
232
233 /*
234 * TODO: The type of each argument should be taken from the symbol
235 * table, in some way.
236 *
237 * The code here does a kind of "heuristic guess" regarding what the
238 * argument values might mean. Sometimes the output looks weird, but
239 * usually it looks good enough.
240 *
241 * Print ".." afterwards to show that there might be more arguments
242 * than were passed in register.
243 */
244 for (x=0; x<n_args_to_print; x++) {
245 int64_t d;
246 #ifdef DYNTRANS_X86
247 d = 0; /* TODO */
248 #else
249 /* Args in registers: */
250 d = cpu->cd.DYNTRANS_ARCH.
251 #ifdef DYNTRANS_ALPHA
252 r[ALPHA_A0
253 #endif
254 #ifdef DYNTRANS_ARM
255 r[0
256 #endif
257 #ifdef DYNTRANS_AVR
258 /* TODO: 24,25 = first register, but then
259 they go downwards, ie. 22,23 and so on */
260 r[24
261 #endif
262 #ifdef DYNTRANS_HPPA
263 r[0 /* TODO */
264 #endif
265 #ifdef DYNTRANS_I960
266 r[0 /* TODO */
267 #endif
268 #ifdef DYNTRANS_IA64
269 r[0 /* TODO */
270 #endif
271 #ifdef DYNTRANS_M68K
272 d[0 /* TODO */
273 #endif
274 #ifdef DYNTRANS_MIPS
275 gpr[MIPS_GPR_A0
276 #endif
277 #ifdef DYNTRANS_PPC
278 gpr[3
279 #endif
280 #ifdef DYNTRANS_SH
281 r[2
282 #endif
283 #ifdef DYNTRANS_SPARC
284 r_i[0
285 #endif
286 + x];
287 #endif
288 symbol = get_symbol_name(&cpu->machine->symbol_context, d, &ot);
289
290 if (d > -256 && d < 256)
291 fatal("%i", (int)d);
292 else if (memory_points_to_string(cpu, cpu->mem, d, 1))
293 fatal("\"%s\"", memory_conv_to_string(cpu,
294 cpu->mem, d, strbuf, sizeof(strbuf)));
295 else if (symbol != NULL && ot == 0)
296 fatal("&%s", symbol);
297 else {
298 if (cpu->is_32bit)
299 fatal("0x%x", (int)d);
300 else
301 fatal("0x%llx", (long long)d);
302 }
303
304 if (x < n_args_to_print - 1)
305 fatal(",");
306 }
307
308 if (print_dots)
309 fatal(",..");
310 }
311 #endif
312
313
314
315 #ifdef DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE
316 /* forward declaration of to_be_translated and end_of_page: */
317 static void instr(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
318 static void instr(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
319 #ifdef DYNTRANS_DUALMODE_32
320 static void instr32(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
321 static void instr32(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
322 #endif
323 /*
324 * XXX_tc_allocate_default_page():
325 *
326 * Create a default page (with just pointers to instr(to_be_translated)
327 * at cpu->translation_cache_cur_ofs.
328 */
329 static void DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE(struct cpu *cpu,
330 uint64_t physaddr)
331 {
332 struct DYNTRANS_TC_PHYSPAGE *ppp;
333 int i;
334
335 /* Create the physpage header: */
336 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
337 + cpu->translation_cache_cur_ofs);
338 ppp->next_ofs = 0;
339 ppp->physaddr = physaddr;
340
341 /* TODO: Is this faster than copying an entire template page? */
342 for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
343 ppp->ics[i].f =
344 #ifdef DYNTRANS_DUALMODE_32
345 cpu->is_32bit? instr32(to_be_translated) :
346 #endif
347 instr(to_be_translated);
348
349 ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE].f =
350 #ifdef DYNTRANS_DUALMODE_32
351 cpu->is_32bit? instr32(end_of_page) :
352 #endif
353 instr(end_of_page);
354
355 cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE);
356 }
357 #endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE */
358
359
360
361 #ifdef DYNTRANS_PC_TO_POINTERS_FUNC
362 /*
363 * XXX_pc_to_pointers_generic():
364 *
365 * Generic case. See DYNTRANS_PC_TO_POINTERS_FUNC below.
366 */
367 void DYNTRANS_PC_TO_POINTERS_GENERIC(struct cpu *cpu)
368 {
369 #ifdef MODE32
370 uint32_t
371 #else
372 uint64_t
373 #endif
374 cached_pc, physaddr;
375 uint32_t physpage_ofs;
376 int ok, pagenr, table_index;
377 uint32_t *physpage_entryp;
378 struct DYNTRANS_TC_PHYSPAGE *ppp;
379
380 #ifdef MODE32
381 int index;
382 cached_pc = cpu->pc;
383 index = cached_pc >> 12;
384 #else
385 #ifdef DYNTRANS_ALPHA
386 uint32_t a, b;
387 int kernel = 0;
388 struct alpha_vph_page *vph_p;
389 cached_pc = cpu->pc;
390 a = (cached_pc >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
391 b = (cached_pc >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
392 if ((cached_pc >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
393 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
394 kernel = 1;
395 } else
396 vph_p = cpu->cd.alpha.vph_table0[a];
397 #else
398 #ifdef DYNTRANS_IA64
399 fatal("IA64 todo\n");
400 #else
401 fatal("Neither alpha, ia64, nor 32-bit? 3\n");
402 exit(1);
403 #endif
404 #endif
405 #endif
406
407 /* Virtual to physical address translation: */
408 ok = 0;
409 #ifdef MODE32
410 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL) {
411 physaddr = cpu->cd.DYNTRANS_ARCH.phys_addr[index];
412 ok = 1;
413 }
414 #else
415 #ifdef DYNTRANS_ALPHA
416 if (vph_p->host_load[b] != NULL) {
417 physaddr = vph_p->phys_addr[b];
418 ok = 1;
419 }
420 #else
421 #ifdef DYNTRANS_IA64
422 fatal("IA64 todo\n");
423 #else
424 fatal("Neither alpha, ia64, nor 32-bit? 4\n");
425 exit(1);
426 #endif
427 #endif
428 #endif
429
430 if (!ok) {
431 uint64_t paddr;
432 if (cpu->translate_address != NULL)
433 ok = cpu->translate_address(cpu, cached_pc,
434 &paddr, FLAG_INSTR);
435 else {
436 paddr = cached_pc;
437 ok = 1;
438 }
439 if (!ok) {
440 /*
441 fatal("TODO: instruction vaddr=>paddr translation"
442 " failed. vaddr=0x%llx\n", (long long)cached_pc);
443 fatal("!! cpu->pc=0x%llx arm_pc=0x%x\n", (long long)cpu->pc,
444 cpu->cd.arm.r[ARM_PC]);
445 */
446 ok = cpu->translate_address(cpu, cpu->pc, &paddr,
447 FLAG_INSTR);
448 /*
449 printf("EXCEPTION HANDLER: vaddr = 0x%x ==> paddr = 0x%x\n",
450 (int)cpu->pc, (int)paddr);
451 fatal("!? cpu->pc=0x%llx arm_pc=0x%x\n", (long long)cpu->pc,
452 cpu->cd.arm.r[ARM_PC]);
453 */
454 if (!ok) {
455 fatal("FATAL: could not find physical"
456 " address of the exception handler?");
457 exit(1);
458 }
459 }
460 cached_pc = cpu->pc;
461 physaddr = paddr;
462 }
463
464 if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE)
465 cpu_create_or_reset_tc(cpu);
466
467 pagenr = DYNTRANS_ADDR_TO_PAGENR(physaddr);
468 table_index = PAGENR_TO_TABLE_INDEX(pagenr);
469
470 physpage_entryp = &(((uint32_t *)cpu->translation_cache)[table_index]);
471 physpage_ofs = *physpage_entryp;
472 ppp = NULL;
473
474 /* Traverse the physical page chain: */
475 while (physpage_ofs != 0) {
476 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
477 + physpage_ofs);
478 /* If we found the page in the cache, then we're done: */
479 if (ppp->physaddr == physaddr)
480 break;
481 /* Try the next page in the chain: */
482 physpage_ofs = ppp->next_ofs;
483 }
484
485 /* If the offset is 0 (or ppp is NULL), then we need to create a
486 new "default" empty translation page. */
487
488 if (ppp == NULL) {
489 /* fatal("CREATING page %lli (physaddr 0x%llx), table index "
490 "%i\n", (long long)pagenr, (long long)physaddr,
491 (int)table_index); */
492 *physpage_entryp = physpage_ofs =
493 cpu->translation_cache_cur_ofs;
494
495 /* Allocate a default page, with to_be_translated entries: */
496 DYNTRANS_TC_ALLOCATE(cpu, physaddr);
497
498 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
499 + physpage_ofs);
500 }
501
502 #ifdef MODE32
503 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL)
504 cpu->cd.DYNTRANS_ARCH.phys_page[index] = ppp;
505 #endif
506
507 #ifdef DYNTRANS_ALPHA
508 if (vph_p->host_load[b] != NULL)
509 vph_p->phys_page[b] = ppp;
510 #endif
511
512 cpu->invalidate_translation_caches_paddr(cpu, physaddr,
513 JUST_MARK_AS_NON_WRITABLE);
514
515 cpu->cd.DYNTRANS_ARCH.cur_physpage = ppp;
516 cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
517 cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
518 DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
519
520 /* printf("cached_pc=0x%016llx pagenr=%lli table_index=%lli, "
521 "physpage_ofs=0x%016llx\n", (long long)cached_pc, (long long)pagenr,
522 (long long)table_index, (long long)physpage_ofs); */
523 }
524
525
526 /*
527 * XXX_pc_to_pointers():
528 *
529 * This function uses the current program counter (a virtual address) to
530 * find out which physical translation page to use, and then sets the current
531 * translation page pointers to that page.
532 *
533 * If there was no translation page for that physical page, then an empty
534 * one is created.
535 *
536 * NOTE: This is the quick lookup version. See
537 * DYNTRANS_PC_TO_POINTERS_GENERIC above for the generic case.
538 */
539 void DYNTRANS_PC_TO_POINTERS_FUNC(struct cpu *cpu)
540 {
541 #ifdef MODE32
542 uint32_t
543 #else
544 uint64_t
545 #endif
546 cached_pc;
547 struct DYNTRANS_TC_PHYSPAGE *ppp;
548
549 #ifdef MODE32
550 int index;
551 cached_pc = cpu->pc;
552 index = cached_pc >> 12;
553 ppp = cpu->cd.DYNTRANS_ARCH.phys_page[index];
554 if (ppp != NULL)
555 goto have_it;
556 #else
557 #ifdef DYNTRANS_ALPHA
558 uint32_t a, b;
559 int kernel = 0;
560 struct alpha_vph_page *vph_p;
561 cached_pc = cpu->pc;
562 a = (cached_pc >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
563 b = (cached_pc >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
564 if ((cached_pc >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
565 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
566 kernel = 1;
567 } else
568 vph_p = cpu->cd.alpha.vph_table0[a];
569 if (vph_p != cpu->cd.alpha.vph_default_page) {
570 ppp = vph_p->phys_page[b];
571 if (ppp != NULL)
572 goto have_it;
573 }
574 #else
575 #ifdef DYNTRANS_IA64
576 fatal("IA64 todo\n");
577 #else
578 fatal("Neither alpha, ia64, nor 32-bit? 1\n");
579 { char *p = (char *) 0; *p = 0; }
580 exit(1);
581 #endif
582 #endif
583 #endif
584
585 DYNTRANS_PC_TO_POINTERS_GENERIC(cpu);
586 return;
587
588 /* Quick return path: */
589 have_it:
590 cpu->cd.DYNTRANS_ARCH.cur_physpage = ppp;
591 cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
592 cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
593 DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
594
595 /* printf("cached_pc=0x%016llx pagenr=%lli table_index=%lli, "
596 "physpage_ofs=0x%016llx\n", (long long)cached_pc, (long long)pagenr,
597 (long long)table_index, (long long)physpage_ofs); */
598 }
599 #endif /* DYNTRANS_PC_TO_POINTERS_FUNC */
600
601
602
603 #ifdef DYNTRANS_INVAL_ENTRY
604 /*
605 * XXX_invalidate_tlb_entry():
606 *
607 * Invalidate one translation entry (based on virtual address).
608 *
609 * If the JUST_MARK_AS_NON_WRITABLE flag is set, then the translation entry
610 * is just downgraded to non-writable (ie the host store page is set to
611 * NULL). Otherwise, the entire translation is removed.
612 */
613 void DYNTRANS_INVALIDATE_TLB_ENTRY(struct cpu *cpu,
614 #ifdef MODE32
615 uint32_t
616 #else
617 uint64_t
618 #endif
619 vaddr_page, int flags)
620 {
621 #ifdef MODE32
622 uint32_t index = vaddr_page >> 12;
623
624 if (flags & JUST_MARK_AS_NON_WRITABLE) {
625 /* printf("JUST MARKING NON-W: vaddr 0x%08x\n",
626 (int)vaddr_page); */
627 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
628 } else {
629 cpu->cd.DYNTRANS_ARCH.host_load[index] = NULL;
630 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
631 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = 0;
632 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
633 }
634 #else
635 /* 2-level: */
636 #ifdef DYNTRANS_ALPHA
637 struct alpha_vph_page *vph_p;
638 uint32_t a, b;
639 int kernel = 0;
640
641 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
642 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
643 if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
644 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
645 kernel = 1;
646 } else
647 vph_p = cpu->cd.alpha.vph_table0[a];
648
649 if (vph_p == cpu->cd.alpha.vph_default_page) {
650 fatal("alpha_invalidate_tlb_entry(): huh? Problem 1.\n");
651 exit(1);
652 }
653
654 if (flags & JUST_MARK_AS_NON_WRITABLE) {
655 vph_p->host_store[b] = NULL;
656 return;
657 }
658 vph_p->host_load[b] = NULL;
659 vph_p->host_store[b] = NULL;
660 vph_p->phys_addr[b] = 0;
661 vph_p->phys_page[b] = NULL;
662 vph_p->refcount --;
663 if (vph_p->refcount < 0) {
664 fatal("alpha_invalidate_tlb_entry(): huh? Problem 2.\n");
665 exit(1);
666 }
667 if (vph_p->refcount == 0) {
668 vph_p->next = cpu->cd.alpha.vph_next_free_page;
669 cpu->cd.alpha.vph_next_free_page = vph_p;
670 if (kernel)
671 cpu->cd.alpha.vph_table0_kernel[a] =
672 cpu->cd.alpha.vph_default_page;
673 else
674 cpu->cd.alpha.vph_table0[a] =
675 cpu->cd.alpha.vph_default_page;
676 }
677 #else /* !DYNTRANS_ALPHA */
678 #ifdef DYNTRANS_IA64
679 fatal("IA64: blah blah TODO\n");
680 #else
681 fatal("Not yet for non-1-level, non-Alpha, non-ia64\n");
682 #endif /* !DYNTRANS_IA64 */
683 #endif /* !DYNTRANS_ALPHA */
684 #endif
685 }
686 #endif
687
688
689 #ifdef DYNTRANS_INVALIDATE_TC_PADDR
690 /*
691 * XXX_invalidate_translation_caches_paddr():
692 *
693 * Invalidate all entries matching a specific physical address, a specific
694 * virtual address, or ALL entries.
695 *
696 * flags should be one of
697 * INVALIDATE_PADDR INVALIDATE_VADDR or INVALIDATE_ALL
698 *
699 * In the case when all translations are invalidated, paddr doesn't need
700 * to be supplied.
701 *
702 * NOTE/TODO: Poorly choosen name for this function, as it can
703 * invalidate based on virtual address as well.
704 */
705 void DYNTRANS_INVALIDATE_TC_PADDR(struct cpu *cpu, uint64_t paddr, int flags)
706 {
707 int r;
708 #ifdef MODE32
709 uint32_t
710 #else
711 uint64_t
712 #endif
713 addr_page = paddr & ~(DYNTRANS_PAGESIZE - 1);
714
715 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
716 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && (
717 (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page ==
718 addr_page && flags & INVALIDATE_PADDR) ||
719 (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page ==
720 addr_page && flags & INVALIDATE_VADDR) ||
721 flags & INVALIDATE_ALL) ) {
722 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
723 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
724 flags);
725 if (flags & JUST_MARK_AS_NON_WRITABLE)
726 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
727 .writeflag = 0;
728 else
729 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
730 .valid = 0;
731 }
732 }
733 }
734 #endif /* DYNTRANS_INVALIDATE_TC_PADDR */
735
736
737
738 #ifdef DYNTRANS_INVALIDATE_TC_CODE
739 /*
740 * XXX_invalidate_code_translation():
741 *
742 * Invalidate code translations for a specific physical address, a specific
743 * virtual address, or for all entries in the cache.
744 */
745 void DYNTRANS_INVALIDATE_TC_CODE(struct cpu *cpu, uint64_t addr, int flags)
746 {
747 int r;
748 #ifdef MODE_32
749 uint32_t
750 #else
751 uint64_t
752 #endif
753 vaddr_page, paddr_page;
754
755 addr &= ~(DYNTRANS_PAGESIZE-1);
756
757 /* printf("DYNTRANS_INVALIDATE_TC_CODE addr=0x%08x flags=%i\n",
758 (int)addr, flags); */
759
760 if (flags & INVALIDATE_PADDR) {
761 int pagenr, table_index;
762 uint32_t physpage_ofs, *physpage_entryp;
763 struct DYNTRANS_TC_PHYSPAGE *ppp;
764
765 pagenr = DYNTRANS_ADDR_TO_PAGENR(addr);
766 table_index = PAGENR_TO_TABLE_INDEX(pagenr);
767
768 physpage_entryp = &(((uint32_t *)cpu->
769 translation_cache)[table_index]);
770 physpage_ofs = *physpage_entryp;
771 ppp = NULL;
772
773 /* Traverse the physical page chain: */
774 while (physpage_ofs != 0) {
775 ppp = (struct DYNTRANS_TC_PHYSPAGE *)
776 (cpu->translation_cache + physpage_ofs);
777 /* If we found the page in the cache,
778 then we're done: */
779 if (ppp->physaddr == addr)
780 break;
781 /* Try the next page in the chain: */
782 physpage_ofs = ppp->next_ofs;
783 }
784
785 /* If the page was found, then we should invalidate all
786 code translations: */
787 if (ppp != NULL) {
788 /* TODO: Is this faster than copying an entire
789 template page? */
790 int i;
791 for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
792 ppp->ics[i].f =
793 #ifdef DYNTRANS_DUALMODE_32
794 cpu->is_32bit? instr32(to_be_translated) :
795 #endif
796 instr(to_be_translated);
797 }
798 }
799
800 /* Invalidate entries in the VPH table: */
801 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
802 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
803 vaddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
804 .vaddr_page & ~(DYNTRANS_PAGESIZE-1);
805 paddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
806 .paddr_page & ~(DYNTRANS_PAGESIZE-1);
807
808 if (flags & INVALIDATE_ALL ||
809 (flags & INVALIDATE_PADDR && paddr_page == addr) ||
810 (flags & INVALIDATE_VADDR && vaddr_page == addr)) {
811 #ifdef MODE32
812 uint32_t index = vaddr_page >> 12;
813 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
814 #else
815 /* 2-level: */
816 #ifdef DYNTRANS_ALPHA
817 struct alpha_vph_page *vph_p;
818 uint32_t a, b;
819 int kernel = 0;
820
821 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT)
822 & (ALPHA_LEVEL0 - 1);
823 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT)
824 & (ALPHA_LEVEL1 - 1);
825 if ((vaddr_page >> ALPHA_TOPSHIFT) ==
826 ALPHA_TOP_KERNEL) {
827 vph_p = cpu->cd.alpha.
828 vph_table0_kernel[a];
829 kernel = 1;
830 } else
831 vph_p = cpu->cd.alpha.vph_table0[a];
832 vph_p->phys_page[b] = NULL;
833 #else /* !DYNTRANS_ALPHA */
834 #ifdef DYNTRANS_IA64
835 fatal("IA64: blah yo yo TODO\n");
836 #else
837 fatal("Not yet for non-1-level, non-Alpha, "
838 "non-ia64\n");
839 #endif /* !DYNTRANS_IA64 */
840 #endif /* !DYNTRANS_ALPHA */
841 #endif
842 }
843 }
844 }
845 }
846 #endif /* DYNTRANS_INVALIDATE_TC_CODE */
847
848
849
850 #ifdef DYNTRANS_UPDATE_TRANSLATION_TABLE
851 /*
852 * XXX_update_translation_table():
853 *
854 * Update the virtual memory translation tables.
855 */
856 void DYNTRANS_UPDATE_TRANSLATION_TABLE(struct cpu *cpu, uint64_t vaddr_page,
857 unsigned char *host_page, int writeflag, uint64_t paddr_page)
858 {
859 int64_t lowest, highest = -1;
860 int found, r, lowest_index;
861
862 #ifdef DYNTRANS_ALPHA
863 uint32_t a, b;
864 struct alpha_vph_page *vph_p;
865 int kernel = 0;
866 /* fatal("update_translation_table(): v=0x%llx, h=%p w=%i"
867 " p=0x%llx\n", (long long)vaddr_page, host_page, writeflag,
868 (long long)paddr_page); */
869 #else
870 #ifdef MODE32
871 uint32_t index;
872 vaddr_page &= 0xffffffffULL;
873 paddr_page &= 0xffffffffULL;
874 /* fatal("update_translation_table(): v=0x%x, h=%p w=%i"
875 " p=0x%x\n", (int)vaddr_page, host_page, writeflag,
876 (int)paddr_page); */
877 #else /* !MODE32 */
878 #ifdef DYNTRANS_IA64
879 fatal("IA64 update todo\n");
880 #else
881 fatal("Neither 32-bit, IA64, nor Alpha? 2\n");
882 exit(1);
883 #endif
884 #endif
885 #endif
886
887 /* Scan the current TLB entries: */
888 found = -1; lowest_index = 0;
889 lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp;
890 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
891 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp < lowest) {
892 lowest = cpu->cd.DYNTRANS_ARCH.
893 vph_tlb_entry[r].timestamp;
894 lowest_index = r;
895 }
896 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp > highest)
897 highest = cpu->cd.DYNTRANS_ARCH.
898 vph_tlb_entry[r].timestamp;
899 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid &&
900 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page ==
901 vaddr_page) {
902 found = r;
903 break;
904 }
905 }
906
907 if (found < 0) {
908 /* Create the new TLB entry, overwriting the oldest one: */
909 r = lowest_index;
910 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
911 /* This one has to be invalidated first: */
912 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
913 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
914 0);
915 }
916
917 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid = 1;
918 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].host_page = host_page;
919 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page = paddr_page;
920 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page = vaddr_page;
921 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = writeflag;
922 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1;
923
924 /* Add the new translation to the table: */
925 #ifdef DYNTRANS_ALPHA
926 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
927 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
928 if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
929 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
930 kernel = 1;
931 } else
932 vph_p = cpu->cd.alpha.vph_table0[a];
933 if (vph_p == cpu->cd.alpha.vph_default_page) {
934 if (cpu->cd.alpha.vph_next_free_page != NULL) {
935 if (kernel)
936 vph_p = cpu->cd.alpha.vph_table0_kernel
937 [a] = cpu->cd.alpha.
938 vph_next_free_page;
939 else
940 vph_p = cpu->cd.alpha.vph_table0[a] =
941 cpu->cd.alpha.vph_next_free_page;
942 cpu->cd.alpha.vph_next_free_page = vph_p->next;
943 } else {
944 if (kernel)
945 vph_p = cpu->cd.alpha.vph_table0_kernel
946 [a] = malloc(sizeof(struct
947 alpha_vph_page));
948 else
949 vph_p = cpu->cd.alpha.vph_table0[a] =
950 malloc(sizeof(struct
951 alpha_vph_page));
952 memset(vph_p, 0, sizeof(struct alpha_vph_page));
953 }
954 }
955 vph_p->refcount ++;
956 vph_p->host_load[b] = host_page;
957 vph_p->host_store[b] = writeflag? host_page : NULL;
958 vph_p->phys_addr[b] = paddr_page;
959 vph_p->phys_page[b] = NULL;
960 #else
961 #ifdef MODE32
962 index = vaddr_page >> 12;
963 cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
964 cpu->cd.DYNTRANS_ARCH.host_store[index] =
965 writeflag? host_page : NULL;
966 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
967 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
968 #endif /* 32 */
969 #endif /* !ALPHA */
970 } else {
971 /*
972 * The translation was already in the TLB.
973 * Writeflag = 0: Do nothing.
974 * Writeflag = 1: Make sure the page is writable.
975 * Writeflag = -1: Downgrade to readonly.
976 */
977 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[found].timestamp =
978 highest + 1;
979 if (writeflag == 1)
980 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1;
981 if (writeflag == -1)
982 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 0;
983 #ifdef DYNTRANS_ALPHA
984 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
985 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
986 if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
987 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
988 kernel = 1;
989 } else
990 vph_p = cpu->cd.alpha.vph_table0[a];
991 vph_p->phys_page[b] = NULL;
992 if (vph_p->phys_addr[b] == paddr_page) {
993 if (writeflag == 1)
994 vph_p->host_store[b] = host_page;
995 if (writeflag == -1)
996 vph_p->host_store[b] = NULL;
997 } else {
998 /* Change the entire physical/host mapping: */
999 vph_p->host_load[b] = host_page;
1000 vph_p->host_store[b] = writeflag? host_page : NULL;
1001 vph_p->phys_addr[b] = paddr_page;
1002 }
1003 #else
1004 #ifdef MODE32
1005 index = vaddr_page >> 12;
1006 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1007 if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) {
1008 if (writeflag == 1)
1009 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1010 host_page;
1011 if (writeflag == -1)
1012 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
1013 } else {
1014 /* Change the entire physical/host mapping: */
1015 cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
1016 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1017 writeflag? host_page : NULL;
1018 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
1019 }
1020 #endif /* 32 */
1021 #endif /* !ALPHA */
1022 }
1023 }
1024 #endif /* DYNTRANS_UPDATE_TRANSLATION_TABLE */
1025
1026
1027 /*****************************************************************************/
1028
1029
1030 #ifdef DYNTRANS_TO_BE_TRANSLATED_HEAD
1031 /*
1032 * Check for breakpoints.
1033 */
1034 if (!single_step_breakpoint) {
1035 #ifdef MODE32
1036 uint32_t curpc = cpu->pc;
1037 #else
1038 uint64_t curpc = cpu->pc;
1039 #endif
1040 int i;
1041 for (i=0; i<cpu->machine->n_breakpoints; i++)
1042 if (curpc ==
1043 #ifdef MODE32
1044 (uint32_t)
1045 #endif
1046 cpu->machine->breakpoint_addr[i]) {
1047 if (!cpu->machine->instruction_trace) {
1048 int old_quiet_mode = quiet_mode;
1049 quiet_mode = 0;
1050 DISASSEMBLE(cpu, ib, 1, 0, 0);
1051 quiet_mode = old_quiet_mode;
1052 }
1053 fatal("BREAKPOINT: pc = 0x%llx\n(The "
1054 "instruction has not yet executed.)\n",
1055 (long long)cpu->pc);
1056 single_step_breakpoint = 1;
1057 single_step = 1;
1058 goto stop_running_translated;
1059 }
1060 }
1061 #endif /* DYNTRANS_TO_BE_TRANSLATED_HEAD */
1062
1063
1064 /*****************************************************************************/
1065
1066
1067 #ifdef DYNTRANS_TO_BE_TRANSLATED_TAIL
1068 /*
1069 * If we end up here, then an instruction was translated.
1070 */
1071 translated;
1072
1073 /*
1074 * Now it is time to check for combinations of instructions that can
1075 * be converted into a single function call.
1076 *
1077 * Note: Single-stepping or instruction tracing doesn't work with
1078 * instruction combination.
1079 */
1080 if (!single_step && !cpu->machine->instruction_trace)
1081 COMBINE_INSTRUCTIONS(cpu, ic, addr);
1082
1083 /* ... and finally execute the translated instruction: */
1084 if (single_step_breakpoint) {
1085 /*
1086 * Special case when single-stepping: Execute the translated
1087 * instruction, but then replace it with a "to be translated"
1088 * directly afterwards.
1089 */
1090 single_step_breakpoint = 0;
1091 ic->f(cpu, ic);
1092 ic->f =
1093 #ifdef DYNTRANS_DUALMODE_32
1094 cpu->is_32bit? instr32(to_be_translated) :
1095 #endif
1096 instr(to_be_translated);
1097 } else
1098 ic->f(cpu, ic);
1099
1100 return;
1101
1102
1103 bad: /*
1104 * Nothing was translated. (Unimplemented or illegal instruction.)
1105 */
1106
1107 quiet_mode = 0;
1108 fatal("to_be_translated(): TODO: unimplemented instruction");
1109
1110 if (cpu->machine->instruction_trace)
1111 #ifdef MODE32
1112 fatal(" at 0x%x\n", (int)cpu->pc);
1113 #else
1114 fatal(" at 0x%llx\n", (long long)cpu->pc);
1115 #endif
1116 else {
1117 fatal(":\n");
1118 DISASSEMBLE(cpu, ib, 1, 0, 0);
1119 }
1120
1121 cpu->running = 0;
1122 cpu->dead = 1;
1123 stop_running_translated:
1124 debugger_n_steps_left_before_interaction = 0;
1125 cpu->running_translated = 0;
1126 ic = cpu->cd.DYNTRANS_ARCH.next_ic = &nothing_call;
1127 cpu->cd.DYNTRANS_ARCH.next_ic ++;
1128
1129 /* Execute the "nothing" instruction: */
1130 ic->f(cpu, ic);
1131 #endif /* DYNTRANS_TO_BE_TRANSLATED_TAIL */
1132

  ViewVC Help
Powered by ViewVC 1.1.26