M88K_CPUComponent.cc Source File

Back to the index.

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

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