cpu_dyntrans.cc Source File

Back to the index.

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

Generated on Tue Aug 25 2020 19:25:06 for GXemul by doxygen 1.8.18