CPUDyntransComponent.cc Source File

Back to the index.

CPUDyntransComponent.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008-2018 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 #include <assert.h>
29 #include <iomanip>
30 
31 #include "AddressDataBus.h"
33 #include "GXemul.h"
34 
35 
36 CPUDyntransComponent::CPUDyntransComponent(const string& className, const string& cpuArchitecture)
37  : CPUComponent(className, cpuArchitecture)
38 {
39  m_abortIC.f = instr_abort;
40 }
41 
42 
43 void CPUDyntransComponent::DyntransInit()
44 {
45  m_nextIC = NULL;
46  m_firstIConPage = NULL;
47 
49 
51  m_dyntransPageMask = (m_pageSize - 1) - ((1 << m_dyntransICshift) - 1);
52 
53  int pageShift = 0;
54  while (pageShift < 32 && (1 << pageShift) != m_pageSize)
55  pageShift ++;
56 
57  if (pageShift >= 32) {
58  std::cerr << "Non-power-of-2 page size?\n";
59  throw std::exception();
60  }
61 
62  // 32 MB translation cache (per emulated CPU):
64 }
65 
66 
67 /*
68  * Dynamic translation core
69  * ------------------------
70  *
71  * The core of GXemul's dynamic translation is a simple function call to
72  * an entry in an array of pointers. Each call also moves the pointer of the
73  * next function call to the next entry in the array. For most simple
74  * instruction implementations, the instruction call pointer (m_nextIC) does
75  * not have to be modified, because it is assumed that an instruction will
76  * change the program counter to the next instruction.
77  *
78  * Before starting the main loop, the pc is used to look up the correct
79  * m_nextIC value, by calling DyntransPCtoPointers().
80  *
81  * During the loop, the pc value is _not_ necessarily updated for each
82  * instruction call. Instead, the low bits of the pc value should be considered
83  * meaningless, and the offset of the m_nextIC pointer within the current
84  * code page (pointed to by m_firstIConPage) defines the lowest pc bits.
85  *
86  * After completing the main loop, the pc value is resynched by calling
87  * DyntransResyncPC().
88  */
89 int CPUDyntransComponent::Execute(GXemul* gxemul, int nrOfCycles)
90 {
91  DyntransInit();
92 
94 
95  struct DyntransIC *ic = m_nextIC;
96  if (m_nextIC == NULL || m_firstIConPage == NULL) {
97  std::cerr << "Internal error: m_nextIC or m_firstIConPage is NULL.\n";
98  throw std::exception();
99  }
100 
101  if (gxemul->GetRunState() == GXemul::SingleStepping) {
102  if (nrOfCycles != 1) {
103  std::cerr << "Internal error: Single stepping,"
104  " but nrOfCycles = " << nrOfCycles << ".\n";
105  throw std::exception();
106  }
107 
108  stringstream disasm;
109  Unassemble(1, false, PCtoInstructionAddress(m_pc), disasm);
110  gxemul->GetUI()->ShowDebugMessage(this, disasm.str());
111 
113  }
114 
115  /*
116  * The normal instruction execution core: Get the instruction call pointer
117  * (and move the nextIC to the following instruction in advance), then
118  * execute the instruction call by calling its f.
119  */
120 #define IC ic = m_nextIC ++; ic->f(this, ic);
121 
122  m_nrOfCyclesToExecute = nrOfCycles;
123  m_executedCycles = 0;
124 
125  // Starting inside a delay slot? Then execute it carefully:
126  if (m_inDelaySlot) {
129  IC
131  m_executedCycles ++;
132 
133  // Fault in delay slot: return immediately.
134  if (m_nextIC->f == instr_abort) {
136  return 0;
137  }
138  }
139 
140  // If possible, do some optimized loops of multiple inlined IC calls...
141  const int ICsPerLoop = 60;
142  const int maxICcycles = 2; // TODO: Longer when instr combos are reimplemented
143  if (nrOfCycles > ICsPerLoop * maxICcycles) {
144  int hazard = nrOfCycles - ICsPerLoop * maxICcycles;
145 
146  for (;;) {
147  IC IC IC IC IC IC IC IC IC IC
148  IC IC IC IC IC IC IC IC IC IC
149  IC IC IC IC IC IC IC IC IC IC
150 
151  IC IC IC IC IC IC IC IC IC IC
152  IC IC IC IC IC IC IC IC IC IC
153  IC IC IC IC IC IC IC IC IC IC
154 
155  m_executedCycles += ICsPerLoop;
156  if (m_executedCycles >= hazard ||
157  m_nextIC->f == instr_abort)
158  break;
159  }
160  }
161 
162  // ... then slowly execute the last few instructions.
163  // Note: -1, because the last thing we execute may be an instruction
164  // with a delay slot (which is automatically executed).
165  for (; m_executedCycles<nrOfCycles-1; ) {
166  int old = m_executedCycles;
167  IC
168  m_executedCycles ++;
169  if (m_executedCycles == old)
170  break;
171  }
172 
173  // If there's one instruction left (and we're not aborted), then
174  // let's execute it:
175  if (m_executedCycles<nrOfCycles && m_nextIC->f != instr_abort) {
177  IC
178  m_executedCycles ++;
179  }
180 
182 
183  // If execution aborted, then reset the aborting instruction slot
184  // to the to-be-translated function:
185  if (m_nextIC->f == instr_abort)
187 
188  return m_executedCycles;
189 }
190 
191 
192 void CPUDyntransComponent::DyntransClearICPage(struct DyntransIC* icpage)
193 {
194  // Fill the page with "to be translated" entries, which when executed
195  // will read the instruction from memory, attempt to translate it, and
196  // then execute it.
198 
199  for (int i=0; i<m_dyntransICentriesPerPage; ++i)
200  icpage[i].f = f;
201 
202  // ... and set the entries after the last instruction slot to
203  // special "end of page" handlers.
204  icpage[m_dyntransICentriesPerPage + 0].f = CPUDyntransComponent::instr_endOfPage;
205  icpage[m_dyntransICentriesPerPage + 1].f = CPUDyntransComponent::instr_endOfPage2;
206 }
207 
208 
209 struct DyntransIC *CPUDyntransComponent::DyntransGetICPage(uint64_t addr)
210 {
211  bool clear = false;
212  struct DyntransIC *icpage = m_translationCache.GetICPage(
213  addr, m_showFunctionTraceCall, clear);
214 
215  if (clear) {
216  // This is either
217  //
218  // a) a completely new page (the address was not in the cache),
219  // or
220  // b) a page which was translated before, but with different
221  // settings (e.g. m_showFunctionTraceCall).
222  //
223  // So let's fill the page with suitable to-be-translated
224  // function pointers.
225  DyntransClearICPage(icpage);
226  }
227 
228  return icpage;
229 }
230 
231 
233 {
234  if (m_nextIC != NULL && m_nextIC->f == instr_abort) {
235  // Already aborted, let's not update m_nextIC.
236  std::cerr << "TODO: Already aborted, let's not update m_nextIC."
237  " Is this correct behavior?\n";
238  return;
239  }
240 
241  m_firstIConPage = DyntransGetICPage(m_pc);
242 
243  assert(m_firstIConPage != NULL);
244 
245  // Here, m_firstIConPage points to a valid page. Calculate m_nextIC from
246  // the low bits of m_pc:
247  int offsetWithinPage = (m_pc & m_dyntransPageMask) >> m_dyntransICshift;
248  m_nextIC = m_firstIConPage + offsetWithinPage;
249 }
250 
251 
253 {
254  // Special case during aborts:
255  if (m_nextIC == &m_abortIC) {
256  // The situation which caused m_nextIC to be set to an abort
257  // IC must have synched PC just before that. So we don't need
258  // to do anything here.
259  return;
260  }
261 
262  std::ptrdiff_t instructionIndex = m_nextIC - m_firstIConPage;
263 
264  // On a page with e.g. 1024 instruction slots, instructionIndex is usually
265  // between 0 and 1023. This means that the PC points to within this
266  // page.
267  //
268  // We synchronize the PC by clearing out the bits within the IC page,
269  // and then adding the offset to the instruction.
270  if (instructionIndex >= 0 && instructionIndex < m_dyntransICentriesPerPage) {
272  m_pc += (instructionIndex << m_dyntransICshift);
273  return;
274  }
275 
276  // However, the instruction index may point outside the IC page.
277  // This happens when synching the PC just after the last instruction
278  // on a page has been executed. This means that we set the PC to
279  // the start of the next page.
280  if (instructionIndex == m_dyntransICentriesPerPage) {
283  return;
284  }
285 
286  if (instructionIndex == m_dyntransICentriesPerPage + 1) {
287  std::cerr << "TODO: DyntransResyncPC: Second end-of-page slot.\n";
288  // This may happen for delay-slot architectures.
289  throw std::exception();
290  }
291 
292  std::cerr << "TODO: DyntransResyncPC: next ic outside of page?!\n";
293  throw std::exception();
294 }
295 
296 
298 {
299  // Resynchronize the PC to the instruction currently being translated.
300  // (m_nextIC should already have been increased, to point to the _next_
301  // instruction slot.)
302  m_nextIC = ic;
304 
305  // TODO: Check for m_pc breakpoints etc.
306 
307  // First, let's assume that the translation will fail.
308  ic->f = NULL;
309 }
310 
311 
313 {
314  // TODO: Fast lookup.
315 
317  bool readable = ReadData(iword, m_isBigEndian? BigEndian : LittleEndian);
318 
319  if (!readable) {
320  UI* ui = GetUI();
321  if (ui != NULL) {
322  stringstream ss;
323  ss.flags(std::ios::hex);
324  ss << "instruction at 0x" << PCtoInstructionAddress(m_pc)
325  << " could not be read!";
326  ui->ShowDebugMessage(this, ss.str());
327  }
328 
329  return false;
330  }
331 
332  return true;
333 }
334 
335 
336 bool CPUDyntransComponent::DyntransReadInstruction(uint32_t& iword, int offset)
337 {
338  // TODO: Fast lookup.
339 
341  bool readable = ReadData(iword, m_isBigEndian? BigEndian : LittleEndian);
342 
343  if (!readable) {
344  UI* ui = GetUI();
345  if (ui != NULL) {
346  stringstream ss;
347  ss.flags(std::ios::hex);
348  ss << "instruction at 0x" << PCtoInstructionAddress(m_pc + offset)
349  << " could not be read!";
350  ui->ShowDebugMessage(this, ss.str());
351  }
352  return false;
353  }
354 
355  return true;
356 }
357 
358 
360 {
361  bool abort = false;
362 
363  if (ic->f == NULL || ic->f == instr_abort) {
364  abort = true;
365 
366  // Instruction translation failed. If we were running in
367  // quiet mode, then simply dropping into the GXemul> prompt
368  // with no good explanation would be bad, so we always turn
369  // off quiet mode on Aborts:
371 
372  UI* ui = GetUI();
373  if (ui != NULL) {
374  bool isSingleStepping = GetRunningGXemulInstance()->GetRunState() == GXemul::SingleStepping;
375 
376  stringstream ss;
377  ss.flags(std::ios::hex);
378  ss << "instruction translation failed";
379 
380  // If we were single-stepping, then the instruction
381  // disassembly has already been displayed. If we were
382  // running in continuous mode, then we need to display
383  // it now:
384  if (!isSingleStepping) {
385  ss << " at";
386 
389  if (symbol != "")
390  ss << " " << symbol;
391 
392  ss << ":\n";
393 
394  Unassemble(1, false, PCtoInstructionAddress(m_pc), ss);
395  }
396 
397  ui->ShowDebugMessage(this, ss.str());
398  }
399 
400  if (ic->f == NULL)
401  ic->f = instr_abort;
402  }
403 
404  // Finally, execute the translated instruction.
405  bool ds = m_inDelaySlot;
406  bool dsExceptionOrAbort = m_exceptionOrAbortInDelaySlot;
407  bool singleInstructionLeft = m_executedCycles == m_nrOfCyclesToExecute - 1;
408 
409  m_nextIC = ic + 1;
410  ic->f(this, ic);
411 
412  if (m_nextIC == &m_abortIC)
413  abort = true;
414 
415  if (singleInstructionLeft && !abort) {
416  // If this instruction was in the delay slot of another instruction,
417  // and we are running a single instruction, then manually branch to
418  // the branch target:
419  if (ds && !dsExceptionOrAbort) {
422  m_inDelaySlot = false;
424  }
425 
426  // Don't leave any "single instruction left" instructions
427  // in any of the slots:
429  }
430 }
431 
432 
433 /*****************************************************************************/
434 
435 
436 /*
437  * A do-nothing instruction. (It still counts as a cylce, though.)
438  */
440 {
441 }
442 
443 
444 /*
445  * A break-out-of-dyntrans function. Setting ic->f to this function will
446  * cause dyntrans execution to be aborted. The cycle counter will _not_
447  * count this as executed cycles.
448  */
450 {
451  // Cycle reduction:
452  -- cpubase->m_executedCycles;
453 
454  // Are we in a delay slot?
455  if (cpubase->m_inDelaySlot)
456  cpubase->m_exceptionOrAbortInDelaySlot = true;
457 
458  cpubase->m_nextIC = ic;
459 }
460 
461 
463 {
464  std::cerr << "TODO: endOfPage\n";
465  throw std::exception();
466 }
467 
468 
470 {
471  std::cerr << "TODO: endOfPage2\n";
472  throw std::exception();
473 }
474 
475 
476 /*
477  * arg 0: pointer to the new IC
478  *
479  * Branches within a dyntrans page.
480  */
482 {
483  cpubase->m_nextIC = (struct DyntransIC *) ic->arg[0].p;
484 }
485 
486 
487 /*
488  * arg 0: 64-bit register
489  * arg 1: 32-bit signed immediate
490  *
491  * Sets the register at arg 0 to the immediate value in arg 1.
492  */
494 {
495  REG64(ic->arg[0]) = (int32_t) ic->arg[1].u32;
496 }
497 
498 
499 /*
500  * arg 0: 64-bit register
501  * arg 1: 64-bit register
502  *
503  * Moves (copies) the contents of arg 1 to arg 0.
504  */
506 {
507  REG64(ic->arg[0]) = REG64(ic->arg[1]);
508 }
509 
510 
511 /*
512  * arg 0: 32-bit register
513  * arg 1: 32-bit register
514  * arg 2: 32-bit unsigned immediate
515  *
516  * Adds the unsigned immediate to arg 1, and stores the result in arg 0.
517  */
519 {
520  REG32(ic->arg[0]) = REG32(ic->arg[1]) + (uint32_t)ic->arg[2].u32;
521 }
522 
523 
524 /*
525  * arg 0: 32-bit register
526  * arg 1: 32-bit register
527  * arg 2: 32-bit register
528  *
529  * Adds arg 1 and arg 2, and stores the result in arg 0.
530  */
532 {
533  REG32(ic->arg[0]) = REG32(ic->arg[1]) + REG32(ic->arg[2]);
534 }
535 
536 
537 /*
538  * arg 0: 64-bit register
539  * arg 1: 64-bit register
540  * arg 2: 32-bit signed immediate
541  *
542  * Adds the signed immediate to arg 1, and stores the result in arg 0, truncated
543  * to a signed 32-bit value.
544  */
545 DYNTRANS_INSTR(CPUDyntransComponent,add_u64_u64_imms32_truncS32)
546 {
547  REG64(ic->arg[0]) = (int32_t) (REG64(ic->arg[1]) + (int32_t)ic->arg[2].u32);
548 }
549 
550 
551 /*
552  * arg 0: 64-bit register
553  * arg 1: 64-bit register
554  * arg 2: 64-bit register
555  *
556  * Adds the the registers in arg 1 and arg 2, and stores the result in arg 0
557  * (truncated to a signed 32-bit value).
558  */
559 DYNTRANS_INSTR(CPUDyntransComponent,add_u64_u64_u64_truncS32)
560 {
561  REG64(ic->arg[0]) = (int32_t) (REG64(ic->arg[1]) + REG64(ic->arg[2]));
562 }
563 
564 
565 /*
566  * arg 0: 64-bit register
567  * arg 1: 64-bit register
568  * arg 2: 32-bit signed immediate
569  *
570  * Adds the signed immediate to arg 1, and stores the result in arg 0.
571  */
573 {
574  REG64(ic->arg[0]) = REG64(ic->arg[1]) + (int64_t)(int32_t)ic->arg[2].u32;
575 }
576 
577 
578 /*
579  * arg 0: 32-bit register
580  * arg 1: 32-bit register
581  * arg 2: 32-bit unsigned immediate
582  *
583  * Subtracts the unsigned immediate from arg 1, and stores the result in arg 0.
584  */
586 {
587  REG32(ic->arg[0]) = REG32(ic->arg[1]) - (uint32_t)ic->arg[2].u32;
588 }
589 
590 
591 /*
592  * arg 0: 32-bit register
593  * arg 1: 32-bit register
594  * arg 2: 32-bit register
595  *
596  * Subtracts arg 2 from arg 1, and stores the result in arg 0.
597  */
599 {
600  REG32(ic->arg[0]) = REG32(ic->arg[1]) - REG32(ic->arg[2]);
601 }
602 
603 
604 /*
605  * arg 0: 64-bit register
606  * arg 1: 64-bit register
607  * arg 2: 64-bit register
608  *
609  * Subtracts arg2 from arg1, and stores the result in arg0
610  * (truncated to a signed 32-bit value).
611  */
612 DYNTRANS_INSTR(CPUDyntransComponent,sub_u64_u64_u64_truncS32)
613 {
614  REG64(ic->arg[0]) = (int32_t) (REG64(ic->arg[1]) - REG64(ic->arg[2]));
615 }
616 
617 
618 /*
619  * arg 0: 32-bit register
620  * arg 1: 32-bit register
621  * arg 2: 32-bit unsigned immediate
622  *
623  * ANDs the 32-bit immediate into arg 1, storing the result in arg 0.
624  */
626 {
627  REG32(ic->arg[0]) = REG32(ic->arg[1]) & ic->arg[2].u32;
628 }
629 
630 
631 /*
632  * arg 0: 64-bit register
633  * arg 1: 64-bit register
634  * arg 2: 32-bit unsigned immediate
635  *
636  * ANDs the 32-bit immediate into arg 1, storing the result in arg 0.
637  *
638  * Note: No sign truncation is performed, i.e. if arg 1 is 0xffffffff80001234
639  * and arg 2 is 0x80001200, then arg 0 becomes 0x0000000080001200 (note: the
640  * upper bits are not sign-extended from bit 31).
641  */
643 {
644  REG64(ic->arg[0]) = REG64(ic->arg[1]) & (uint32_t)ic->arg[2].u32;
645 }
646 
647 
648 /*
649  * arg 0: 32-bit register
650  * arg 1: 32-bit register
651  * arg 2: 32-bit unsigned immediate
652  *
653  * ORs arg 1 and arg 2 together, and stores the result in arg 0.
654  */
656 {
657  REG32(ic->arg[0]) = REG32(ic->arg[1]) | ic->arg[2].u32;
658 }
659 
660 
661 /*
662  * arg 0: 32-bit register
663  * arg 1: 32-bit register
664  * arg 2: 32-bit register
665  *
666  * ORs arg 1 and arg 2 together, and stores the result in arg 0.
667  */
669 {
670  REG32(ic->arg[0]) = REG32(ic->arg[1]) | REG32(ic->arg[2]);
671 }
672 
673 
674 /*
675  * arg 0: 64-bit register
676  * arg 1: 64-bit register
677  * arg 2: 32-bit unsigned immediate
678  *
679  * ORs the 32-bit immediate into arg 1, storing the result in arg 0.
680  *
681  * Note: No sign truncation is performed, i.e. if arg 1 is 0x0000000000001234
682  * and arg 2 is 0x80001200, then arg 0 becomes 0x0000000080001234 (note: the
683  * upper bits are not sign extended from bit 31).
684  */
686 {
687  REG64(ic->arg[0]) = REG64(ic->arg[1]) | (uint32_t)ic->arg[2].u32;
688 }
689 
690 
691 /*
692  * arg 0: 32-bit register
693  * arg 1: 32-bit register
694  * arg 2: 32-bit unsigned immediate
695  *
696  * XORs arg 1 and arg 2, and stores the result in arg 0.
697  */
699 {
700  REG32(ic->arg[0]) = REG32(ic->arg[1]) ^ ic->arg[2].u32;
701 }
702 
703 
704 /*
705  * arg 0: 32-bit register
706  * arg 1: 32-bit register
707  * arg 2: 32-bit register
708  *
709  * XORs arg 1 and arg 2, and stores the result in arg 0.
710  */
712 {
713  REG32(ic->arg[0]) = REG32(ic->arg[1]) ^ REG32(ic->arg[2]);
714 }
715 
716 
717 /*
718  * arg 0: 64-bit register
719  * arg 1: 64-bit register
720  * arg 2: 32-bit unsigned immediate
721  *
722  * XORs the 32-bit immediate into arg 1, storing the result in arg 0.
723  *
724  * Note: No sign truncation is performed, i.e. if arg 1 is 0xffffffff80001234
725  * and arg 2 is 0x80001200, then arg 0 becomes 0xffffffff00000034 (note: the
726  * upper bits are not sign-extended from bit 31).
727  */
729 {
730  REG64(ic->arg[0]) = REG64(ic->arg[1]) ^ (uint32_t)ic->arg[2].u32;
731 }
732 
733 
734 /*
735  * arg 0: 64-bit register
736  * arg 1: 64-bit register
737  * arg 2: 64-bit register
738  *
739  * XORs the arg 1 and arg 2, storing the result in arg 0.
740  *
741  * Note: No sign truncation is performed, i.e. if arg 1 is 0xffffffff80001234
742  * and arg 2 is 0x80001200, then arg 0 becomes 0xffffffff00000034 (note: the
743  * upper bits are not sign-extended from bit 31).
744  */
746 {
747  REG64(ic->arg[0]) = REG64(ic->arg[1]) ^ REG64(ic->arg[2]);
748 }
749 
750 
751 /*
752  * arg 0: 64-bit register
753  * arg 1: 64-bit register
754  * arg 2: 5-bit immediate
755  *
756  * Left-shifts arg 1 the number of steps indicated by the immediate, storing
757  * the result in arg 0 truncated to a signed 32-bit value.
758  */
759 DYNTRANS_INSTR(CPUDyntransComponent,shift_left_u64_u64_imm5_truncS32)
760 {
761  REG64(ic->arg[0]) = (int32_t)(REG64(ic->arg[1]) << (ic->arg[2].u32 & 0x1f));
762 }
763 
764 
765 /*
766  * arg 0: 64-bit register
767  * arg 1: 64-bit register
768  * arg 2: 5-bit immediate
769  *
770  * Right-shifts arg 1 (truncated into an unsigned 32-bit) the number of steps
771  * indicated by the immediate, storing the result in arg 0 truncated to a
772  * signed 32-bit value.
773  */
774 DYNTRANS_INSTR(CPUDyntransComponent,shift_right_u64_u64asu32_imm5_truncS32)
775 {
776  REG64(ic->arg[0]) = (int32_t)(((uint32_t)REG64(ic->arg[1])) >> (ic->arg[2].u32 & 0x1f));
777 }
778 
779 
780 /*****************************************************************************/
781 
782 
783 #ifdef WITHUNITTESTS
784 
785 #include "ComponentFactory.h"
786 
787 static void Test_CPUDyntransComponent_Dyntrans_PreReq()
788 {
789  UnitTest::Assert("nr of dyntrans args too few", N_DYNTRANS_IC_ARGS >= 3);
790 }
791 
793 {
794  UNITTEST(Test_CPUDyntransComponent_Dyntrans_PreReq);
795 }
796 
797 #endif
798 
virtual void ShowDebugMessage(const string &msg)=0
Shows a debug message.
#define DYNTRANS_PAGE_NSPECIALENTRIES
DYNTRANS_INSTR(CPUDyntransComponent, nop)
void DyntransResyncPC()
Calculate m_pc based on m_nextIC and m_firstIConPage.
bool DyntransReadInstruction(uint16_t &iword)
RunState GetRunState() const
Gets the current RunState.
Definition: GXemul.cc:749
DyntransTranslationCache m_translationCache
void(* f)(CPUDyntransComponent *, DyntransIC *)
void COMBINE() nop(struct cpu *cpu, struct mips_instr_call *ic, int low_addr)
struct arm_instr_call * ic
CPUDyntransComponent(const string &className, const string &cpuKind)
Constructs a CPUDyntransComponent.
uint64_t m_delaySlotTarget
Definition: CPUComponent.h:223
UI * GetUI()
Gets an UI reference for outputting debug messages during runtime.
Definition: Component.cc:583
#define REG32(arg)
void f(int s, int func, int only_name)
virtual void(*)(CPUDyntransComponent *cpu, DyntransIC *ic) GetDyntransToBeTranslated()
virtual uint64_t PCtoInstructionAddress(uint64_t pc)
Convert PC value to instuction address.
Definition: CPUComponent.h:174
void DyntransToBeTranslatedBegin(struct DyntransIC *)
bool m_inDelaySlot
Definition: CPUComponent.h:222
A dyntrans instruction call.
#define REG64(arg)
The main emulator class.
Definition: GXemul.h:54
struct DyntransIC m_abortIC
#define UNITTESTS(class)
Helper for unit test case execution.
Definition: UnitTest.h:184
bool m_showFunctionTraceCall
Definition: CPUComponent.h:216
struct DyntransIC * m_firstIConPage
#define IC
bool m_exceptionOrAbortInDelaySlot
Definition: CPUComponent.h:231
string LookupAddress(uint64_t vaddr, bool allowOffset) const
Looks up an address.
bool m_isBigEndian
Definition: CPUComponent.h:213
virtual void AddressSelect(uint64_t address)
Place an address on the bus.
void DyntransToBeTranslatedDone(struct DyntransIC *)
#define N_DYNTRANS_IC_ARGS
uint64_t m_pc
Definition: CPUComponent.h:205
SymbolRegistry & GetSymbolRegistry()
Gets a reference to the CPU&#39;s symbol registry.
Definition: CPUComponent.h:63
uint32_t addr
virtual int GetDyntransICshift() const =0
A base-class for processors Component implementations that use dynamic translation.
void DyntransPCtoPointers()
Calculate m_nextIC and m_firstIConPage, based on m_pc.
A base-class for processors Component implementations.
Definition: CPUComponent.h:43
static void Assert(const string &strFailMessage, bool condition)
Asserts that a boolean condition is correct.
Definition: UnitTest.cc:40
Definition: symbol.h:37
virtual int Execute(GXemul *gxemul, int nrOfCycles)
Execute one or more cycles.
UI * GetUI()
Gets a pointer to the GXemul instance&#39; active UI.
Definition: GXemul.cc:661
Base class for a User Interface.
Definition: UI.h:40
void SetQuietMode(bool quietMode)
Sets whether or not to run in quiet mode.
Definition: GXemul.cc:794
uint64_t Unassemble(int nRows, bool indicatePC, uint64_t vaddr, ostream &output)
struct DyntransIC * m_nextIC
virtual bool ReadData(uint8_t &data, Endianness endianness)
Reads 8-bit data from the currently selected address.
GXemul * GetRunningGXemulInstance()
Returns a reference to the current GXemul instance.
Definition: Component.cc:569
#define UNITTEST(functionname)
Helper for unit test case execution.
Definition: UnitTest.h:217

Generated on Fri Dec 7 2018 19:52:23 for GXemul by doxygen 1.8.13