MIPS_CPUComponent.cc Source File

Back to the index.

MIPS_CPUComponent.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008-2010 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 <stdio.h>
30 #include <string.h>
31 #include <iomanip>
32 
33 #include "ComponentFactory.h"
34 #include "GXemul.h"
36 #include "mips_cpu_types.h"
37 #include "opcodes_mips.h"
38 
39 static const char* hi6_names[] = HI6_NAMES;
40 static const char* regnames_old[] = MIPS_OLDABI_REGISTER_NAMES;
41 static const char* regnames[] = MIPS_REGISTER_NAMES;
42 static const char* special_names[] = SPECIAL_NAMES;
43 static const char* special_rot_names[] = SPECIAL_ROT_NAMES;
44 static const char* regimm_names[] = REGIMM_NAMES;
45 static mips_cpu_type_def cpu_type_defs[] = MIPS_CPU_TYPE_DEFS;
46 
47 
48 static const char* regname(int i, const string& abi)
49 {
50  if (abi == "o32")
51  return regnames_old[i];
52  else
53  return regnames[i];
54 }
55 
56 
58  : CPUDyntransComponent("mips_cpu", "MIPS")
59  , m_mips_type("5KE") // defaults to a MIPS64 rev 2 cpu
60  , m_abi("n64")
61 {
62  m_frequency = 100e6;
63 
64  // Find (and cache) the cpu type in m_type:
65  memset((void*) &m_type, 0, sizeof(m_type));
66  for (size_t j=0; cpu_type_defs[j].name != NULL; j++) {
67  if (m_mips_type == cpu_type_defs[j].name) {
68  m_type = cpu_type_defs[j];
69  break;
70  }
71  }
72 
73  if (m_type.name == NULL) {
74  std::cerr << "Internal error: Unimplemented MIPS type?\n";
75  throw std::exception();
76  }
77 
78  ResetState();
79 
80  AddVariable("model", &m_mips_type);
81  AddVariable("abi", &m_abi);
82 
83  AddVariable("hi", &m_hi);
84  AddVariable("lo", &m_lo);
85 
86  // TODO: This only registers using the new ABI names. How should
87  // this be handled? Custom "aliasing" variables?
88  for (size_t i=0; i<N_MIPS_GPRS; i++)
89  AddVariable(regname(i, m_abi), &m_gpr[i]);
90 
91  AddVariable("inDelaySlot", &m_inDelaySlot);
92  AddVariable("delaySlotTarget", &m_delaySlotTarget);
93 }
94 
95 
97 {
98  // Defaults:
100  settings["model"] = "5KE";
101 
102  if (!ComponentFactory::GetCreationArgOverrides(settings, args))
103  return NULL;
104 
106  if (!cpu->SetVariableValue("model", "\"" + settings["model"] + "\""))
107  return NULL;
108 
109  return cpu;
110 }
111 
112 
114 {
115  // Most MIPS CPUs use 4 KB native page size.
116  // However, a few use 1 KB pages; this should be supported as well.
117  // TODO: Always use 1024 (worst case) on those CPUs? Or switch during
118  // runtime from 4096 to 1024? (More complicated...)
119  m_pageSize = 4096;
120 
121  m_hi = 0;
122  m_lo = 0;
123  m_scratch = 0;
124 
125  for (size_t i=0; i<N_MIPS_GPRS; i++)
126  m_gpr[i] = 0;
127 
128  // MIPS CPUs are hardwired to start at 0xffffffffbfc00000:
130 
131  // Reasonable initial stack pointer.
133 
135 }
136 
137 
139 {
140  if (m_gpr[MIPS_GPR_ZERO] != 0) {
141  gxemul->GetUI()->ShowDebugMessage(this, "the zero register (zr) "
142  "must contain the value 0.\n");
143  return false;
144  }
145 
146  if (m_pc & 0x2) {
147  gxemul->GetUI()->ShowDebugMessage(this, "the pc register"
148  " can not have bit 1 set!\n");
149  return false;
150  }
151 
152  if (Is32Bit()) {
153  // All registers must be sign-extended correctly.
154  if ((int64_t)m_pc != (int64_t)(int32_t)m_pc) {
155  gxemul->GetUI()->ShowDebugMessage(this, "The emulated "
156  "CPU is 32-bit, but the pc register is not"
157  " a correctly sign-extended 32-bit value!\n");
158  return false;
159  }
160 
161  for (size_t i=1; i<N_MIPS_GPRS; i++) {
162  if ((int64_t)m_gpr[i] != (int64_t)(int32_t)m_gpr[i]) {
163  gxemul->GetUI()->ShowDebugMessage(this, (string)"The emulated "
164  "CPU is 32-bit, but the " + regname(i, m_abi) + " register is not"
165  " a correctly sign-extended 32-bit value!\n");
166  return false;
167  }
168  }
169 
170  // TODO: Some more registers?
171  }
172 
174 }
175 
176 
177 bool MIPS_CPUComponent::CheckVariableWrite(StateVariable& var, const string& oldValue)
178 {
179  UI* ui = GetUI();
180 
181  if (m_gpr[MIPS_GPR_ZERO] != 0) {
182  if (ui != NULL) {
183  ui->ShowDebugMessage(this, "the zero register (zr) "
184  "must contain the value 0.\n");
185  }
186  return false;
187  }
188 
189  if (m_mips_type != m_type.name) {
190  bool found = false;
191  for (size_t j=0; cpu_type_defs[j].name != NULL; j++) {
192  if (m_mips_type == cpu_type_defs[j].name) {
193  m_type = cpu_type_defs[j];
194  found = true;
195  break;
196  }
197  }
198 
199  if (!found) {
200  if (ui != NULL) {
201  stringstream ss;
202  ss << "Unknown model \"" + m_mips_type + "\". Available types are:\n";
203  for (size_t j=0; cpu_type_defs[j].name != NULL; j++) {
204  if ((j % 6) != 0)
205  ss << "\t";
206  ss << cpu_type_defs[j].name;
207  if ((j % 6) == 5)
208  ss << "\n";
209  }
210  ui->ShowDebugMessage(this, ss.str());
211  }
212  return false;
213  }
214  }
215 
216  return CPUDyntransComponent::CheckVariableWrite(var, oldValue);
217 }
218 
219 
220 bool MIPS_CPUComponent::Is32Bit() const
221 {
222  return m_type.isa_level == 32 || m_type.isa_level <= 2;
223 }
224 
225 
226 static uint64_t Trunc3264(uint64_t x, bool is32bit)
227 {
228  return is32bit? (uint32_t)x : x;
229 }
230 
231 
232 static uint64_t TruncSigned3264(uint64_t x, bool is32bit)
233 {
234  return is32bit? (int32_t)x : x;
235 }
236 
237 
238 void MIPS_CPUComponent::ShowRegisters(GXemul* gxemul, const vector<string>& arguments) const
239 {
240  bool is32bit = Is32Bit();
241  stringstream ss;
242 
243  ss.flags(std::ios::hex);
244  ss << std::setfill('0');
245 
246  // Yuck, this is horrible. Is there some portable way to put e.g.
247  // std::setw(16) into an object, and just pass that same object several
248  // times?
249 
250  ss << "pc=";
251  if (is32bit)
252  ss << std::setw(8);
253  else
254  ss << std::setw(16);
255  ss << Trunc3264(m_pc, is32bit);
256  string symbol = GetSymbolRegistry().LookupAddress(TruncSigned3264(m_pc, is32bit), true);
257  if (symbol != "")
258  ss << " <" << symbol << ">";
259  ss << "\n";
260 
261  ss << "hi=";
262  if (is32bit)
263  ss << std::setw(8);
264  else
265  ss << std::setw(16);
266  ss << Trunc3264(m_hi, is32bit) << " lo=";
267  if (is32bit)
268  ss << std::setw(8);
269  else
270  ss << std::setw(16);
271  ss << Trunc3264(m_lo, is32bit) << "\n";
272 
273  for (size_t i=0; i<N_MIPS_GPRS; i++) {
274  ss << regname(i, m_abi) << "=";
275  if (is32bit)
276  ss << std::setw(8);
277  else
278  ss << std::setw(16);
279  ss << Trunc3264(m_gpr[i], is32bit);
280  if ((i&3) == 3)
281  ss << "\n";
282  else
283  ss << " ";
284  }
285 
286  gxemul->GetUI()->ShowDebugMessage(ss.str());
287 }
288 
289 
291 {
292  // On old 32-bit ABIs, registers 4..7 (a0..a3) are used. On newer
293  // ABIs (both 32-bit and 64-bit), registers 4..11 are used (a0..a7).
294 
295  if (m_abi == "o32")
296  return 4;
297 
298  return 8;
299 }
300 
301 
303 {
304  // See comment for FunctionTraceArgumentCount above.
305  return m_gpr[MIPS_GPR_A0 + n];
306 }
307 
308 
310 {
311  // v0 and v1 may hold return values. However, v1 is only used for
312  // returning 64-bit values on old 32-bit ABIs, and 128-bit values
313  // on newer ABIs, so for now I'll ignore it.
314 
315  retval = m_gpr[MIPS_GPR_V0];
316  return true;
317 }
318 
319 
321 {
322  bool mips16 = m_pc & 1? true : false;
323 
324  // Normal encoding: 4 bytes per instruction, i.e. shift is 2 bits.
325  // MIPS16 encoding: 2 bytes per instruction, i.e. shift is 1 bit.
326  return mips16? 1 : 2;
327 }
328 
329 
331 {
332  bool mips16 = m_pc & 1? true : false;
333  return mips16? instr_ToBeTranslated_MIPS16 : instr_ToBeTranslated;
334 }
335 
336 
337 bool MIPS_CPUComponent::VirtualToPhysical(uint64_t vaddr, uint64_t& paddr,
338  bool& writable)
339 {
340  if (Is32Bit())
341  vaddr = (int32_t)vaddr;
342 
343  // TODO. For now, just return the lowest 29 bits.
344  if (vaddr >= 0xffffffff80000000ULL && vaddr < 0xffffffffc0000000ULL) {
345  paddr = vaddr & 0x1fffffff;
346  writable = true;
347  return true;
348  }
349 
350  // TODO ... or the lowest 44.
351  if (vaddr >= 0xa800000000000000ULL && vaddr < 0xa8000fffffffffffULL) {
352  paddr = vaddr & 0xfffffffffffULL;
353  writable = true;
354  return true;
355  }
356 
357  return false;
358 }
359 
360 
362 {
363  // MIPS16 has the lowest bit set, but the instruction is aligned as
364  // if the lowest bit was 0.
365  return pc & ~1;
366 }
367 
368 
369 size_t MIPS_CPUComponent::DisassembleInstructionMIPS16(uint64_t vaddr,
370  unsigned char *instruction, vector<string>& result)
371 {
372  // Read the instruction word:
373  uint16_t iword = *((uint16_t *) instruction);
374  if (m_isBigEndian)
375  iword = BE16_TO_HOST(iword);
376  else
377  iword = LE16_TO_HOST(iword);
378 
379  // ... and add it to the result:
380  char tmp[5];
381  snprintf(tmp, sizeof(tmp), "%04x", iword);
382  result.push_back(tmp);
383 
384  int hi5 = iword >> 11;
385  int rx = (iword >> 8) & 7;
386  int ry = (iword >> 5) & 7;
387 // int rz = (iword >> 2) & 7;
388  int imm5 = iword & 0x1f;
389 
390  // Registers are: 16 17 2 3 4 5 6 7, and T(24) and SP(29).
391  if (rx <= 1)
392  rx += 16;
393  if (ry <= 1)
394  ry += 16;
395 
396  switch (hi5) {
397 
398  case 0x14: /* lbu y,5(x) */
399  case 0x18: /* sb y,5(x) */
400  {
401  stringstream ss;
402  switch (hi5) {
403  case 0x14: result.push_back("lbu"); break;
404  case 0x18: result.push_back("sb"); break;
405  }
406 
407  int ofs = imm5; // TODO: scaling?
408 
409  ss << regname(ry, m_abi) << "," << ofs << "(" << regname(rx, m_abi) << ")";
410  result.push_back(ss.str());
411  }
412  break;
413 
414  default:
415  {
416  stringstream ss;
417  ss.flags(std::ios::hex);
418  ss << "unimplemented MIPS16 opcode 0x" << hi5;
419  result.push_back(ss.str());
420  }
421  break;
422  }
423 
424  return sizeof(uint16_t);
425 }
426 
427 
428 size_t MIPS_CPUComponent::DisassembleInstruction(uint64_t vaddr, size_t maxLen,
429  unsigned char *instruction, vector<string>& result)
430 {
431  const bool mips16 = m_pc & 1? true : false;
432  const size_t instrSize = mips16? sizeof(uint16_t) : sizeof(uint32_t);
433 
434  if (maxLen < instrSize) {
435  assert(false);
436  return 0;
437  }
438 
439  if (mips16)
440  return DisassembleInstructionMIPS16(vaddr,
441  instruction, result);
442 
443  // Read the instruction word:
444  uint32_t instructionWord = *((uint32_t *) instruction);
445  if (m_isBigEndian)
446  instructionWord = BE32_TO_HOST(instructionWord);
447  else
448  instructionWord = LE32_TO_HOST(instructionWord);
449 
450  const uint32_t iword = instructionWord;
451 
452  // ... and add it to the result:
453  {
454  stringstream ss;
455  ss.flags(std::ios::hex);
456  ss << std::setfill('0') << std::setw(8) << (uint32_t) iword;
457  if (PCtoInstructionAddress(m_pc) == vaddr && m_inDelaySlot)
458  ss << " (delayslot)";
459  result.push_back(ss.str());
460  }
461 
462  const int hi6 = iword >> 26;
463  const int rs = (iword >> 21) & 31;
464  const int rt = (iword >> 16) & 31;
465  const int rd = (iword >> 11) & 31;
466  const int sa = (iword >> 6) & 31;
467 
468  switch (hi6) {
469 
470  case HI6_SPECIAL:
471  {
472  int special6 = iword & 0x3f;
473  int sub = rs;
474  stringstream ss;
475 
476  switch (special6) {
477 
478  case SPECIAL_SLL:
479  case SPECIAL_SRL:
480  case SPECIAL_SRA:
481  case SPECIAL_DSLL:
482  case SPECIAL_DSRL:
483  case SPECIAL_DSRA:
484  case SPECIAL_DSLL32:
485  case SPECIAL_DSRL32:
486  case SPECIAL_DSRA32:
487  if (rd == 0 && special6 == SPECIAL_SLL) {
488  if (sa == 0)
489  ss << "nop";
490  else if (sa == 1)
491  ss << "ssnop";
492  else if (sa == 3)
493  ss << "ehb";
494  else
495  ss << "nop (weird, sa="
496  << sa << ")";
497 
498  result.push_back(ss.str());
499  break;
500  }
501 
502  switch (sub) {
503  case 0x00:
504  result.push_back(
505  special_names[special6]);
506  ss << regname(rd, m_abi) << "," <<
507  regname(rt, m_abi) << "," << sa;
508  result.push_back(ss.str());
509  break;
510  case 0x01:
511  result.push_back(
512  special_rot_names[special6]);
513  ss << regname(rd, m_abi) << "," <<
514  regname(rt, m_abi) << "," << sa;
515  result.push_back(ss.str());
516  break;
517  default:ss << "unimpl special, sub=" << sub;
518  result.push_back(ss.str());
519  }
520  break;
521 
522  case SPECIAL_DSRLV:
523  case SPECIAL_DSRAV:
524  case SPECIAL_DSLLV:
525  case SPECIAL_SLLV:
526  case SPECIAL_SRAV:
527  case SPECIAL_SRLV:
528  sub = sa;
529 
530  switch (sub) {
531  case 0x00:
532  result.push_back(
533  special_names[special6]);
534  ss << regname(rd, m_abi) << "," <<
535  regname(rt, m_abi) << "," <<
536  regname(rs, m_abi);
537  result.push_back(ss.str());
538  break;
539  case 0x01:
540  result.push_back(
541  special_rot_names[special6]);
542  ss << regname(rd, m_abi) << "," <<
543  regname(rt, m_abi) << "," <<
544  regname(rs, m_abi);
545  result.push_back(ss.str());
546  break;
547  default:ss << "unimpl special, sub="
548  << sub;
549  result.push_back(ss.str());
550  }
551  break;
552 
553  case SPECIAL_JR:
554  /* .hb = hazard barrier hint on MIPS32/64
555  rev 2 */
556  if ((iword >> 10) & 1)
557  result.push_back("jr.hb");
558  else
559  result.push_back("jr");
560  ss << regname(rs, m_abi);
561  result.push_back(ss.str());
562  break;
563 
564  case SPECIAL_JALR:
565  /* .hb = hazard barrier hint on
566  MIPS32/64 rev 2 */
567  if ((iword >> 10) & 1)
568  result.push_back("jalr.hb");
569  else
570  result.push_back("jalr");
571  ss << regname(rd, m_abi) << "," << regname(rs, m_abi);
572  result.push_back(ss.str());
573  break;
574 
575  case SPECIAL_MFHI:
576  case SPECIAL_MFLO:
577  result.push_back(special_names[special6]);
578  result.push_back(regname(rd, m_abi));
579  break;
580 
581  case SPECIAL_MTLO:
582  case SPECIAL_MTHI:
583  result.push_back(special_names[special6]);
584  result.push_back(regname(rs, m_abi));
585  break;
586 
587  case SPECIAL_ADD:
588  case SPECIAL_ADDU:
589  case SPECIAL_SUB:
590  case SPECIAL_SUBU:
591  case SPECIAL_AND:
592  case SPECIAL_OR:
593  case SPECIAL_XOR:
594  case SPECIAL_NOR:
595  case SPECIAL_SLT:
596  case SPECIAL_SLTU:
597  case SPECIAL_DADD:
598  case SPECIAL_DADDU:
599  case SPECIAL_DSUB:
600  case SPECIAL_DSUBU:
601  case SPECIAL_MOVZ:
602  case SPECIAL_MOVN:
603  result.push_back(special_names[special6]);
604  ss << regname(rd, m_abi) << "," <<
605  regname(rs, m_abi) << "," << regname(rt, m_abi);
606  result.push_back(ss.str());
607  break;
608 
609  case SPECIAL_MULT:
610  case SPECIAL_MULTU:
611  case SPECIAL_DMULT:
612  case SPECIAL_DMULTU:
613  case SPECIAL_DIV:
614  case SPECIAL_DIVU:
615  case SPECIAL_DDIV:
616  case SPECIAL_DDIVU:
617  case SPECIAL_TGE:
618  case SPECIAL_TGEU:
619  case SPECIAL_TLT:
620  case SPECIAL_TLTU:
621  case SPECIAL_TEQ:
622  case SPECIAL_TNE:
623  result.push_back(special_names[special6]);
624  if (rd != 0) {
625  if (m_type.rev == MIPS_R5900) {
626  if (special6 == SPECIAL_MULT ||
627  special6 == SPECIAL_MULTU)
628  ss << regname(rd, m_abi)<<",";
629  else
630  ss << "WEIRD_R5900_RD,";
631  } else {
632  ss << "WEIRD_R5900_RD,";
633  }
634  }
635 
636  ss << regname(rs, m_abi) << "," << regname(rt, m_abi);
637  result.push_back(ss.str());
638  break;
639 
640  case SPECIAL_SYNC:
641  result.push_back(special_names[special6]);
642  ss << ((iword >> 6) & 31);
643  result.push_back(ss.str());
644  break;
645 
646  case SPECIAL_SYSCALL:
647  case SPECIAL_BREAK:
648  result.push_back(special_names[special6]);
649  if (((iword >> 6) & 0xfffff) != 0) {
650  ss << ((iword >> 6) & 0xfffff);
651  result.push_back(ss.str());
652  }
653  break;
654 
655  case SPECIAL_MFSA:
656  if (m_type.rev == MIPS_R5900) {
657  result.push_back("mfsa");
658  result.push_back(regname(rd, m_abi));
659  } else {
660  result.push_back(
661  "unimplemented special 0x28");
662  }
663  break;
664 
665  case SPECIAL_MTSA:
666  if (m_type.rev == MIPS_R5900) {
667  result.push_back("mtsa");
668  result.push_back(regname(rs, m_abi));
669  } else {
670  result.push_back(
671  "unimplemented special 0x29");
672  }
673  break;
674 
675  default:
676  ss << "unimplemented: " <<
677  special_names[special6];
678  result.push_back(ss.str());
679  break;
680  }
681  }
682  break;
683 
684  case HI6_BEQ:
685  case HI6_BEQL:
686  case HI6_BNE:
687  case HI6_BNEL:
688  case HI6_BGTZ:
689  case HI6_BGTZL:
690  case HI6_BLEZ:
691  case HI6_BLEZL:
692  {
693  int imm = (int16_t) iword;
694  uint64_t addr = vaddr + 4 + (imm << 2);
695 
696  stringstream ss;
697 
698  if (hi6 == HI6_BEQ && rt == MIPS_GPR_ZERO &&
699  rs == MIPS_GPR_ZERO) {
700  result.push_back("b");
701  } else {
702  result.push_back(hi6_names[hi6]);
703 
704  switch (hi6) {
705  case HI6_BEQ:
706  case HI6_BEQL:
707  case HI6_BNE:
708  case HI6_BNEL:
709  ss << regname(rt, m_abi) << ",";
710  }
711 
712  ss << regname(rs, m_abi) << ",";
713  }
714 
715  ss.flags(std::ios::hex | std::ios::showbase);
716  ss << addr;
717  result.push_back(ss.str());
718 
719  string symbol = GetSymbolRegistry().LookupAddress(addr, true);
720  if (symbol != "")
721  result.push_back("; <" + symbol + ">");
722  }
723  break;
724 
725  case HI6_ADDI:
726  case HI6_ADDIU:
727  case HI6_DADDI:
728  case HI6_DADDIU:
729  case HI6_SLTI:
730  case HI6_SLTIU:
731  case HI6_ANDI:
732  case HI6_ORI:
733  case HI6_XORI:
734  {
735  result.push_back(hi6_names[hi6]);
736 
737  stringstream ss;
738  ss << regname(rt, m_abi) << "," << regname(rs, m_abi) << ",";
739  if (hi6 == HI6_ANDI || hi6 == HI6_ORI ||
740  hi6 == HI6_XORI) {
741  ss.flags(std::ios::hex | std::ios::showbase);
742  ss << (uint16_t) iword;
743  } else {
744  ss << (int16_t) iword;
745  }
746  result.push_back(ss.str());
747  }
748  break;
749 
750  case HI6_LUI:
751  {
752  result.push_back(hi6_names[hi6]);
753 
754  stringstream ss;
755  ss << regname(rt, m_abi) << ",";
756  ss.flags(std::ios::hex | std::ios::showbase);
757  ss << (uint16_t) iword;
758  result.push_back(ss.str());
759  }
760  break;
761 
762  case HI6_LB:
763  case HI6_LBU:
764  case HI6_LH:
765  case HI6_LHU:
766  case HI6_LW:
767  case HI6_LWU:
768  case HI6_LD:
769  case HI6_LQ_MDMX:
770  case HI6_LWC1:
771  case HI6_LWC2:
772  case HI6_LWC3:
773  case HI6_LDC1:
774  case HI6_LDC2:
775  case HI6_LL:
776  case HI6_LLD:
777  case HI6_SB:
778  case HI6_SH:
779  case HI6_SW:
780  case HI6_SD:
781  case HI6_SQ_SPECIAL3:
782  case HI6_SC:
783  case HI6_SCD:
784  case HI6_SWC1:
785  case HI6_SWC2:
786  case HI6_SWC3:
787  case HI6_SDC1:
788  case HI6_SDC2:
789  case HI6_LWL:
790  case HI6_LWR:
791  case HI6_LDL:
792  case HI6_LDR:
793  case HI6_SWL:
794  case HI6_SWR:
795  case HI6_SDL:
796  case HI6_SDR:
797  {
798  if (hi6 == HI6_LQ_MDMX && m_type.rev != MIPS_R5900) {
799  result.push_back("mdmx (UNIMPLEMENTED)");
800  break;
801  }
802  if (hi6 == HI6_SQ_SPECIAL3 && m_type.rev!=MIPS_R5900) {
803  result.push_back("special3 (UNIMPLEMENTED)");
804  break;
805  }
806 
807 
808  int imm = (int16_t) iword;
809  stringstream ss;
810 
811  /* LWC3 is PREF in the newer ISA levels: */
812  /* TODO: Which ISAs? IV? V? 32? 64? */
813  if (m_type.isa_level >= 4 && hi6 == HI6_LWC3) {
814  result.push_back("pref");
815 
816  ss << rt << "," << imm <<
817  "(" << regname(rs, m_abi) << ")";
818  result.push_back(ss.str());
819  break;
820  }
821 
822  result.push_back(hi6_names[hi6]);
823 
824  if (hi6 == HI6_SWC1 || hi6 == HI6_SWC2 ||
825  hi6 == HI6_SWC3 ||
826  hi6 == HI6_SDC1 || hi6 == HI6_SDC2 ||
827  hi6 == HI6_LWC1 || hi6 == HI6_LWC2 ||
828  hi6 == HI6_LWC3 ||
829  hi6 == HI6_LDC1 || hi6 == HI6_LDC2)
830  ss << "r" << rt;
831  else
832  ss << regname(rt, m_abi);
833 
834  ss << "," << imm << "(" << regname(rs, m_abi) << ")";
835 
836  result.push_back(ss.str());
837  }
838  break;
839 
840  case HI6_J:
841  case HI6_JAL:
842  {
843  result.push_back(hi6_names[hi6]);
844 
845  int imm = (iword & 0x03ffffff) << 2;
846  uint64_t addr = (vaddr + 4) & ~((1 << 28) - 1);
847  addr |= imm;
848 
849  stringstream ss;
850  ss.flags(std::ios::hex | std::ios::showbase);
851  ss << addr;
852  result.push_back(ss.str());
853 
854  string symbol = GetSymbolRegistry().LookupAddress(addr, true);
855  if (symbol != "")
856  result.push_back("; <" + symbol + ">");
857  }
858  break;
859 
860  // CopX here. TODO
861  // Cache
862  // Special2
863 
864  case HI6_REGIMM:
865  {
866  int regimm5 = (iword >> 16) & 0x1f;
867  int imm = (int16_t) iword;
868  uint64_t addr = (vaddr + 4) + (imm << 2);
869 
870  stringstream ss;
871  ss.flags(std::ios::hex | std::ios::showbase);
872 
873  switch (regimm5) {
874 
875  case REGIMM_BLTZ:
876  case REGIMM_BGEZ:
877  case REGIMM_BLTZL:
878  case REGIMM_BGEZL:
879  case REGIMM_BLTZAL:
880  case REGIMM_BLTZALL:
881  case REGIMM_BGEZAL:
882  case REGIMM_BGEZALL:
883  result.push_back(regimm_names[regimm5]);
884 
885  ss << regname(rs, m_abi) << "," << addr;
886  result.push_back(ss.str());
887  break;
888 
889  case REGIMM_SYNCI:
890  result.push_back(regimm_names[regimm5]);
891 
892  ss << imm << "(" << regname(rs, m_abi) << ")";
893  result.push_back(ss.str());
894  break;
895 
896  default:
897  {
898  ss << "unimplemented: " <<
899  regimm_names[regimm5];
900  result.push_back(ss.str());
901  }
902  }
903  }
904  break;
905 
906  default:
907  {
908  stringstream ss;
909  ss << "unimplemented: " << hi6_names[hi6];
910  result.push_back(ss.str());
911  }
912  break;
913  }
914 
915  return instrSize;
916 }
917 
918 
919 string MIPS_CPUComponent::GetAttribute(const string& attributeName)
920 {
921  if (attributeName == "stable")
922  return "yes";
923 
924  if (attributeName == "description")
925  return "MIPS processor.";
926 
927  return Component::GetAttribute(attributeName);
928 }
929 
930 
931 /*****************************************************************************/
932 
933 
934 /*
935  * b*: Branch on condition
936  *
937  * op 0: beq rs == rt
938  * op 1: bne rs != rt
939  * op 2: blez rs <= 0 (signed)
940  * op 3: bgtz rs > 0 (signed)
941  *
942  * arg[0] = pointer to register rs
943  * arg[1] = pointer to register rt
944  * arg[2] = signed offset from start of current page to branch to _OR_ pointer to new instr_call
945  */
946 template<int op, bool samepage, bool singlestep> void MIPS_CPUComponent::instr_b(CPUDyntransComponent* cpubase, DyntransIC* ic)
947 {
949 
950  bool cond;
951 
952  if (op == 0) cond = REG64(ic->arg[0]) == REG64(ic->arg[1]); // beq
953  else if (op == 1) cond = REG64(ic->arg[0]) != REG64(ic->arg[1]); // bne
954  else if (op == 2) cond = (int64_t)REG64(ic->arg[0]) <= 0; // blez
955  else /* op == 3 */ cond = (int64_t)REG64(ic->arg[0]) > 0; // bgtz
956 
957  if (singlestep) {
959 
960  // Prepare for the branch.
961  cpu->m_inDelaySlot = true;
962  cpu->m_exceptionOrAbortInDelaySlot = false;
963 
964  if (cond) {
965  if (samepage) {
966  std::cerr << "MIPS b instruction: samepage singlestep: should not happen.\n";
967  throw std::exception();
968  } else {
969  cpu->m_delaySlotTarget = cpu->m_pc & ~cpu->m_dyntransPageMask;
970  cpu->m_delaySlotTarget = cpu->m_delaySlotTarget + (int32_t)ic->arg[2].u32;
971  }
972  } else {
973  cpu->m_delaySlotTarget = cpu->m_pc + 8;
974  }
975 
976  cpu->m_nextIC = ic + 1;
977  } else {
978  // Prepare for the branch.
979  cpu->m_inDelaySlot = true;
980  cpu->m_exceptionOrAbortInDelaySlot = false;
981 
982  // Execute the next instruction:
983  ic[1].f(cpu, ic+1);
984  cpu->m_executedCycles ++;
985 
986  // If there was no exception, then branch:
987  if (!cpu->m_exceptionOrAbortInDelaySlot) {
988  if (cond) {
989  if (samepage) {
990  cpu->m_nextIC = (DyntransIC*) ic->arg[2].p;
991  } else {
992  cpu->m_pc &= ~cpu->m_dyntransPageMask;
993  cpu->m_pc = cpu->m_pc + (int32_t)ic->arg[2].u32;
994  cpu->DyntransPCtoPointers();
995  }
996  } else {
997  cpu->m_nextIC = ic + 2;
998  }
999 
1000  cpu->m_inDelaySlot = false;
1001  }
1002 
1003  // The next instruction is now either the target of the branch
1004  // instruction, the instruction 2 steps after this one,
1005  // or the first instruction of an exception handler.
1006  cpu->m_exceptionOrAbortInDelaySlot = false;
1007  }
1008 }
1009 
1010 
1011 /*
1012  * j, jal: Jump [and link]
1013  *
1014  * arg[0] = lowest 28 bits of new pc
1015  */
1016 template<bool link, bool singlestep> void MIPS_CPUComponent::instr_j(CPUDyntransComponent* cpubase, DyntransIC* ic)
1017 {
1019 
1020  if (link) {
1022  cpu->m_gpr[MIPS_GPR_RA] = cpu->m_pc + 8;
1023 
1024  if (cpu->m_showFunctionTraceCall) {
1025  uint64_t saved_pc = cpu->m_pc;
1026  cpu->m_pc = cpu->m_pc & ~0x0fffffffUL;
1027  cpu->m_pc += ic->arg[0].u32;
1028  cpu->FunctionTraceCall();
1029  cpu->m_pc = saved_pc;
1030  }
1031  }
1032 
1033  if (singlestep) {
1034  // Prepare for the branch.
1035  cpu->m_inDelaySlot = true;
1036  cpu->m_exceptionOrAbortInDelaySlot = false;
1037 
1038  cpu->m_delaySlotTarget = cpu->m_pc & ~0x0fffffffUL;
1039  cpu->m_delaySlotTarget += ic->arg[0].u32;
1040 
1041  cpu->m_nextIC = ic + 1;
1042  } else {
1043  // Prepare for the branch.
1044  cpu->m_inDelaySlot = true;
1045  cpu->m_exceptionOrAbortInDelaySlot = false;
1046 
1047  // Execute the next instruction:
1048  ic[1].f(cpu, ic+1);
1049  cpu->m_executedCycles ++;
1050 
1051  // If there was no exception, then branch:
1052  if (!cpu->m_exceptionOrAbortInDelaySlot) {
1053  cpu->m_pc = cpu->m_pc & ~0x0fffffffUL;
1054  cpu->m_pc += ic->arg[0].u32;
1055  cpu->DyntransPCtoPointers();
1056 
1057  cpu->m_inDelaySlot = false;
1058  }
1059 
1060  // The next instruction is now either the target of the branch
1061  // instruction, the instruction 2 steps after this one,
1062  // or the first instruction of an exception handler.
1063  cpu->m_exceptionOrAbortInDelaySlot = false;
1064  }
1065 }
1066 
1067 
1068 /*
1069  * jr, jalr: Jump to register [and link]
1070  *
1071  * arg[0] = pointer to register rs (to jump to)
1072  * arg[1] = pointer to register rd (to store return address in; this is never the zero register)
1073  */
1074 template<bool link, bool singlestep> void MIPS_CPUComponent::instr_jr(CPUDyntransComponent* cpubase, DyntransIC* ic)
1075 {
1077 
1078  if (link) {
1080  REG32(ic->arg[1]) = cpu->m_pc + 8;
1081 
1082  if (cpu->m_showFunctionTraceCall && ic->arg[1].p == &cpu->m_gpr[MIPS_GPR_RA]) {
1083  uint64_t saved_pc = cpu->m_pc;
1084  cpu->m_pc = REG64(ic->arg[0]);
1085  cpu->FunctionTraceCall();
1086  cpu->m_pc = saved_pc;
1087  }
1088  }
1089 
1090  if (!link && cpu->m_showFunctionTraceCall && ic->arg[0].p == &cpu->m_gpr[MIPS_GPR_RA])
1091  cpu->FunctionTraceReturn();
1092 
1093  if (singlestep) {
1094  // Prepare for the branch.
1095  cpu->m_inDelaySlot = true;
1096  cpu->m_exceptionOrAbortInDelaySlot = false;
1097 
1098  cpu->m_delaySlotTarget = REG64(ic->arg[0]);
1099  cpu->m_nextIC = ic + 1;
1100  } else {
1101  // Prepare for the branch.
1102  cpu->m_inDelaySlot = true;
1103  cpu->m_exceptionOrAbortInDelaySlot = false;
1104 
1105  // Execute the next instruction:
1106  ic[1].f(cpu, ic+1);
1107  cpu->m_executedCycles ++;
1108 
1109  // If there was no exception, then branch:
1110  if (!cpu->m_exceptionOrAbortInDelaySlot) {
1111  cpu->m_pc = REG64(ic->arg[0]);
1112  cpu->DyntransPCtoPointers();
1113 
1114  cpu->m_inDelaySlot = false;
1115  }
1116 
1117  // The next instruction is now either the target of the branch
1118  // instruction, the instruction 2 steps after this one,
1119  // or the first instruction of an exception handler.
1120  cpu->m_exceptionOrAbortInDelaySlot = false;
1121  }
1122 }
1123 
1124 
1126 {
1128 
1129  uint32_t a = REG64(ic->arg[1]), b = REG64(ic->arg[2]);
1130  uint64_t res = (uint64_t)a * (uint64_t)b;
1131 
1132  cpu->m_lo = (int32_t)res;
1133  cpu->m_hi = (int32_t)(res >> 32);
1134 }
1135 
1136 
1138 {
1139  REG64(ic->arg[0]) = (int64_t)REG64(ic->arg[1]) < (int64_t)REG64(ic->arg[2]);
1140 }
1141 
1142 
1144 {
1145  REG64(ic->arg[0]) = (uint64_t)REG64(ic->arg[1]) < (uint64_t)REG64(ic->arg[2]);
1146 }
1147 
1148 
1149 template<bool store, typename addressType, typename T, bool signedLoad> void MIPS_CPUComponent::instr_loadstore(CPUDyntransComponent* cpubase, DyntransIC* ic)
1150 {
1152 
1153  // TODO: fast lookups
1154 
1155  uint64_t addr;
1156 
1157  if (sizeof(addressType) == sizeof(uint64_t))
1158  addr = REG64(ic->arg[1]) + (int32_t)ic->arg[2].u32;
1159  else
1160  addr = (int32_t) (REG64(ic->arg[1]) + (int32_t)ic->arg[2].u32);
1161 
1162  if (sizeof(T) > 1 && (addr & (sizeof(T)-1))) {
1163  std::cerr << "TODO: MIPS unaligned data access exception!\n";
1164  throw std::exception();
1165  // DYNTRANS_SYNCH_PC;
1166  // cpu->Exception(M88K_EXCEPTION_MISALIGNED_ACCESS, 0);
1167  return;
1168  }
1169 
1170  cpu->AddressSelect(addr);
1171 
1172  if (store) {
1173  T data = REG64(ic->arg[0]);
1174  if (!cpu->WriteData(data, cpu->m_isBigEndian? BigEndian : LittleEndian)) {
1175  // TODO: failed to access memory was probably an exception. Handle this!
1176  }
1177  } else {
1178  T data;
1179  if (!cpu->ReadData(data, cpu->m_isBigEndian? BigEndian : LittleEndian)) {
1180  // TODO: failed to access memory was probably an exception. Handle this!
1181  }
1182 
1183  if (signedLoad) {
1184  if (sizeof(T) == sizeof(uint32_t))
1185  REG64(ic->arg[0]) = (int32_t)data;
1186  if (sizeof(T) == sizeof(uint16_t))
1187  REG64(ic->arg[0]) = (int16_t)data;
1188  if (sizeof(T) == sizeof(uint8_t))
1189  REG64(ic->arg[0]) = (int8_t)data;
1190  } else {
1191  REG64(ic->arg[0]) = data;
1192  }
1193  }
1194 }
1195 
1196 
1197 /*****************************************************************************/
1198 
1199 
1200 void MIPS_CPUComponent::Translate(uint32_t iword, struct DyntransIC* ic)
1201 {
1202  bool singleInstructionLeft = (m_executedCycles == m_nrOfCyclesToExecute - 1);
1203  UI* ui = GetUI(); // for debug messages
1204  int requiredISA = 1; // 1, 2, 3, 4, 32, or 64
1205  int requiredISArevision = 1; // 1 or 2 (for MIPS32/64)
1206 
1207  int hi6 = iword >> 26;
1208  int rs = (iword >> 21) & 31;
1209  int rt = (iword >> 16) & 31;
1210  int rd = (iword >> 11) & 31;
1211  int sa = (iword >> 6) & 31;
1212  int32_t imm = (int16_t)iword;
1213  int s6 = iword & 63;
1214 // int s10 = (rs << 5) | sa;
1215 
1216  switch (hi6) {
1217 
1218  case HI6_SPECIAL:
1219  switch (s6) {
1220 
1221  case SPECIAL_SLL:
1222 // case SPECIAL_SLLV:
1223  case SPECIAL_SRL:
1224 /* case SPECIAL_SRLV:
1225  case SPECIAL_SRA:
1226  case SPECIAL_SRAV:
1227  case SPECIAL_DSRL:
1228  case SPECIAL_DSRLV:
1229  case SPECIAL_DSRL32:
1230  case SPECIAL_DSLL:
1231  case SPECIAL_DSLLV:
1232  case SPECIAL_DSLL32:
1233  case SPECIAL_DSRA:
1234  case SPECIAL_DSRAV:
1235  case SPECIAL_DSRA32: */
1236  switch (s6) {
1237  case SPECIAL_SLL: ic->f = instr_shift_left_u64_u64_imm5_truncS32; break;
1238 // case SPECIAL_SLLV: ic->f = instr(sllv); sa = -1; break;
1239  case SPECIAL_SRL: ic->f = instr_shift_right_u64_u64asu32_imm5_truncS32; break;
1240 /* case SPECIAL_SRLV: ic->f = instr(srlv); sa = -1; break;
1241  case SPECIAL_SRA: ic->f = instr(sra); break;
1242  case SPECIAL_SRAV: ic->f = instr(srav); sa = -1; break;
1243  case SPECIAL_DSRL: ic->f = instr(dsrl); x64=1; break;
1244  case SPECIAL_DSRLV:ic->f = instr(dsrlv);
1245  x64 = 1; sa = -1; break;
1246  case SPECIAL_DSRL32:ic->f= instr(dsrl); x64=1;
1247  sa += 32; break;
1248  case SPECIAL_DSLL: ic->f = instr(dsll); x64=1; break;
1249  case SPECIAL_DSLLV:ic->f = instr(dsllv);
1250  x64 = 1; sa = -1; break;
1251  case SPECIAL_DSLL32:ic->f= instr(dsll); x64=1;
1252  sa += 32; break;
1253  case SPECIAL_DSRA: ic->f = instr(dsra); x64=1; break;
1254  case SPECIAL_DSRAV:ic->f = instr(dsrav);
1255  x64 = 1; sa = -1; break;
1256  case SPECIAL_DSRA32:ic->f = instr(dsra); x64=1;
1257  sa += 32; break; */
1258  }
1259 
1260  ic->arg[0].p = &m_gpr[rd];
1261  ic->arg[1].p = &m_gpr[rt];
1262  if (sa >= 0)
1263  ic->arg[2].u32 = sa;
1264  else
1265  ic->arg[2].p = &m_gpr[rs];
1266 
1267  /* Special checks for MIPS32/64 revision 2 opcodes,
1268  such as rotation instructions: */
1269 // if (sa >= 0 && rs != 0x00) {
1270 // if (m_type.isa_level < 32 ||
1271 // m_type.isa_revision < 2) {
1272 // static int warning_rotate = 0;
1273 // if (!warning_rotate &&
1274 // !cpu->translation_readahead) {
1275 // fatal("[ WARNING! MIPS32/64 "
1276 // "revision 2 rotate opcode"
1277 // " used, but the %s process"
1278 // "or does not implement "
1279 // "such instructions. Only "
1280 // "printing this "
1281 // "warning once. ]\n",
1282 // cpu->cd.mips.cpu_type.name);
1283 // warning_rotate = 1;
1284 // }
1285 // ic->f = NULL; // TODO instr(reserved);
1286 // break;
1287 // }
1288 //
1289 // switch (rs) {
1290 // case 0x01:
1291 // switch (s6) {
1292 // case SPECIAL_SRL: /* ror */
1293 // ic->f = NULL; //TODO instr(ror);
1294 // break;
1295 // }
1296 // break;
1297 // }
1298 // }
1299 
1300 // if (sa < 0 && (s10 & 0x1f) != 0) {
1301 // switch (s10 & 0x1f) {
1302 // /* TODO: [d]rorv, etc. */
1303 // }
1304 // }
1305 
1306  if (rd == MIPS_GPR_ZERO)
1307  ic->f = instr_nop;
1308 
1309  break;
1310 
1311 // case SPECIAL_ADD:
1312  case SPECIAL_ADDU:
1313 // case SPECIAL_SUB:
1314  case SPECIAL_SUBU:
1315 // case SPECIAL_DADD:
1316 // case SPECIAL_DADDU:
1317 // case SPECIAL_DSUB:
1318 // case SPECIAL_DSUBU:
1319  case SPECIAL_SLT:
1320  case SPECIAL_SLTU:
1321 // case SPECIAL_AND:
1322 // case SPECIAL_OR:
1323  case SPECIAL_XOR:
1324 // case SPECIAL_NOR:
1325 // case SPECIAL_MOVN:
1326 // case SPECIAL_MOVZ:
1327  case SPECIAL_MFHI:
1328  case SPECIAL_MFLO:
1329  case SPECIAL_MTHI:
1330  case SPECIAL_MTLO:
1331 // case SPECIAL_DIV:
1332 // case SPECIAL_DIVU:
1333 // case SPECIAL_DDIV:
1334 // case SPECIAL_DDIVU:
1335 // case SPECIAL_MULT:
1336  case SPECIAL_MULTU:
1337 // case SPECIAL_DMULT:
1338 // case SPECIAL_DMULTU:
1339 // case SPECIAL_TGE:
1340 // case SPECIAL_TGEU:
1341 // case SPECIAL_TLT:
1342 // case SPECIAL_TLTU:
1343 // case SPECIAL_TEQ:
1344 // case SPECIAL_TNE:
1345  switch (s6) {
1346 // case SPECIAL_ADD: ic->f = instr(add); break;
1347  case SPECIAL_ADDU: ic->f = instr_add_u64_u64_u64_truncS32; break;
1348 // case SPECIAL_SUB: ic->f = instr(sub); break;
1349  case SPECIAL_SUBU: ic->f = instr_sub_u64_u64_u64_truncS32; break;
1350 // case SPECIAL_DADD: ic->f = instr(dadd); x64=1; break;
1351 // case SPECIAL_DADDU: ic->f = instr(daddu); x64=1; break;
1352 // case SPECIAL_DSUB: ic->f = instr(dsub); x64=1; break;
1353 // case SPECIAL_DSUBU: ic->f = instr(dsubu); x64=1; break;
1354  case SPECIAL_SLT: ic->f = instr_slt; break;
1355  case SPECIAL_SLTU: ic->f = instr_sltu; break;
1356 // case SPECIAL_AND: ic->f = instr(and); break;
1357 // case SPECIAL_OR: ic->f = instr(or); break;
1358  case SPECIAL_XOR: ic->f = instr_xor_u64_u64_u64; break;
1359 // case SPECIAL_NOR: ic->f = instr(nor); break;
1360  case SPECIAL_MFHI: ic->f = instr_mov_u64_u64; break;
1361  case SPECIAL_MFLO: ic->f = instr_mov_u64_u64; break;
1362  case SPECIAL_MTHI: ic->f = instr_mov_u64_u64; break;
1363  case SPECIAL_MTLO: ic->f = instr_mov_u64_u64; break;
1364 // case SPECIAL_DIV: ic->f = instr(div); break;
1365 // case SPECIAL_DIVU: ic->f = instr(divu); break;
1366 // case SPECIAL_DDIV: ic->f = instr(ddiv); x64=1; break;
1367 // case SPECIAL_DDIVU: ic->f = instr(ddivu); x64=1; break;
1368 // case SPECIAL_MULT : ic->f = instr(mult); break;
1369  case SPECIAL_MULTU: ic->f = instr_multu; break;
1370 // case SPECIAL_DMULT: ic->f = instr(dmult); x64=1; break;
1371 // case SPECIAL_DMULTU:ic->f = instr(dmultu); x64=1; break;
1372 // case SPECIAL_TGE: ic->f = instr(tge); break;
1373 // case SPECIAL_TGEU: ic->f = instr(tgeu); break;
1374 // case SPECIAL_TLT: ic->f = instr(tlt); break;
1375 // case SPECIAL_TLTU: ic->f = instr(tltu); break;
1376 // case SPECIAL_TEQ: ic->f = instr(teq); break;
1377 // case SPECIAL_TNE: ic->f = instr(tne); break;
1378 // case SPECIAL_MOVN: ic->f = instr(movn); break;
1379 // case SPECIAL_MOVZ: ic->f = instr(movz); break;
1380  }
1381 
1382  // NOTE: When uncommenting instruction above, make sure they
1383  // use the same rd, rs, rt format!
1384 
1385  ic->arg[0].p = &m_gpr[rd];
1386  ic->arg[1].p = &m_gpr[rs];
1387  ic->arg[2].p = &m_gpr[rt];
1388 
1389  switch (s6) {
1390  case SPECIAL_MFHI: ic->arg[1].p = &m_hi; break;
1391  case SPECIAL_MFLO: ic->arg[1].p = &m_lo; break;
1392  case SPECIAL_MTHI: ic->arg[0].p = &m_hi; break;
1393  case SPECIAL_MTLO: ic->arg[0].p = &m_lo; break;
1394  }
1395 
1396  // Special cases for rd:
1397  switch (s6) {
1398  case SPECIAL_MTHI:
1399  case SPECIAL_MTLO:
1400  case SPECIAL_DIV:
1401  case SPECIAL_DIVU:
1402  case SPECIAL_DDIV:
1403  case SPECIAL_DDIVU:
1404  case SPECIAL_MULT:
1405  case SPECIAL_MULTU:
1406  case SPECIAL_DMULT:
1407  case SPECIAL_DMULTU:
1408  if (s6 == SPECIAL_MULT && rd != MIPS_GPR_ZERO) {
1409  if (m_type.rev == MIPS_R5900) {
1410  // ic->f = instr(mult_r5900);
1411  ic->f = NULL;
1412  break;
1413  }
1414  break;
1415  }
1416  if (s6 == SPECIAL_MULTU && rd!=MIPS_GPR_ZERO) {
1417  if (m_type.rev == MIPS_R5900) {
1418  // ic->f = instr(multu_r5900);
1419  ic->f = NULL;
1420  break;
1421  }
1422  }
1423  if (rd != MIPS_GPR_ZERO) {
1424  std::cerr << "TODO: rd NON-zero\n";
1425  ic->f = NULL;
1426  }
1427  // These instructions don't use rd.
1428  break;
1429  case SPECIAL_TGE:
1430  case SPECIAL_TGEU:
1431  case SPECIAL_TLT:
1432  case SPECIAL_TLTU:
1433  case SPECIAL_TEQ:
1434  case SPECIAL_TNE:
1435  // In these instructions, rd is a 'code',
1436  // only read by trap handling software.
1437  break;
1438  default:if (rd == MIPS_GPR_ZERO)
1439  ic->f = instr_nop;
1440  }
1441 
1442  break;
1443 
1444  case SPECIAL_JR:
1445  case SPECIAL_JALR:
1446  {
1447  void (*f_singleStepping)(CPUDyntransComponent*, struct DyntransIC*) = NULL;
1448 
1449  if (s6 == SPECIAL_JALR && rd == MIPS_GPR_ZERO)
1450  s6 = SPECIAL_JR;
1451 
1452  switch (s6) {
1453  case SPECIAL_JR:
1454  ic->f = instr_jr<false, false>;
1455  f_singleStepping = instr_jr<false, true>;
1456  break;
1457  case SPECIAL_JALR:
1458  ic->f = instr_jr<true, false>;
1459  f_singleStepping = instr_jr<true, true>;
1460  break;
1461  }
1462 
1463  // Only one instruction left, then we carefully single-step it.
1464  if (singleInstructionLeft)
1465  ic->f = f_singleStepping;
1466 
1467  ic->arg[0].p = &m_gpr[rs];
1468  ic->arg[1].p = &m_gpr[rd];
1469 
1470  if (m_inDelaySlot) {
1471  if (ui != NULL)
1472  ui->ShowDebugMessage(this, "branch in delay slot?!"
1473  " TODO: How should this be handled?");
1474 
1475  ic->f = NULL;
1476  }
1477  }
1478  break;
1479 
1480  default:
1481  if (ui != NULL) {
1482  stringstream ss;
1483  ss.flags(std::ios::hex);
1484  ss << "unimplemented opcode HI6_SPECIAL, s6 = 0x" << s6;
1485  ui->ShowDebugMessage(this, ss.str());
1486  }
1487  }
1488  break;
1489 
1490  case HI6_BEQ:
1491  case HI6_BNE:
1492 // case HI6_BEQL:
1493 // case HI6_BNEL:
1494  case HI6_BLEZ:
1495 // case HI6_BLEZL:
1496  case HI6_BGTZ:
1497 // case HI6_BGTZL:
1498  {
1499  void (*f_singleStepping)(CPUDyntransComponent*, struct DyntransIC*) = NULL;
1500  void (*samepage_function)(CPUDyntransComponent*, struct DyntransIC*) = NULL;
1501  bool warnAboutNonZeroRT = false;
1502 
1503  switch (hi6) {
1504  case HI6_BEQ:
1505  ic->f = instr_b<0, false, false>;
1506  samepage_function = instr_b<0, true, false>;
1507  f_singleStepping = instr_b<0, false, true>;
1508  break;
1509  case HI6_BNE:
1510  ic->f = instr_b<1, false, false>;
1511  samepage_function = instr_b<1, true, false>;
1512  f_singleStepping = instr_b<1, false, true>;
1513  break;
1514  case HI6_BLEZ:
1515  ic->f = instr_b<2, false, false>;
1516  samepage_function = instr_b<2, true, false>;
1517  f_singleStepping = instr_b<2, false, true>;
1518  warnAboutNonZeroRT = true;
1519  break;
1520  case HI6_BGTZ:
1521  ic->f = instr_b<3, false, false>;
1522  samepage_function = instr_b<3, true, false>;
1523  f_singleStepping = instr_b<3, false, true>;
1524  warnAboutNonZeroRT = true;
1525  break;
1526  }
1527 
1528  if (singleInstructionLeft) {
1529  // Only one instruction left, then we carefully single-step it.
1530  // (No need to optimize for samepage.)
1531  ic->f = f_singleStepping;
1532  samepage_function = NULL;
1533  }
1534 
1535  uint32_t mask = m_dyntransPageMask & ~3; // 0xffc for 4 KB pages
1536 
1537  ic->arg[0].p = &m_gpr[rs];
1538  ic->arg[1].p = &m_gpr[rt];
1539  // TODO: MIPS16 offset!
1540  ic->arg[2].u32 = (int32_t) ( (imm << m_dyntransICshift) + (m_pc & mask) + 4 );
1541 
1542  if (rt != MIPS_GPR_ZERO && warnAboutNonZeroRT && ui != NULL)
1543  ui->ShowDebugMessage(this, "MIPS branch with rt non-zero, where it should have been zero?");
1544 
1545  // Is the offset from the start of the current page still
1546  // within the same page? Then use the samepage_function:
1547  if (samepage_function != NULL &&
1548  ic->arg[2].u32 < (uint32_t)((m_dyntransICentriesPerPage - 1)
1549  << m_dyntransICshift) && (m_pc & mask) < mask) {
1550  ic->arg[2].p = (m_firstIConPage +
1551  ((ic->arg[2].u32 >> m_dyntransICshift)
1552  & (m_dyntransICentriesPerPage - 1)));
1553  ic->f = samepage_function;
1554  }
1555 
1556  if (m_inDelaySlot) {
1557  if (ui != NULL)
1558  ui->ShowDebugMessage(this, "branch in delay slot?!"
1559  " TODO: How should this be handled?");
1560 
1561  ic->f = NULL;
1562  }
1563  }
1564  break;
1565 
1566 // case HI6_ADDI:
1567  case HI6_ADDIU:
1568 // case HI6_SLTI:
1569 // case HI6_SLTIU:
1570 // case HI6_DADDI:
1571  case HI6_DADDIU:
1572  case HI6_ANDI:
1573  case HI6_ORI:
1574  case HI6_XORI:
1575  ic->arg[0].p = &m_gpr[rt];
1576  ic->arg[1].p = &m_gpr[rs];
1577  if (hi6 == HI6_ADDI || hi6 == HI6_ADDIU ||
1578  hi6 == HI6_SLTI || hi6 == HI6_SLTIU ||
1579  hi6 == HI6_DADDI || hi6 == HI6_DADDIU)
1580  ic->arg[2].u32 = (int16_t)iword;
1581  else
1582  ic->arg[2].u32 = (uint16_t)iword;
1583 
1584  switch (hi6) {
1585 // case HI6_ADDI: ic->f = instr(addi); break;
1586  case HI6_ADDIU: ic->f = instr_add_u64_u64_imms32_truncS32; break;
1587 // case HI6_SLTI: ic->f = instr(slti); break;
1588 // case HI6_SLTIU: ic->f = instr(sltiu); break;
1589 // case HI6_DADDI: ic->f = instr(daddi); requiredISA = 3; break;
1590  case HI6_DADDIU: ic->f = instr_add_u64_u64_imms32; requiredISA = 3; break;
1591  case HI6_ANDI: ic->f = instr_and_u64_u64_immu32; break;
1592  case HI6_ORI: ic->f = instr_or_u64_u64_immu32; break;
1593  case HI6_XORI: ic->f = instr_xor_u64_u64_immu32; break;
1594  }
1595 
1596  if (rt == MIPS_GPR_ZERO)
1597  ic->f = instr_nop;
1598  break;
1599 
1600  case HI6_LUI:
1601  ic->f = instr_set_u64_imms32;
1602  ic->arg[0].p = &m_gpr[rt];
1603  ic->arg[1].u32 = (int32_t) (imm << 16);
1604 
1605  if (rt == MIPS_GPR_ZERO)
1606  ic->f = instr_nop;
1607  break;
1608 
1609  case HI6_J:
1610  case HI6_JAL:
1611  {
1612  void (*f_singleStepping)(CPUDyntransComponent*, struct DyntransIC*) = NULL;
1613 
1614  switch (hi6) {
1615  case HI6_J:
1616  ic->f = instr_j<false, false>;
1617  f_singleStepping = instr_j<false, true>;
1618  break;
1619  case HI6_JAL:
1620  ic->f = instr_j<true, false>;
1621  f_singleStepping = instr_j<true, true>;
1622  break;
1623  }
1624 
1625  // Only one instruction left, then we carefully single-step it.
1626  if (singleInstructionLeft)
1627  ic->f = f_singleStepping;
1628 
1629  ic->arg[0].u32 = (iword & 0x03ffffff) << 2;
1630 
1631  if (m_inDelaySlot) {
1632  if (ui != NULL)
1633  ui->ShowDebugMessage(this, "branch in delay slot?!"
1634  " TODO: How should this be handled?");
1635 
1636  ic->f = NULL;
1637  }
1638 
1639  break;
1640  }
1641 
1642 // case HI6_LB:
1643 // case HI6_LBU:
1644  case HI6_SB:
1645 // case HI6_LH:
1646 // case HI6_LHU:
1647 // case HI6_SH:
1648  case HI6_LW:
1649 // case HI6_LWU:
1650  case HI6_SW:
1651 // case HI6_LD:
1652 // case HI6_SD:
1653  {
1654  ic->arg[0].p = &m_gpr[rt];
1655  ic->arg[1].p = &m_gpr[rs];
1656  ic->arg[2].u32 = (int32_t)imm;
1657 
1658  bool store = false;
1659 
1660  if (Is32Bit()) {
1661  switch (hi6) {
1662  case HI6_LW: ic->f = instr_loadstore<false, int32_t, uint32_t, true>; break;
1663  case HI6_SB: ic->f = instr_loadstore<true, int32_t, uint8_t, false>; store = true; break;
1664  case HI6_SW: ic->f = instr_loadstore<true, int32_t, uint32_t, false>; store = true; break;
1665  }
1666  } else {
1667  switch (hi6) {
1668  case HI6_LW: ic->f = instr_loadstore<false, uint64_t, uint32_t, true>; break;
1669  case HI6_SB: ic->f = instr_loadstore<true, uint64_t, uint8_t, false>; store = true; break;
1670  case HI6_SW: ic->f = instr_loadstore<true, uint64_t, uint32_t, false>; store = true; break;
1671  }
1672  }
1673 
1674  /* Load into the dummy scratch register, if rt = zero */
1675  if (!store && rt == MIPS_GPR_ZERO)
1676  ic->arg[0].p = &m_scratch;
1677  }
1678  break;
1679 
1680  default:
1681  if (ui != NULL) {
1682  stringstream ss;
1683  ss.flags(std::ios::hex);
1684  ss << "unimplemented opcode 0x" << hi6;
1685  ui->ShowDebugMessage(this, ss.str());
1686  }
1687  }
1688 
1689  // Attempting a MIPS32 instruction on e.g. a MIPS IV CPU?
1690  if (requiredISA > m_type.isa_level) {
1691  // TODO: Cause MIPS "unimplemented instruction" exception instead.
1692  ic->f = NULL;
1693 
1694  // TODO: Only print the warning once; actual real-world code may
1695  // rely on this mechanism to detect cpu type, or similar.
1696  if (ui != NULL) {
1697  stringstream ss;
1698  ss.flags(std::ios::hex);
1699  ss << "instruction at 0x" << m_pc << " requires ISA level ";
1700  ss.flags(std::ios::dec);
1701  ss << requiredISA << "; this cpu supports only ISA level " <<
1702  m_type.isa_level << "\n";
1703  ui->ShowDebugMessage(this, ss.str());
1704  }
1705  }
1706 
1707  // Attempting a MIPS III or IV instruction on e.g. a MIPS32 CPU?
1708  if ((requiredISA == 3 || requiredISA == 4) && Is32Bit()) {
1709  // TODO: Cause MIPS "unimplemented instruction" exception instead.
1710  ic->f = NULL;
1711 
1712  // TODO: Only print the warning once; actual real-world code may
1713  // rely on this mechanism to detect cpu type, or similar.
1714  if (ui != NULL) {
1715  stringstream ss;
1716  ss.flags(std::ios::hex);
1717  ss << "instruction at 0x" << m_pc << " is a 64-bit instruction,"
1718  " which cannot be executed on this CPU\n";
1719  ui->ShowDebugMessage(this, ss.str());
1720  }
1721  }
1722 
1723  // Attempting a revision 2 opcode on a revision1 MIPS32/64 CPU?
1724  if (requiredISArevision > 1 && m_type.isa_revision) {
1725  // TODO: Cause MIPS "unimplemented instruction" exception instead.
1726  ic->f = NULL;
1727 
1728  // TODO: Only print the warning once; actual real-world code may
1729  // rely on this mechanism to detect cpu type, or similar.
1730  if (ui != NULL) {
1731  stringstream ss;
1732  ss.flags(std::ios::hex);
1733  ss << "instruction at 0x" << m_pc << " is a MIPS32/64 revision ";
1734  ss << requiredISArevision << " instruction; this cpu supports"
1735  " only revision " << m_type.isa_revision << "\n";
1736  ui->ShowDebugMessage(this, ss.str());
1737  }
1738  }
1739 }
1740 
1741 
1743 {
1745 
1746  cpu->DyntransToBeTranslatedBegin(ic);
1747 
1748  uint32_t iword;
1749  if (cpu->DyntransReadInstruction(iword))
1750  cpu->Translate(iword, ic);
1751 
1752  if (cpu->m_inDelaySlot && ic->f == NULL)
1753  ic->f = instr_abort;
1754 
1755  cpu->DyntransToBeTranslatedDone(ic);
1756 }
1757 
1758 
1759 DYNTRANS_INSTR(MIPS_CPUComponent,ToBeTranslated_MIPS16)
1760 {
1762 
1763  cpu->DyntransToBeTranslatedBegin(ic);
1764 
1765  uint16_t iword;
1766  if (cpu->DyntransReadInstruction(iword)) {
1767  // TODO: Recode
1768  UI* ui = cpu->GetUI();
1769  if (ui != NULL) {
1770  stringstream ss;
1771  ss.flags(std::ios::hex);
1772  ss << "TODO: recode MIPS16 => regular MIPS instruction\n";
1773  ui->ShowDebugMessage(cpu, ss.str());
1774  }
1775 
1776  //cpu->Translate(iword, ic);
1777  }
1778 
1779  cpu->DyntransToBeTranslatedDone(ic);
1780 }
1781 
1782 
1783 /*****************************************************************************/
1784 
1785 
1786 #ifdef WITHUNITTESTS
1787 
1788 #include "ComponentFactory.h"
1789 
1790 static void Test_MIPS_CPUComponent_IsStable()
1791 {
1792  UnitTest::Assert("the MIPS_CPUComponent should be stable",
1793  ComponentFactory::HasAttribute("mips_cpu", "stable"));
1794 }
1795 
1796 static void Test_MIPS_CPUComponent_Create()
1797 {
1800  UnitTest::Assert("component was not created?", !cpu.IsNULL());
1801 
1802  const StateVariable * p = cpu->GetVariable("pc");
1803  UnitTest::Assert("cpu has no pc state variable?", p != NULL);
1804  UnitTest::Assert("initial pc", p->ToString(), "0xffffffffbfc00000");
1805 }
1806 
1807 static void Test_MIPS_CPUComponent_IsCPU()
1808 {
1811  CPUComponent* cpu = mips_cpu->AsCPUComponent();
1812  UnitTest::Assert("mips_cpu is not a CPUComponent?", cpu != NULL);
1813 }
1814 
1815 static void Test_MIPS_CPUComponent_DefaultModel()
1816 {
1819 
1820  // 5KE is a good default model (MIPS64 rev 2 ISA)
1821  UnitTest::Assert("wrong default model",
1822  cpu->GetVariable("model")->ToString(), "5KE");
1823 }
1824 
1825 static void Test_MIPS_CPUComponent_ModelChange()
1826 {
1829 
1830  cpu->SetVariableValue("model", "\"R2000\"");
1831  UnitTest::Assert("model change was not applied",
1832  cpu->GetVariable("model")->ToString(), "R2000");
1833 
1834  cpu->SetVariableValue("model", "\"R1000\"");
1835  UnitTest::Assert("model change was applied when it should NOT have been",
1836  cpu->GetVariable("model")->ToString(), "R2000");
1837 }
1838 
1839 static void Test_MIPS_CPUComponent_Disassembly_Basic()
1840 {
1843  CPUComponent* cpu = mips_cpu->AsCPUComponent();
1844 
1845  vector<string> result;
1846  size_t len;
1847  unsigned char instruction[sizeof(uint32_t)];
1848  // This assumes that the default endianness is BigEndian...
1849  instruction[0] = 0x27;
1850  instruction[1] = 0xbd;
1851  instruction[2] = 0xff;
1852  instruction[3] = 0xd8;
1853 
1854  len = cpu->DisassembleInstruction(0x12345678, sizeof(uint32_t),
1855  instruction, result);
1856 
1857  UnitTest::Assert("disassembled instruction was wrong length?", len, 4);
1858  UnitTest::Assert("disassembly result incomplete?", result.size(), 3);
1859  UnitTest::Assert("disassembly result[0]", result[0], "27bdffd8");
1860  UnitTest::Assert("disassembly result[1]", result[1], "addiu");
1861  UnitTest::Assert("disassembly result[2]", result[2], "sp,sp,-40");
1862 }
1863 
1864 static void Test_MIPS_CPUComponent_Execute_DelayBranchWithValidInstruction()
1865 {
1866  GXemul gxemul;
1867  gxemul.GetCommandInterpreter().RunCommand("add testmips");
1868 
1869  refcount_ptr<Component> cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0");
1870  UnitTest::Assert("huh? no cpu?", !cpu.IsNULL());
1871 
1872  AddressDataBus* bus = cpu->AsAddressDataBus();
1873  UnitTest::Assert("cpu should be addressable", bus != NULL);
1874 
1875  uint32_t data32 = 0x10000111; // b 0xffffffff80004448
1876  bus->AddressSelect(0xffffffff80004000ULL);
1877  bus->WriteData(data32, BigEndian);
1878 
1879  data32 = 0x27bdffd8; // Something valid, addiu sp,sp,-40
1880  bus->AddressSelect(0xffffffff80004004ULL);
1881  bus->WriteData(data32, BigEndian);
1882 
1883  cpu->SetVariableValue("pc", "0xffffffff80004000");
1884  UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004000ULL);
1885  UnitTest::Assert("sp before execute", cpu->GetVariable("sp")->ToInteger(), 0xffffffffa0007f00ULL);
1886 
1887  // This tests that execute 2 steps will execute both the delay branch
1888  // and the delay slot instruction.
1889  gxemul.SetRunState(GXemul::Running);
1890  gxemul.Execute(2);
1891 
1892  UnitTest::Assert("pc should have changed", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004448ULL);
1893  UnitTest::Assert("sp should have changed", cpu->GetVariable("sp")->ToInteger(), 0xffffffffa0007ed8ULL);
1894 }
1895 
1896 static void Test_MIPS_CPUComponent_Execute_DelayBranchWithValidInstruction_SingleStepping()
1897 {
1898  GXemul gxemul;
1899  gxemul.GetCommandInterpreter().RunCommand("add testmips");
1900 
1901  refcount_ptr<Component> cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0");
1902  UnitTest::Assert("huh? no cpu?", !cpu.IsNULL());
1903 
1904  AddressDataBus* bus = cpu->AsAddressDataBus();
1905  UnitTest::Assert("cpu should be addressable", bus != NULL);
1906 
1907  uint32_t data32 = 0x10000111; // b 0xffffffff80004448
1908  bus->AddressSelect(0xffffffff80004000ULL);
1909  bus->WriteData(data32, BigEndian);
1910 
1911  data32 = 0x27bdffd8; // Something valid, addiu sp,sp,-40
1912  bus->AddressSelect(0xffffffff80004004ULL);
1913  bus->WriteData(data32, BigEndian);
1914 
1915  cpu->SetVariableValue("pc", "0xffffffff80004000");
1916  UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004000ULL);
1917  UnitTest::Assert("sp before execute", cpu->GetVariable("sp")->ToInteger(), 0xffffffffa0007f00ULL);
1918 
1919  // This tests that execute 2 steps will execute both the delay branch
1920  // and the delay slot instruction.
1922  gxemul.Execute(1);
1923 
1924  // Should now be in the delay slot.
1925  UnitTest::Assert("pc should have changed 1", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004004ULL);
1926  UnitTest::Assert("delay slot", cpu->GetVariable("inDelaySlot")->ToString(), "true");
1927  UnitTest::Assert("sp should not yet have changed", cpu->GetVariable("sp")->ToInteger(), 0xffffffffa0007f00ULL);
1928 
1930  gxemul.Execute(1);
1931 
1932  UnitTest::Assert("pc should have changed 2", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004448ULL);
1933  UnitTest::Assert("delay slot after branch", cpu->GetVariable("inDelaySlot")->ToString(), "false");
1934  UnitTest::Assert("sp should have changed", cpu->GetVariable("sp")->ToInteger(), 0xffffffffa0007ed8ULL);
1935 }
1936 
1937 static void Test_MIPS_CPUComponent_Execute_DelayBranchWithValidInstruction_RunTwoTimes()
1938 {
1939  GXemul gxemul;
1940  gxemul.GetCommandInterpreter().RunCommand("add testmips");
1941 
1942  refcount_ptr<Component> cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0");
1943  UnitTest::Assert("huh? no cpu?", !cpu.IsNULL());
1944 
1945  AddressDataBus* bus = cpu->AsAddressDataBus();
1946  UnitTest::Assert("cpu should be addressable", bus != NULL);
1947 
1948  uint32_t data32 = 0x10000111; // b 0xffffffff80004448
1949  bus->AddressSelect(0xffffffff80004000ULL);
1950  bus->WriteData(data32, BigEndian);
1951 
1952  data32 = 0x27bdffd8; // Something valid, addiu sp,sp,-40
1953  bus->AddressSelect(0xffffffff80004004ULL);
1954  bus->WriteData(data32, BigEndian);
1955 
1956  cpu->SetVariableValue("pc", "0xffffffff80004000");
1957  UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004000ULL);
1958  UnitTest::Assert("sp before execute", cpu->GetVariable("sp")->ToInteger(), 0xffffffffa0007f00ULL);
1959 
1960  // This tests that execute 1 step with normal running, two times, will
1961  // execute both the delay branch and the delay slot instruction correctly.
1962  gxemul.SetRunState(GXemul::Running);
1963  gxemul.Execute(1);
1964 
1965  // Should now be in the delay slot.
1966  UnitTest::Assert("pc should have changed 1", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004004ULL);
1967  UnitTest::Assert("delay slot", cpu->GetVariable("inDelaySlot")->ToString(), "true");
1968  UnitTest::Assert("sp should not yet have changed", cpu->GetVariable("sp")->ToInteger(), 0xffffffffa0007f00ULL);
1969 
1970  gxemul.SetRunState(GXemul::Running);
1971  gxemul.Execute(1);
1972 
1973  UnitTest::Assert("pc should have changed 2", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004448ULL);
1974  UnitTest::Assert("delay slot after branch", cpu->GetVariable("inDelaySlot")->ToString(), "false");
1975  UnitTest::Assert("sp should have changed", cpu->GetVariable("sp")->ToInteger(), 0xffffffffa0007ed8ULL);
1976 }
1977 
1978 static void Test_MIPS_CPUComponent_Execute_DelayBranchWithFault()
1979 {
1980  GXemul gxemul;
1981  gxemul.GetCommandInterpreter().RunCommand("add testmips");
1982 
1983  refcount_ptr<Component> cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0");
1984  UnitTest::Assert("huh? no cpu?", !cpu.IsNULL());
1985 
1986  AddressDataBus* bus = cpu->AsAddressDataBus();
1987  UnitTest::Assert("cpu should be addressable", bus != NULL);
1988 
1989  uint32_t data32 = 0x10000111; // b 0xffffffff80004048
1990  bus->AddressSelect(0xffffffff80004000ULL);
1991  bus->WriteData(data32, BigEndian);
1992 
1993  data32 = 0xffffffff; // Something invalid.
1994  bus->AddressSelect(0xffffffff80004004ULL);
1995  bus->WriteData(data32, BigEndian);
1996 
1997  cpu->SetVariableValue("pc", "0xffffffff80004000");
1998  UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004000ULL);
1999  UnitTest::Assert("should not be in delay slot before execution", cpu->GetVariable("inDelaySlot")->ToString(), "false");
2000 
2001  // This tests that execute 100 steps will only execute 1, if the instruction
2002  // in the delay slot fails.
2003  gxemul.SetRunState(GXemul::Running);
2004  gxemul.Execute(100);
2005 
2006  UnitTest::Assert("pc should have increased one step", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004004ULL);
2007  UnitTest::Assert("should be in delay slot after execution", cpu->GetVariable("inDelaySlot")->ToString(), "true");
2008 
2010  gxemul.Execute(1);
2011 
2012  UnitTest::Assert("pc should not have increased", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004004ULL);
2013  UnitTest::Assert("should still be in delay slot", cpu->GetVariable("inDelaySlot")->ToString(), "true");
2014 }
2015 
2017 {
2018  UNITTEST(Test_MIPS_CPUComponent_IsStable);
2019  UNITTEST(Test_MIPS_CPUComponent_Create);
2020  UNITTEST(Test_MIPS_CPUComponent_IsCPU);
2021  UNITTEST(Test_MIPS_CPUComponent_DefaultModel);
2022  UNITTEST(Test_MIPS_CPUComponent_ModelChange);
2023 
2024  // Disassembly:
2025  UNITTEST(Test_MIPS_CPUComponent_Disassembly_Basic);
2026 
2027  // Dyntrans execution:
2028  UNITTEST(Test_MIPS_CPUComponent_Execute_DelayBranchWithValidInstruction);
2029  UNITTEST(Test_MIPS_CPUComponent_Execute_DelayBranchWithValidInstruction_SingleStepping);
2030  UNITTEST(Test_MIPS_CPUComponent_Execute_DelayBranchWithValidInstruction_RunTwoTimes);
2031  UNITTEST(Test_MIPS_CPUComponent_Execute_DelayBranchWithFault);
2032 }
2033 
2034 #endif
2035 
#define SPECIAL_MOVN
Definition: opcodes_mips.h:180
void SetRunState(RunState newState)
Sets the RunState.
Definition: GXemul.cc:741
virtual bool CheckVariableWrite(StateVariable &var, const string &oldValue)
Checks whether a write to a variable is OK.
virtual CPUComponent * AsCPUComponent()
Returns the component&#39;s CPUComponent interface.
Definition: Component.cc:360
#define MIPS_REGISTER_NAMES
#define SPECIAL_SRAV
Definition: opcodes_mips.h:176
double m_frequency
Definition: CPUComponent.h:197
#define HI6_SWC2
Definition: opcodes_mips.h:474
virtual void ShowDebugMessage(const string &msg)=0
Shows a debug message.
#define LE16_TO_HOST(x)
Definition: misc.h:172
#define SPECIAL_DSRA32
Definition: opcodes_mips.h:232
StateVariable * GetVariable(const string &name)
Gets a pointer to a state variable.
Definition: Component.cc:949
static string GetAttribute(const string &attributeName)
#define HI6_SDC1
Definition: opcodes_mips.h:477
#define SPECIAL_DSLLV
Definition: opcodes_mips.h:189
#define SPECIAL_DIV
Definition: opcodes_mips.h:195
#define SPECIAL_DMULT
Definition: opcodes_mips.h:197
#define SPECIAL_TEQ
Definition: opcodes_mips.h:221
static refcount_ptr< Component > CreateComponent(const string &componentNameAndOptionalArgs, GXemul *gxemul=NULL)
Creates a component given a short component name.
#define HI6_SW
Definition: opcodes_mips.h:459
#define SPECIAL_DIVU
Definition: opcodes_mips.h:196
#define HI6_SDR
Definition: opcodes_mips.h:461
#define HI6_LL
Definition: opcodes_mips.h:464
#define MIPS_GPR_SP
void(* f)(CPUDyntransComponent *, DyntransIC *)
#define REGIMM_BGEZ
Definition: opcodes_mips.h:236
#define SPECIAL_SLLV
Definition: opcodes_mips.h:173
struct arm_instr_call * ic
#define MIPS_OLDABI_REGISTER_NAMES
#define HI6_SDC2
Definition: opcodes_mips.h:478
uint64_t m_delaySlotTarget
Definition: CPUComponent.h:223
#define MIPS_GPR_A0
#define BE32_TO_HOST(x)
Definition: misc.h:181
virtual int64_t FunctionTraceArgument(int n)
#define HI6_NAMES
Definition: opcodes_mips.h:60
#define SPECIAL_TLTU
Definition: opcodes_mips.h:220
#define HI6_SWR
Definition: opcodes_mips.h:462
#define HI6_LWU
Definition: opcodes_mips.h:455
#define HI6_LWL
Definition: opcodes_mips.h:450
bool RunCommand(const string &command, bool *pSuccess=NULL)
Runs a command, given as a string.
#define SPECIAL_SLTU
Definition: opcodes_mips.h:212
virtual bool PreRunCheckForComponent(GXemul *gxemul)
Checks the state of this component, before starting execution.
#define HI6_ORI
Definition: opcodes_mips.h:265
virtual void ShowRegisters(GXemul *gxemul, const vector< string > &arguments) const
bool AddVariable(const string &name, T *variablePointer)
Adds a state variable of type T to the Component.
Definition: Component.h:563
UI * GetUI()
Gets an UI reference for outputting debug messages during runtime.
Definition: Component.cc:583
#define HI6_LHU
Definition: opcodes_mips.h:453
#define REG32(arg)
#define HI6_ADDIU
Definition: opcodes_mips.h:261
#define HI6_SWL
Definition: opcodes_mips.h:458
#define SPECIAL_TGE
Definition: opcodes_mips.h:217
union DyntransIC::@0 arg[N_DYNTRANS_IC_ARGS]
#define HI6_JAL
Definition: opcodes_mips.h:255
#define HI6_LH
Definition: opcodes_mips.h:449
#define REGIMM_BLTZL
Definition: opcodes_mips.h:237
#define SPECIAL_SUBU
Definition: opcodes_mips.h:204
static refcount_ptr< Component > Create(const ComponentCreateArgs &args)
Creates a MIPS_CPUComponent.
#define SPECIAL_DADD
Definition: opcodes_mips.h:213
#define SPECIAL_MTLO
Definition: opcodes_mips.h:188
bool m_inDelaySlot
Definition: CPUComponent.h:222
#define HI6_SWC1
Definition: opcodes_mips.h:473
#define SPECIAL_DSUBU
Definition: opcodes_mips.h:216
A dyntrans instruction call.
#define SPECIAL_SYSCALL
Definition: opcodes_mips.h:181
#define HI6_SLTI
Definition: opcodes_mips.h:262
#define HI6_LWC2
Definition: opcodes_mips.h:466
#define HI6_REGIMM
Definition: opcodes_mips.h:234
#define HI6_LB
Definition: opcodes_mips.h:448
#define HI6_SWC3
Definition: opcodes_mips.h:475
#define REG64(arg)
#define HI6_BNEL
Definition: opcodes_mips.h:306
#define HI6_BNE
Definition: opcodes_mips.h:257
#define HI6_BGTZL
Definition: opcodes_mips.h:308
#define REGIMM_BGEZAL
Definition: opcodes_mips.h:246
char * cond[16]
An interface for implementing components that read/write data via an address bus. ...
static string GetAttribute(const string &attributeName)
Creates a Component.
Definition: Component.cc:66
#define HI6_ANDI
Definition: opcodes_mips.h:264
#define REGIMM_BGEZALL
Definition: opcodes_mips.h:248
#define HI6_LDR
Definition: opcodes_mips.h:312
#define SPECIAL_DSRL32
Definition: opcodes_mips.h:231
The main emulator class.
Definition: GXemul.h:54
MIPS_CPUComponent()
Constructs a MIPS_CPUComponent.
#define MIPS_GPR_RA
#define UNITTESTS(class)
Helper for unit test case execution.
Definition: UnitTest.h:184
CommandInterpreter & GetCommandInterpreter()
Gets a reference to the CommandInterpreter.
Definition: GXemul.cc:631
map< string, string > ComponentCreationSettings
Definition: Component.h:46
#define HI6_LW
Definition: opcodes_mips.h:451
#define SPECIAL_BREAK
Definition: opcodes_mips.h:182
virtual size_t DisassembleInstruction(uint64_t vaddr, size_t maxlen, unsigned char *instruction, vector< string > &result)
Disassembles an instruction into readable strings.
#define HI6_LWC3
Definition: opcodes_mips.h:467
#define HI6_DADDIU
Definition: opcodes_mips.h:310
struct DyntransIC * m_firstIConPage
#define SPECIAL_NOR
Definition: opcodes_mips.h:208
#define LE32_TO_HOST(x)
Definition: misc.h:180
#define HI6_SCD
Definition: opcodes_mips.h:476
#define SPECIAL_JR
Definition: opcodes_mips.h:177
#define SPECIAL_DMULTU
Definition: opcodes_mips.h:198
#define MIPS_R5900
Definition: mips_cpuregs.h:723
string LookupAddress(uint64_t vaddr, bool allowOffset) const
Looks up an address.
#define HI6_XORI
Definition: opcodes_mips.h:266
#define SPECIAL_DSLL
Definition: opcodes_mips.h:225
virtual bool PreRunCheckForComponent(GXemul *gxemul)
Checks the state of this component, before starting execution.
virtual int FunctionTraceArgumentCount()
#define SPECIAL_JALR
Definition: opcodes_mips.h:178
#define SPECIAL_MTHI
Definition: opcodes_mips.h:186
string ToString() const
Returns the variable as a readable string.
u_short data
Definition: siireg.h:79
static bool HasAttribute(const string &name, const string &attributeName)
Checks if a component has a specific attribute.
bool m_isBigEndian
Definition: CPUComponent.h:213
#define SPECIAL_MTSA
Definition: opcodes_mips.h:210
#define BE16_TO_HOST(x)
Definition: misc.h:173
#define DYNTRANS_SYNCH_PC
#define HI6_LLD
Definition: opcodes_mips.h:468
A Component representing a MIPS processor.
#define HI6_SQ_SPECIAL3
Definition: opcodes_mips.h:431
virtual void ResetState()
Resets the state variables of this component.
#define HI6_SC
Definition: opcodes_mips.h:472
#define HI6_LDC2
Definition: opcodes_mips.h:470
#define SPECIAL_DADDU
Definition: opcodes_mips.h:214
virtual bool FunctionTraceReturnImpl(int64_t &retval)
#define SPECIAL_SLT
Definition: opcodes_mips.h:211
#define SPECIAL_SUB
Definition: opcodes_mips.h:203
#define SPECIAL_TGEU
Definition: opcodes_mips.h:218
#define HI6_LDL
Definition: opcodes_mips.h:311
#define HI6_LBU
Definition: opcodes_mips.h:452
#define SPECIAL_SRLV
Definition: opcodes_mips.h:175
uint64_t m_pc
Definition: CPUComponent.h:205
#define SPECIAL_ADD
Definition: opcodes_mips.h:201
SymbolRegistry & GetSymbolRegistry()
Gets a reference to the CPU&#39;s symbol registry.
Definition: CPUComponent.h:63
uint32_t addr
#define SPECIAL_MULT
Definition: opcodes_mips.h:193
#define SPECIAL_MFHI
Definition: opcodes_mips.h:185
#define SPECIAL_DSRL
Definition: opcodes_mips.h:227
#define SPECIAL_SYNC
Definition: opcodes_mips.h:184
#define MIPS_CPU_TYPE_DEFS
#define SPECIAL_MFSA
Definition: opcodes_mips.h:209
#define HI6_LWR
Definition: opcodes_mips.h:454
DYNTRANS_INSTR(MIPS_CPUComponent, multu)
#define HI6_BLEZL
Definition: opcodes_mips.h:307
#define SPECIAL_DSLL32
Definition: opcodes_mips.h:229
#define HI6_SLTIU
Definition: opcodes_mips.h:263
Definition: cpu.h:326
#define SPECIAL_DSUB
Definition: opcodes_mips.h:215
#define SPECIAL_MOVZ
Definition: opcodes_mips.h:179
#define MIPS_GPR_ZERO
#define HI6_SDL
Definition: opcodes_mips.h:460
A base-class for processors Component implementations that use dynamic translation.
#define HI6_ADDI
Definition: opcodes_mips.h:260
#define HI6_BEQ
Definition: opcodes_mips.h:256
uint64_t ToInteger() const
Returns the variable as an unsignedinteger value.
#define SPECIAL_DDIVU
Definition: opcodes_mips.h:200
virtual void(*)(CPUDyntransComponent *, DyntransIC *) GetDyntransToBeTranslated()
StateVariables make up the persistent state of Component objects.
Definition: StateVariable.h:67
#define SPECIAL_NAMES
Definition: opcodes_mips.h:76
virtual bool CheckVariableWrite(StateVariable &var, const string &oldValue)
Checks whether a write to a variable is OK.
Definition: Component.cc:969
#define SPECIAL_AND
Definition: opcodes_mips.h:205
#define SPECIAL_TNE
Definition: opcodes_mips.h:223
#define SPECIAL_SRA
Definition: opcodes_mips.h:172
#define HI6_SB
Definition: opcodes_mips.h:456
#define REGIMM_SYNCI
Definition: opcodes_mips.h:251
#define SPECIAL_DSRA
Definition: opcodes_mips.h:228
A base-class for processors Component implementations.
Definition: CPUComponent.h:43
#define HI6_LDC1
Definition: opcodes_mips.h:469
#define MIPS_INITIAL_STACK_POINTER
virtual size_t DisassembleInstruction(uint64_t vaddr, size_t maxLen, unsigned char *instruction, vector< string > &result)=0
Disassembles an instruction into readable strings.
#define SPECIAL_MULTU
Definition: opcodes_mips.h:194
static void Assert(const string &strFailMessage, bool condition)
Asserts that a boolean condition is correct.
Definition: UnitTest.cc:40
#define SPECIAL_XOR
Definition: opcodes_mips.h:207
virtual void ResetState()
Resets the state variables of this component.
Definition: CPUComponent.cc:82
#define HI6_BEQL
Definition: opcodes_mips.h:305
#define SPECIAL_DSRAV
Definition: opcodes_mips.h:192
bool SetVariableValue(const string &name, const string &expression)
Sets a variable to a new value.
Definition: Component.cc:1030
#define SPECIAL_DDIV
Definition: opcodes_mips.h:199
refcount_ptr< Component > GetRootComponent()
Gets a pointer to the root configuration component.
Definition: GXemul.cc:667
#define HI6_LD
Definition: opcodes_mips.h:471
#define SPECIAL_ADDU
Definition: opcodes_mips.h:202
virtual AddressDataBus * AsAddressDataBus()
Returns the component&#39;s AddressDataBus interface, if any.
Definition: Component.cc:367
#define SPECIAL_MFLO
Definition: opcodes_mips.h:187
#define SPECIAL_ROT_NAMES
Definition: opcodes_mips.h:87
#define REGIMM_BLTZ
Definition: opcodes_mips.h:235
#define SPECIAL_TLT
Definition: opcodes_mips.h:219
#define HI6_BGTZ
Definition: opcodes_mips.h:259
#define REGIMM_BGEZL
Definition: opcodes_mips.h:238
#define MIPS_GPR_V0
Definition: symbol.h:37
#define REGIMM_NAMES
Definition: opcodes_mips.h:70
#define MIPS_INITIAL_PC
#define DYNTRANS_INSTR_HEAD(class)
#define SPECIAL_OR
Definition: opcodes_mips.h:206
UI * GetUI()
Gets a pointer to the GXemul instance&#39; active UI.
Definition: GXemul.cc:661
static bool GetCreationArgOverrides(ComponentCreationSettings &settings, const ComponentCreateArgs &createArgs)
Get override arguments for component creation.
#define HI6_LUI
Definition: opcodes_mips.h:267
#define HI6_DADDI
Definition: opcodes_mips.h:309
#define REGIMM_BLTZAL
Definition: opcodes_mips.h:245
#define HI6_SH
Definition: opcodes_mips.h:457
virtual int GetDyntransICshift() const
Base class for a User Interface.
Definition: UI.h:40
#define SPECIAL_SLL
Definition: opcodes_mips.h:169
virtual bool VirtualToPhysical(uint64_t vaddr, uint64_t &paddr, bool &writable)
Virtual to physical address translation (MMU).
#define N_MIPS_GPRS
const refcount_ptr< Component > LookupPath(string path) const
Looks up a path from this Component, and returns a pointer to the found Component, if any.
Definition: Component.cc:778
#define HI6_SPECIAL
Definition: opcodes_mips.h:168
#define REGIMM_BLTZALL
Definition: opcodes_mips.h:247
#define HI6_SD
Definition: opcodes_mips.h:479
virtual uint64_t PCtoInstructionAddress(uint64_t pc)
Convert PC value to instuction address.
void Execute(const int longestTotalRun=100000)
Run the emulation for "a while".
Definition: GXemul.cc:894
char * op[16]
#define SPECIAL_SRL
Definition: opcodes_mips.h:171
#define HI6_LQ_MDMX
Definition: opcodes_mips.h:429
#define HI6_BLEZ
Definition: opcodes_mips.h:258
#define HI6_LWC1
Definition: opcodes_mips.h:465
#define UNITTEST(functionname)
Helper for unit test case execution.
Definition: UnitTest.h:217
bool IsNULL() const
Checks whether or not an object is referenced by the reference counted pointer.
Definition: refcount_ptr.h:216
#define HI6_J
Definition: opcodes_mips.h:254
#define SPECIAL_DSRLV
Definition: opcodes_mips.h:191

Generated on Sun Sep 30 2018 16:05:18 for GXemul by doxygen 1.8.13