M88K_CPUComponent.cc Source File

Back to the index.

M88K_CPUComponent.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009-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 <algorithm>
32 #include <iomanip>
33 
34 #include "ComponentFactory.h"
35 #include "GXemul.h"
37 
38 static const char* opcode_names[] = M88K_OPCODE_NAMES;
39 static const char* opcode_names_3c[] = M88K_3C_OPCODE_NAMES;
40 static const char* opcode_names_3d[] = M88K_3D_OPCODE_NAMES;
41 static m88k_cpu_type_def cpu_type_defs[] = M88K_CPU_TYPE_DEFS;
42 
43 static const char *memop[4] = { ".d", "", ".h", ".b" };
44 
45 static const char *m88k_cr_names[] = M88K_CR_NAMES;
46 //static const char *m88k_cr_197_names[] = M88K_CR_NAMES_197;
47 
48 static const char *m88k_cr_name(int i)
49 {
50  const char **cr_names = m88k_cr_names;
51 
52  // TODO: Is this really MVME197 specific? Or 88110?
53  //if (cpu->machine->machine_subtype == MACHINE_MVME88K_197)
54  // cr_names = m88k_cr_197_names;
55 
56  return cr_names[i];
57 }
58 
59 
61  : CPUDyntransComponent("m88k_cpu", "Motorola 88000")
62  , m_m88k_type("88100")
63 {
64  m_frequency = 50e6; // 50 MHz
65 
66  // Find (and cache) the cpu type in m_type:
67  memset((void*) &m_type, 0, sizeof(m_type));
68  for (size_t j=0; cpu_type_defs[j].name != NULL; j++) {
69  if (m_m88k_type == cpu_type_defs[j].name) {
70  m_type = cpu_type_defs[j];
71  break;
72  }
73  }
74 
75  if (m_type.name == NULL) {
76  std::cerr << "Internal error: Unimplemented M88K type?\n";
77  throw std::exception();
78  }
79 
80  AddVariable("model", &m_m88k_type);
81 
82  for (size_t i=0; i<N_M88K_REGS; i++) {
83  stringstream ss;
84  ss << "r" << i;
85  AddVariable(ss.str(), &m_r[i]);
86  }
87 
88  for (size_t i=0; i<N_M88K_CONTROL_REGS; i++) {
89  stringstream ss;
90  ss << "cr" << i;
91  AddVariable(ss.str(), &m_cr[i]);
92  }
93 
94  for (size_t i=0; i<N_M88K_FPU_CONTROL_REGS; i++) {
95  stringstream ss;
96  ss << "fcr" << i;
97  AddVariable(ss.str(), &m_fcr[i]);
98  }
99 
100  m_initial_r31 = 0x00000000;
101  AddVariable("initial_r31", &m_initial_r31);
102 
103  AddVariable("inDelaySlot", &m_inDelaySlot);
104  AddVariable("delaySlotTarget", &m_delaySlotTarget);
105 
106  ResetState();
107 }
108 
109 
111 {
112  // Defaults:
114  settings["model"] = "88100";
115  settings["r31"] = "0x00000000";
116 
117  if (!ComponentFactory::GetCreationArgOverrides(settings, args))
118  return NULL;
119 
120  // Create the CPU...
122 
123  // ... and apply settings:
124  if (!cpu->SetVariableValue("model", "\"" + settings["model"] + "\""))
125  return NULL;
126 
127  if (!cpu->SetVariableValue("initial_r31", settings["r31"]))
128  return NULL;
129  if (!cpu->SetVariableValue("r31", settings["r31"]))
130  return NULL;
131 
132  return cpu;
133 }
134 
135 
137 {
138  m_pageSize = 4096;
139 
140  // r0 .. r31 and the extra "r32/r0" zero register:
141  for (size_t i=0; i<N_M88K_REGS+1; i++)
142  m_r[i] = 0;
143 
144  // ... but change r31 to the initial stack pointer value:
145  m_r[M88K_STACKPOINTER_REG] = m_initial_r31;
146 
147  for (size_t i=0; i<N_M88K_CONTROL_REGS; i++)
148  m_cr[i] = 0;
149 
150  for (size_t i=0; i<N_M88K_FPU_CONTROL_REGS; i++)
151  m_fcr[i] = 0;
152 
153  m_pc = 0;
154 
155  // Set the Processor ID:
156  m_cr[M88K_CR_PID] = m_type.pid | M88K_PID_MC;
157 
158  // Start in supervisor mode, with interrupts disabled.
160  if (!m_isBigEndian)
161  m_cr[M88K_CR_PSR] |= M88K_PSR_BO;
162 
164 }
165 
166 
168 {
169  if (m_r[M88K_ZERO_REG] != 0) {
170  gxemul->GetUI()->ShowDebugMessage(this, "the r0 register "
171  "must contain the value 0.\n");
172  return false;
173  }
174 
175  if (m_pc > (uint64_t)0xffffffff) {
176  gxemul->GetUI()->ShowDebugMessage(this, "the pc register "
177  "must be a 32-bit value.\n");
178  return false;
179  }
180 
181  if (m_pc & 0x2) {
182  gxemul->GetUI()->ShowDebugMessage(this, "the pc register must have"
183  " its lower two bits clear!\n");
184  return false;
185  }
186 
187  if (m_r[N_M88K_REGS] != 0) {
188  gxemul->GetUI()->ShowDebugMessage(this, "internal error: the "
189  "register following r31 must mimic the r0 register.\nIf"
190  " you encounter this message, please write a bug report!\n");
191  return false;
192  }
193 
195 }
196 
197 
198 bool M88K_CPUComponent::CheckVariableWrite(StateVariable& var, const string& oldValue)
199 {
200  UI* ui = GetUI();
201 
202  if (m_r[M88K_ZERO_REG] != 0) {
203  if (ui != NULL) {
204  ui->ShowDebugMessage(this, "the zero register (r0) "
205  "must contain the value 0.\n");
206  }
207  return false;
208  }
209 
210  if (m_m88k_type != m_type.name) {
211  bool found = false;
212  for (size_t j=0; cpu_type_defs[j].name != NULL; j++) {
213  if (m_m88k_type == cpu_type_defs[j].name) {
214  m_type = cpu_type_defs[j];
215  found = true;
216  break;
217  }
218  }
219 
220  if (!found) {
221  if (ui != NULL) {
222  stringstream ss;
223  ss << "Unknown model \"" + m_m88k_type + "\". Available types are:\n";
224  for (size_t j=0; cpu_type_defs[j].name != NULL; j++) {
225  if ((j % 6) != 0)
226  ss << "\t";
227  ss << cpu_type_defs[j].name;
228  if ((j % 6) == 5)
229  ss << "\n";
230  }
231  ui->ShowDebugMessage(this, ss.str());
232  }
233  return false;
234  }
235  }
236 
237  return CPUDyntransComponent::CheckVariableWrite(var, oldValue);
238 }
239 
240 
241 void M88K_CPUComponent::ShowRegisters(GXemul* gxemul, const vector<string>& arguments) const
242 {
243  bool done = false;
244 
245  stringstream ss;
246  ss.flags(std::ios::hex);
247 
248  if (arguments.size() == 0 ||
249  find(arguments.begin(), arguments.end(), "r") != arguments.end()) {
250  ss << " pc = 0x" << std::setfill('0') << std::setw(8) << m_pc;
251 
252  string symbol = GetSymbolRegistry().LookupAddress(m_pc, true);
253  if (symbol != "")
254  ss << " <" << symbol << ">";
255  ss << "\n";
256 
257  for (size_t i=0; i<N_M88K_REGS; i++) {
258  stringstream regname;
259  regname << "r" << i;
260 
261  ss << std::setfill(' ');
262  ss << std::setw(5) << regname.str() << " = 0x";
263  ss << std::setfill('0') << std::setw(8) << m_r[i];
264  if ((i&3) == 3)
265  ss << "\n";
266  else
267  ss << " ";
268  }
269 
270  done = true;
271  }
272 
273  if (find(arguments.begin(), arguments.end(), "cr") != arguments.end()) {
274  for (size_t i=0; i<N_M88K_CONTROL_REGS; i++) {
275  stringstream regname;
276  regname << "cr" << i;
277 
278  ss << std::setfill(' ');
279  ss << std::setw(5) << regname.str() << " = 0x";
280  ss << std::setfill('0') << std::setw(8) << m_cr[i];
281  if ((i&3) == 3)
282  ss << "\n";
283  else
284  ss << " ";
285  }
286 
287  done = true;
288  }
289 
290  if (find(arguments.begin(), arguments.end(), "crn") != arguments.end()) {
291  for (size_t i=0; i<N_M88K_CONTROL_REGS; i++) {
292  ss << std::setfill(' ');
293  ss << std::setw(5) << m88k_cr_name(i) << " = 0x";
294  ss << std::setfill('0') << std::setw(8) << m_cr[i];
295  if ((i&3) == 3)
296  ss << "\n";
297  else
298  ss << " ";
299  }
300 
301  done = true;
302  }
303 
304  if (find(arguments.begin(), arguments.end(), "fcr") != arguments.end()) {
305  for (size_t i=0; i<N_M88K_FPU_CONTROL_REGS; i++) {
306  stringstream regname;
307  regname << "fcr" << i;
308 
309  ss << std::setfill(' ');
310  ss << std::setw(5) << regname.str() << " = 0x";
311  ss << std::setfill('0') << std::setw(8) << m_fcr[i];
312  if ((i&3) == 3)
313  ss << "\n";
314  else
315  ss << " ";
316  }
317 
318  done = true;
319  }
320 
321  if (!done) {
322  ss << "M88K usage: .registers [r] [cr] [crn] [fcr]\n"
323  "r = pc and general purpose registers (default)\n"
324  "cr = control registers\n"
325  "crn = control registers with symbolic names instead of crX\n"
326  "fcr = floating point control registers\n";
327  }
328 
329  gxemul->GetUI()->ShowDebugMessage(ss.str());
330 }
331 
332 
334 {
335  // 4 bytes per instruction, i.e. shift is 2 bits.
337 }
338 
339 
341 {
342  return instr_ToBeTranslated;
343 }
344 
345 
346 bool M88K_CPUComponent::VirtualToPhysical(uint64_t vaddr, uint64_t& paddr,
347  bool& writable)
348 {
349  // TODO. For now, just return paddr = vaddr.
350 
351  paddr = vaddr & 0xffffffff;
352  writable = true;
353  return true;
354 }
355 
356 
357 void M88K_CPUComponent::Exception(int vector, int is_trap)
358 {
359  std::cerr << "TODO: M88K exception\n";
360  throw std::exception();
361 }
362 
363 
364 size_t M88K_CPUComponent::DisassembleInstruction(uint64_t vaddr, size_t maxLen,
365  unsigned char *instruction, vector<string>& result)
366 {
367  const size_t instrSize = sizeof(uint32_t);
368 
369  if (maxLen < instrSize) {
370  assert(false);
371  return 0;
372  }
373 
374  // Read the instruction word:
375  uint32_t instructionWord = *((uint32_t *)(void*) instruction);
376  if (m_isBigEndian)
377  instructionWord = BE32_TO_HOST(instructionWord);
378  else
379  instructionWord = LE32_TO_HOST(instructionWord);
380 
381  const uint32_t iw = instructionWord;
382 
383  // ... and add it to the result:
384  {
385  stringstream ss;
386  ss.flags(std::ios::hex);
387  ss << std::setfill('0') << std::setw(8) << (uint32_t) iw;
388  if (m_pc == vaddr && m_inDelaySlot)
389  ss << " (delayslot)";
390  result.push_back(ss.str());
391  }
392 
393  const uint32_t op26 = (iw >> 26) & 0x3f;
394  const uint32_t op11 = (iw >> 11) & 0x1f;
395  const uint32_t op10 = (iw >> 10) & 0x3f;
396  const uint32_t d = (iw >> 21) & 0x1f;
397  const uint32_t s1 = (iw >> 16) & 0x1f;
398  const uint32_t s2 = iw & 0x1f;
399  const uint32_t op3d = (iw >> 8) & 0xff;
400  const uint32_t imm16 = iw & 0xffff;
401  const uint32_t w5 = (iw >> 5) & 0x1f;
402  const uint32_t cr6 = (iw >> 5) & 0x3f;
403  const int32_t d16 = ((int16_t) (iw & 0xffff)) * 4;
404  const int32_t d26 = ((int32_t)((iw & 0x03ffffff) << 6)) >> 4;
405 
406  switch (op26) {
407 
408  case 0x00: /* xmem.bu */
409  case 0x01: /* xmem */
410  case 0x02: /* ld.hu */
411  case 0x03: /* ld.bu */
412  case 0x04: /* ld.d */
413  case 0x05: /* ld */
414  case 0x06: /* ld.h */
415  case 0x07: /* ld.b */
416  case 0x08: /* st.d */
417  case 0x09: /* st */
418  case 0x0a: /* st.h */
419  case 0x0b: /* st.b */
420  case 0x10: /* and */
421  case 0x11: /* and.u */
422  case 0x12: /* mask */
423  case 0x13: /* mask.u */
424  case 0x14: /* xor */
425  case 0x15: /* xor.u */
426  case 0x16: /* or */
427  case 0x17: /* or.u */
428  case 0x18: /* addu */
429  case 0x19: /* subu */
430  case 0x1a: /* divu */
431  case 0x1b: /* mulu */
432  case 0x1c: /* add */
433  case 0x1d: /* sub */
434  case 0x1e: /* div */
435  case 0x1f: /* cmp */
436  if (iw == 0x00000000) {
437  result.push_back("-");
438  } else {
439  // Two registers (d, s1) and an immediate.
440  result.push_back(opcode_names[op26]);
441 
442  stringstream ss;
443  ss << "r" << d << ",r" << s1;
444  ss.flags(std::ios::hex | std::ios::showbase);
445  ss << "," << imm16;
446  result.push_back(ss.str());
447  }
448  break;
449 
450  case 0x20:
451  if ((iw & 0x001ff81f) == 0x00004000) {
452  result.push_back("ldcr");
453  stringstream ss;
454  ss << "r" << d << ",cr" << cr6;
455  result.push_back(ss.str());
456 
457  stringstream comment;
458  comment << "; cr" << cr6 << " = " << m88k_cr_name(cr6);
459  result.push_back(comment.str());
460  } else if ((iw & 0x001ff81f) == 0x00004800) {
461  result.push_back("fldcr");
462  stringstream ss;
463  ss << "r" << d << ",fcr" << cr6;
464  result.push_back(ss.str());
465  } else if ((iw & 0x03e0f800) == 0x00008000) {
466  result.push_back("stcr");
467  stringstream ss;
468  ss << "r" << s1 << ",cr" << cr6;
469  result.push_back(ss.str());
470  if (s1 != s2)
471  result.push_back("; Weird encoding: s1 != s2");
472 
473  stringstream comment;
474  comment << "; cr" << cr6 << " = " << m88k_cr_name(cr6);
475  result.push_back(comment.str());
476  } else if ((iw & 0x03e0f800) == 0x00008800) {
477  result.push_back("fstcr");
478  stringstream ss;
479  ss << "r" << s1 << ",fcr" << cr6;
480  result.push_back(ss.str());
481  if (s1 != s2)
482  result.push_back("; Weird encoding: s1 != s2");
483  } else if ((iw & 0x0000f800) == 0x0000c000) {
484  result.push_back("xcr");
485  stringstream ss;
486  ss << "r" << d << ",r" << s1 << ",cr" << cr6;
487  result.push_back(ss.str());
488  if (s1 != s2)
489  result.push_back("; Weird encoding: s1 != s2");
490 
491  stringstream comment;
492  comment << "; cr" << cr6 << " = " << m88k_cr_name(cr6);
493  result.push_back(comment.str());
494  } else if ((iw & 0x0000f800) == 0x0000c800) {
495  result.push_back("fxcr");
496  stringstream ss;
497  ss << "r" << d << ",r" << s1 << ",fcr" << cr6;
498  result.push_back(ss.str());
499  if (s1 != s2)
500  result.push_back("; Weird encoding: s1 != s2");
501  } else {
502  result.push_back("unimpl_0x20_variant");
503  }
504  break;
505 
506  case 0x21:
507  switch (op11) {
508  case 0x00: /* fmul */
509  case 0x05: /* fadd */
510  case 0x06: /* fsub */
511  case 0x07: /* fcmp */
512  case 0x0e: /* fdiv */
513  {
514  stringstream ss;
515  switch (op11) {
516  case 0x00: ss << "fmul"; break;
517  case 0x05: ss << "fadd"; break;
518  case 0x06: ss << "fsub"; break;
519  case 0x07: ss << "fcmp"; break;
520  case 0x0e: ss << "fdiv"; break;
521  }
522  ss << "." <<
523  (((iw >> 5) & 1)? "d" : "s") <<
524  (((iw >> 9) & 1)? "d" : "s") <<
525  (((iw >> 7) & 1)? "d" : "s");
526  result.push_back(ss.str());
527 
528  stringstream ss2;
529  ss2 << "r" << d << ",r" << s1 << ",r" << s2;
530  result.push_back(ss2.str());
531  }
532  break;
533  case 0x04: /* flt */
534  {
535  stringstream ss;
536  switch (op11) {
537  case 0x04: ss << "flt"; break;
538  }
539  ss << "." << (((iw >> 5) & 1)? "d" : "s") << "s";
540  result.push_back(ss.str());
541 
542  stringstream ss2;
543  ss2 << "r" << d << ",r" << s2;
544  result.push_back(ss2.str());
545  }
546  break;
547  case 0x09: /* int */
548  case 0x0a: /* nint */
549  case 0x0b: /* trnc */
550  {
551  stringstream ss;
552  switch (op11) {
553  case 0x09: ss << "int"; break;
554  case 0x0a: ss << "nint"; break;
555  case 0x0b: ss << "trnc"; break;
556  }
557  ss << ".s" << (((iw >> 7) & 1)? "d" : "s");
558  result.push_back(ss.str());
559 
560  stringstream ss2;
561  ss2 << "r" << d << ",r" << s2;
562  result.push_back(ss2.str());
563  }
564  break;
565  default:{
566  stringstream ss;
567  ss << "unimpl_0x21, op11=" << op11;
568  result.push_back(ss.str());
569  }
570  }
571  break;
572 
573  case 0x30: /* br */
574  case 0x31: /* br.n */
575  case 0x32: /* bsr */
576  case 0x33: /* bsr.n */
577  {
578  result.push_back(opcode_names[op26]);
579 
580  stringstream ss;
581  ss.flags(std::ios::hex | std::ios::showbase);
582  ss << ((uint32_t) (vaddr + d26));
583  result.push_back(ss.str());
584 
586  (uint32_t) (vaddr + d26), true);
587  if (symbol != "")
588  result.push_back("; <" + symbol + ">");
589  }
590  break;
591 
592  case 0x34: /* bb0 */
593  case 0x35: /* bb0.n */
594  case 0x36: /* bb1 */
595  case 0x37: /* bb1.n */
596  case 0x3a: /* bcnd */
597  case 0x3b: /* bcnd.n */
598  {
599  result.push_back(opcode_names[op26]);
600 
601  stringstream ss;
602  if (op26 == 0x3a || op26 == 0x3b) {
603  /* Attempt to decode bcnd condition: */
604  switch (d) {
605  case 0x1: ss << "gt0"; break;
606  case 0x2: ss << "eq0"; break;
607  case 0x3: ss << "ge0"; break;
608  case 0x7: ss << "not_maxneg"; break;
609  case 0x8: ss << "maxneg"; break;
610  case 0xc: ss << "lt0"; break;
611  case 0xd: ss << "ne0"; break;
612  case 0xe: ss << "le0"; break;
613  default: ss << "unk_" << d;
614  }
615  } else {
616  ss << d;
617  }
618 
619  ss << ",r" << s1 << ",";
620 
621  ss.flags(std::ios::hex | std::ios::showbase);
622  ss << ((uint32_t) (vaddr + d16));
623  result.push_back(ss.str());
624 
626  (uint32_t) (vaddr + d16), true);
627  if (symbol != "")
628  result.push_back("; <" + symbol + ">");
629  }
630 
631  break;
632 
633  case 0x3c:
634  if ((iw & 0x0000f000)==0x1000 || (iw & 0x0000f000)==0x2000) {
635  /* Load/store: */
636  stringstream ss;
637  ss << ((iw & 0x0000f000) == 0x1000? "ld" : "st");
638 
639  switch (iw & 0x00000c00) {
640  case 0x000: ss << ".d"; break;
641  case 0x400: break;
642  case 0x800: ss << ".x"; break;
643  default: ss << ".UNIMPLEMENTED";
644  }
645 
646  if (iw & 0x100)
647  ss << ".usr";
648  if (iw & 0x80)
649  ss << ".wt";
650 
651  result.push_back(ss.str());
652 
653  stringstream ss2;
654  ss2 << "r" << d << ",r" << s1;
655  if (iw & 0x200)
656  ss2 << "[r" << s2 << "]";
657  else
658  ss2 << ",r" << s2;
659 
660  result.push_back(ss2.str());
661  } else switch (op10) {
662  case 0x20: /* clr */
663  case 0x22: /* set */
664  case 0x24: /* ext */
665  case 0x26: /* extu */
666  case 0x28: /* mak */
667  case 0x2a: /* rot */
668  /* Two-register plus bit position/length: */
669  {
670  result.push_back(opcode_names_3c[op10]);
671 
672  stringstream ss;
673  ss << "r" << d << ",r" << s1 << ",";
674 
675  /* Don't include w5 for the rot instruction: */
676  if (op10 != 0x2a)
677  ss << w5;
678 
679  /* Note: o5 = s2: */
680  ss << "<" << s2 << ">";
681 
682  result.push_back(ss.str());
683  }
684  break;
685  case 0x34: /* tb0 */
686  case 0x36: /* tb1 */
687  /* B5 bit index, register, plus 9-bit immediate vector: */
688  {
689  result.push_back(opcode_names_3c[op10]);
690 
691  stringstream ss;
692  ss << d << ",r" << s1 << ",";
693  ss.flags(std::ios::hex | std::ios::showbase);
694  ss << (iw & 0x1ff);
695  result.push_back(ss.str());
696  }
697  break;
698  default:{
699  stringstream ss;
700  ss << "unimpl_" << opcode_names_3c[op10];
701  result.push_back(ss.str());
702  }
703  }
704  break;
705 
706  case 0x3d:
707  if ((iw & 0xf000) <= 0x3fff) {
708  /* Load, Store, xmem, and lda: */
709  stringstream op;
710 
711  switch (iw & 0xf000) {
712  case 0x2000: op << "st"; break;
713  case 0x3000: op << "lda"; break;
714  default: if ((iw & 0xf800) >= 0x0800)
715  op << "ld";
716  else
717  op << "xmem";
718  }
719 
720  if ((iw & 0xf000) >= 0x1000) {
721  /* ld, st, lda */
722  op << memop[(iw >> 10) & 3];
723  } else if ((iw & 0xf800) == 0x0000) {
724  /* xmem */
725  if (!(iw & 0x400))
726  op << ".bu";
727  } else {
728  /* ld */
729  if ((iw & 0xf00) < 0xc00)
730  op << ".hu";
731  else
732  op << ".bu";
733  }
734 
735  if (iw & 0x100)
736  op << ".usr";
737  if (iw & 0x80)
738  op << ".wt";
739 
740  result.push_back(op.str());
741 
742  stringstream ss;
743  ss << "r" << d << ",r" << s1;
744  if (iw & 0x200)
745  ss << "[r" << s2 << "]";
746  else
747  ss << ",r" << s2;
748 
749  result.push_back(ss.str());
750  } else switch (op3d) {
751  case 0x40: /* and */
752  case 0x44: /* and.c */
753  case 0x50: /* xor */
754  case 0x54: /* xor.c */
755  case 0x58: /* or */
756  case 0x5c: /* or.c */
757  case 0x60: /* addu */
758  case 0x61: /* addu.co */
759  case 0x62: /* addu.ci */
760  case 0x63: /* addu.cio */
761  case 0x64: /* subu */
762  case 0x65: /* subu.co */
763  case 0x66: /* subu.ci */
764  case 0x67: /* subu.cio */
765  case 0x68: /* divu */
766  case 0x69: /* divu.d */
767  case 0x6c: /* mul */
768  case 0x6d: /* mulu.d */
769  case 0x6e: /* muls */
770  case 0x70: /* add */
771  case 0x71: /* add.co */
772  case 0x72: /* add.ci */
773  case 0x73: /* add.cio */
774  case 0x74: /* sub */
775  case 0x75: /* sub.co */
776  case 0x76: /* sub.ci */
777  case 0x77: /* sub.cio */
778  case 0x78: /* div */
779  case 0x7c: /* cmp */
780  case 0x80: /* clr */
781  case 0x88: /* set */
782  case 0x90: /* ext */
783  case 0x98: /* extu */
784  case 0xa0: /* mak */
785  case 0xa8: /* rot */
786  /* Three-register opcodes: */
787  {
788  result.push_back(opcode_names_3d[op3d]);
789 
790  stringstream ss;
791  ss << "r" << d << ",r" << s1 << ",r" << s2;
792  result.push_back(ss.str());
793  }
794  break;
795  case 0xc0: /* jmp */
796  case 0xc4: /* jmp.n */
797  case 0xc8: /* jsr */
798  case 0xcc: /* jsr.n */
799  /* One-register jump opcodes: */
800  {
801  result.push_back(opcode_names_3d[op3d]);
802 
803  stringstream ss;
804  ss << "(r" << s2 << ")";
805  result.push_back(ss.str());
806  }
807  break;
808  case 0xe8: /* ff1 */
809  case 0xec: /* ff0 */
810  /* Two-register opcodes d,s2: */
811  {
812  result.push_back(opcode_names_3d[op3d]);
813 
814  stringstream ss;
815  ss << "r" << d << ",r" << s2;
816  result.push_back(ss.str());
817  }
818  break;
819  case 0xf8: /* tbnd */
820  /* Two-register opcodes s1,s2: */
821  {
822  result.push_back(opcode_names_3d[op3d]);
823 
824  stringstream ss;
825  ss << "r" << s1 << ",r" << s2;
826  result.push_back(ss.str());
827  }
828  break;
829  case 0xfc:
830  switch (iw & 0xff) {
831  case 0x00:
832  result.push_back("rte");
833  break;
834  case 0x01:
835  case 0x02:
836  case 0x03:
837  {
838  stringstream ss;
839  ss << "illop" << (iw & 0xff);
840  result.push_back(ss.str());
841  }
842  break;
843  case (M88K_PROM_INSTR & 0xff):
844  result.push_back("gxemul_prom_call");
845  break;
846  case (M88K_FAIL_EARLY_INSTR & 0xff):
847  result.push_back("gxemul_fail_early");
848  break;
849  case (M88K_FAIL_LATE_INSTR & 0xff):
850  result.push_back("gxemul_fail_late");
851  break;
852  default:{
853  stringstream ss;
854  ss << "unimpl_3d_0xfc_" << (iw & 0xff);
855  result.push_back(ss.str());
856  }
857  }
858  break;
859  default:{
860  stringstream ss;
861  ss << "unimpl_" << opcode_names_3d[op3d];
862  result.push_back(ss.str());
863  }
864  }
865  break;
866 
867  case 0x3e: /* tbnd */
868  {
869  result.push_back(opcode_names[op26]);
870 
871  stringstream ss;
872  ss << "r" << s1;
873  ss.flags(std::ios::hex | std::ios::showbase);
874  ss << "," << imm16;
875  result.push_back(ss.str());
876  }
877  break;
878 
879  default:
880  {
881  stringstream ss;
882  ss << "unimpl_" << opcode_names[op26];
883  result.push_back(ss.str());
884  }
885  break;
886  }
887 
888  return instrSize;
889 }
890 
891 
892 string M88K_CPUComponent::GetAttribute(const string& attributeName)
893 {
894  if (attributeName == "stable")
895  return "yes";
896 
897  if (attributeName == "description")
898  return "Motorola 88000 processor.";
899 
900  return Component::GetAttribute(attributeName);
901 }
902 
903 
904 /*****************************************************************************/
905 
906 
907 void M88K_CPUComponent::stcr(int cr, uint32_t value, bool is_rte)
908 {
909  uint32_t old = m_cr[cr];
910 
911  switch (cr) {
912 
913  case M88K_CR_PSR: /* Processor Status Regoster */
914  if ((!m_isBigEndian && !(value & M88K_PSR_BO)) ||
915  (m_isBigEndian && (value & M88K_PSR_BO))) {
916  std::cerr << "TODO: attempt to change endianness by flipping"
917  " the endianness bit in the PSR. How should this"
918  " be handled? Aborting.\n";
919  std::cerr << "TODO: abort in a nicer way\n";
920  throw std::exception();
921  }
922 
923  if (!is_rte && (old & M88K_PSR_MODE) && !(value & M88K_PSR_MODE)) {
924  UI* ui = GetUI();
925  if (ui != NULL) {
926  ui->ShowDebugMessage(this, "m88k stcr: WARNING! the PSR_MODE bit is being"
927  " cleared; this should be done using the RTE "
928  "instruction only, according to the M88100 "
929  "manual! Continuing anyway.\n");
930  }
931  }
932 
933  if (value & M88K_PSR_MXM) {
934  std::cerr << "m88k stcr: TODO: MXM support\n";
935  std::cerr << "TODO: abort in a nicer way\n";
936  throw std::exception();
937  }
938 
939  if ((old & M88K_PSR_MODE) != (value & M88K_PSR_MODE)) {
940 // cpu->invalidate_translation_caches(
941 // cpu, 0, INVALIDATE_ALL);
942  std::cerr << "m88k stcr: TODO: PSR mode switch.\n";
943  std::cerr << "TODO: abort in a nicer way\n";
944  throw std::exception();
945  }
946 
947  m_cr[cr] = value;
948  break;
949 
950  case M88K_CR_EPSR:
951  m_cr[cr] = value;
952  break;
953 
954  case M88K_CR_SXIP:
955  case M88K_CR_SNIP:
956  case M88K_CR_SFIP:
957  m_cr[cr] = value;
958  break;
959 
960  case M88K_CR_SSBR: /* Shadow ScoreBoard Register */
961  if (value & 1) {
962  UI* ui = GetUI();
963  if (ui != NULL)
964  ui->ShowDebugMessage(this, "WARNING! bit 0 non-zero when writing to SSBR\n");
965  }
966 
967  m_cr[cr] = value;
968  break;
969 
970  case M88K_CR_VBR:
971  if (value & 0x00000fff) {
972  UI* ui = GetUI();
973  if (ui != NULL)
974  ui->ShowDebugMessage(this, "WARNING! bits 0..11 non-zero when writing to VBR\n");
975  }
976 
977  m_cr[cr] = value;
978  break;
979 
980  case M88K_CR_DMT0:
981  case M88K_CR_DMT1:
982  case M88K_CR_DMT2:
983  m_cr[cr] = value;
984  break;
985 
986  case M88K_CR_SR0: /* Supervisor Storage Registers 0..3 */
987  case M88K_CR_SR1:
988  case M88K_CR_SR2:
989  case M88K_CR_SR3:
990  m_cr[cr] = value;
991  break;
992 
993  default:std::cerr << "m88k stcr: UNIMPLEMENTED cr = " << cr << "\n";
994  std::cerr << "TODO: abort in a nicer way\n";
995  throw std::exception();
996  }
997 }
998 
999 
1000 /*
1001  * cmp_imm: Compare S1 with immediate value.
1002  * cmp: Compare S1 with S2.
1003  *
1004  * arg[0] = pointer to register d
1005  * arg[1] = pointer to register s1
1006  * arg[2] = pointer to register s2 or imm
1007  */
1008 void M88K_CPUComponent::m88k_cmp(struct DyntransIC *ic, uint32_t y)
1009 {
1010  uint32_t x = REG32(ic->arg[1]);
1011  uint32_t r;
1012 
1013  if (x == y) {
1016  } else {
1017  if (x > y)
1019  else
1021  if ((int32_t)x > (int32_t)y)
1022  r |= M88K_CMP_GE | M88K_CMP_GT;
1023  else
1024  r |= M88K_CMP_LT | M88K_CMP_LE;
1025  }
1026 
1027  REG32(ic->arg[0]) = r;
1028 }
1029 
1030 
1032 {
1034  cpu->m88k_cmp(ic, REG32(ic->arg[2]));
1035 }
1036 
1037 
1039 {
1041  cpu->m88k_cmp(ic, ic->arg[2].u32);
1042 }
1043 
1044 
1045 /*
1046  * extu_imm: Extract bits, unsigned, immediate W<O>.
1047  * extu: Extract bits, unsigned, W<O> taken from register s2.
1048  * ext_imm: Extract bits, signed, immediate W<O>.
1049  * ext: Extract bits, signed, W<O> taken from register s2.
1050  *
1051  * arg[0] = pointer to register d
1052  * arg[1] = pointer to register s1
1053  * arg[2] = pointer to register s2 or 10 bits wwwwwooooo
1054  */
1055 void M88K_CPUComponent::m88k_extu(struct DyntransIC *ic, int w, int o)
1056 {
1057  uint32_t x = REG32(ic->arg[1]) >> o;
1058  if (w != 0) {
1059  x <<= (32-w);
1060  x >>= (32-w);
1061  }
1062 
1063  REG32(ic->arg[0]) = x;
1064 }
1065 void M88K_CPUComponent::m88k_ext(struct DyntransIC *ic, int w, int o)
1066 {
1067  int32_t x = REG32(ic->arg[1]);
1068  x >>= o; /* signed (arithmetic) shift */
1069  if (w != 0) {
1070  x <<= (32-w);
1071  x >>= (32-w);
1072  }
1073 
1074  REG32(ic->arg[0]) = x;
1075 }
1077 {
1079  cpu->m88k_extu(ic, ic->arg[2].u32 >> 5, ic->arg[2].u32 & 0x1f);
1080 }
1082 {
1084  cpu->m88k_extu(ic, (REG32(ic->arg[2]) >> 5) & 0x1f, REG32(ic->arg[2]) & 0x1f);
1085 }
1087 {
1089  cpu->m88k_ext(ic, ic->arg[2].u32 >> 5, ic->arg[2].u32 & 0x1f);
1090 }
1092 {
1094  cpu->m88k_ext(ic, (REG32(ic->arg[2]) >> 5) & 0x1f, REG32(ic->arg[2]) & 0x1f);
1095 }
1096 
1097 
1098 /*
1099  * mak: Make bit field, W<O> taken from register s2.
1100  * mak_imm: Make bit field, immediate W<O>.
1101  *
1102  * arg[0] = pointer to register d
1103  * arg[1] = pointer to register s1
1104  * arg[2] = pointer to register s2 or immediate.
1105  */
1106 void M88K_CPUComponent::m88k_mak(struct DyntransIC *ic, int w, int o)
1107 {
1108  uint32_t x = REG32(ic->arg[1]);
1109  if (w != 0) {
1110  x <<= (32-w);
1111  x >>= (32-w);
1112  }
1113 
1114  REG32(ic->arg[0]) = x << o;
1115 }
1116 
1117 
1119 {
1121  cpu->m88k_mak(ic, (REG32(ic->arg[2]) >> 5) & 0x1f, REG32(ic->arg[2]) & 0x1f);
1122 }
1123 
1124 
1126 {
1128  cpu->m88k_mak(ic, ic->arg[2].u32 >> 5, ic->arg[2].u32 & 0x1f);
1129 }
1130 
1131 
1132 /*
1133  * divu_imm: d = s1 / immediate
1134  * mulu_imm: d = s1 * immediate
1135  *
1136  * arg[0] = pointer to register d
1137  * arg[1] = pointer to register s1
1138  * arg[2] = immediate.
1139  */
1141 {
1143 
1144  // TODO: 88100 only, not 88110:
1145  if (cpu->m_cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1148  cpu->Exception(M88K_EXCEPTION_SFU1_PRECISE, 0);
1149  } else if (ic->arg[2].u32 == 0) {
1152  } else {
1153  REG32(ic->arg[0]) = REG32(ic->arg[1]) / ic->arg[2].u32;
1154  }
1155 }
1157 {
1159 
1160  // TODO: 88100 only, not 88110:
1161  if (cpu->m_cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1164  cpu->Exception(M88K_EXCEPTION_SFU1_PRECISE, 0);
1165  } else {
1166  REG32(ic->arg[0]) = REG32(ic->arg[1]) * ic->arg[2].u32;
1167  }
1168 }
1169 
1170 
1172 {
1174 
1176  cpu->m_r[M88K_RETURN_REG] = cpu->m_pc + ic->arg[2].u32;
1177 
1178  cpu->m_pc = (uint32_t) (cpu->m_pc + ic->arg[1].u32);
1179  cpu->DyntransPCtoPointers();
1180 }
1181 
1182 
1184 {
1186 
1187  cpu->m_r[M88K_RETURN_REG] = (cpu->m_pc & ~((M88K_IC_ENTRIES_PER_PAGE-1)
1188  << M88K_INSTR_ALIGNMENT_SHIFT)) + ic->arg[2].u32;
1189  cpu->m_nextIC = (struct DyntransIC *) ic->arg[0].p;
1190 }
1191 
1192 
1193 DYNTRANS_INSTR(M88K_CPUComponent,bsr_functioncalltrace)
1194 {
1196 
1198  cpu->m_r[M88K_RETURN_REG] = cpu->m_pc + ic->arg[2].u32;
1199 
1200  cpu->m_pc = (uint32_t) (cpu->m_pc + ic->arg[1].u32);
1201 
1202  bool continueExecution = cpu->FunctionTraceCall();
1203  cpu->DyntransPCtoPointers();
1204 
1205  if (!continueExecution)
1206  cpu->m_nextIC = &cpu->m_abortIC;
1207 }
1208 
1209 
1211 {
1213 
1214  uint32_t startOfPage = cpu->m_pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT);
1215  cpu->m_r[M88K_RETURN_REG] = startOfPage + ic->arg[2].u32;
1216 
1217  // Prepare for the branch.
1218  cpu->m_exceptionOrAbortInDelaySlot = false;
1219  cpu->m_inDelaySlot = true;
1220  cpu->m_delaySlotTarget = (uint32_t) (startOfPage + ic->arg[1].u32);
1221 
1222  // Execute the next instruction:
1223  ic[1].f(cpu, ic+1);
1224  cpu->m_executedCycles ++;
1225 
1226  // If there was no exception, then branch:
1227  if (!cpu->m_exceptionOrAbortInDelaySlot) {
1228  cpu->m_pc = (uint32_t) (startOfPage + ic->arg[1].u32);
1229  cpu->DyntransPCtoPointers();
1230 
1231  cpu->m_inDelaySlot = false;
1232  }
1233 
1234  // The next instruction is now either the target of the branch
1235  // instruction, or the first instruction of an exception handler.
1236  cpu->m_exceptionOrAbortInDelaySlot = false;
1237 }
1238 
1239 
1240 DYNTRANS_INSTR(M88K_CPUComponent,bsr_n_functioncalltrace)
1241 {
1243 
1244  uint32_t startOfPage = cpu->m_pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT);
1245  cpu->m_r[M88K_RETURN_REG] = startOfPage + ic->arg[2].u32;
1246 
1247  // Prepare for the branch.
1248  cpu->m_inDelaySlot = true;
1249  cpu->m_exceptionOrAbortInDelaySlot = false;
1250 
1251  // Execute the next instruction:
1252  ic[1].f(cpu, ic+1);
1253  cpu->m_executedCycles ++;
1254 
1255  // If there was no exception, then branch:
1256  if (!cpu->m_exceptionOrAbortInDelaySlot) {
1257  cpu->m_pc = (uint32_t) (startOfPage + ic->arg[1].u32);
1258 
1259  bool continueExecution = cpu->FunctionTraceCall();
1260  cpu->DyntransPCtoPointers();
1261 
1262  cpu->m_inDelaySlot = false;
1263 
1264  if (!continueExecution)
1265  cpu->m_nextIC = &cpu->m_abortIC;
1266  }
1267 
1268  // The next instruction is now either the target of the branch
1269  // instruction, or the first instruction of an exception handler.
1270  cpu->m_exceptionOrAbortInDelaySlot = false;
1271 }
1272 
1273 
1274 // Note: This IC function is used both when function call trace is enabled
1275 // and disabled. (Ok, since it is only used when singlestepping.)
1276 DYNTRANS_INSTR(M88K_CPUComponent,bsr_n_functioncalltrace_singlestep)
1277 {
1279 
1280  // Prepare for the delayed branch.
1281  cpu->m_inDelaySlot = true;
1282  cpu->m_exceptionOrAbortInDelaySlot = false;
1283 
1285  cpu->m_r[M88K_RETURN_REG] = cpu->m_pc + ic->arg[2].u32;
1286 
1287  uint32_t old_pc = cpu->m_pc;
1288 
1289  cpu->m_pc = (uint32_t) (cpu->m_pc + ic->arg[1].u32);
1290 
1291  if (cpu->m_showFunctionTraceCall)
1292  cpu->FunctionTraceCall();
1293 
1294  cpu->m_delaySlotTarget = cpu->m_pc;
1295 
1296  // make m_nextIC (and pc!) point to the next instruction:
1297  cpu->m_nextIC = ic + 1;
1298  cpu->m_pc = old_pc; // at least the same page... not necessarily more correct than that.
1299 }
1300 
1301 
1302 /*
1303  * bcnd, bcnd.n: Branch on condition
1304  *
1305  * arg[0] = pointer to register s1
1306  * arg[2] = offset from start of current page to branch to _OR_ pointer to new instr_call
1307  */
1308 template<bool n, int op, bool singlestep> void M88K_CPUComponent::instr_bcnd(CPUDyntransComponent* cpubase, DyntransIC* ic)
1309 {
1311 
1312  bool cond;
1313  if (op == 1) cond = ((int32_t)REG32(ic->arg[0]) > 0); // gt0
1314  else if (op == 2) cond = ((int32_t)REG32(ic->arg[0]) == 0); // eq0
1315  else if (op == 3) cond = ((int32_t)REG32(ic->arg[0]) >= 0); // ge0
1316  else if (op == 7) cond = ((uint32_t)REG32(ic->arg[0]) != 0x80000000UL); // not_maxneg
1317  else if (op == 8) cond = ((uint32_t)REG32(ic->arg[0]) == 0x80000000UL); // maxneg
1318  else if (op == 12) cond = ((int32_t)REG32(ic->arg[0]) < 0); // lt0
1319  else if (op == 13) cond = ((int32_t)REG32(ic->arg[0]) != 0); // ne0
1320  else /* op == 14 */ cond = ((int32_t)REG32(ic->arg[0]) <= 0); // le0
1321 
1322  if (n) {
1323  if (singlestep) {
1325 
1326  // Prepare for the branch.
1327  cpu->m_inDelaySlot = true;
1328  cpu->m_exceptionOrAbortInDelaySlot = false;
1329 
1330  if (cond) {
1331  cpu->m_delaySlotTarget = cpu->m_pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT);
1332  cpu->m_delaySlotTarget = (uint32_t) (cpu->m_delaySlotTarget + ic->arg[2].u32);
1333  } else {
1334  cpu->m_delaySlotTarget = cpu->m_pc + 8;
1335  }
1336 
1337  cpu->m_nextIC = ic + 1;
1338  } else {
1339  // Prepare for the branch.
1340  cpu->m_inDelaySlot = true;
1341  cpu->m_exceptionOrAbortInDelaySlot = false;
1342 
1343  // Execute the next instruction:
1344  ic[1].f(cpu, ic+1);
1345  cpu->m_executedCycles ++;
1346 
1347  // If there was no exception, then branch:
1348  if (!cpu->m_exceptionOrAbortInDelaySlot) {
1349  if (cond) {
1351  cpu->m_pc = (uint32_t) (cpu->m_pc + ic->arg[2].u32);
1352  cpu->DyntransPCtoPointers();
1353  } else {
1354  cpu->m_nextIC = ic + 2;
1355  }
1356 
1357  cpu->m_inDelaySlot = false;
1358  }
1359 
1360  // The next instruction is now either the target of the branch
1361  // instruction, the instruction 2 steps after this one,
1362  // or the first instruction of an exception handler.
1363  cpu->m_exceptionOrAbortInDelaySlot = false;
1364  }
1365  } else {
1366  // bcnd without the .n flag:
1367  if (cond) {
1369  cpu->m_pc = (uint32_t) (cpu->m_pc + ic->arg[2].u32);
1370  cpu->DyntransPCtoPointers();
1371  } else {
1372  // m_nextIC should already point to the next ic.
1373  }
1374  }
1375 }
1376 
1377 
1378 /*
1379  * bb0, bb1: Branch if a bit in a register is 0 or 1
1380  * bb0.n, bb1.n: Branch if a bit in a register is 0 or 1 with delay slot
1381  *
1382  * arg[0] = pointer to register s1
1383  * arg[1] = uint32_t bitmask to test
1384  * arg[2] = offset from start of current page to branch to _OR_ pointer to new instr_call
1385  */
1386 template<bool one, bool samepage> void M88K_CPUComponent::instr_bb(CPUDyntransComponent* cpubase, DyntransIC* ic)
1387 {
1389 
1390  bool bit = REG32(ic->arg[0]) & ic->arg[1].u32;
1391  if (bit == one) {
1392  if (samepage) {
1393  cpu->m_nextIC = (DyntransIC*) ic->arg[2].p;
1394  } else {
1396  cpu->m_pc = (uint32_t) (cpu->m_pc + ic->arg[2].u32);
1397  cpu->DyntransPCtoPointers();
1398  }
1399  }
1400 }
1401 
1402 
1403 template<bool one> void M88K_CPUComponent::instr_bb_n(CPUDyntransComponent* cpubase, DyntransIC* ic)
1404 {
1406 
1407  bool bit = REG32(ic->arg[0]) & ic->arg[1].u32;
1408 
1409  // Prepare for the branch.
1410  cpu->m_inDelaySlot = true;
1411  cpu->m_exceptionOrAbortInDelaySlot = false;
1412 
1413  // Execute the next instruction:
1414  ic[1].f(cpu, ic+1);
1415  cpu->m_executedCycles ++;
1416 
1417  // If there was no exception, then branch:
1418  if (!cpu->m_exceptionOrAbortInDelaySlot) {
1419  if (bit == one) {
1421  cpu->m_pc = (uint32_t) (cpu->m_pc + ic->arg[2].u32);
1422  cpu->DyntransPCtoPointers();
1423  } else {
1424  cpu->m_nextIC = ic + 2;
1425  }
1426 
1427  cpu->m_inDelaySlot = false;
1428  }
1429 
1430  // The next instruction is now either the target of the branch
1431  // instruction, the instruction 2 steps after this one,
1432  // or the first instruction of an exception handler.
1433  cpu->m_exceptionOrAbortInDelaySlot = false;
1434 }
1435 
1436 
1437 template<bool one> void M88K_CPUComponent::instr_bb_n_singlestep(CPUDyntransComponent* cpubase, DyntransIC* ic)
1438 {
1440 
1441  bool bit = REG32(ic->arg[0]) & ic->arg[1].u32;
1442 
1444 
1445  // Prepare for the branch.
1446  cpu->m_inDelaySlot = true;
1447  cpu->m_exceptionOrAbortInDelaySlot = false;
1448 
1449  if (bit == one) {
1450  cpu->m_delaySlotTarget = cpu->m_pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT);
1451  cpu->m_delaySlotTarget = (uint32_t) (cpu->m_delaySlotTarget + ic->arg[2].u32);
1452  } else {
1453  cpu->m_delaySlotTarget = cpu->m_pc + 8;
1454  }
1455 
1456  cpu->m_nextIC = ic + 1;
1457 }
1458 
1459 
1461 {
1463  bool continueExecution = true;
1464 
1465  if (cpu->m_showFunctionTraceCall && ic->arg[2].p == &cpu->m_r[M88K_RETURN_REG])
1466  continueExecution = cpu->FunctionTraceReturn();
1467 
1468  cpu->m_pc = REG32(ic->arg[2]);
1469  cpu->DyntransPCtoPointers();
1470 
1471  if (!continueExecution)
1472  cpu->m_nextIC = &cpu->m_abortIC;
1473 }
1474 
1475 
1477 {
1479 
1480  // Prepare for the branch.
1481  cpu->m_inDelaySlot = true;
1482  cpu->m_exceptionOrAbortInDelaySlot = false;
1483  uint32_t branchTarget = REG32(ic->arg[2]);
1484 
1485  // Execute the next instruction:
1486  ic[1].f(cpu, ic+1);
1487  cpu->m_executedCycles ++;
1488 
1489  // If there was no exception, then branch:
1490  if (!cpu->m_exceptionOrAbortInDelaySlot) {
1491  cpu->m_pc = branchTarget;
1492  cpu->DyntransPCtoPointers();
1493 
1494  cpu->m_inDelaySlot = false;
1495  }
1496 
1497  // The next instruction is now either the target of the branch
1498  // instruction, the instruction 2 steps after this one,
1499  // or the first instruction of an exception handler.
1500  cpu->m_exceptionOrAbortInDelaySlot = false;
1501 }
1502 
1503 
1504 DYNTRANS_INSTR(M88K_CPUComponent,jmp_n_functioncalltrace)
1505 {
1507 
1508  // Prepare for the branch.
1509  cpu->m_inDelaySlot = true;
1510  cpu->m_exceptionOrAbortInDelaySlot = false;
1511  uint32_t branchTarget = REG32(ic->arg[2]);
1512 
1513  // Execute the next instruction:
1514  ic[1].f(cpu, ic+1);
1515  cpu->m_executedCycles ++;
1516 
1517  // If there was no exception, then branch:
1518  if (!cpu->m_exceptionOrAbortInDelaySlot) {
1519  bool continueExecution = true;
1520  if (cpu->m_showFunctionTraceCall && ic->arg[2].p == &cpu->m_r[M88K_RETURN_REG])
1521  continueExecution = cpu->FunctionTraceReturn();
1522 
1523  cpu->m_pc = branchTarget;
1524  cpu->DyntransPCtoPointers();
1525 
1526  cpu->m_inDelaySlot = false;
1527 
1528  if (!continueExecution)
1529  cpu->m_nextIC = &cpu->m_abortIC;
1530  }
1531 
1532  // The next instruction is now either the target of the branch
1533  // instruction, the instruction 2 steps after this one,
1534  // or the first instruction of an exception handler.
1535  cpu->m_exceptionOrAbortInDelaySlot = false;
1536 }
1537 
1538 
1539 // Note: This IC function is used both when function call trace is enabled
1540 // and disabled. (Ok, since it is only used when singlestepping.)
1541 DYNTRANS_INSTR(M88K_CPUComponent,jmp_n_functioncalltrace_singlestep)
1542 {
1544 
1545  if (cpu->m_showFunctionTraceCall && ic->arg[2].p == &cpu->m_r[M88K_RETURN_REG])
1546  cpu->FunctionTraceReturn();
1547 
1548  // Prepare for the delayed branch.
1549  cpu->m_inDelaySlot = true;
1550  cpu->m_exceptionOrAbortInDelaySlot = false;
1551 
1552  cpu->m_delaySlotTarget = REG32(ic->arg[2]);
1553 
1554  // m_nextIC already points to the next instruction
1555 }
1556 
1557 
1558 /*
1559  * ldcr: Load value from a control register, store in register d.
1560  *
1561  * arg[0] = pointer to register d
1562  * arg[1] = 6-bit control register number
1563  */
1565 {
1567 
1568  if (cpu->m_cr[M88K_CR_PSR] & M88K_PSR_MODE) {
1569  int cr = ic->arg[1].u32;
1570  REG32(ic->arg[0]) = cpu->m_cr[cr];
1571  } else {
1573  cpu->Exception(M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
1574  }
1575 }
1576 
1577 
1578 /*
1579  * stcr: Store value from register s1 into a control register.
1580  *
1581  * arg[0] = pointer to register s1
1582  * arg[1] = 6-bit control register number
1583  */
1585 {
1587 
1589 
1590  if (!(cpu->m_cr[M88K_CR_PSR] & M88K_PSR_MODE)) {
1591  cpu->Exception(M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
1592  return;
1593  }
1594 
1595  cpu->stcr(ic->arg[1].u32, REG32(ic->arg[0]), false);
1596 
1597  cpu->m_nextIC = ic + 1;
1598 }
1599 
1600 
1601 /*
1602  * tb0, tb1: Trap on bit Clear/Set
1603  *
1604  * arg[0] = bitmask to check (e.g. 0x00020000 for bit 17)
1605  * arg[1] = pointer to register s1
1606  * arg[2] = 9-bit vector number
1607  */
1608 template<bool one> void M88K_CPUComponent::instr_tb(CPUDyntransComponent* cpubase, DyntransIC* ic)
1609 {
1611 
1612  if (!(cpu->m_cr[M88K_CR_PSR] & M88K_PSR_MODE)
1613  && ic->arg[2].u32 < M88K_EXCEPTION_USER_TRAPS_START) {
1615  cpu->Exception(M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
1616  return;
1617  }
1618 
1619  bool bit = (REG32(ic->arg[1]) & ic->arg[0].u32) > 0;
1620  if (bit == one) {
1622  cpu->Exception(ic->arg[2].u32, 1);
1623  }
1624 }
1625 
1626 
1627 /*
1628  * lda: d = s1 + s2 * scaleFactor
1629  *
1630  * arg[0] = pointer to register d
1631  * arg[1] = pointer to register s1
1632  * arg[2] = pointer to register s2
1633  */
1634 template<int scaleFactor> void M88K_CPUComponent::instr_lda(CPUDyntransComponent* cpubase, DyntransIC* ic)
1635 {
1636  REG32(ic->arg[0]) = REG32(ic->arg[1]) + scaleFactor * REG32(ic->arg[2]);
1637 }
1638 
1639 
1640 /*
1641  * Loads and stores:
1642  *
1643  * arg[0] = pointer to register d
1644  * arg[1] = pointer to register s1
1645  * arg[2] = pointer to register s2 or uint16_t offset
1646  */
1647 template<bool store, typename T, bool doubleword, bool regofs, bool scaled, bool signedLoad> void M88K_CPUComponent::instr_loadstore(CPUDyntransComponent* cpubase, DyntransIC* ic)
1648 {
1650 
1651  // TODO: fast lookups
1652  // TODO: usr access
1653 
1654  // TODO: place in M88K's "ongoing memory transaction" registers!
1655 
1656  uint32_t addr = REG32(ic->arg[1]) +
1657  (scaled? (doubleword? sizeof(uint64_t) : sizeof(T)) : 1) *
1658  (regofs? REG32(ic->arg[2]) : ic->arg[2].u32);
1659 
1660  if (sizeof(T) > 1 && (addr & (sizeof(T)-1))) {
1662  cpu->Exception(M88K_EXCEPTION_MISALIGNED_ACCESS, 0);
1663  return;
1664  }
1665 
1666  cpu->AddressSelect(addr);
1667 
1668  if (store) {
1669  T data = REG32(ic->arg[0]);
1670  if (!cpu->WriteData(data, cpu->m_isBigEndian? BigEndian : LittleEndian)) {
1671  // TODO: failed to access memory was probably an exception. Handle this!
1672  }
1673  } else {
1674  T data;
1675  if (!cpu->ReadData(data, cpu->m_isBigEndian? BigEndian : LittleEndian)) {
1676  // TODO: failed to access memory was probably an exception. Handle this!
1677  }
1678 
1679  if (signedLoad) {
1680  if (sizeof(T) == sizeof(uint16_t))
1681  data = (int16_t)data;
1682  if (sizeof(T) == sizeof(uint8_t))
1683  data = (int8_t)data;
1684  }
1685 
1686  REG32(ic->arg[0]) = data;
1687  }
1688 
1689  // Special handling of second word in a double-word read or write:
1690  if (doubleword) {
1691  if (store) {
1692  uint32_t data2 = (* (((uint32_t*)(ic->arg[0].p)) + 1) );
1693  cpu->AddressSelect(addr + sizeof(uint32_t));
1694  if (!cpu->WriteData(data2, cpu->m_isBigEndian? BigEndian : LittleEndian)) {
1695  // TODO: failed to access memory was probably an exception. Handle this!
1696  }
1697  } else {
1698  uint32_t data2;
1699  cpu->AddressSelect(addr + sizeof(uint32_t));
1700  if (!cpu->ReadData(data2, cpu->m_isBigEndian? BigEndian : LittleEndian)) {
1701  // TODO: failed to access memory was probably an exception. Handle this!
1702  }
1703 
1704  (* (((uint32_t*)(ic->arg[0].p)) + 1) ) = data2;
1705  }
1706  }
1707 }
1708 
1709 
1710 /*****************************************************************************/
1711 
1712 
1713 /*
1714  * For unit tests:
1715  *
1716  * fail_early: Results in an abort before doing anything.
1717  * fail_late: Results in an abort after increasing r1.
1718  */
1720 {
1722 
1723  // Point to this instruction...
1725 
1726  // We didn't actually do anything in this instruction.
1727  cpu->m_executedCycles --;
1728 
1729  // ... and then abort.
1730  cpu->m_nextIC = &cpu->m_abortIC;
1731  if (cpu->m_inDelaySlot)
1732  cpu->m_exceptionOrAbortInDelaySlot = true;
1733 }
1734 
1736 {
1738 
1739  // Do something...
1740  cpu->m_r[1] ++;
1741 
1742  // Point to next instruction...
1744  cpu->m_pc += sizeof(uint32_t);
1745 
1746  // ... and abort.
1747  cpu->m_nextIC = &cpu->m_abortIC;
1748  if (cpu->m_inDelaySlot)
1749  cpu->m_exceptionOrAbortInDelaySlot = true;
1750 }
1751 
1752 
1753 /*****************************************************************************/
1754 
1755 
1756 void M88K_CPUComponent::Translate(uint32_t iw, struct DyntransIC* ic)
1757 {
1758  bool singleInstructionLeft = (m_executedCycles == m_nrOfCyclesToExecute - 1);
1759  UI* ui = GetUI(); // for debug messages
1760 
1761  uint32_t op26 = (iw >> 26) & 0x3f;
1762 // uint32_t op11 = (iw >> 11) & 0x1f;
1763  uint32_t op10 = (iw >> 10) & 0x3f;
1764  uint32_t d = (iw >> 21) & 0x1f;
1765  uint32_t s1 = (iw >> 16) & 0x1f;
1766  uint32_t s2 = iw & 0x1f;
1767 // uint32_t op3d = (iw >> 8) & 0xff;
1768  uint32_t imm16 = iw & 0xffff;
1769 // uint32_t w5 = (iw >> 5) & 0x1f;
1770  uint32_t cr6 = (iw >> 5) & 0x3f;
1771  int32_t d16 = ((int16_t) (iw & 0xffff)) * 4;
1772  int32_t d26 = ((int32_t)((iw & 0x03ffffff) << 6)) >> 4;
1773 
1774  switch (op26) {
1775 
1776  case 0x02: /* ld.hu */
1777  case 0x03: /* ld.bu */
1778  case 0x04: /* ld.d */
1779  case 0x05: /* ld */
1780  case 0x06: /* ld.h */
1781  case 0x07: /* ld.b */
1782  case 0x08: /* st.d */
1783  case 0x09: /* st */
1784  case 0x0a: /* st.h */
1785  case 0x0b: /* st.b */
1786  {
1787  bool store = op26 >= 0x08;
1788  int opsize = 0;
1789 
1790  ic->arg[0].p = &m_r[d];
1791  ic->arg[1].p = &m_r[s1];
1792  ic->arg[2].u32 = imm16;
1793 
1794  switch (op26) {
1795  case 0x02: ic->f = instr_loadstore<false, uint16_t, false, false, false, false>; opsize = 1; break;
1796  case 0x03: ic->f = instr_loadstore<false, uint8_t, false, false, false, false>; opsize = 0; break;
1797  case 0x04: ic->f = instr_loadstore<false, uint32_t, true, false, false, false>; opsize = 3; break;
1798  case 0x05: ic->f = instr_loadstore<false, uint32_t, false, false, false, false>; opsize = 2; break;
1799  case 0x06: ic->f = instr_loadstore<false, uint16_t, false, false, false, true>; opsize = 1; break;
1800  case 0x07: ic->f = instr_loadstore<false, uint8_t, false, false, false, true>; opsize = 0; break;
1801  case 0x08: ic->f = instr_loadstore<true, uint32_t, true, false, false, false>; opsize = 3; break;
1802  case 0x09: ic->f = instr_loadstore<true, uint32_t, false, false, false, false>; opsize = 2; break;
1803  case 0x0a: ic->f = instr_loadstore<true, uint16_t, false, false, false, false>; opsize = 1; break;
1804  case 0x0b: ic->f = instr_loadstore<true, uint8_t, false, false, false, false>; opsize = 0; break;
1805  }
1806 
1807  if (opsize == 3 && d == 31) {
1808  // m88k load/store of register pair r31/r0 is not
1809  // yet implemented: TODO: figure out how to deal with this.
1810  ic->f = NULL;
1811  break;
1812  }
1813 
1814  // Loads into the zero register => load into scratch register.
1815  // According to the MC88110 manual: special cache operation
1816  // "(touch, allocate, or flush) may be performed". (TODO)
1817  if (!store && d == M88K_ZERO_REG && ic->f != NULL)
1818  ic->arg[0].p = &m_zero_scratch;
1819  }
1820  break;
1821 
1822  case 0x10: /* and immu32 */
1823  case 0x11: /* and.u immu32 */
1824  case 0x12: /* mask immu32 */
1825  case 0x13: /* mask.u immu32 */
1826  case 0x14: /* xor immu32 */
1827  case 0x15: /* xor.u immu32 */
1828  case 0x16: /* or immu32 */
1829  case 0x17: /* or.u immu32 */
1830  case 0x18: /* addu immu32 */
1831  case 0x19: /* subu immu32 */
1832  case 0x1a: /* divu immu32 */
1833  case 0x1b: /* mulu immu32 */
1834  case 0x1f: /* cmp immu32 */
1835  {
1836  int shift = 0;
1837  switch (op26) {
1838  case 0x10: ic->f = instr_and_u32_u32_immu32; break; // Note (see below): and only ands upper or lower part!
1839  case 0x11: ic->f = instr_and_u32_u32_immu32; shift = 16; break;
1840  case 0x12: ic->f = instr_and_u32_u32_immu32; break; // Note: mask is implemented using and
1841  case 0x13: ic->f = instr_and_u32_u32_immu32; shift = 16; break;
1842  case 0x14: ic->f = instr_xor_u32_u32_immu32; break;
1843  case 0x15: ic->f = instr_xor_u32_u32_immu32; shift = 16; break;
1844  case 0x16: ic->f = instr_or_u32_u32_immu32; break;
1845  case 0x17: ic->f = instr_or_u32_u32_immu32; shift = 16; break;
1846  case 0x18: ic->f = instr_add_u32_u32_immu32; break;
1847  case 0x19: ic->f = instr_sub_u32_u32_immu32; break;
1848  case 0x1a: ic->f = instr_divu_imm; break;
1849  case 0x1b: ic->f = instr_mulu_imm; break;
1850  // case 0x1c: ic->f = instr(add_imm); break;
1851  // case 0x1d: ic->f = instr(sub_imm); break;
1852  // case 0x1e: ic->f = instr(div_imm); break;
1853  case 0x1f: ic->f = instr_cmp_imm; break;
1854  }
1855 
1856  ic->arg[0].p = &m_r[d];
1857  ic->arg[1].p = &m_r[s1];
1858  ic->arg[2].u32 = imm16 << shift;
1859 
1860  // The 'and' instruction only ands bits in the upper or
1861  // lower parts of the word; the 'mask' instruction works
1862  // on the whole register.
1863  if (op26 == 0x10)
1864  ic->arg[2].u32 |= 0xffff0000;
1865  if (op26 == 0x11)
1866  ic->arg[2].u32 |= 0x0000ffff;
1867 
1868  if (d == M88K_ZERO_REG)
1869  ic->f = instr_nop;
1870  }
1871  break;
1872 
1873  case 0x20:
1874  if ((iw & 0x001ff81f) == 0x00004000) {
1875  ic->f = instr_ldcr;
1876  ic->arg[0].p = &m_r[d];
1877  ic->arg[1].u32 = cr6;
1878  if (d == M88K_ZERO_REG)
1879  ic->arg[0].p = &m_zero_scratch;
1880 // } else if ((iword & 0x001ff81f) == 0x00004800) {
1881 // ic->f = instr(fldcr);
1882 // ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1883 // ic->arg[1] = cr6;
1884 // if (d == M88K_ZERO_REG)
1885 // ic->arg[0] = (size_t)
1886 // &cpu->cd.m88k.zero_scratch;
1887  } else if ((iw & 0x03e0f800) == 0x00008000) {
1888  ic->f = instr_stcr;
1889  ic->arg[0].p = &m_r[s1];
1890  ic->arg[1].u32 = cr6;
1891  if (s1 != s2) {
1892  ic->f = NULL;
1893  if (ui != NULL) {
1894  stringstream ss;
1895  ss.flags(std::ios::hex);
1896  ss << "stcr with s1 != s2? TODO: how "
1897  "should this be handled? s1=0x"
1898  << s1 << ", s2=0x" << s2;
1899  ui->ShowDebugMessage(this, ss.str());
1900  }
1901  }
1902 // } else if ((iword & 0x03e0f800) == 0x00008800) {
1903 // ic->f = instr(fstcr);
1904 // ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1];
1905 // ic->arg[1] = cr6;
1906 // if (s1 != s2)
1907 // goto bad;
1908 // } else if ((iword & 0x0000f800) == 0x0000c000) {
1909 // ic->f = instr(xcr);
1910 // ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1911 // ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
1912 // ic->arg[2] = cr6;
1913 // if (s1 != s2)
1914 // goto bad;
1915  } else if (ui != NULL) {
1916  ui->ShowDebugMessage(this, "unimplemented variant of opcode 0x20");
1917  }
1918  break;
1919 
1920 
1921  case 0x30: /* br */
1922 // case 0x31: /* br.n */
1923  case 0x32: /* bsr */
1924  case 0x33: /* bsr.n */
1925  {
1926  void (*f_singleStepping)(CPUDyntransComponent*, struct DyntransIC*) = NULL;
1927  void (*samepage_function)(CPUDyntransComponent*, struct DyntransIC*) = NULL;
1928 
1929  switch (op26) {
1930  case 0x30:
1931  ic->f = NULL; // instr(br);
1932  samepage_function = instr_branch_samepage;
1933  break;
1934  // case 0x31:
1935  // ic->f = instr(br_n);
1936  // if (cpu->translation_readahead > 2)
1937  // cpu->translation_readahead = 2;
1938  // break;
1939  case 0x32:
1940  ic->f = instr_bsr;
1941  samepage_function = instr_bsr_samepage;
1942  break;
1943  case 0x33:
1944  ic->f = instr_bsr_n;
1945  // TODO samepage_function = instr_bsr_samepage;
1946  f_singleStepping = instr_bsr_n_functioncalltrace_singlestep;
1947  break;
1948  }
1949 
1950  if (singleInstructionLeft && (op26 == 0x31 || op26 == 0x33)) {
1951  ic->f = f_singleStepping;
1952  samepage_function = NULL;
1953  }
1954 
1955  int offset = (m_pc & 0xffc) + d26;
1956 
1957  /* Prepare both samepage and offset style args.
1958  (Only one will be used in the actual instruction.) */
1959  ic->arg[0].p = ( m_firstIConPage + (offset >> M88K_INSTR_ALIGNMENT_SHIFT) );
1960  ic->arg[1].u32 = offset;
1961 
1962  /* Return offset for bsr and bsr.n (stored in m_r[M88K_RETURN_REG]): */
1963  ic->arg[2].u32 = (m_pc & 0xffc) + ((op26 & 1)? 8 : 4);
1964 
1965  if (offset >= 0 && offset <= 0xffc && samepage_function != NULL)
1966  ic->f = samepage_function;
1967 
1969  if (op26 == 0x32)
1970  ic->f = instr_bsr_functioncalltrace;
1971  if (op26 == 0x33) {
1972  if (singleInstructionLeft)
1973  ic->f = instr_bsr_n_functioncalltrace_singlestep;
1974  else
1975  ic->f = instr_bsr_n_functioncalltrace;
1976  }
1977  }
1978  }
1979  break;
1980 
1981  case 0x34: /* bb0 */
1982  case 0x35: /* bb0.n */
1983  case 0x36: /* bb1 */
1984  case 0x37: /* bb1.n */
1985  {
1986  void (*samepage_function)(CPUDyntransComponent*, struct DyntransIC*) = NULL;
1987  void (*singlestep_function)(CPUDyntransComponent*, struct DyntransIC*) = NULL;
1988 
1989  switch (op26) {
1990  case 0x34:
1991  ic->f = instr_bb<false,false>;
1992  samepage_function = instr_bb<false,true>;
1993  break;
1994  case 0x35:
1995  ic->f = instr_bb_n<false>;
1996  singlestep_function = instr_bb_n_singlestep<false>;
1997  break;
1998  case 0x36:
1999  ic->f = instr_bb<true,false>;
2000  samepage_function = instr_bb<true,true>;
2001  break;
2002  case 0x37:
2003  ic->f = instr_bb_n<true>;
2004  singlestep_function = instr_bb_n_singlestep<true>;
2005  break;
2006  }
2007 
2008  ic->arg[0].p = &m_r[s1];
2009  ic->arg[1].u32 = (1 << d);
2010 
2011  int offset = (m_pc & 0xffc) + d16;
2012  ic->arg[2].u32 = offset;
2013 
2014  if (singleInstructionLeft && singlestep_function != NULL)
2015  ic->f = singlestep_function;
2016  else if (offset >= 0 && offset <= 0xffc && samepage_function != NULL) {
2017  ic->f = samepage_function;
2018  ic->arg[2].p = ( m_firstIConPage + (offset >> M88K_INSTR_ALIGNMENT_SHIFT) );
2019  }
2020  }
2021  break;
2022 
2023  case 0x3a: /* bcnd */
2024  case 0x3b: /* bcnd.n */
2025  {
2026  void (*samepage_function)(CPUDyntransComponent*, struct DyntransIC*) = NULL;
2027  void (*singlestep_f)(CPUDyntransComponent*, struct DyntransIC*) = NULL;
2028 
2029  if (op26 & 1) {
2030  switch (d) {
2031  case 1: ic->f = instr_bcnd<true,1, false>; singlestep_f = instr_bcnd<true,1, true>; break;
2032  case 2: ic->f = instr_bcnd<true,2, false>; singlestep_f = instr_bcnd<true,2, true>; break;
2033  case 3: ic->f = instr_bcnd<true,3, false>; singlestep_f = instr_bcnd<true,3, true>; break;
2034  case 7: ic->f = instr_bcnd<true,7, false>; singlestep_f = instr_bcnd<true,7, true>; break;
2035  case 8: ic->f = instr_bcnd<true,8, false>; singlestep_f = instr_bcnd<true,8, true>; break;
2036  case 12: ic->f = instr_bcnd<true,12,false>; singlestep_f = instr_bcnd<true,12,true>; break;
2037  case 13: ic->f = instr_bcnd<true,13,false>; singlestep_f = instr_bcnd<true,13,true>; break;
2038  case 14: ic->f = instr_bcnd<true,14,false>; singlestep_f = instr_bcnd<true,14,true>; break;
2039  }
2040  } else {
2041  switch (d) {
2042  case 1: ic->f = instr_bcnd<false,1, false>; break;
2043  case 2: ic->f = instr_bcnd<false,2, false>; break;
2044  case 3: ic->f = instr_bcnd<false,3, false>; break;
2045  case 7: ic->f = instr_bcnd<false,7, false>; break;
2046  case 8: ic->f = instr_bcnd<false,8, false>; break;
2047  case 12: ic->f = instr_bcnd<false,12,false>; break;
2048  case 13: ic->f = instr_bcnd<false,13,false>; break;
2049  case 14: ic->f = instr_bcnd<false,14,false>; break;
2050  }
2051  }
2052 
2053  // TODO: samepage optimization: probably easiest to do using
2054  // another template bit...
2055  // samepage_function = m88k_bcnd[64 + d + 32 * (op26 & 1)];
2056 
2057  if (ic->f == NULL) {
2058  if (ui != NULL) {
2059  stringstream ss;
2060  ss.flags(std::ios::hex);
2061  ss << "unimplemented bcnd condition code d = " << d;
2062  ui->ShowDebugMessage(this, ss.str());
2063  }
2064 
2065  break;
2066  }
2067 
2068  ic->arg[0].p = &m_r[s1];
2069 
2070  int offset = (m_pc & 0xffc) + d16;
2071  ic->arg[2].u32 = offset;
2072 
2073  if (singleInstructionLeft && singlestep_f != NULL) {
2074  ic->f = singlestep_f;
2075  } else if (offset >= 0 && offset <= 0xffc && samepage_function != NULL) {
2076  ic->f = samepage_function;
2077  ic->arg[2].p = ( m_firstIConPage + (offset >> M88K_INSTR_ALIGNMENT_SHIFT) );
2078  }
2079  }
2080  break;
2081 
2082  case 0x3c:
2083  switch (op10) {
2084 
2085 // case 0x20: /* clr */
2086 // case 0x22: /* set */
2087  case 0x24: /* ext */
2088  case 0x26: /* extu */
2089  case 0x28: /* mak */
2090  ic->arg[0].p = &m_r[d];
2091  ic->arg[1].p = &m_r[s1];
2092  ic->arg[2].u32 = iw & 0x3ff;
2093 
2094  switch (op10) {
2095 // case 0x20: ic->f = instr(mask_imm);
2096 // {
2097 // int w = ic->arg[2] >> 5;
2098 // int o = ic->arg[2] & 0x1f;
2099 // uint32_t x = w == 0? 0xffffffff
2100 // : ((uint32_t)1 << w) - 1;
2101 // x <<= o;
2102 // ic->arg[2] = ~x;
2103 // }
2104 // break;
2105 // case 0x22: ic->f = instr(or_imm);
2106 // {
2107 // int w = ic->arg[2] >> 5;
2108 // int o = ic->arg[2] & 0x1f;
2109 // uint32_t x = w == 0? 0xffffffff
2110 // : ((uint32_t)1 << w) - 1;
2111 // x <<= o;
2112 // ic->arg[2] = x;
2113 // }
2114 // break;
2115  case 0x24: ic->f = instr_ext_imm; break;
2116  case 0x26: ic->f = instr_extu_imm; break;
2117  case 0x28: ic->f = instr_mak_imm; break;
2118  }
2119 
2120  if (d == M88K_ZERO_REG)
2121  ic->f = instr_nop;
2122  break;
2123 
2124  case 0x34: /* tb0 */
2125  case 0x36: /* tb1 */
2126  ic->arg[0].u32 = 1 << d; // d is called B5 in the manual
2127  ic->arg[1].p = &m_r[s1];
2128  ic->arg[2].u32 = iw & 0x1ff;
2129  switch (op10) {
2130  case 0x34: ic->f = instr_tb<false>; break;
2131  case 0x36: ic->f = instr_tb<true>; break;
2132  }
2133  break;
2134 
2135  default:
2136  if (ui != NULL) {
2137  stringstream ss;
2138  ss.flags(std::ios::hex);
2139  ss << "unimplemented opcode 0x" << op26 << ",0x" << op10;
2140  ui->ShowDebugMessage(this, ss.str());
2141  }
2142  }
2143  break;
2144 
2145  case 0x3d:
2146  if ((iw & 0xf000) <= 0x3fff ) {
2147  // Load, Store, xmem, and lda:
2148  int op = 0, opsize, user = 0, wt = 0;
2149  int signedness = 1, scaled = 0;
2150 
2151  switch (iw & 0xf000) {
2152  case 0x2000: op = 1; /* st */ break;
2153  case 0x3000: op = 2; /* lda */ break;
2154  default: if ((iw & 0xf800) >= 0x0800)
2155  op = 0; /* ld */
2156  else
2157  op = 3; /* xmem */
2158  }
2159 
2160  /* for (most) ld, st, lda: */
2161  opsize = (iw >> 10) & 3;
2162 
2163  /* Turn opsize into x, where size = 1 << x: */
2164  opsize = 3 - opsize;
2165 
2166  if (op == 3) {
2167  /* xmem: */
2168  opsize = -1;
2169  switch ((iw >> 10) & 3) {
2170  case 0: opsize = 0; break;
2171  case 1: opsize = 2; break;
2172  default:// Weird xmem opsize/type? TODO
2173  break;
2174  }
2175  if (opsize < 0)
2176  break;
2177  } else {
2178  if ((iw & 0xf800) == 0x800) {
2179  signedness = 0;
2180  if ((iw & 0xf00) < 0xc00)
2181  opsize = 1;
2182  else
2183  opsize = 0;
2184  } else {
2185  if (opsize >= 2 || op == 1)
2186  signedness = 0;
2187  }
2188  }
2189 
2190  if (iw & 0x100)
2191  user = 1;
2192  if (iw & 0x80)
2193  wt = 1;
2194  if (iw & 0x200)
2195  scaled = 1;
2196 
2197  if (wt) {
2198  // wt bit not yet implemented! TODO
2199  ic->f = NULL;
2200  break;
2201  }
2202 
2203  ic->arg[0].p = &m_r[d];
2204  ic->arg[1].p = &m_r[s1];
2205  ic->arg[2].p = &m_r[s2];
2206 
2207  if (op == 0 || op == 1) {
2208  /* ld or st: */
2209 
2210  int n = opsize +
2211  ((op == 1)? 4 : 0) +
2212  (signedness? 8 : 0) +
2213  (m_isBigEndian? 16 : 0) +
2214  (scaled? 32 : 0) +
2215  (user? 64 : 0);
2216 
2217  // <bool store, typename T, bool doubleword, bool regofs, bool scaled, bool signedLoad>
2218  // 4 , 0123 , 3 , true , 32 , 8 , user (TODO)
2219  switch (n) {
2220  // load = 0
2221  case 0 + 0 + 0 + 0 + 0 + 0: ic->f = instr_loadstore<false, uint8_t, false, true, false, false>; break;
2222  case 0 + 0 + 0 + 0 + 32 + 0: ic->f = instr_loadstore<false, uint8_t, false, true, true, false>; break;
2223  case 0 + 0 + 0 + 16 + 0 + 0: ic->f = instr_loadstore<false, uint8_t, false, true, false, false>; break;
2224  case 0 + 0 + 0 + 16 + 32 + 0: ic->f = instr_loadstore<false, uint8_t, false, true, true, false>; break;
2225  case 1 + 0 + 0 + 0 + 0 + 0: ic->f = instr_loadstore<false, uint16_t, false, true, false, false>; break;
2226  case 1 + 0 + 0 + 0 + 32 + 0: ic->f = instr_loadstore<false, uint16_t, false, true, true, false>; break;
2227  case 1 + 0 + 0 + 16 + 0 + 0: ic->f = instr_loadstore<false, uint16_t, false, true, false, false>; break;
2228  case 1 + 0 + 0 + 16 + 32 + 0: ic->f = instr_loadstore<false, uint16_t, false, true, true, false>; break;
2229  case 2 + 0 + 0 + 0 + 0 + 0: ic->f = instr_loadstore<false, uint32_t, false, true, false, false>; break;
2230  case 2 + 0 + 0 + 0 + 32 + 0: ic->f = instr_loadstore<false, uint32_t, false, true, true, false>; break;
2231  case 2 + 0 + 0 + 16 + 0 + 0: ic->f = instr_loadstore<false, uint32_t, false, true, false, false>; break;
2232  case 2 + 0 + 0 + 16 + 32 + 0: ic->f = instr_loadstore<false, uint32_t, false, true, true, false>; break;
2233  case 3 + 0 + 0 + 0 + 0 + 0: ic->f = instr_loadstore<false, uint32_t, true, true, false, false>; break;
2234  case 3 + 0 + 0 + 0 + 32 + 0: ic->f = instr_loadstore<false, uint32_t, true, true, true, false>; break;
2235  case 3 + 0 + 0 + 16 + 0 + 0: ic->f = instr_loadstore<false, uint32_t, true, true, false, false>; break;
2236  case 3 + 0 + 0 + 16 + 32 + 0: ic->f = instr_loadstore<false, uint32_t, true, true, true, false>; break;
2237  // store = 4
2238  case 0 + 4 + 0 + 0 + 0 + 0: ic->f = instr_loadstore<true, uint8_t, false, true, false, false>; break;
2239  case 0 + 4 + 0 + 0 + 32 + 0: ic->f = instr_loadstore<true, uint8_t, false, true, true, false>; break;
2240  case 0 + 4 + 0 + 16 + 0 + 0: ic->f = instr_loadstore<true, uint8_t, false, true, false, false>; break;
2241  case 0 + 4 + 0 + 16 + 32 + 0: ic->f = instr_loadstore<true, uint8_t, false, true, true, false>; break;
2242  case 1 + 4 + 0 + 0 + 0 + 0: ic->f = instr_loadstore<true, uint16_t, false, true, false, false>; break;
2243  case 1 + 4 + 0 + 0 + 32 + 0: ic->f = instr_loadstore<true, uint16_t, false, true, true, false>; break;
2244  case 1 + 4 + 0 + 16 + 0 + 0: ic->f = instr_loadstore<true, uint16_t, false, true, false, false>; break;
2245  case 1 + 4 + 0 + 16 + 32 + 0: ic->f = instr_loadstore<true, uint16_t, false, true, true, false>; break;
2246  case 2 + 4 + 0 + 0 + 0 + 0: ic->f = instr_loadstore<true, uint32_t, false, true, false, false>; break;
2247  case 2 + 4 + 0 + 0 + 32 + 0: ic->f = instr_loadstore<true, uint32_t, false, true, true, false>; break;
2248  case 2 + 4 + 0 + 16 + 0 + 0: ic->f = instr_loadstore<true, uint32_t, false, true, false, false>; break;
2249  case 2 + 4 + 0 + 16 + 32 + 0: ic->f = instr_loadstore<true, uint32_t, false, true, true, false>; break;
2250  case 3 + 4 + 0 + 0 + 0 + 0: ic->f = instr_loadstore<true, uint32_t, true, true, false, false>; break;
2251  case 3 + 4 + 0 + 0 + 32 + 0: ic->f = instr_loadstore<true, uint32_t, true, true, true, false>; break;
2252  case 3 + 4 + 0 + 16 + 0 + 0: ic->f = instr_loadstore<true, uint32_t, true, true, false, false>; break;
2253  case 3 + 4 + 0 + 16 + 32 + 0: ic->f = instr_loadstore<true, uint32_t, true, true, true, false>; break;
2254  default:
2255  std::cerr << "TODO generalize! scaled="<<scaled << " user="<<
2256  user<<" signedness="<<signedness << " opsize=" << opsize << "\n";
2257  }
2258 
2259  // Loads into the zero register are changed to load into
2260  // the scratch register.
2261  // According to the MC88110 manual: special cache operation
2262  // "(touch, allocate, or flush) may be performed". (TODO)
2263  if (op == 0 && d == M88K_ZERO_REG && ic->f != NULL)
2264  ic->arg[0].p = &m_zero_scratch;
2265 
2266  if (opsize == 3 && d == 31) {
2267  // m88k load/store of register pair r31/r0 is not
2268  // yet implemented: TODO: figure out how to deal with this.
2269  ic->f = NULL;
2270  break;
2271  }
2272  } else if (op == 2) {
2273  /* lda: */
2274  if (scaled) {
2275  switch (opsize) {
2276 // case 0: // TODO: 88110 vs 88100 etc. ic->f = instr(addu); break;
2277  case 1: ic->f = instr_lda<2>; break;
2278  case 2: ic->f = instr_lda<4>; break;
2279  case 3: ic->f = instr_lda<8>; break;
2280  }
2281  } else {
2282  // TODO: 88110 vs 88100 etc.
2283  // ic->f = instr(addu);
2284  }
2285 
2286  // TODO: Perhaps 88110 loads into 0 are not nops, but cache ops? Look in docs.
2287  if (d == M88K_ZERO_REG && ic->f != NULL)
2288  ic->f = instr_nop;
2289  } else {
2290  /* xmem: */
2291 // TODO
2292 // ic->f = instr(xmem_slow);
2293 // ic->arg[0] = iw;
2294 // if (d == M88K_ZERO_REG)
2295 // ic->f = instr(nop);
2296  }
2297  } else switch ((iw >> 8) & 0xff) {
2298 // case 0x40: /* and */
2299 // case 0x44: /* and.c */
2300  case 0x50: /* xor */
2301 // case 0x54: /* xor.c */
2302  case 0x58: /* or */
2303 // case 0x5c: /* or.c */
2304  case 0x60: /* addu */
2305 // case 0x61: /* addu.co */
2306 // case 0x62: /* addu.ci */
2307  case 0x64: /* subu */
2308 // case 0x65: /* subu.co */
2309 // case 0x66: /* subu.ci */
2310 // case 0x68: /* divu */
2311 // case 0x6c: /* mul */
2312 // case 0x70: /* add */
2313 // case 0x78: /* div */
2314  case 0x7c: /* cmp */
2315 // case 0x80: /* clr */
2316 // case 0x88: /* set */
2317  case 0x90: /* ext */
2318  case 0x98: /* extu */
2319  case 0xa0: /* mak */
2320 // case 0xa8: /* rot */
2321  ic->arg[0].p = &m_r[d];
2322  ic->arg[1].p = &m_r[s1];
2323  ic->arg[2].p = &m_r[s2];
2324 
2325  switch ((iw >> 8) & 0xff) {
2326 // case 0x40: ic->f = instr(and); break;
2327 // case 0x44: ic->f = instr(and_c); break;
2328  case 0x50: ic->f = instr_xor_u32_u32_u32; break;
2329 // case 0x54: ic->f = instr(xor_c); break;
2330  case 0x58: ic->f = instr_or_u32_u32_u32; break;
2331 // case 0x5c: ic->f = instr(or_c); break;
2332  case 0x60: ic->f = instr_add_u32_u32_u32; break;
2333 // case 0x61: ic->f = instr(addu_co); break;
2334 // case 0x62: ic->f = instr(addu_ci); break;
2335  case 0x64: ic->f = instr_sub_u32_u32_u32; break;
2336 // case 0x65: ic->f = instr(subu_co); break;
2337 // case 0x66: ic->f = instr(subu_ci); break;
2338 // case 0x68: ic->f = instr(divu); break;
2339 // case 0x6c: ic->f = instr(mul); break;
2340 // case 0x70: ic->f = instr(add); break;
2341 // case 0x78: ic->f = instr(div); break;
2342  case 0x7c: ic->f = instr_cmp; break;
2343 // case 0x80: ic->f = instr(clr); break;
2344 // case 0x88: ic->f = instr(set); break;
2345  case 0x90: ic->f = instr_ext; break;
2346  case 0x98: ic->f = instr_extu; break;
2347  case 0xa0: ic->f = instr_mak; break;
2348 // case 0xa8: ic->f = instr(rot); break;
2349  }
2350 
2351  /*
2352  * Handle the case when the destination register is r0:
2353  *
2354  * If there is NO SIDE-EFFECT! (i.e. no carry out, no possibility
2355  * of exceptions, etc), then replace the instruction with a nop.
2356  * If there is a possible side-effect, we still have to run the
2357  * instruction, so replace the destination register with the
2358  * scratch register.
2359  */
2360  if (d == M88K_ZERO_REG && ic->f != NULL) {
2361  int opc = (iw >> 8) & 0xff;
2362  if (opc != 0x61 /* addu.co */ && opc != 0x63 /* addu.cio */ &&
2363  opc != 0x65 /* subu.co */ && opc != 0x67 /* subu.cio */ &&
2364  opc != 0x71 /* add.co */ && opc != 0x73 /* add.cio */ &&
2365  opc != 0x75 /* sub.co */ && opc != 0x77 /* sub.cio */ &&
2366  opc != 0x68 /* divu */ && opc != 0x69 /* divu.d */ &&
2367  opc != 0x6c /* mul */ && opc != 0x6d /* mulu.d */ &&
2368  opc != 0x6e /* muls */ && opc != 0x78 /* div */)
2369  ic->f = instr_nop;
2370  else
2371  ic->arg[0].p = &m_zero_scratch;
2372  }
2373 
2374  if (ic->f == NULL && ui != NULL) {
2375  stringstream ss;
2376  ss.flags(std::ios::hex);
2377  ss << "unimplemented opcode 0x3d,0x" << ((iw >> 8) & 0xff);
2378  ui->ShowDebugMessage(this, ss.str());
2379  }
2380 
2381  break;
2382  case 0xc0: /* jmp */
2383  case 0xc4: /* jmp.n */
2384 // case 0xc8: /* jsr */
2385 // case 0xcc: /* jsr.n */
2386  {
2387  void (*f_ss)(CPUDyntransComponent*, struct DyntransIC*) = NULL;
2388 
2389  switch ((iw >> 8) & 0xff) {
2390  case 0xc0: ic->f = instr_jmp; break;
2391  case 0xc4: ic->f = instr_jmp_n; f_ss = instr_jmp_n_functioncalltrace_singlestep; break;
2392  // case 0xc8: ic->f = instr(jsr); break;
2393  // case 0xcc: ic->f = instr(jsr_n); break;
2394  }
2395 
2396  ic->arg[1].u32 = (m_pc & 0xffc) + 4;
2397  ic->arg[2].p = &m_r[s2];
2398 
2399  if (((iw >> 8) & 0x04) == 0x04)
2400  ic->arg[1].u32 = (m_pc & 0xffc) + 8;
2401 
2403  if (ic->f == instr_jmp_n) {
2404  ic->f = instr_jmp_n_functioncalltrace;
2405  f_ss = instr_jmp_n_functioncalltrace_singlestep;
2406  }
2407  }
2408 
2409  // if (m_showFunctionTraceCall) {
2410  // if (ic->f == instr(jsr))
2411  // ic->f = instr(jsr_trace);
2412  // TODO f_ss
2413  // if (ic->f == instr(jsr_n))
2414  // ic->f = instr(jsr_n_trace);
2415  // TODO f_ss
2416  // }
2417 
2418  if (singleInstructionLeft && f_ss != NULL)
2419  ic->f = f_ss;
2420  }
2421  break;
2422 // case 0xe8: /* ff1 */
2423 // case 0xec: /* ff0 */
2424  // TODO
2425  case 0xfc:
2426  switch (iw & 0xff) {
2427 // case 0x00: /* rte */
2428 // case 0x01: /* illop1 */
2429 // case 0x02: /* illop2 */
2430 // case 0x03: /* illop3 */
2431 // case (M88K_PROM_INSTR & 0xff):
2432  case (M88K_FAIL_EARLY_INSTR & 0xff):
2433  ic->f = instr_fail_early;
2434  break;
2435 // case (M88K_FAIL_LATE_INSTR & 0xff):
2436 // break;
2437  default:if (ui != NULL) {
2438  stringstream ss;
2439  ss.flags(std::ios::hex);
2440  ss << "unimplemented opcode 0x3d,0xfc,0x" << (iw & 0xff);
2441  ui->ShowDebugMessage(this, ss.str());
2442  }
2443  }
2444  break;
2445  default:
2446  if (ui != NULL) {
2447  stringstream ss;
2448  ss.flags(std::ios::hex);
2449  ss << "unimplemented opcode 0x3d,0x" << ((iw >> 8) & 0xff);
2450  ui->ShowDebugMessage(this, ss.str());
2451  }
2452  }
2453  break;
2454 
2455  default:
2456  if (ui != NULL) {
2457  stringstream ss;
2458  ss.flags(std::ios::hex);
2459  ss << "unimplemented opcode 0x" << op26;
2460  ui->ShowDebugMessage(this, ss.str());
2461  }
2462  }
2463 }
2464 
2465 
2467 {
2469 
2470  cpu->DyntransToBeTranslatedBegin(ic);
2471 
2472  uint32_t iword;
2473  if (cpu->DyntransReadInstruction(iword))
2474  cpu->Translate(iword, ic);
2475 
2476  if (cpu->m_inDelaySlot && ic->f == NULL)
2477  ic->f = instr_abort;
2478 
2479  cpu->DyntransToBeTranslatedDone(ic);
2480 }
2481 
2482 
2483 /*****************************************************************************/
2484 
2485 
2486 #ifdef WITHUNITTESTS
2487 
2488 #include "ComponentFactory.h"
2489 
2490 static void Test_M88K_CPUComponent_IsStable()
2491 {
2492  UnitTest::Assert("the M88K_CPUComponent should be stable",
2493  ComponentFactory::HasAttribute("m88k_cpu", "stable"));
2494 }
2495 
2496 static void Test_M88K_CPUComponent_Create()
2497 {
2500  UnitTest::Assert("component was not created?", !cpu.IsNULL());
2501 
2502  const StateVariable * p = cpu->GetVariable("pc");
2503  UnitTest::Assert("cpu has no pc state variable?", p != NULL);
2504  UnitTest::Assert("initial pc", p->ToString(), "0");
2505 
2506  const StateVariable * r31 = cpu->GetVariable("r31");
2507  UnitTest::Assert("cpu has no r31 state variable?", r31 != NULL);
2508  UnitTest::Assert("initial r31", r31->ToString(), "0");
2509 }
2510 
2511 static void Test_M88K_CPUComponent_Create_with_r31()
2512 {
2514  ComponentFactory::CreateComponent("m88k_cpu(r31=0x12345678)");
2515  UnitTest::Assert("component was not created?", !cpu.IsNULL());
2516 
2517  const StateVariable * p = cpu->GetVariable("pc");
2518  UnitTest::Assert("cpu has no pc state variable?", p != NULL);
2519  UnitTest::Assert("initial pc", p->ToString(), "0");
2520 
2521  const StateVariable * r31 = cpu->GetVariable("r31");
2522  UnitTest::Assert("cpu has no r31 state variable?", r31 != NULL);
2523  UnitTest::Assert("initial r31", r31->ToString(), "0x12345678");
2524 
2525  cpu->SetVariableValue("r31", "0xf00");
2526 
2527  const StateVariable * r31_updated = cpu->GetVariable("r31");
2528  UnitTest::Assert("could not update r31?", r31_updated->ToString(), "0xf00");
2529 
2530  cpu->Reset();
2531 
2532  const StateVariable * r31_after_reset = cpu->GetVariable("r31");
2533  UnitTest::Assert("r31 after reset should have been reset", r31_after_reset->ToString(), "0x12345678");
2534 }
2535 
2536 static void Test_M88K_CPUComponent_IsCPU()
2537 {
2540 
2541  CPUComponent* cpu = m88k_cpu->AsCPUComponent();
2542  UnitTest::Assert("m88k_cpu is not a CPUComponent?", cpu != NULL);
2543 }
2544 
2545 static void Test_M88K_CPUComponent_DefaultModel()
2546 {
2549 
2550  // Suitable default models would be 88100 and 88110 (the only two
2551  // implementations there were of the 88K architecture). However,
2552  // right now (2009-07-27), 88110 emulation isn't implemented yet.
2553  UnitTest::Assert("wrong default model",
2554  cpu->GetVariable("model")->ToString(), "88100");
2555 }
2556 
2557 static void Test_M88K_CPUComponent_Disassembly_Basic()
2558 {
2561  CPUComponent* cpu = m88k_cpu->AsCPUComponent();
2562 
2563  vector<string> result;
2564  size_t len;
2565  unsigned char instruction[sizeof(uint32_t)];
2566  // This assumes that the default endianness is BigEndian...
2567  instruction[0] = 0x63;
2568  instruction[1] = 0xdf;
2569  instruction[2] = 0x00;
2570  instruction[3] = 0x10;
2571 
2572  len = cpu->DisassembleInstruction(0x12345678, sizeof(uint32_t),
2573  instruction, result);
2574 
2575  UnitTest::Assert("disassembled instruction was wrong length?", len, 4);
2576  UnitTest::Assert("disassembly result incomplete?", result.size(), 3);
2577  UnitTest::Assert("disassembly result[0]", result[0], "63df0010");
2578  UnitTest::Assert("disassembly result[1]", result[1], "addu");
2579  UnitTest::Assert("disassembly result[2]", result[2], "r30,r31,0x10");
2580 }
2581 
2582 static void Test_M88K_CPUComponent_Execute_Basic()
2583 {
2584  GXemul gxemul;
2585  gxemul.GetCommandInterpreter().RunCommand("add testm88k");
2586 
2587  refcount_ptr<Component> cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0");
2588  UnitTest::Assert("huh? no cpu?", !cpu.IsNULL());
2589 
2590  AddressDataBus* bus = cpu->AsAddressDataBus();
2591  UnitTest::Assert("cpu should be addressable", bus != NULL);
2592 
2593  // Place a hardcoded instruction in memory, and try to execute it.
2594  // addu r30, r31, 0x10
2595  uint32_t data32 = 0x63df0010;
2596  bus->AddressSelect(48);
2597  bus->WriteData(data32, BigEndian);
2598 
2599  bus->AddressSelect(52);
2600  bus->WriteData(data32, BigEndian);
2601 
2602  cpu->SetVariableValue("pc", "48");
2603  cpu->SetVariableValue("r30", "1234");
2604  cpu->SetVariableValue("r31", "5678");
2605 
2606  gxemul.SetRunState(GXemul::Running);
2607  gxemul.Execute(1);
2608 
2609  UnitTest::Assert("pc should have increased", cpu->GetVariable("pc")->ToInteger(), 52);
2610  UnitTest::Assert("r30 should have been modified", cpu->GetVariable("r30")->ToInteger(), 5678 + 0x10);
2611  UnitTest::Assert("r31 should not have been modified", cpu->GetVariable("r31")->ToInteger(), 5678);
2612 
2613  cpu->SetVariableValue("r31", "1111");
2614 
2616  gxemul.Execute(1);
2617 
2618  UnitTest::Assert("pc should have increased again", cpu->GetVariable("pc")->ToInteger(), 56);
2619  UnitTest::Assert("r30 should have been modified again", cpu->GetVariable("r30")->ToInteger(), 1111 + 0x10);
2620 }
2621 
2622 static void Test_M88K_CPUComponent_Execute_DelayBranchWithValidInstruction()
2623 {
2624  GXemul gxemul;
2625  gxemul.GetCommandInterpreter().RunCommand("add testm88k");
2626 
2627  refcount_ptr<Component> cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0");
2628  UnitTest::Assert("huh? no cpu?", !cpu.IsNULL());
2629 
2630  AddressDataBus* bus = cpu->AsAddressDataBus();
2631  UnitTest::Assert("cpu should be addressable", bus != NULL);
2632 
2633  uint32_t data32 = 0xcc000010; // bsr.n 0x1000 + 10*4, i.e. 0x1040
2634  bus->AddressSelect(0x1000ULL);
2635  bus->WriteData(data32, BigEndian);
2636 
2637  data32 = 0x63df0010; // Something valid, addu r30, r31, 0x10
2638  bus->AddressSelect(0x1004ULL);
2639  bus->WriteData(data32, BigEndian);
2640 
2641  cpu->SetVariableValue("pc", "0x1000");
2642  UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0x1000);
2643  UnitTest::Assert("r30 before execute", cpu->GetVariable("r30")->ToInteger(), 0);
2644  UnitTest::Assert("r31 before execute", cpu->GetVariable("r31")->ToInteger(), 0xff0);
2645 
2646  // This tests that execute 2 steps will execute both the delay branch
2647  // and the delay slot instruction.
2648  gxemul.SetRunState(GXemul::Running);
2649  gxemul.Execute(2);
2650 
2651  UnitTest::Assert("pc should have changed", cpu->GetVariable("pc")->ToInteger(), 0x1040);
2652  UnitTest::Assert("delay slot after execute", cpu->GetVariable("inDelaySlot")->ToString(), "false");
2653  UnitTest::Assert("r30 after execute", cpu->GetVariable("r30")->ToInteger(), 0x1000);
2654  UnitTest::Assert("r31 after execute", cpu->GetVariable("r31")->ToInteger(), 0xff0);
2655 }
2656 
2657 static void Test_M88K_CPUComponent_Execute_DelayBranchWithValidInstruction_SingleStepping()
2658 {
2659  GXemul gxemul;
2660  gxemul.GetCommandInterpreter().RunCommand("add testm88k");
2661 
2662  refcount_ptr<Component> cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0");
2663  UnitTest::Assert("huh? no cpu?", !cpu.IsNULL());
2664 
2665  AddressDataBus* bus = cpu->AsAddressDataBus();
2666  UnitTest::Assert("cpu should be addressable", bus != NULL);
2667 
2668  uint32_t data32 = 0xcc000010; // bsr.n 0x1000 + 10*4, i.e. 0x1040
2669  bus->AddressSelect(0x1000ULL);
2670  bus->WriteData(data32, BigEndian);
2671 
2672  data32 = 0x63df0010; // Something valid, addu r30, r31, 0x10
2673  bus->AddressSelect(0x1004ULL);
2674  bus->WriteData(data32, BigEndian);
2675 
2676  cpu->SetVariableValue("pc", "0x1000");
2677  UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0x1000);
2678  UnitTest::Assert("r30 before execute", cpu->GetVariable("r30")->ToInteger(), 0);
2679  UnitTest::Assert("r31 before execute", cpu->GetVariable("r31")->ToInteger(), 0xff0);
2680 
2681  // This tests that execute 2 steps (using single-stepping) will execute both
2682  // the delay branch and the delay slot instruction.
2684  gxemul.Execute(1);
2685 
2686  // Should now be in the delay slot.
2687  UnitTest::Assert("pc should have changed 1", cpu->GetVariable("pc")->ToInteger(), 0x1004);
2688  UnitTest::Assert("delay slot after execute 1", cpu->GetVariable("inDelaySlot")->ToString(), "true");
2689  UnitTest::Assert("r30 after execute 1", cpu->GetVariable("r30")->ToInteger(), 0);
2690  UnitTest::Assert("r31 after execute 1", cpu->GetVariable("r31")->ToInteger(), 0xff0);
2691 
2693  gxemul.Execute(1);
2694 
2695  UnitTest::Assert("delay slot after execute 2", cpu->GetVariable("inDelaySlot")->ToString(), "false");
2696  UnitTest::Assert("pc should have changed 2", cpu->GetVariable("pc")->ToInteger(), 0x1040);
2697  UnitTest::Assert("r30 after execute 2", cpu->GetVariable("r30")->ToInteger(), 0x1000);
2698  UnitTest::Assert("r31 after execute 2", cpu->GetVariable("r31")->ToInteger(), 0xff0);
2699 }
2700 
2701 static void Test_M88K_CPUComponent_Execute_DelayBranchWithValidInstruction_RunTwoTimes()
2702 {
2703  GXemul gxemul;
2704  gxemul.GetCommandInterpreter().RunCommand("add testm88k");
2705 
2706  refcount_ptr<Component> cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0");
2707  UnitTest::Assert("huh? no cpu?", !cpu.IsNULL());
2708 
2709  AddressDataBus* bus = cpu->AsAddressDataBus();
2710  UnitTest::Assert("cpu should be addressable", bus != NULL);
2711 
2712  uint32_t data32 = 0xcc000010; // bsr.n 0x1000 + 10*4, i.e. 0x1040
2713  bus->AddressSelect(0x1000ULL);
2714  bus->WriteData(data32, BigEndian);
2715 
2716  data32 = 0x63df0010; // Something valid, addu r30, r31, 0x10
2717  bus->AddressSelect(0x1004ULL);
2718  bus->WriteData(data32, BigEndian);
2719 
2720  cpu->SetVariableValue("pc", "0x1000");
2721  UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0x1000);
2722  UnitTest::Assert("r30 before execute", cpu->GetVariable("r30")->ToInteger(), 0);
2723  UnitTest::Assert("r31 before execute", cpu->GetVariable("r31")->ToInteger(), 0xff0);
2724 
2725  // This tests that execute 2 steps (using single-stepping) will execute both
2726  // the delay branch and the delay slot instruction.
2727  gxemul.SetRunState(GXemul::Running);
2728  gxemul.Execute(1);
2729 
2730  // Should now be in the delay slot.
2731  UnitTest::Assert("pc should have changed 1", cpu->GetVariable("pc")->ToInteger(), 0x1004);
2732  UnitTest::Assert("delay slot after execute 1", cpu->GetVariable("inDelaySlot")->ToString(), "true");
2733  UnitTest::Assert("r30 after execute 1", cpu->GetVariable("r30")->ToInteger(), 0);
2734  UnitTest::Assert("r31 after execute 1", cpu->GetVariable("r31")->ToInteger(), 0xff0);
2735 
2736  gxemul.SetRunState(GXemul::Running);
2737  gxemul.Execute(1);
2738 
2739  UnitTest::Assert("delay slot after execute 2", cpu->GetVariable("inDelaySlot")->ToString(), "false");
2740  UnitTest::Assert("pc should have changed 2", cpu->GetVariable("pc")->ToInteger(), 0x1040);
2741  UnitTest::Assert("r30 after execute 2", cpu->GetVariable("r30")->ToInteger(), 0x1000);
2742  UnitTest::Assert("r31 after execute 2", cpu->GetVariable("r31")->ToInteger(), 0xff0);
2743 }
2744 
2745 static void Test_M88K_CPUComponent_Execute_DelayBranchWithFault()
2746 {
2747  GXemul gxemul;
2748  gxemul.GetCommandInterpreter().RunCommand("add testm88k");
2749 
2750  refcount_ptr<Component> cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0");
2751  UnitTest::Assert("huh? no cpu?", !cpu.IsNULL());
2752 
2753  AddressDataBus* bus = cpu->AsAddressDataBus();
2754  UnitTest::Assert("cpu should be addressable", bus != NULL);
2755 
2756  uint32_t data32 = 0xcc000010; // bsr.n 0x1000 + 10*4, i.e. 0x1040
2757  bus->AddressSelect(0x1000ULL);
2758  bus->WriteData(data32, BigEndian);
2759 
2760  data32 = 0xffffffff; // Something invalid
2761  bus->AddressSelect(0x1004ULL);
2762  bus->WriteData(data32, BigEndian);
2763 
2764  cpu->SetVariableValue("pc", "0x1000");
2765  UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0x1000);
2766  UnitTest::Assert("r30 before execute", cpu->GetVariable("r30")->ToInteger(), 0);
2767  UnitTest::Assert("r31 before execute", cpu->GetVariable("r31")->ToInteger(), 0xff0);
2768 
2769  // This tests that execute 100 steps will only execute 1, if the instruction
2770  // in the delay slot fails.
2771  gxemul.SetRunState(GXemul::Running);
2772  gxemul.Execute(100);
2773 
2774  UnitTest::Assert("pc should have increased one step", cpu->GetVariable("pc")->ToInteger(), 0x1004ULL);
2775  UnitTest::Assert("should be in delay slot after execution", cpu->GetVariable("inDelaySlot")->ToString(), "true");
2776 
2778  gxemul.Execute(1);
2779 
2780  UnitTest::Assert("pc should not have increased", cpu->GetVariable("pc")->ToInteger(), 0x1004ULL);
2781  UnitTest::Assert("should still be in delay slot", cpu->GetVariable("inDelaySlot")->ToString(), "true");
2782 }
2783 
2784 static void Test_M88K_CPUComponent_Execute_EarlyAbortDuringRuntime_Singlestep()
2785 {
2786  GXemul gxemul;
2787  gxemul.GetCommandInterpreter().RunCommand("add testm88k");
2788 
2789  refcount_ptr<Component> cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0");
2790  UnitTest::Assert("huh? no cpu?", !cpu.IsNULL());
2791 
2792  AddressDataBus* bus = cpu->AsAddressDataBus();
2793  UnitTest::Assert("cpu should be addressable", bus != NULL);
2794 
2795  uint32_t data32 = 0xcc000010; // bsr.n 0x1000 + 10*4, i.e. 0x1040
2796  bus->AddressSelect(0x1000ULL);
2797  bus->WriteData(data32, BigEndian);
2798 
2799  data32 = 0xf400fc93; // Something which is valid during interpretation,
2800  // but invalid during runtime (i.e. aborts).
2801  bus->AddressSelect(0x1004ULL);
2802  bus->WriteData(data32, BigEndian);
2803 
2804  cpu->SetVariableValue("pc", "0x1000");
2805  UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0x1000);
2806 
2807  // This tests that execute 100 steps will only execute 1, if the
2808  // instruction in the delay slot aborts early.
2810  gxemul.Execute(100);
2811 
2812  UnitTest::Assert("1 step should have executed", cpu->GetVariable("step")->ToInteger(), 1);
2813  UnitTest::Assert("pc should have increased one step", cpu->GetVariable("pc")->ToInteger(), 0x1004ULL);
2814  UnitTest::Assert("should be in delay slot after execution", cpu->GetVariable("inDelaySlot")->ToString(), "true");
2815  UnitTest::Assert("delay target should have been updated", cpu->GetVariable("delaySlotTarget")->ToInteger(), 0x1040);
2816 
2818  gxemul.Execute(1);
2819 
2820  UnitTest::Assert("no more steps should have executed", cpu->GetVariable("step")->ToInteger(), 1);
2821  UnitTest::Assert("pc should not have increased", cpu->GetVariable("pc")->ToInteger(), 0x1004ULL);
2822  UnitTest::Assert("should still be in delay slot", cpu->GetVariable("inDelaySlot")->ToString(), "true");
2823  UnitTest::Assert("delay target should not have been updated", cpu->GetVariable("delaySlotTarget")->ToInteger(), 0x1040);
2824 }
2825 
2826 static void Test_M88K_CPUComponent_Execute_EarlyAbortDuringRuntime_Running()
2827 {
2828  GXemul gxemul;
2829  gxemul.GetCommandInterpreter().RunCommand("add testm88k");
2830 
2831  refcount_ptr<Component> cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0");
2832  UnitTest::Assert("huh? no cpu?", !cpu.IsNULL());
2833 
2834  AddressDataBus* bus = cpu->AsAddressDataBus();
2835  UnitTest::Assert("cpu should be addressable", bus != NULL);
2836 
2837  uint32_t data32 = 0xcc000010; // bsr.n 0x1000 + 10*4, i.e. 0x1040
2838  bus->AddressSelect(0x1000ULL);
2839  bus->WriteData(data32, BigEndian);
2840 
2841  data32 = 0xf400fc93; // Something which is valid during interpretation,
2842  // but invalid during runtime (i.e. aborts).
2843  bus->AddressSelect(0x1004ULL);
2844  bus->WriteData(data32, BigEndian);
2845 
2846  cpu->SetVariableValue("pc", "0x1000");
2847  UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0x1000);
2848 
2849  // This tests that execute 100 steps will only execute 1, if the
2850  // instruction in the delay slot aborts early.
2851  gxemul.SetRunState(GXemul::Running);
2852  gxemul.Execute(100);
2853 
2854  UnitTest::Assert("1 step should have executed", cpu->GetVariable("step")->ToInteger(), 1);
2855  UnitTest::Assert("pc should have increased one step", cpu->GetVariable("pc")->ToInteger(), 0x1004ULL);
2856  UnitTest::Assert("should be in delay slot after execution", cpu->GetVariable("inDelaySlot")->ToString(), "true");
2857  UnitTest::Assert("delay target should have been updated", cpu->GetVariable("delaySlotTarget")->ToInteger(), 0x1040);
2858 
2860  gxemul.Execute(1);
2861 
2862  UnitTest::Assert("no more steps should have executed", cpu->GetVariable("step")->ToInteger(), 1);
2863  UnitTest::Assert("pc should not have increased", cpu->GetVariable("pc")->ToInteger(), 0x1004ULL);
2864  UnitTest::Assert("should still be in delay slot", cpu->GetVariable("inDelaySlot")->ToString(), "true");
2865  UnitTest::Assert("delay target should not have been updated", cpu->GetVariable("delaySlotTarget")->ToInteger(), 0x1040);
2866 }
2867 
2869 {
2870  UNITTEST(Test_M88K_CPUComponent_IsStable);
2871  UNITTEST(Test_M88K_CPUComponent_Create);
2872  UNITTEST(Test_M88K_CPUComponent_Create_with_r31);
2873  UNITTEST(Test_M88K_CPUComponent_IsCPU);
2874  UNITTEST(Test_M88K_CPUComponent_DefaultModel);
2875 
2876  // Disassembly:
2877  UNITTEST(Test_M88K_CPUComponent_Disassembly_Basic);
2878 
2879  // Dyntrans execution:
2880  UNITTEST(Test_M88K_CPUComponent_Execute_Basic);
2881  UNITTEST(Test_M88K_CPUComponent_Execute_DelayBranchWithValidInstruction);
2882  UNITTEST(Test_M88K_CPUComponent_Execute_DelayBranchWithValidInstruction_SingleStepping);
2883  UNITTEST(Test_M88K_CPUComponent_Execute_DelayBranchWithValidInstruction_RunTwoTimes);
2884  UNITTEST(Test_M88K_CPUComponent_Execute_DelayBranchWithFault);
2885  UNITTEST(Test_M88K_CPUComponent_Execute_EarlyAbortDuringRuntime_Singlestep);
2886  UNITTEST(Test_M88K_CPUComponent_Execute_EarlyAbortDuringRuntime_Running);
2887 // UNITTEST(Test_M88K_CPUComponent_Execute_LateAbortDuringRuntime);
2888 }
2889 
2890 #endif
2891 
void SetRunState(RunState newState)
Sets the RunState.
Definition: GXemul.cc:741
virtual CPUComponent * AsCPUComponent()
Returns the component&#39;s CPUComponent interface.
Definition: Component.cc:360
double m_frequency
Definition: CPUComponent.h:197
virtual bool VirtualToPhysical(uint64_t vaddr, uint64_t &paddr, bool &writable)
Virtual to physical address translation (MMU).
#define M88K_CR_SR0
#define M88K_FPECR_FUNIMP
#define M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE
#define M88K_CR_VBR
virtual void ShowDebugMessage(const string &msg)=0
Shows a debug message.
#define N_M88K_REGS
#define M88K_CMP_HS
StateVariable * GetVariable(const string &name)
Gets a pointer to a state variable.
Definition: Component.cc:949
#define M88K_EXCEPTION_USER_TRAPS_START
#define M88K_CMP_GE
#define M88K_CR_SSBR
virtual void ShowRegisters(GXemul *gxemul, const vector< string > &arguments) const
#define M88K_CMP_HI
static refcount_ptr< Component > CreateComponent(const string &componentNameAndOptionalArgs, GXemul *gxemul=NULL)
Creates a component given a short component name.
#define M88K_CMP_LS
void(* f)(CPUDyntransComponent *, DyntransIC *)
struct arm_instr_call * ic
#define M88K_PSR_MODE
Definition: m88k_psl.h:70
#define M88K_IC_ENTRIES_PER_PAGE
uint64_t m_delaySlotTarget
Definition: CPUComponent.h:223
static refcount_ptr< Component > Create(const ComponentCreateArgs &args)
Creates a M88K_CPUComponent.
#define BE32_TO_HOST(x)
Definition: misc.h:181
#define M88K_CR_DMT0
#define M88K_CR_PID
bool RunCommand(const string &command, bool *pSuccess=NULL)
Runs a command, given as a string.
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 REG32(arg)
#define M88K_CMP_LT
union DyntransIC::@0 arg[N_DYNTRANS_IC_ARGS]
#define M88K_CR_SNIP
bool m_inDelaySlot
Definition: CPUComponent.h:222
#define M88K_CR_NAMES
A dyntrans instruction call.
#define M88K_CR_SR2
A Component representing a Motorola 88000 processor.
#define M88K_CMP_GT
#define N_M88K_CONTROL_REGS
char * cond[16]
#define M88K_PROM_INSTR
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 M88K_CR_DMT2
#define M88K_EXCEPTION_SFU1_PRECISE
#define M88K_OPCODE_NAMES
#define M88K_EXCEPTION_MISALIGNED_ACCESS
The main emulator class.
Definition: GXemul.h:54
#define M88K_PSR_MXM
Definition: m88k_psl.h:80
#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 M88K_STACKPOINTER_REG
bool m_showFunctionTraceCall
Definition: CPUComponent.h:216
struct DyntransIC * m_firstIConPage
#define M88K_CR_PSR
M88K_CPUComponent()
Constructs a M88K_CPUComponent.
#define LE32_TO_HOST(x)
Definition: misc.h:180
virtual void(*)(CPUDyntransComponent *, DyntransIC *) GetDyntransToBeTranslated()
#define M88K_FAIL_LATE_INSTR
#define M88K_CR_EPSR
virtual bool CheckVariableWrite(StateVariable &var, const string &oldValue)
Checks whether a write to a variable is OK.
string LookupAddress(uint64_t vaddr, bool allowOffset) const
Looks up an address.
virtual bool PreRunCheckForComponent(GXemul *gxemul)
Checks the state of this component, before starting execution.
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.
#define M88K_CMP_LO
bool m_isBigEndian
Definition: CPUComponent.h:213
#define M88K_CMP_LE
#define DYNTRANS_SYNCH_PC
#define M88K_PID_MC
Definition: m88k_psl.h:64
#define M88K_3D_OPCODE_NAMES
#define M88K_3C_OPCODE_NAMES
#define M88K_CR_SR3
virtual bool PreRunCheckForComponent(GXemul *gxemul)
Checks the state of this component, before starting execution.
#define M88K_EXCEPTION_PRIVILEGE_VIOLATION
uint64_t m_pc
Definition: CPUComponent.h:205
SymbolRegistry & GetSymbolRegistry()
Gets a reference to the CPU&#39;s symbol registry.
Definition: CPUComponent.h:63
uint32_t addr
#define M88K_PSR_IND
Definition: m88k_psl.h:81
#define M88K_CR_SR1
Definition: cpu.h:326
virtual size_t DisassembleInstruction(uint64_t vaddr, size_t maxlen, unsigned char *instruction, vector< string > &result)
Disassembles an instruction into readable strings.
A base-class for processors Component implementations that use dynamic translation.
uint64_t ToInteger() const
Returns the variable as an unsignedinteger value.
#define M88K_CR_SXIP
#define M88K_CPU_TYPE_DEFS
DYNTRANS_INSTR(M88K_CPUComponent, cmp)
StateVariables make up the persistent state of Component objects.
Definition: StateVariable.h:67
virtual bool CheckVariableWrite(StateVariable &var, const string &oldValue)
Checks whether a write to a variable is OK.
Definition: Component.cc:969
#define M88K_CMP_NE
virtual void ResetState()
Resets the state variables of this component.
A base-class for processors Component implementations.
Definition: CPUComponent.h:43
virtual size_t DisassembleInstruction(uint64_t vaddr, size_t maxLen, unsigned char *instruction, vector< string > &result)=0
Disassembles an instruction into readable strings.
#define N_M88K_FPU_CONTROL_REGS
static void Assert(const string &strFailMessage, bool condition)
Asserts that a boolean condition is correct.
Definition: UnitTest.cc:40
virtual int GetDyntransICshift() const
virtual void ResetState()
Resets the state variables of this component.
Definition: CPUComponent.cc:82
#define M88K_PSR_SFD1
Definition: m88k_psl.h:79
#define M88K_CMP_EQ
bool SetVariableValue(const string &name, const string &expression)
Sets a variable to a new value.
Definition: Component.cc:1030
#define M88K_ZERO_REG
refcount_ptr< Component > GetRootComponent()
Gets a pointer to the root configuration component.
Definition: GXemul.cc:667
virtual AddressDataBus * AsAddressDataBus()
Returns the component&#39;s AddressDataBus interface, if any.
Definition: Component.cc:367
void Reset()
Resets the state of this component and all its children.
Definition: Component.cc:281
Definition: symbol.h:37
#define M88K_CR_SFIP
#define DYNTRANS_INSTR_HEAD(class)
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 M88K_RETURN_REG
#define M88K_PSR_BO
Definition: m88k_psl.h:71
static string GetAttribute(const string &attributeName)
Base class for a User Interface.
Definition: UI.h:40
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 M88K_INSTR_ALIGNMENT_SHIFT
void Execute(const int longestTotalRun=100000)
Run the emulation for "a while".
Definition: GXemul.cc:894
char * op[16]
#define M88K_FAIL_EARLY_INSTR
#define M88K_FPCR_FPECR
#define UNITTEST(functionname)
Helper for unit test case execution.
Definition: UnitTest.h:217
#define M88K_CR_DMT1
bool IsNULL() const
Checks whether or not an object is referenced by the reference counted pointer.
Definition: refcount_ptr.h:216

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