CPUDyntransComponent.cc Source File

Back to the index.

CPUDyntransComponent.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008-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 #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. For architectures with delay slots,
204  // there need to be two, otherwise one would suffice.
205  icpage[m_dyntransICentriesPerPage + 0].f = CPUDyntransComponent::instr_endOfPage;
206  icpage[m_dyntransICentriesPerPage + 1].f = CPUDyntransComponent::instr_endOfPage2;
207 }
208 
209 
210 struct DyntransIC *CPUDyntransComponent::DyntransGetICPage(uint64_t addr)
211 {
212  bool clear = false;
213  struct DyntransIC *icpage = m_translationCache.GetICPage(
214  addr, m_showFunctionTraceCall, clear);
215 
216  if (clear) {
217  // This is either
218  //
219  // a) a completely new page (the address was not in the cache),
220  // or
221  // b) a page which was translated before, but with different
222  // settings (e.g. m_showFunctionTraceCall).
223  //
224  // So let's fill the page with suitable to-be-translated
225  // function pointers.
226  DyntransClearICPage(icpage);
227  }
228 
229  return icpage;
230 }
231 
232 
234 {
235  if (m_nextIC != NULL && m_nextIC->f == instr_abort) {
236  // Already aborted, let's not update m_nextIC.
237  std::cerr << "TODO: Already aborted, let's not update m_nextIC."
238  " Is this correct behavior?\n";
239  return;
240  }
241 
242  m_firstIConPage = DyntransGetICPage(m_pc);
243 
244  assert(m_firstIConPage != NULL);
245 
246  // Here, m_firstIConPage points to a valid page. Calculate m_nextIC from
247  // the low bits of m_pc:
248  int offsetWithinPage = (m_pc & m_dyntransPageMask) >> m_dyntransICshift;
249  m_nextIC = m_firstIConPage + offsetWithinPage;
250 }
251 
252 
254 {
255  // Special case during aborts:
256  if (m_nextIC == &m_abortIC) {
257  // The situation which caused m_nextIC to be set to an abort
258  // IC must have synched PC just before that. So we don't need
259  // to do anything here.
260  return;
261  }
262 
263  std::ptrdiff_t instructionIndex = m_nextIC - m_firstIConPage;
264 
265  // On a page with e.g. 1024 instruction slots, instructionIndex is usually
266  // between 0 and 1023. This means that the PC points to within this
267  // page.
268  //
269  // We synchronize the PC by clearing out the bits within the IC page,
270  // and then adding the offset to the instruction.
271  if (instructionIndex >= 0 && instructionIndex < m_dyntransICentriesPerPage) {
273  m_pc += (instructionIndex << m_dyntransICshift);
274  return;
275  }
276 
277  // However, the instruction index may point outside the IC page.
278  // This happens when synching the PC just after the last instruction
279  // on a page has been executed. This means that we set the PC to
280  // the start of the next page.
281  if (instructionIndex == m_dyntransICentriesPerPage) {
284  return;
285  }
286 
287  if (instructionIndex == m_dyntransICentriesPerPage + 1) {
288  std::cerr << "TODO: DyntransResyncPC: Second end-of-page slot.\n";
289  // This may happen for delay-slot architectures.
290  throw std::exception();
291  }
292 
293  std::cerr << "TODO: DyntransResyncPC: next ic outside of page?!\n";
294  throw std::exception();
295 }
296 
297 
299 {
300  // Resynchronize the PC to the instruction currently being translated.
301  // (m_nextIC should already have been increased, to point to the _next_
302  // instruction slot.)
303  m_nextIC = ic;
305 
306  // TODO: Check for m_pc breakpoints etc.
307 
308  // First, let's assume that the translation will fail.
309  ic->f = NULL;
310 }
311 
312 
313 bool CPUDyntransComponent::DyntransReadInstruction(uint16_t& iword, int offset)
314 {
315  // TODO: Fast lookup.
316 
318  bool readable = ReadData(iword, m_isBigEndian? BigEndian : LittleEndian);
319 
320  if (!readable) {
321  UI* ui = GetUI();
322  if (ui != NULL) {
323  stringstream ss;
324  ss.flags(std::ios::hex);
325  ss << "instruction at 0x" << PCtoInstructionAddress(m_pc + offset)
326  << " could not be read!";
327  ui->ShowDebugMessage(this, ss.str());
328  }
329 
330  return false;
331  }
332 
333  return true;
334 }
335 
336 
337 bool CPUDyntransComponent::DyntransReadInstruction(uint32_t& iword, int offset)
338 {
339  // TODO: Fast lookup.
340 
342  bool readable = ReadData(iword, m_isBigEndian? BigEndian : LittleEndian);
343 
344  if (!readable) {
345  UI* ui = GetUI();
346  if (ui != NULL) {
347  stringstream ss;
348  ss.flags(std::ios::hex);
349  ss << "instruction at 0x" << PCtoInstructionAddress(m_pc + offset)
350  << " could not be read!";
351  ui->ShowDebugMessage(this, ss.str());
352  }
353  return false;
354  }
355 
356  return true;
357 }
358 
359 
361 {
362  bool abort = false;
363 
364  if (ic->f == NULL || ic->f == instr_abort) {
365  abort = true;
366 
367  // Instruction translation failed. If we were running in
368  // quiet mode, then simply dropping into the GXemul> prompt
369  // with no good explanation would be bad, so we always turn
370  // off quiet mode on Aborts:
372 
373  UI* ui = GetUI();
374  if (ui != NULL) {
375  bool isSingleStepping = GetRunningGXemulInstance()->GetRunState() == GXemul::SingleStepping;
376 
377  stringstream ss;
378  ss.flags(std::ios::hex);
379  ss << "instruction translation failed";
380 
381  // If we were single-stepping, then the instruction
382  // disassembly has already been displayed. If we were
383  // running in continuous mode, then we need to display
384  // it now:
385  if (!isSingleStepping) {
386  ss << " at";
387 
390  if (symbol != "")
391  ss << " " << symbol;
392 
393  ss << ":\n";
394 
395  Unassemble(1, false, PCtoInstructionAddress(m_pc), ss);
396  }
397 
398  ui->ShowDebugMessage(this, ss.str());
399  }
400 
401  if (ic->f == NULL)
402  ic->f = instr_abort;
403  }
404 
405  // Finally, execute the translated instruction.
406  bool ds = m_inDelaySlot;
407  bool dsExceptionOrAbort = m_exceptionOrAbortInDelaySlot;
408  bool singleInstructionLeft = m_executedCycles == m_nrOfCyclesToExecute - 1;
409 
410  m_nextIC = ic + 1;
411  ic->f(this, ic);
412 
413  if (m_nextIC == &m_abortIC)
414  abort = true;
415 
416  if (singleInstructionLeft && !abort) {
417  // If this instruction was in the delay slot of another instruction,
418  // and we are running a single instruction, then manually branch to
419  // the branch target:
420  if (ds && !dsExceptionOrAbort) {
423  m_inDelaySlot = false;
425  }
426 
427  // Don't leave any "single instruction left" instructions
428  // in any of the slots:
430  }
431 }
432 
433 
434 /*****************************************************************************/
435 
436 
437 /*
438  * A do-nothing instruction. (It still counts as a cylce, though.)
439  */
441 {
442 }
443 
444 
445 /*
446  * A break-out-of-dyntrans function. Setting ic->f to this function will
447  * cause dyntrans execution to be aborted. The cycle counter will _not_
448  * count this as executed cycles.
449  */
451 {
452  // Cycle reduction:
453  -- cpubase->m_executedCycles;
454 
455  // Are we in a delay slot?
456  if (cpubase->m_inDelaySlot)
457  cpubase->m_exceptionOrAbortInDelaySlot = true;
458 
459  cpubase->m_nextIC = ic;
460 }
461 
462 
464 {
465  std::cerr << "TODO: endOfPage\n";
466  throw std::exception();
467 }
468 
469 
471 {
472  std::cerr << "TODO: endOfPage2\n";
473  throw std::exception();
474 }
475 
476 
477 /*
478  * arg 0: pointer to the new IC
479  *
480  * Branches within a dyntrans page.
481  */
483 {
484  cpubase->m_nextIC = (struct DyntransIC *) ic->arg[0].p;
485 }
486 
487 
488 /*
489  * arg 0: 64-bit register
490  * arg 1: 32-bit signed immediate
491  *
492  * Sets the register at arg 0 to the immediate value in arg 1.
493  */
495 {
496  REG64(ic->arg[0]) = (int32_t) ic->arg[1].u32;
497 }
498 
499 
500 /*
501  * arg 0: 64-bit register
502  * arg 1: 64-bit register
503  *
504  * Moves (copies) the contents of arg 1 to arg 0.
505  */
507 {
508  REG64(ic->arg[0]) = REG64(ic->arg[1]);
509 }
510 
511 
512 /*
513  * arg 0: 32-bit register
514  * arg 1: 32-bit register
515  * arg 2: 32-bit unsigned immediate
516  *
517  * Adds the unsigned immediate to arg 1, and stores the result in arg 0.
518  */
520 {
521  REG32(ic->arg[0]) = REG32(ic->arg[1]) + (uint32_t)ic->arg[2].u32;
522 }
523 
524 
525 /*
526  * arg 0: 32-bit register
527  * arg 1: 32-bit register
528  * arg 2: 32-bit register
529  *
530  * Adds arg 1 and arg 2, and stores the result in arg 0.
531  */
533 {
534  REG32(ic->arg[0]) = REG32(ic->arg[1]) + REG32(ic->arg[2]);
535 }
536 
537 
538 /*
539  * arg 0: 64-bit register
540  * arg 1: 64-bit register
541  * arg 2: 32-bit signed immediate
542  *
543  * Adds the signed immediate to arg 1, and stores the result in arg 0, truncated
544  * to a signed 32-bit value.
545  */
546 DYNTRANS_INSTR(CPUDyntransComponent,add_u64_u64_imms32_truncS32)
547 {
548  REG64(ic->arg[0]) = (int32_t) (REG64(ic->arg[1]) + (int32_t)ic->arg[2].u32);
549 }
550 
551 
552 /*
553  * arg 0: 64-bit register
554  * arg 1: 64-bit register
555  * arg 2: 64-bit register
556  *
557  * Adds the the registers in arg 1 and arg 2, and stores the result in arg 0
558  * (truncated to a signed 32-bit value).
559  */
560 DYNTRANS_INSTR(CPUDyntransComponent,add_u64_u64_u64_truncS32)
561 {
562  REG64(ic->arg[0]) = (int32_t) (REG64(ic->arg[1]) + REG64(ic->arg[2]));
563 }
564 
565 
566 /*
567  * arg 0: 64-bit register
568  * arg 1: 64-bit register
569  * arg 2: 32-bit signed immediate
570  *
571  * Adds the signed immediate to arg 1, and stores the result in arg 0.
572  */
574 {
575  REG64(ic->arg[0]) = REG64(ic->arg[1]) + (int64_t)(int32_t)ic->arg[2].u32;
576 }
577 
578 
579 /*
580  * arg 0: 32-bit register
581  * arg 1: 32-bit register
582  * arg 2: 32-bit unsigned immediate
583  *
584  * Subtracts the unsigned immediate from arg 1, and stores the result in arg 0.
585  */
587 {
588  REG32(ic->arg[0]) = REG32(ic->arg[1]) - (uint32_t)ic->arg[2].u32;
589 }
590 
591 
592 /*
593  * arg 0: 32-bit register
594  * arg 1: 32-bit register
595  * arg 2: 32-bit register
596  *
597  * Subtracts arg 2 from arg 1, and stores the result in arg 0.
598  */
600 {
601  REG32(ic->arg[0]) = REG32(ic->arg[1]) - REG32(ic->arg[2]);
602 }
603 
604 
605 /*
606  * arg 0: 64-bit register
607  * arg 1: 64-bit register
608  * arg 2: 64-bit register
609  *
610  * Subtracts arg2 from arg1, and stores the result in arg0
611  * (truncated to a signed 32-bit value).
612  */
613 DYNTRANS_INSTR(CPUDyntransComponent,sub_u64_u64_u64_truncS32)
614 {
615  REG64(ic->arg[0]) = (int32_t) (REG64(ic->arg[1]) - REG64(ic->arg[2]));
616 }
617 
618 
619 /*
620  * arg 0: 32-bit register
621  * arg 1: 32-bit register
622  * arg 2: 32-bit unsigned immediate
623  *
624  * ANDs the 32-bit immediate into arg 1, storing the result in arg 0.
625  */
627 {
628  REG32(ic->arg[0]) = REG32(ic->arg[1]) & ic->arg[2].u32;
629 }
630 
631 
632 /*
633  * arg 0: 64-bit register
634  * arg 1: 64-bit register
635  * arg 2: 32-bit unsigned immediate
636  *
637  * ANDs the 32-bit immediate into arg 1, storing the result in arg 0.
638  *
639  * Note: No sign truncation is performed, i.e. if arg 1 is 0xffffffff80001234
640  * and arg 2 is 0x80001200, then arg 0 becomes 0x0000000080001200 (note: the
641  * upper bits are not sign-extended from bit 31).
642  */
644 {
645  REG64(ic->arg[0]) = REG64(ic->arg[1]) & (uint32_t)ic->arg[2].u32;
646 }
647 
648 
649 /*
650  * arg 0: 32-bit register
651  * arg 1: 32-bit register
652  * arg 2: 32-bit unsigned immediate
653  *
654  * ORs arg 1 and arg 2 together, and stores the result in arg 0.
655  */
657 {
658  REG32(ic->arg[0]) = REG32(ic->arg[1]) | ic->arg[2].u32;
659 }
660 
661 
662 /*
663  * arg 0: 32-bit register
664  * arg 1: 32-bit register
665  * arg 2: 32-bit register
666  *
667  * ORs arg 1 and arg 2 together, and stores the result in arg 0.
668  */
670 {
671  REG32(ic->arg[0]) = REG32(ic->arg[1]) | REG32(ic->arg[2]);
672 }
673 
674 
675 /*
676  * arg 0: 64-bit register
677  * arg 1: 64-bit register
678  * arg 2: 32-bit unsigned immediate
679  *
680  * ORs the 32-bit immediate into arg 1, storing the result in arg 0.
681  *
682  * Note: No sign truncation is performed, i.e. if arg 1 is 0x0000000000001234
683  * and arg 2 is 0x80001200, then arg 0 becomes 0x0000000080001234 (note: the
684  * upper bits are not sign extended from bit 31).
685  */
687 {
688  REG64(ic->arg[0]) = REG64(ic->arg[1]) | (uint32_t)ic->arg[2].u32;
689 }
690 
691 
692 /*
693  * arg 0: 32-bit register
694  * arg 1: 32-bit register
695  * arg 2: 32-bit unsigned immediate
696  *
697  * XORs arg 1 and arg 2, and stores the result in arg 0.
698  */
700 {
701  REG32(ic->arg[0]) = REG32(ic->arg[1]) ^ ic->arg[2].u32;
702 }
703 
704 
705 /*
706  * arg 0: 32-bit register
707  * arg 1: 32-bit register
708  * arg 2: 32-bit register
709  *
710  * XORs arg 1 and arg 2, and stores the result in arg 0.
711  */
713 {
714  REG32(ic->arg[0]) = REG32(ic->arg[1]) ^ REG32(ic->arg[2]);
715 }
716 
717 
718 /*
719  * arg 0: 64-bit register
720  * arg 1: 64-bit register
721  * arg 2: 32-bit unsigned immediate
722  *
723  * XORs the 32-bit immediate into arg 1, storing the result in arg 0.
724  *
725  * Note: No sign truncation is performed, i.e. if arg 1 is 0xffffffff80001234
726  * and arg 2 is 0x80001200, then arg 0 becomes 0xffffffff00000034 (note: the
727  * upper bits are not sign-extended from bit 31).
728  */
730 {
731  REG64(ic->arg[0]) = REG64(ic->arg[1]) ^ (uint32_t)ic->arg[2].u32;
732 }
733 
734 
735 /*
736  * arg 0: 64-bit register
737  * arg 1: 64-bit register
738  * arg 2: 64-bit register
739  *
740  * XORs the arg 1 and arg 2, storing the result in arg 0.
741  *
742  * Note: No sign truncation is performed, i.e. if arg 1 is 0xffffffff80001234
743  * and arg 2 is 0x80001200, then arg 0 becomes 0xffffffff00000034 (note: the
744  * upper bits are not sign-extended from bit 31).
745  */
747 {
748  REG64(ic->arg[0]) = REG64(ic->arg[1]) ^ REG64(ic->arg[2]);
749 }
750 
751 
752 /*
753  * arg 0: 64-bit register
754  * arg 1: 64-bit register
755  * arg 2: 5-bit immediate
756  *
757  * Left-shifts arg 1 the number of steps indicated by the immediate, storing
758  * the result in arg 0 truncated to a signed 32-bit value.
759  */
760 DYNTRANS_INSTR(CPUDyntransComponent,shift_left_u64_u64_imm5_truncS32)
761 {
762  REG64(ic->arg[0]) = (int32_t)(REG64(ic->arg[1]) << (ic->arg[2].u32 & 0x1f));
763 }
764 
765 
766 /*
767  * arg 0: 64-bit register
768  * arg 1: 64-bit register
769  * arg 2: 5-bit immediate
770  *
771  * Right-shifts arg 1 (truncated into an unsigned 32-bit) the number of steps
772  * indicated by the immediate, storing the result in arg 0 truncated to a
773  * signed 32-bit value.
774  */
775 DYNTRANS_INSTR(CPUDyntransComponent,shift_right_u64_u64asu32_imm5_truncS32)
776 {
777  REG64(ic->arg[0]) = (int32_t)(((uint32_t)REG64(ic->arg[1])) >> (ic->arg[2].u32 & 0x1f));
778 }
779 
780 
781 /*****************************************************************************/
782 
783 
784 #ifdef WITHUNITTESTS
785 
786 #include "ComponentFactory.h"
787 
788 static void Test_CPUDyntransComponent_Dyntrans_PreReq()
789 {
790  UnitTest::Assert("nr of dyntrans args too few", N_DYNTRANS_IC_ARGS >= 3);
791 }
792 
794 {
795  UNITTEST(Test_CPUDyntransComponent_Dyntrans_PreReq);
796 }
797 
798 #endif
799 
CPUComponent::m_inDelaySlot
bool m_inDelaySlot
Definition: CPUComponent.h:219
CPUDyntransComponent::Execute
virtual int Execute(GXemul *gxemul, int nrOfCycles)
Execute one or more cycles.
Definition: CPUDyntransComponent.cc:89
f
void f(int s, int func, int only_name)
Definition: generate_arm_r.c:45
CPUComponent::GetSymbolRegistry
SymbolRegistry & GetSymbolRegistry()
Gets a reference to the CPU's symbol registry.
Definition: CPUComponent.h:63
ComponentFactory.h
N_DYNTRANS_IC_ARGS
#define N_DYNTRANS_IC_ARGS
Definition: CPUDyntransComponent.h:43
GXemul
The main emulator class.
Definition: GXemul.h:55
CPUComponent::Unassemble
uint64_t Unassemble(int nRows, bool indicatePC, uint64_t vaddr, ostream &output)
Definition: CPUComponent.cc:325
LittleEndian
@ LittleEndian
Definition: misc.h:159
IC
#define IC
CPUDyntransComponent::m_dyntransPageMask
int m_dyntransPageMask
Definition: CPUDyntransComponent.h:615
CPUDyntransComponent::m_firstIConPage
struct DyntransIC * m_firstIConPage
Definition: CPUDyntransComponent.h:613
UNITTESTS
#define UNITTESTS(class)
Helper for unit test case execution.
Definition: UnitTest.h:184
addr
uint32_t addr
Definition: tmp_arm_multi.cc:52
CPUDyntransComponent::m_nextIC
struct DyntransIC * m_nextIC
Definition: CPUDyntransComponent.h:614
CPUDyntransComponent::m_executedCycles
int m_executedCycles
Definition: CPUDyntransComponent.h:618
Component::GetUI
UI * GetUI()
Gets an UI reference for outputting debug messages during runtime.
Definition: Component.cc:583
CPUDyntransComponent
A base-class for processors Component implementations that use dynamic translation.
Definition: CPUDyntransComponent.h:91
REG32
#define REG32(arg)
Definition: CPUDyntransComponent.h:79
UNITTEST
#define UNITTEST(functionname)
Helper for unit test case execution.
Definition: UnitTest.h:217
UI
Base class for a User Interface.
Definition: UI.h:42
CPUDyntransComponent::m_translationCache
DyntransTranslationCache m_translationCache
Definition: CPUDyntransComponent.h:624
UnitTest::Assert
static void Assert(const string &strFailMessage, bool condition)
Asserts that a boolean condition is correct.
Definition: UnitTest.cc:40
DyntransIC
Definition: CPUDyntransComponent.h:55
CPUComponent::m_pc
uint64_t m_pc
Definition: CPUComponent.h:202
CPUDyntransComponent::DyntransResyncPC
void DyntransResyncPC()
Calculate m_pc based on m_nextIC and m_firstIConPage.
Definition: CPUDyntransComponent.cc:253
UI::ShowDebugMessage
virtual void ShowDebugMessage(const string &msg)=0
Shows a debug message.
ic
struct arm_instr_call * ic
Definition: tmp_arm_multi.cc:50
CPUDyntransComponent::m_dyntransICshift
int m_dyntransICshift
Definition: CPUDyntransComponent.h:617
CPUDyntransComponent::DyntransPCtoPointers
void DyntransPCtoPointers()
Calculate m_nextIC and m_firstIConPage, based on m_pc.
Definition: CPUDyntransComponent.cc:233
CPUDyntransComponent.h
SymbolRegistry::LookupAddress
string LookupAddress(uint64_t vaddr, bool allowOffset) const
Looks up an address.
Definition: SymbolRegistry.cc:48
CPUDyntransComponent::m_abortIC
struct DyntransIC m_abortIC
Definition: CPUDyntransComponent.h:629
CPUComponent::m_pageSize
int m_pageSize
Definition: CPUComponent.h:199
CPUDyntransComponent::GetDyntransToBeTranslated
virtual DyntransIC_t GetDyntransToBeTranslated()=0
CPUComponent::m_isBigEndian
bool m_isBigEndian
Definition: CPUComponent.h:210
GXemul::GetRunState
RunState GetRunState() const
Gets the current RunState.
Definition: GXemul.cc:741
DYNTRANS_INSTR
DYNTRANS_INSTR(CPUDyntransComponent, nop)
Definition: CPUDyntransComponent.cc:440
nop
void COMBINE() nop(struct cpu *cpu, struct mips_instr_call *ic, int low_addr)
Definition: cpu_mips_instr.cc:3365
GXemul::SetQuietMode
void SetQuietMode(bool quietMode)
Sets whether or not to run in quiet mode.
Definition: GXemul.cc:786
symbol
Definition: symbol.h:37
GXemul::GetUI
UI * GetUI()
Gets a pointer to the GXemul instance' active UI.
Definition: GXemul.cc:653
GXemul::SingleStepping
@ SingleStepping
Definition: GXemul.h:60
CPUDyntransComponent::DyntransReadInstruction
bool DyntransReadInstruction(uint16_t &iword, int offset=0)
Definition: CPUDyntransComponent.cc:313
CPUComponent::ReadData
virtual bool ReadData(uint8_t &data, Endianness endianness)
Reads 8-bit data from the currently selected address.
Definition: CPUComponent.cc:504
CPUDyntransComponent::GetDyntransICshift
virtual int GetDyntransICshift() const =0
DYNTRANS_PAGE_NSPECIALENTRIES
#define DYNTRANS_PAGE_NSPECIALENTRIES
Definition: CPUDyntransComponent.h:69
CPUDyntransComponent::DyntransToBeTranslatedDone
void DyntransToBeTranslatedDone(struct DyntransIC *)
Definition: CPUDyntransComponent.cc:360
CPUDyntransComponent::CPUDyntransComponent
CPUDyntransComponent(const string &className, const string &cpuKind)
Constructs a CPUDyntransComponent.
Definition: CPUDyntransComponent.cc:36
DyntransIC_t
void(* DyntransIC_t)(class CPUDyntransComponent *, struct DyntransIC *)
Definition: CPUDyntransComponent.h:52
CPUComponent::PCtoInstructionAddress
virtual uint64_t PCtoInstructionAddress(uint64_t pc)
Convert PC value to instuction address.
Definition: CPUComponent.h:171
CPUComponent::m_showFunctionTraceCall
bool m_showFunctionTraceCall
Definition: CPUComponent.h:213
AddressDataBus.h
CPUDyntransComponent::m_nrOfCyclesToExecute
int m_nrOfCyclesToExecute
Definition: CPUDyntransComponent.h:619
CPUDyntransComponent::m_dyntransICentriesPerPage
int m_dyntransICentriesPerPage
Definition: CPUDyntransComponent.h:616
BigEndian
@ BigEndian
Definition: misc.h:158
CPUComponent::m_delaySlotTarget
uint64_t m_delaySlotTarget
Definition: CPUComponent.h:220
CPUComponent::m_exceptionOrAbortInDelaySlot
bool m_exceptionOrAbortInDelaySlot
Definition: CPUComponent.h:228
DyntransIC::f
DyntransIC_t f
Definition: CPUDyntransComponent.h:56
CPUComponent::AddressSelect
virtual void AddressSelect(uint64_t address)
Place an address on the bus.
Definition: CPUComponent.cc:498
GXemul.h
Component::GetRunningGXemulInstance
GXemul * GetRunningGXemulInstance()
Returns a reference to the current GXemul instance.
Definition: Component.cc:569
CPUComponent
A base-class for processors Component implementations.
Definition: CPUComponent.h:47
CPUDyntransComponent::DyntransToBeTranslatedBegin
void DyntransToBeTranslatedBegin(struct DyntransIC *)
Definition: CPUDyntransComponent.cc:298
REG64
#define REG64(arg)
Definition: CPUDyntransComponent.h:80

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