1 /******************************************************************************/
2 /* Mednafen - Multi-system Emulator                                           */
3 /******************************************************************************/
4 /* m68k.cpp - Motorola 68000 CPU Emulator
5 **  Copyright (C) 2015-2016 Mednafen Team
6 **
7 ** This program is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU General Public License
9 ** as published by the Free Software Foundation; either version 2
10 ** of the License, or (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software Foundation, Inc.,
19 ** 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 */
21 
22 // TODO: Check CHK
23 //
24 // TODO: Address errors(or just cheap out and mask off the lower bit on 16-bit memory accesses).
25 //
26 // TODO: Predec, postinc order for same address register.
27 //
28 // TODO: Fix instruction timings(currently execute too fast).
29 //
30 // TODO: Fix division timing, and make sure flags are ok for divide by zero.
31 //
32 // FIXME: Handle NMI differently; how to test?  Maybe MOVEM to interrupt control registers...
33 //
34 // TODO: Test MOVEM
35 //
36 /*
37  Be sure to test the following thoroughly:
38 	SUBA -(a0), a0
39 	SUBX -(a0),-(a0)
40 	CMPM (a0)+,(a0)+
41 
42 	SUBA -(a7), a7
43 	SUBX -(a7),-(a7)
44 	CMPM (a7)+,(a7)+
45 */
46 
47 #include <mednafen/mednafen.h>
48 #include "m68k.h"
49 
50 #include <tuple>
51 
52 #pragma GCC optimize ("no-crossjumping,no-gcse")
53 
54 namespace Mednafen
55 {
56 
Dummy_BusRESET(bool state)57 static MDFN_FASTCALL void Dummy_BusRESET(bool state)
58 {
59 
60 }
61 
DummyDBG(const char * format,...)62 static void DummyDBG(const char* format, ...) noexcept
63 {
64 
65 }
66 
M68K(const bool rev_e)67 M68K::M68K(const bool rev_e) : Revision_E(rev_e),
68 	       BusReadInstr(nullptr), BusRead8(nullptr), BusRead16(nullptr),
69 	       BusWrite8(nullptr), BusWrite16(nullptr),
70 	       BusRMW(nullptr),
71 	       BusIntAck(nullptr),
72 	       BusRESET(Dummy_BusRESET),
73 	       DBG_Warning(DummyDBG),
74 	       DBG_Verbose(DummyDBG)
75 {
76  timestamp = 0;
77  XPending = 0;
78  IPL = 0;
79  Reset(true);
80 }
81 
~M68K()82 M68K::~M68K()
83 {
84 
85 }
86 
StateAction(StateMem * sm,const unsigned load,const bool data_only,const char * sname)87 void M68K::StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname)
88 {
89  SFORMAT StateRegs[] =
90  {
91   SFVAR(DA),
92   SFVAR(PC),
93   SFVAR(SRHB),
94   SFVAR(IPL),
95 
96   SFVAR(Flag_Z),
97   SFVAR(Flag_N),
98   SFVAR(Flag_X),
99   SFVAR(Flag_C),
100   SFVAR(Flag_V),
101 
102   SFVAR(SP_Inactive),
103 
104   SFVAR(XPending),
105 
106   SFEND
107  };
108 
109  MDFNSS_StateAction(sm, load, data_only, StateRegs, sname);
110 
111  if(load)
112   XPending &= XPENDING_MASK__VALID;
113 }
114 
LoadOldState(const uint8 * osm)115 void M68K::LoadOldState(const uint8* osm)
116 {
117  uint32 old_C, old_V, old_notZ, old_N, old_X, old_I, old_S;
118  uint32 old_USP, old_Status, old_IRQLine;
119 
120  osm += 4;
121 
122  for(unsigned i = 0; i < 16; i++)
123  {
124   DA[i] = MDFN_de32lsb(osm);
125   osm += 4;
126  }
127 
128  old_C = MDFN_de32lsb(osm); osm += 4;
129  old_V = MDFN_de32lsb(osm); osm += 4;
130  old_notZ = MDFN_de32lsb(osm); osm += 4;
131  old_N = MDFN_de32lsb(osm); osm += 4;
132  old_X = MDFN_de32lsb(osm); osm += 4;
133  old_I = MDFN_de32lsb(osm); osm += 4;
134  old_S = MDFN_de32lsb(osm); osm += 4;
135  old_USP = MDFN_de32lsb(osm); osm += 4;
136  PC = MDFN_de32lsb(osm); osm += 4;
137  old_Status = MDFN_de32lsb(osm); osm += 4;
138  old_IRQLine = MDFN_de32lsb(osm); osm += 4;
139 
140  if(MDFN_de32lsb(osm) != 0xDEADBEEF)
141   throw MDFN_Error(0, _("Malformed old 68K save state."));
142  //
143  //
144  Flag_C = (old_C >> 8) & 1;
145  Flag_V = (old_V >> 7) & 1;
146  Flag_Z = !old_notZ;
147  Flag_N = (old_N >> 7) & 1;
148  Flag_X = (old_X >> 8) & 1;
149  SRHB = ((old_S >> 8) & 0x20) | (old_I & 0x7);
150  SP_Inactive = old_USP;
151 
152  XPending = ((old_Status & 0x02) ? XPENDING_MASK_STOPPED : 0);
153  IPL = old_IRQLine & 0x7;
154 
155  RecalcInt();
156 }
157 
RecalcInt(void)158 INLINE void M68K::RecalcInt(void)
159 {
160  XPending &= ~XPENDING_MASK_INT;
161 
162  if(IPL > (SRHB & 0x7))
163   XPending |= XPENDING_MASK_INT;
164 }
165 
SetIPL(uint8 ipl_new)166 void M68K::SetIPL(uint8 ipl_new)
167 {
168  if(IPL < 0x7 && ipl_new == 0x7)
169   XPending |= XPENDING_MASK_NMI;
170  else if(ipl_new < 0x7)
171   XPending &= ~XPENDING_MASK_NMI;
172 
173  IPL = ipl_new;
174  RecalcInt();
175 }
176 
SetExtHalted(bool state)177 void M68K::SetExtHalted(bool state)
178 {
179  XPending &= ~XPENDING_MASK_EXTHALTED;
180  if(state)
181   XPending |= XPENDING_MASK_EXTHALTED;
182 }
183 
184 template<typename T>
Read(uint32 addr)185 INLINE T M68K::Read(uint32 addr)
186 {
187  if(sizeof(T) == 4)
188  {
189   uint32 ret;
190 
191   ret = BusRead16(addr) << 16;
192   ret |= BusRead16(addr + 2);
193 
194   return ret;
195  }
196  else if(sizeof(T) == 2)
197   return BusRead16(addr);
198  else
199   return BusRead8(addr);
200 }
201 
ReadOp(void)202 INLINE uint16 M68K::ReadOp(void)
203 {
204  uint16 ret;
205 
206  ret = BusReadInstr(PC);
207  PC += 2;
208 
209  return ret;
210 }
211 
212 template<typename T, bool long_dec>
Write(uint32 addr,const T val)213 INLINE void M68K::Write(uint32 addr, const T val)
214 {
215  if(sizeof(T) == 4)
216  {
217   if(long_dec)
218   {
219    BusWrite16(addr + 2, val);
220    BusWrite16(addr, val >> 16);
221   }
222   else
223   {
224    BusWrite16(addr, val >> 16);
225    BusWrite16(addr + 2, val);
226   }
227  }
228  else if(sizeof(T) == 2)
229   BusWrite16(addr, val);
230  else
231   BusWrite8(addr, val);
232 }
233 
234 template<typename T>
Push(const T value)235 INLINE void M68K::Push(const T value)
236 {
237  static_assert(sizeof(T) != 1, "Wrong type.");
238  A[7] -= sizeof(T);
239  Write<T, true>(A[7], value);
240 }
241 
242 template<typename T>
Pull(void)243 INLINE T M68K::Pull(void)
244 {
245  static_assert(sizeof(T) != 1, "Wrong type.");
246 
247  T ret;
248 
249  ret = Read<T>(A[7]);
250 
251  A[7] += sizeof(T);
252 
253  return ret;
254 }
255 
256 //
257 // MOVE byte and word: instructions, 2 cycle penalty for source predecrement only
258 //  	2 cycle penalty for (d8, An, Xn) for both source and dest ams
259 //  	2 cycle penalty for (d8, PC, Xn) for dest am
260 //
261 
262 //
263 // Careful on declaration order of HAM objects(needs to be source then dest).
264 //
265 template<typename T, M68K::AddressMode am>
266 struct M68K::HAM
267 {
HAMMednafen::M68K::HAM268  INLINE HAM(M68K* z) : zptr(z), reg(0), have_ea(false)
269  {
270   static_assert(am == PC_DISP || am == PC_INDEX || am == ABS_SHORT || am == ABS_LONG || am == IMMEDIATE, "Wrong arg count.");
271 
272   switch(am)
273   {
274    case PC_DISP:   // (d16, PC)
275    case PC_INDEX:  // PC with index
276 	ea = zptr->PC;
277 	ext = zptr->ReadOp();
278 	break;
279 
280    case ABS_SHORT: // (xxxx).W
281 	ext = zptr->ReadOp();
282 	break;
283 
284    case ABS_LONG: // (xxxx).L
285 	ext = zptr->ReadOp() << 16;
286 	ext |= zptr->ReadOp();
287 	break;
288 
289    case IMMEDIATE: // Immediate
290 	if(sizeof(T) == 4)
291 	{
292 	 ext = zptr->ReadOp() << 16;
293 	 ext |= zptr->ReadOp();
294 	}
295 	else
296 	{
297 	 ext = zptr->ReadOp();
298 	}
299 	break;
300   }
301  }
302 
HAMMednafen::M68K::HAM303  INLINE HAM(M68K* z, uint32 arg) : zptr(z), reg(arg), have_ea(false)
304  {
305   static_assert(am != PC_DISP && am != PC_INDEX && am != ABS_SHORT && am != ABS_LONG, "Wrong arg count.");
306 
307   static_assert(am != ADDR_REG_DIR || sizeof(T) != 1, "Wrong size for address reg direct read");
308 
309   switch(am)
310   {
311    case DATA_REG_DIR:
312    case ADDR_REG_DIR:
313    case ADDR_REG_INDIR:
314    case ADDR_REG_INDIR_POST:
315    case ADDR_REG_INDIR_PRE:
316    	break;
317 
318    case ADDR_REG_INDIR_DISP:	// (d16, An)
319    case ADDR_REG_INDIR_INDX: 	// (d8, An, Xn)
320 	ext = zptr->ReadOp();
321 	break;
322 
323    case IMMEDIATE: 	// Immediate (quick)
324 	ext = arg;
325 	break;
326   }
327  }
328 
329  private:
calceaMednafen::M68K::HAM330  INLINE void calcea(const int predec_penalty)
331  {
332   if(have_ea)
333    return;
334 
335   have_ea = true;
336 
337   switch(am)
338   {
339    default:
340 	break;
341 
342    case ADDR_REG_INDIR:
343 	ea = zptr->A[reg];
344 	break;
345 
346    case ADDR_REG_INDIR_POST:
347 	ea = zptr->A[reg];
348 	zptr->A[reg] += (sizeof(T) == 1 && reg == 0x7) ? 2 : sizeof(T);
349 	break;
350 
351    case ADDR_REG_INDIR_PRE:
352 	zptr->timestamp += predec_penalty;
353 	zptr->A[reg] -= (sizeof(T) == 1 && reg == 0x7) ? 2 : sizeof(T);
354 	ea = zptr->A[reg];
355 	break;
356 
357    case ADDR_REG_INDIR_DISP:
358 	ea = zptr->A[reg] + (int16)ext;
359 	break;
360 
361    case ADDR_REG_INDIR_INDX:
362 	zptr->timestamp += 2;
363 	ea = zptr->A[reg] + (int8)ext + ((ext & 0x800) ? zptr->DA[ext >> 12] : (int16)zptr->DA[ext >> 12]);
364 	break;
365 
366    case ABS_SHORT:
367 	ea = (int16)ext;
368 	break;
369 
370    case ABS_LONG:
371 	ea = ext;
372 	break;
373 
374    case PC_DISP:
375 	ea = ea + (int16)ext;
376 	break;
377 
378    case PC_INDEX:
379 	zptr->timestamp += 2;
380 	ea = ea + (int8)ext + ((ext & 0x800) ? zptr->DA[ext >> 12] : (int16)zptr->DA[ext >> 12]);
381 	break;
382   }
383  }
384  public:
385 
386  //
387  // TODO: check pre-decrement 32-bit->2x 16-bit write order
388  //
389 
writeMednafen::M68K::HAM390  INLINE void write(const T val, const int predec_penalty = 2)
391  {
392   static_assert(am != PC_DISP && am != PC_INDEX && am != IMMEDIATE, "What");
393 
394   static_assert(am != ADDR_REG_DIR || sizeof(T) == 4, "Wrong size for address reg direct write");
395 
396   switch(am)
397   {
398    case ADDR_REG_DIR:
399 	zptr->A[reg] = val;
400 	break;
401 
402    case DATA_REG_DIR:
403 	#ifdef MSB_FIRST
404 	memcpy((uint8*)&zptr->D[reg] + (4 - sizeof(T)), &val, sizeof(T));
405 	#else
406 	memcpy((uint8*)&zptr->D[reg] + 0, &val, sizeof(T));
407 	#endif
408 	break;
409 
410    case ADDR_REG_INDIR:
411    case ADDR_REG_INDIR_POST:
412    case ADDR_REG_INDIR_PRE:
413    case ADDR_REG_INDIR_DISP:
414    case ADDR_REG_INDIR_INDX:
415    case ABS_SHORT:
416    case ABS_LONG:
417 	calcea(predec_penalty);
418 	zptr->Write<T, am == ADDR_REG_INDIR_PRE>(ea, val);
419 	break;
420   }
421  }
422 
readMednafen::M68K::HAM423  INLINE T read(void)
424  {
425   switch(am)
426   {
427    case DATA_REG_DIR:
428 	return zptr->D[reg];
429 
430    case ADDR_REG_DIR:
431 	return zptr->A[reg];
432 
433    case IMMEDIATE:
434 	return ext;
435 
436    case ADDR_REG_INDIR:
437    case ADDR_REG_INDIR_POST:
438    case ADDR_REG_INDIR_PRE:
439    case ADDR_REG_INDIR_DISP:
440    case ADDR_REG_INDIR_INDX:
441    case ABS_SHORT:
442    case ABS_LONG:
443    case PC_DISP:
444    case PC_INDEX:
445 	calcea(2);
446 	return zptr->Read<T>(ea);
447   }
448  }
449 
rmwMednafen::M68K::HAM450  INLINE void rmw(T (MDFN_FASTCALL *cb)(M68K*, T))
451  {
452   static_assert(am != PC_DISP && am != PC_INDEX && am != IMMEDIATE, "What");
453 
454   switch(am)
455   {
456    case DATA_REG_DIR:
457 	{
458 	 T tmp = cb(zptr, zptr->D[reg]);
459 	 #ifdef MSB_FIRST
460 	 memcpy((uint8*)&zptr->D[reg] + (4 - sizeof(T)), &tmp, sizeof(T));
461 	 #else
462 	 memcpy((uint8*)&zptr->D[reg] + 0, &tmp, sizeof(T));
463 	 #endif
464 	}
465 	break;
466 
467    case ADDR_REG_INDIR:
468    case ADDR_REG_INDIR_POST:
469    case ADDR_REG_INDIR_PRE:
470    case ADDR_REG_INDIR_DISP:
471    case ADDR_REG_INDIR_INDX:
472    case ABS_SHORT:
473    case ABS_LONG:
474 	calcea(2);
475 
476 	zptr->BusRMW(ea, cb);
477 	break;
478   }
479  }
480 
481 
jumpMednafen::M68K::HAM482  INLINE void jump(void)
483  {
484   calcea(0);
485   zptr->PC = ea;
486  }
487 
geteaMednafen::M68K::HAM488  INLINE uint32 getea(void)
489  {
490   static_assert(am == ADDR_REG_INDIR || am == ADDR_REG_INDIR_DISP || am == ADDR_REG_INDIR_INDX || am == ABS_SHORT || am == ABS_LONG || am == PC_DISP || am == PC_INDEX, "Wrong addressing mode");
491   calcea(0);
492   return ea;
493  }
494 
495  M68K* zptr;
496 
497  uint32 ea;
498  uint32 ext;
499  const unsigned reg;
500 
501  private:
502  bool have_ea;
503 };
504 
505 
506 
SetC(bool val)507 INLINE void M68K::SetC(bool val) { Flag_C = val; }
SetV(bool val)508 INLINE void M68K::SetV(bool val) { Flag_V = val; }
SetZ(bool val)509 INLINE void M68K::SetZ(bool val) { Flag_Z = val; }
SetN(bool val)510 INLINE void M68K::SetN(bool val) { Flag_N = val; }
SetX(bool val)511 INLINE void M68K::SetX(bool val) { Flag_X = val; }
512 
GetC(void)513 INLINE bool M68K::GetC(void) { return Flag_C; }
GetV(void)514 INLINE bool M68K::GetV(void) { return Flag_V; }
GetZ(void)515 INLINE bool M68K::GetZ(void) { return Flag_Z; }
GetN(void)516 INLINE bool M68K::GetN(void) { return Flag_N; }
GetX(void)517 INLINE bool M68K::GetX(void) { return Flag_X; }
518 
519 
SetCX(bool val)520 INLINE void M68K::SetCX(bool val)
521 {
522  SetC(val);
523  SetX(val);
524 }
525 
526 //
527 // Z_OnlyClear should be true for ADDX, SUBX, NEGX, ABCD, SBCD, NBCD.
528 //
529 template<typename T, bool Z_OnlyClear>
CalcZN(const T val)530 INLINE void M68K::CalcZN(const T val)
531 {
532  if(Z_OnlyClear)
533  {
534   if(val != 0)
535    SetZ(false);
536  }
537  else
538   SetZ(val == 0);
539 
540  SetN(static_cast<typename std::make_signed<T>::type>(val) < 0);
541 }
542 
543 template<typename T>
CalcCX(const uint64 & val)544 INLINE void M68K::CalcCX(const uint64& val)
545 {
546  SetCX((val >> (sizeof(T) * 8)) & 1);
547 }
548 
GetCCR(void)549 INLINE uint8 M68K::GetCCR(void)
550 {
551  return (GetC() << 0) | (GetV() << 1) | (GetZ() << 2) | (GetN() << 3) | (GetX() << 4);
552 }
553 
SetCCR(uint8 val)554 INLINE void M68K::SetCCR(uint8 val)
555 {
556  SetC((val >> 0) & 1);
557  SetV((val >> 1) & 1);
558  SetZ((val >> 2) & 1);
559  SetN((val >> 3) & 1);
560  SetX((val >> 4) & 1);
561 }
562 
GetSR(void)563 INLINE uint16 M68K::GetSR(void)
564 {
565  return GetCCR() | (SRHB << 8);
566 }
567 
SetSR(uint16 val)568 INLINE void M68K::SetSR(uint16 val)
569 {
570  const uint8 new_srhb = (val >> 8) & 0xA7;
571 
572  SetCCR(val);
573 
574  if((SRHB ^ new_srhb) & 0x20)	// Supervisor mode change
575  {
576   std::swap(A[7], SP_Inactive);
577  }
578 
579  SRHB = new_srhb;
580  RecalcInt();
581 }
582 
GetIMask(void)583 INLINE uint8 M68K::GetIMask(void)
584 {
585  return (GetSR() >> 8) & 0x7;
586 }
587 
SetIMask(uint8 val)588 INLINE void M68K::SetIMask(uint8 val)
589 {
590  SetSR((GetSR() & ~0x0700) | ((val & 0x7) << 8));
591 }
592 
GetSVisor(void)593 INLINE bool M68K::GetSVisor(void)
594 {
595  return (bool)(GetSR() & 0x2000);
596 }
597 
SetSVisor(bool value)598 INLINE void M68K::SetSVisor(bool value)
599 {
600  SetSR((GetSR() & ~0x2000) | (value << 13));
601 }
602 
GetTrace(void)603 INLINE bool M68K::GetTrace(void)
604 {
605  return (bool)(GetSR() & 0x8000);
606 }
607 
SetTrace(bool value)608 INLINE void M68K::SetTrace(bool value)
609 {
610  SetSR((GetSR() & ~0x8000) | (value << 15));
611 }
612 
613 //
614 //
615 //
616 enum
617 {
618  VECNUM_RESET_SSP = 0,
619  VECNUM_RESET_PC  = 1,
620  VECNUM_BUS_ERROR = 2,
621  VECNUM_ADDRESS_ERROR = 3,
622  VECNUM_ILLEGAL = 4,
623  VECNUM_ZERO_DIVIDE = 5,
624  VECNUM_CHK = 6,
625  VECNUM_TRAPV = 7,
626  VECNUM_PRIVILEGE = 8,
627  VECNUM_TRACE = 9,
628  VECNUM_LINEA = 10,
629  VECNUM_LINEF = 11,
630 
631  VECNUM_UNINI_INT = 15,
632 
633  VECNUM_SPURIOUS_INT = 24,
634  VECNUM_INT_BASE = 24,
635 
636  VECNUM_TRAP_BASE = 32
637 };
638 
639 enum
640 {
641  EXCEPTION_RESET = 0,
642  EXCEPTION_BUS_ERROR,
643  EXCEPTION_ADDRESS_ERROR,
644  EXCEPTION_ILLEGAL,
645  EXCEPTION_ZERO_DIVIDE,
646  EXCEPTION_CHK,
647  EXCEPTION_TRAPV,
648  EXCEPTION_PRIVILEGE,
649  EXCEPTION_TRACE,
650 
651  EXCEPTION_INT,
652  EXCEPTION_TRAP
653 };
654 
655 //
656 // Instruction traps(TRAP, TRAPV, CHK, DIVS, DIVU):
657 //	Saved PC points to the instruction after the instruction that triggered the exception.
658 //
659 // Illegal instructions:
660 //
661 //
662 // Privilege violation:
663 // 	Saved PC points to the instruction that generated the privilege violation.
664 //
665 // Base exception timing is 34 cycles?
Exception(unsigned which,unsigned vecnum)666 void NO_INLINE M68K::Exception(unsigned which, unsigned vecnum)
667 {
668  const uint32 PC_save = PC;
669  const uint16 SR_save = GetSR();
670 
671  SetSVisor(true);
672  SetTrace(false);
673 
674  if(which == EXCEPTION_INT)
675  {
676   unsigned evn;
677 
678   timestamp += 4;
679 
680   SetIMask(IPL);
681 
682   evn = BusIntAck(IPL);
683 
684   if(evn > 255)
685    vecnum = vecnum + IPL;
686   else
687    vecnum = evn;
688 
689   timestamp += 2;
690  }
691 
692  Push<uint32>(PC_save);
693  Push<uint16>(SR_save);
694  PC = Read<uint32>(vecnum << 2);
695 
696  //
697  {
698   auto dbgw = DBG_Verbose;
699 
700   if(which != EXCEPTION_INT || vecnum == VECNUM_UNINI_INT || vecnum == VECNUM_SPURIOUS_INT)
701    dbgw = DBG_Warning;
702 
703   dbgw("[M68K] Exception %u(vec=%u) @PC=0x%08x SR=0x%04x ---> PC=0x%08x, SR=0x%04x\n", which, vecnum, PC_save, SR_save, PC, GetSR());
704  }
705  //
706 
707  // TODO: Prefetch
708  ReadOp();
709  ReadOp();
710  PC -= 4;
711 }
712 
713 //
714 //
715 //
716 
717 //
718 // ADD
719 //
720 template<typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM>
ADD(HAM<T,SAM> & src,HAM<DT,DAM> & dst)721 INLINE void M68K::ADD(HAM<T, SAM> &src, HAM<DT, DAM> &dst)
722 {
723  static_assert(DAM == ADDR_REG_DIR || std::is_same<T, DT>::value, "Type mismatch");
724 
725  uint32 const src_data = (DT)static_cast<typename std::make_signed<T>::type>(src.read());
726  uint32 const dst_data = dst.read();
727  uint64 const result = (uint64)dst_data + src_data;
728 
729  if(DAM == ADDR_REG_DIR)
730  {
731   if(sizeof(T) != 4 || SAM == DATA_REG_DIR || SAM == ADDR_REG_DIR || SAM == IMMEDIATE)
732    timestamp += 4;
733   else
734    timestamp += 2;
735  }
736  else if(DAM == DATA_REG_DIR && sizeof(DT) == 4)
737  {
738   if(SAM == DATA_REG_DIR || SAM == IMMEDIATE)
739    timestamp += 4;
740   else
741    timestamp += 2;
742  }
743 
744  if(DAM != ADDR_REG_DIR)
745  {
746   CalcZN<DT>(result);
747   SetCX((result >> (sizeof(DT) * 8)) & 1);
748   SetV((((~(dst_data ^ src_data)) & (dst_data ^ result)) >> (sizeof(DT) * 8 - 1)) & 1);
749  }
750 
751  dst.write(result);
752 }
753 
754 
755 //
756 // ADDX
757 //
758 template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
ADDX(HAM<T,SAM> & src,HAM<T,DAM> & dst)759 INLINE void M68K::ADDX(HAM<T, SAM> &src, HAM<T, DAM> &dst)
760 {
761  uint32 const src_data = src.read();
762  uint32 const dst_data = dst.read();
763  uint64 const result = (uint64)dst_data + src_data + GetX();
764 
765  if(DAM != DATA_REG_DIR)
766  {
767   timestamp += 2;
768  }
769  else
770  {
771   if(sizeof(T) == 4)
772    timestamp += 4;
773  }
774 
775  CalcZN<T, true>(result);
776  SetCX((result >> (sizeof(T) * 8)) & 1);
777  SetV((((~(dst_data ^ src_data)) & (dst_data ^ result)) >> (sizeof(T) * 8 - 1)) & 1);
778 
779  dst.write(result);
780 }
781 
782 
783 //
784 // Used to implement SUB, SUBA, SUBX, NEG, NEGX
785 //
786 template<bool X_form, typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM>
Subtract(HAM<T,SAM> & src,HAM<DT,DAM> & dst)787 INLINE DT M68K::Subtract(HAM<T, SAM> &src, HAM<DT, DAM> &dst)
788 {
789  static_assert(DAM == ADDR_REG_DIR || std::is_same<T, DT>::value, "Type mismatch");
790  static_assert(DAM == ADDR_REG_DIR || DAM == DATA_REG_DIR || DAM == IMMEDIATE || SAM == ADDR_REG_DIR || SAM == DATA_REG_DIR || SAM == IMMEDIATE || X_form, "Wrong addressing modes.");
791 
792  uint32 const src_data = (DT)static_cast<typename std::make_signed<T>::type>(src.read());
793  uint32 const dst_data = dst.read();
794  const uint64 result = (uint64)dst_data - src_data - (X_form ? GetX() : 0);
795 
796  if(DAM == ADDR_REG_DIR)	// SUBA, SUBQ(A) only.
797  {
798   if(sizeof(T) != 4 || SAM == DATA_REG_DIR || SAM == ADDR_REG_DIR || SAM == IMMEDIATE)
799    timestamp += 4;
800   else
801    timestamp += 2;
802  }
803  else if(DAM == DATA_REG_DIR)	// SUB, SUBQ, SUBX only.
804  {
805   if(sizeof(DT) == 4)
806   {
807    if(SAM == DATA_REG_DIR || SAM == IMMEDIATE)
808     timestamp += 4;
809    else
810     timestamp += 2;
811   }
812  }
813  else if(DAM == IMMEDIATE)	// NEG, NEGX only and always.
814  {
815   if(sizeof(T) == 4)
816   {
817    timestamp += 2;
818   }
819  }
820  else if(SAM != IMMEDIATE && SAM != ADDR_REG_DIR && SAM != DATA_REG_DIR) // SUBX m,m
821  {
822   timestamp += 2;
823  }
824 
825 
826  if(DAM != ADDR_REG_DIR)
827  {
828   CalcZN<DT, X_form>(result);
829   SetCX((result >> (sizeof(DT) * 8)) & 1);
830   SetV(((((dst_data ^ src_data)) & (dst_data ^ result)) >> (sizeof(DT) * 8 - 1)) & 1);
831  }
832 
833  return result;
834 }
835 
836 
837 //
838 // SUB
839 //
840 template<typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM>
SUB(HAM<T,SAM> & src,HAM<DT,DAM> & dst)841 INLINE void M68K::SUB(HAM<T, SAM> &src, HAM<DT, DAM> &dst)
842 {
843  dst.write(Subtract<false>(src, dst));
844 }
845 
846 
847 //
848 // SUBX
849 //
850 template<typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM>
SUBX(HAM<T,SAM> & src,HAM<DT,DAM> & dst)851 INLINE void M68K::SUBX(HAM<T, SAM> &src, HAM<DT, DAM> &dst)
852 {
853  dst.write(Subtract<true>(src, dst));
854 }
855 
856 
857 //
858 // NEG
859 //
860 template<typename DT, M68K::AddressMode DAM>
NEG(HAM<DT,DAM> & dst)861 INLINE void M68K::NEG(HAM<DT, DAM> &dst)
862 {
863  HAM<DT, IMMEDIATE> dummy_zero(this, 0);
864 
865  dst.write(Subtract<false>(dst, dummy_zero));
866 }
867 
868 
869 //
870 // NEGX
871 //
872 template<typename DT, M68K::AddressMode DAM>
NEGX(HAM<DT,DAM> & dst)873 INLINE void M68K::NEGX(HAM<DT, DAM> &dst)
874 {
875  HAM<DT, IMMEDIATE> dummy_zero(this, 0);
876 
877  dst.write(Subtract<true>(dst, dummy_zero));
878 }
879 
880 
881 //
882 // CMP
883 //
884 template<typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM>
CMP(HAM<T,SAM> & src,HAM<DT,DAM> & dst)885 INLINE void M68K::CMP(HAM<T, SAM> &src, HAM<DT, DAM> &dst)
886 {
887  static_assert(DAM == ADDR_REG_DIR || std::is_same<T, DT>::value, "Type mismatch");
888 
889  // Doesn't affect X flag
890  uint32 const src_data = (DT)static_cast<typename std::make_signed<T>::type>(src.read());
891  uint32 const dst_data = dst.read();
892  uint64 const result = (uint64)dst_data - src_data;
893 
894  CalcZN<DT>(result);
895  SetC((result >> (sizeof(DT) * 8)) & 1);
896  SetV(((((dst_data ^ src_data)) & (dst_data ^ result)) >> (sizeof(DT) * 8 - 1)) & 1);
897 }
898 
899 
900 //
901 // CHK
902 //
903 // Exception on dst < 0 || dst > src
904 template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
CHK(HAM<T,SAM> & src,HAM<T,DAM> & dst)905 INLINE void M68K::CHK(HAM<T, SAM> &src, HAM<T, DAM> &dst)
906 {
907  uint32 const src_data = src.read();
908  uint32 const dst_data = dst.read();
909 
910  timestamp += 6;
911 
912  CalcZN<T>(dst_data);
913  if(GetN())
914  {
915   Exception(EXCEPTION_CHK, VECNUM_CHK);
916  }
917  else
918  {
919   // 7 - 1
920   uint64 const result = (uint64)dst_data - src_data;
921 
922   CalcZN<T>(result);
923   SetC((result >> (sizeof(T) * 8)) & 1);
924   SetV(((((dst_data ^ src_data)) & (dst_data ^ result)) >> (sizeof(T) * 8 - 1)) & 1);
925 
926   if(GetN() == GetV() && !GetZ())
927   {
928    Exception(EXCEPTION_CHK, VECNUM_CHK);
929   }
930  }
931 }
932 
933 
934 //
935 // OR
936 //
937 template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
OR(HAM<T,SAM> & src,HAM<T,DAM> & dst)938 INLINE void M68K::OR(HAM<T, SAM> &src, HAM<T, DAM> &dst)
939 {
940  T const src_data = src.read();
941  T const dst_data = dst.read();
942  T const result = dst_data | src_data;
943 
944  if(sizeof(T) == 4 && DAM == DATA_REG_DIR)
945  {
946   if(SAM == IMMEDIATE || SAM == DATA_REG_DIR)
947    timestamp += 4;
948   else
949    timestamp += 2;
950  }
951 
952  CalcZN<T>(result);
953  SetC(false);
954  SetV(false);
955 
956  dst.write(result);
957 }
958 
959 
960 //
961 // EOR
962 //
963 template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
EOR(HAM<T,SAM> & src,HAM<T,DAM> & dst)964 INLINE void M68K::EOR(HAM<T, SAM> &src, HAM<T, DAM> &dst)
965 {
966  T const src_data = src.read();
967  T const dst_data = dst.read();
968  T const result = dst_data ^ src_data;
969 
970  if(sizeof(T) == 4 && DAM == DATA_REG_DIR)
971  {
972   if(SAM == IMMEDIATE || SAM == DATA_REG_DIR)
973    timestamp += 4;
974   else
975    timestamp += 2;
976  }
977 
978  CalcZN<T>(result);
979  SetC(false);
980  SetV(false);
981 
982  dst.write(result);
983 }
984 
985 
986 //
987 // AND
988 //
989 template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
AND(HAM<T,SAM> & src,HAM<T,DAM> & dst)990 INLINE void M68K::AND(HAM<T, SAM> &src, HAM<T, DAM> &dst)
991 {
992  T const src_data = src.read();
993  T const dst_data = dst.read();
994  T const result = dst_data & src_data;
995 
996  if(sizeof(T) == 4 && DAM == DATA_REG_DIR)
997  {
998   if(SAM == IMMEDIATE || SAM == DATA_REG_DIR)
999    timestamp += 4;
1000   else
1001    timestamp += 2;
1002  }
1003 
1004  CalcZN<T>(result);
1005  SetC(false);
1006  SetV(false);
1007 
1008  dst.write(result);
1009 }
1010 
1011 
1012 //
1013 // ORI CCR
1014 //
ORI_CCR(void)1015 INLINE void M68K::ORI_CCR(void)
1016 {
1017  const uint8 imm = ReadOp();
1018 
1019  SetCCR(GetCCR() | imm);
1020 
1021  //
1022  //
1023  timestamp += 8;
1024  ReadOp();
1025  PC -= 2;
1026 }
1027 
1028 
1029 //
1030 // ORI SR
1031 //
ORI_SR(void)1032 INLINE void M68K::ORI_SR(void)
1033 {
1034  const uint16 imm = ReadOp();
1035 
1036  SetSR(GetSR() | imm);
1037 
1038  //
1039  //
1040  timestamp += 8;
1041  ReadOp();
1042  PC -= 2;
1043 }
1044 
1045 
1046 //
1047 // ANDI CCR
1048 //
ANDI_CCR(void)1049 INLINE void M68K::ANDI_CCR(void)
1050 {
1051  const uint8 imm = ReadOp();
1052 
1053  SetCCR(GetCCR() & imm);
1054 
1055  //
1056  //
1057  timestamp += 8;
1058  ReadOp();
1059  PC -= 2;
1060 }
1061 
1062 
1063 //
1064 // ANDI SR
1065 //
ANDI_SR(void)1066 INLINE void M68K::ANDI_SR(void)
1067 {
1068  const uint16 imm = ReadOp();
1069 
1070  SetSR(GetSR() & imm);
1071 
1072  //
1073  //
1074  timestamp += 8;
1075  ReadOp();
1076  PC -= 2;
1077 }
1078 
1079 
1080 //
1081 // EORI CCR
1082 //
EORI_CCR(void)1083 INLINE void M68K::EORI_CCR(void)
1084 {
1085  const uint8 imm = ReadOp();
1086 
1087  SetCCR(GetCCR() ^ imm);
1088 
1089  //
1090  //
1091  timestamp += 8;
1092  ReadOp();
1093  PC -= 2;
1094 }
1095 
1096 
1097 //
1098 // EORI SR
1099 //
EORI_SR(void)1100 INLINE void M68K::EORI_SR(void)
1101 {
1102  const uint16 imm = ReadOp();
1103 
1104  SetSR(GetSR() ^ imm);
1105 
1106  //
1107  //
1108  timestamp += 8;
1109  ReadOp();
1110  PC -= 2;
1111 }
1112 
1113 
1114 //
1115 // MULU
1116 //
1117 template<typename T, M68K::AddressMode SAM>
MULU(HAM<T,SAM> & src,const unsigned dr)1118 INLINE void M68K::MULU(HAM<T, SAM> &src, const unsigned dr)
1119 {
1120  // Doesn't affect X flag
1121  static_assert(sizeof(T) == 2, "Wrong type.");
1122 
1123  T const src_data = src.read();
1124  uint32 const result = (uint32)(uint16)D[dr] * (uint32)src_data;
1125 
1126  timestamp += 34;
1127 
1128  for(uint32 tmp = src_data; tmp; tmp &= tmp - 1)
1129   timestamp += 2;
1130 
1131  CalcZN<uint32>(result);
1132  SetC(false);
1133  SetV(false);
1134 
1135  D[dr] = result;
1136 }
1137 
1138 
1139 //
1140 // MULS
1141 //
1142 template<typename T, M68K::AddressMode SAM>
MULS(HAM<T,SAM> & src,const unsigned dr)1143 INLINE void M68K::MULS(HAM<T, SAM> &src, const unsigned dr)
1144 {
1145  // Doesn't affect X flag
1146  static_assert(sizeof(T) == 2, "Wrong type.");
1147 
1148  T const src_data = src.read();
1149  uint32 const result = (int16)D[dr] * (int16)src_data;
1150 
1151  timestamp += 34;
1152 
1153  for(uint32 tmp = src_data << 1, i = 0; i < 16; tmp >>= 1, i++)
1154   timestamp += (tmp ^ (tmp << 1)) & 2;
1155 
1156  CalcZN<uint32>(result);
1157  SetC(false);
1158  SetV(false);
1159 
1160  D[dr] = result;
1161 }
1162 
1163 
1164 template<bool sdiv>
Divide(uint16 divisor,const unsigned dr)1165 INLINE void M68K::Divide(uint16 divisor, const unsigned dr)
1166 {
1167  uint32 dividend = D[dr];
1168  uint32 tmp;
1169  bool neg_quotient = false;
1170  bool neg_remainder = false;
1171  bool oflow = false;
1172 
1173  if(!divisor)
1174  {
1175   Exception(EXCEPTION_ZERO_DIVIDE, VECNUM_ZERO_DIVIDE);
1176   return;
1177  }
1178 
1179  if(sdiv)
1180  {
1181   neg_quotient = (dividend >> 31) ^ (divisor >> 15);
1182   if(dividend & 0x80000000)
1183   {
1184    dividend = -dividend;
1185    neg_remainder = true;
1186   }
1187 
1188   if(divisor & 0x8000)
1189    divisor = -divisor;
1190  }
1191 
1192  tmp = dividend;
1193 
1194  for(int i = 0; i < 16; i++)
1195  {
1196   bool lb = false;
1197   bool ob;
1198 
1199   if(tmp >= ((uint32)divisor << 15))
1200   {
1201    tmp -= divisor << 15;
1202    lb = true;
1203   }
1204 
1205   ob = tmp >> 31;
1206   tmp = (tmp << 1) | lb;
1207 
1208   if(ob)
1209   {
1210    oflow = true;
1211    //puts("OVERFLOW");
1212    //break;
1213   }
1214  }
1215 
1216  if(sdiv)
1217  {
1218   if((tmp & 0xFFFF) > (uint32)(0x7FFF + neg_quotient))
1219    oflow = true;
1220  }
1221 
1222  if((uint32)(tmp >> 16) >= divisor)
1223   oflow = true;
1224 
1225  if(sdiv && !oflow)
1226  {
1227   if(neg_quotient)
1228    tmp = ((-tmp) & 0xFFFF) | (tmp & 0xFFFF0000);
1229 
1230   if(neg_remainder)
1231    tmp = (((-(tmp >> 16)) << 16) & 0xFFFF0000) | (tmp & 0xFFFF);
1232  }
1233 
1234  //
1235  // Doesn't affect X flag
1236  //
1237  CalcZN<uint16>(tmp);
1238  SetC(false);
1239  SetV(oflow);
1240 
1241  if(!oflow)
1242   D[dr] = tmp;
1243 }
1244 
1245 
1246 //
1247 // DIVU
1248 //
1249 template<typename T, M68K::AddressMode SAM>
DIVU(HAM<T,SAM> & src,const unsigned dr)1250 INLINE void M68K::DIVU(HAM<T, SAM> &src, const unsigned dr)
1251 {
1252  static_assert(sizeof(T) == 2, "Wrong type.");
1253 
1254  T const src_data = src.read();
1255 
1256  Divide<false>(src_data, dr);
1257 }
1258 
1259 
1260 //
1261 // DIVS
1262 //
1263 template<typename T, M68K::AddressMode SAM>
DIVS(HAM<T,SAM> & src,const unsigned dr)1264 INLINE void M68K::DIVS(HAM<T, SAM> &src, const unsigned dr)
1265 {
1266  // Doesn't affect X flag
1267  static_assert(sizeof(T) == 2, "Wrong type.");
1268 
1269  T const src_data = src.read();
1270 
1271  Divide<true>(src_data, dr);
1272 }
1273 
1274 
1275 //
1276 // ABCD
1277 //
1278 template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
ABCD(HAM<T,SAM> & src,HAM<T,DAM> & dst)1279 INLINE void M68K::ABCD(HAM<T, SAM> &src, HAM<T, DAM> &dst)	// ...XYZ, now I know my ABCs~
1280 {
1281  static_assert(sizeof(T) == 1, "Wrong size.");
1282 
1283  bool V = false;
1284  uint8 const src_data = src.read();
1285  uint8 const dst_data = dst.read();
1286  uint32 tmp;
1287 
1288  tmp = dst_data + src_data + GetX();
1289 
1290  if(((dst_data ^ src_data ^ tmp) & 0x10) || (tmp & 0xF) >= 0x0A)
1291  {
1292   uint8 prev_tmp = tmp;
1293   tmp += 0x06;
1294   V |= ((~prev_tmp & 0x80) & (tmp & 0x80));
1295  }
1296 
1297  if(tmp >= 0xA0)
1298  {
1299   uint8 prev_tmp = tmp;
1300   tmp += 0x60;
1301   V |= ((~prev_tmp & 0x80) & (tmp & 0x80));
1302  }
1303 
1304  CalcZN<uint8, true>(tmp);
1305  SetCX((bool)(tmp >> 8));
1306  SetV(V);
1307 
1308  if(DAM == DATA_REG_DIR)
1309   timestamp += 2;
1310  else
1311   timestamp += 4;
1312 
1313  dst.write(tmp);
1314 }
1315 
1316 
DecimalSubtractX(const uint8 src_data,const uint8 dst_data)1317 INLINE uint8 M68K::DecimalSubtractX(const uint8 src_data, const uint8 dst_data)
1318 {
1319  bool V = false;
1320  uint32 tmp;
1321 
1322  tmp = dst_data - src_data - GetX();
1323 
1324  const bool adj0 = ((dst_data ^ src_data ^ tmp) & 0x10);
1325  const bool adj1 = (tmp & 0x100);
1326 
1327  if(adj0)
1328  {
1329   uint8 prev_tmp = tmp;
1330   tmp -= 0x06;
1331   V |= (prev_tmp & 0x80) & (~tmp & 0x80);
1332  }
1333 
1334  if(adj1)
1335  {
1336   uint8 prev_tmp = tmp;
1337   tmp -= 0x60;
1338   V |= (prev_tmp & 0x80) & (~tmp & 0x80);
1339  }
1340 
1341  SetV(V);
1342  CalcZN<uint8, true>(tmp);
1343  SetCX((bool)(tmp >> 8));
1344 
1345  return tmp;
1346 }
1347 
1348 //
1349 // SBCD
1350 //
1351 template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
SBCD(HAM<T,SAM> & src,HAM<T,DAM> & dst)1352 INLINE void M68K::SBCD(HAM<T, SAM> &src, HAM<T, DAM> &dst)
1353 {
1354  static_assert(sizeof(T) == 1, "Wrong size.");
1355  uint8 const src_data = src.read();
1356  uint8 const dst_data = dst.read();
1357 
1358  if(DAM == DATA_REG_DIR)
1359   timestamp += 2;
1360  else
1361   timestamp += 4;
1362 
1363  dst.write(DecimalSubtractX(src_data, dst_data));
1364 }
1365 
1366 
1367 //
1368 // NBCD
1369 //
1370 template<typename T, M68K::AddressMode DAM>
NBCD(HAM<T,DAM> & dst)1371 INLINE void M68K::NBCD(HAM<T, DAM> &dst)
1372 {
1373  static_assert(sizeof(T) == 1, "Wrong size.");
1374  uint8 const dst_data = dst.read();
1375 
1376  timestamp += 2;
1377 
1378  dst.write(DecimalSubtractX(dst_data, 0));
1379 }
1380 
1381 //
1382 // MOVEP
1383 //
1384 template<typename T, bool reg_to_mem>
MOVEP(const unsigned ar,const unsigned dr)1385 INLINE void M68K::MOVEP(const unsigned ar, const unsigned dr)
1386 {
1387  const int16 ext = ReadOp();
1388  uint32 ea = A[ar] + (int16)ext;
1389  unsigned shift = (sizeof(T) - 1) << 3;
1390 
1391  for(unsigned i = 0; i < sizeof(T); i++)
1392  {
1393   if(reg_to_mem)
1394    Write<uint8>(ea, D[dr] >> shift);
1395   else
1396   {
1397    D[dr] &= ~(0xFF << shift);
1398    D[dr] |= Read<uint8>(ea) << shift;
1399   }
1400   ea += 2;
1401   shift -= 8;
1402  }
1403 }
1404 
1405 
1406 template<typename T, M68K::AddressMode TAM>
BTST(HAM<T,TAM> & targ,unsigned wb)1407 INLINE void M68K::BTST(HAM<T, TAM> &targ, unsigned wb)
1408 {
1409  T const src_data = targ.read();
1410  wb &= (sizeof(T) << 3) - 1;
1411 
1412  SetZ(((src_data >> wb) & 1) == 0);
1413 }
1414 
1415 template<typename T, M68K::AddressMode TAM>
BCHG(HAM<T,TAM> & targ,unsigned wb)1416 INLINE void M68K::BCHG(HAM<T, TAM> &targ, unsigned wb)
1417 {
1418  T const src_data = targ.read();
1419  wb &= (sizeof(T) << 3) - 1;
1420 
1421  SetZ(((src_data >> wb) & 1) == 0);
1422 
1423  targ.write(src_data ^ (1U << wb));
1424 }
1425 
1426 template<typename T, M68K::AddressMode TAM>
BCLR(HAM<T,TAM> & targ,unsigned wb)1427 INLINE void M68K::BCLR(HAM<T, TAM> &targ, unsigned wb)
1428 {
1429  T const src_data = targ.read();
1430  wb &= (sizeof(T) << 3) - 1;
1431 
1432  SetZ(((src_data >> wb) & 1) == 0);
1433 
1434  targ.write(src_data & ~(1U << wb));
1435 }
1436 
1437 template<typename T, M68K::AddressMode TAM>
BSET(HAM<T,TAM> & targ,unsigned wb)1438 INLINE void M68K::BSET(HAM<T, TAM> &targ, unsigned wb)
1439 {
1440  T const src_data = targ.read();
1441  wb &= (sizeof(T) << 3) - 1;
1442 
1443  SetZ(((src_data >> wb) & 1) == 0);
1444 
1445  targ.write(src_data | (1U << wb));
1446 }
1447 
1448 
1449 
1450 //
1451 // MOVE
1452 //
1453 template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
MOVE(HAM<T,SAM> & src,HAM<T,DAM> & dst)1454 INLINE void M68K::MOVE(HAM<T, SAM> &src, HAM<T, DAM> &dst)
1455 {
1456  T const tmp = src.read();
1457 
1458  if(DAM != ADDR_REG_DIR)
1459  {
1460   CalcZN<T>(tmp);
1461   SetV(false);
1462   SetC(false);
1463  }
1464 
1465  dst.write(tmp);
1466 }
1467 
1468 template<typename T, M68K::AddressMode SAM>
MOVEA(HAM<T,SAM> & src,const unsigned ar)1469 INLINE void M68K::MOVEA(HAM<T, SAM> &src, const unsigned ar)
1470 {
1471  uint32 const src_data = static_cast<typename std::make_signed<T>::type>(src.read());
1472 
1473  A[ar] = src_data;
1474 }
1475 
1476 
1477 //
1478 // MOVEM to memory
1479 //
1480 template<bool pseudo_predec, typename T, M68K::AddressMode DAM>
MOVEM_to_MEM(const uint16 reglist,HAM<T,DAM> & dst)1481 INLINE void M68K::MOVEM_to_MEM(const uint16 reglist, HAM<T, DAM> &dst)
1482 {
1483  static_assert(DAM != ADDR_REG_INDIR_PRE && DAM != ADDR_REG_INDIR_POST, "Wrong address mode.");
1484  static_assert(!pseudo_predec || DAM == ADDR_REG_INDIR, "Wrong address mode.");
1485 
1486  uint32 ea = dst.getea();
1487 
1488  for(unsigned i = 0; i < 16; i++)
1489  {
1490   if(reglist & (1U << i))
1491   {
1492    if(pseudo_predec)
1493     ea -= sizeof(T);
1494 
1495    Write<T, pseudo_predec>(ea, DA[(pseudo_predec ? (15 - i) : i)]);
1496 
1497    if(!pseudo_predec)
1498     ea += sizeof(T);
1499   }
1500  }
1501 
1502  if(pseudo_predec)
1503   A[dst.reg] = ea;
1504 }
1505 
1506 
1507 //
1508 // MOVEM to regs(from memory)
1509 //
1510 template<bool pseudo_postinc, typename T, M68K::AddressMode SAM>
MOVEM_to_REGS(HAM<T,SAM> & src,const uint16 reglist)1511 INLINE void M68K::MOVEM_to_REGS(HAM<T, SAM> &src, const uint16 reglist)
1512 {
1513  static_assert(SAM != ADDR_REG_INDIR_PRE && SAM != ADDR_REG_INDIR_POST, "Wrong address mode.");
1514  static_assert(!pseudo_postinc || SAM == ADDR_REG_INDIR, "Wrong address mode.");
1515 
1516  uint32 ea = src.getea();
1517 
1518  for(unsigned i = 0; i < 16; i++)
1519  {
1520   if(reglist & (1U << i))
1521   {
1522    T tmp = Read<T>(ea);
1523 
1524    DA[i] = static_cast<typename std::make_signed<T>::type>(tmp);
1525 
1526    ea += sizeof(T);
1527   }
1528  }
1529 
1530  Read<uint16>(ea);	// or should be <T> ?
1531 
1532  if(pseudo_postinc)
1533   A[src.reg] = ea;
1534 }
1535 
1536 
1537 template<typename T, M68K::AddressMode TAM, bool Arithmetic, bool ShiftLeft>
ShiftBase(HAM<T,TAM> & targ,unsigned count)1538 INLINE void M68K::ShiftBase(HAM<T, TAM> &targ, unsigned count)
1539 {
1540  T vchange = 0;
1541  T result = targ.read();
1542  count &= 0x3F;
1543 
1544  if(TAM == DATA_REG_DIR)
1545   timestamp += (sizeof(T) == 4) ? 4 : 2;
1546 
1547  if(count == 0)
1548  {
1549   // X is unaffected with a shift count of 0!
1550   SetC(false);
1551  }
1552  else
1553  {
1554   bool shifted_out = false;
1555 
1556   do
1557   {
1558    if(TAM == DATA_REG_DIR)
1559     timestamp += 2;
1560 
1561    if(ShiftLeft)
1562     shifted_out = (result >> (sizeof(T) * 8 - 1)) & 1;
1563    else
1564     shifted_out = result & 1;
1565 
1566    if(Arithmetic)
1567    {
1568     const T prev = result;
1569 
1570     if(ShiftLeft)
1571      result = result << 1;
1572     else
1573      result = static_cast<typename std::make_signed<T>::type>(result) >> 1;
1574 
1575     vchange |= prev ^ result;
1576    }
1577    else
1578    {
1579     if(ShiftLeft)
1580      result = result << 1;
1581     else
1582      result = result >> 1;
1583    }
1584   } while(--count != 0);
1585 
1586   SetCX(shifted_out);
1587  }
1588 
1589  CalcZN<T>(result);
1590 
1591  if(Arithmetic)
1592   SetV((vchange >> (sizeof(T) * 8 - 1)) & 1);
1593  else
1594   SetV(false);
1595 
1596  targ.write(result);
1597 }
1598 
1599 template<typename T, M68K::AddressMode TAM>
ASL(HAM<T,TAM> & targ,unsigned count)1600 INLINE void M68K::ASL(HAM<T, TAM> &targ, unsigned count)
1601 {
1602  ShiftBase<T, TAM, true, true>(targ, count);
1603 }
1604 
1605 template<typename T, M68K::AddressMode TAM>
ASR(HAM<T,TAM> & targ,unsigned count)1606 INLINE void M68K::ASR(HAM<T, TAM> &targ, unsigned count)
1607 {
1608  ShiftBase<T, TAM, true, false>(targ, count);
1609 }
1610 
1611 template<typename T, M68K::AddressMode TAM>
LSL(HAM<T,TAM> & targ,unsigned count)1612 INLINE void M68K::LSL(HAM<T, TAM> &targ, unsigned count)
1613 {
1614  ShiftBase<T, TAM, false, true>(targ, count);
1615 }
1616 
1617 template<typename T, M68K::AddressMode TAM>
LSR(HAM<T,TAM> & targ,unsigned count)1618 INLINE void M68K::LSR(HAM<T, TAM> &targ, unsigned count)
1619 {
1620  ShiftBase<T, TAM, false, false>(targ, count);
1621 }
1622 
1623 template<typename T, M68K::AddressMode TAM, bool X_Form, bool ShiftLeft>
RotateBase(HAM<T,TAM> & targ,unsigned count)1624 INLINE void M68K::RotateBase(HAM<T, TAM> &targ, unsigned count)
1625 {
1626  T result = targ.read();
1627  count &= 0x3F;
1628 
1629  if(TAM == DATA_REG_DIR)
1630   timestamp += (sizeof(T) == 4) ? 4 : 2;
1631 
1632  if(count == 0)
1633  {
1634   if(X_Form)
1635    SetC(GetX());
1636   else
1637    SetC(false);
1638  }
1639  else
1640  {
1641   bool shifted_out = GetX();
1642 
1643   do
1644   {
1645    const bool shift_in = shifted_out;
1646 
1647    if(TAM == DATA_REG_DIR)
1648     timestamp += 2;
1649 
1650    if(ShiftLeft)
1651    {
1652     shifted_out = (result >> (sizeof(T) * 8 - 1)) & 1;
1653     result <<= 1;
1654     result |= (X_Form ? shift_in : shifted_out);
1655    }
1656    else
1657    {
1658     shifted_out = (result & 1);
1659     result >>= 1;
1660     result |= (T)(X_Form ? shift_in : shifted_out) << (sizeof(T) * 8 - 1);
1661    }
1662   } while(--count != 0);
1663 
1664   SetC(shifted_out);
1665   if(X_Form)
1666    SetX(shifted_out);
1667  }
1668 
1669  CalcZN<T>(result);
1670  SetV(false);
1671 
1672  targ.write(result);
1673 }
1674 
1675 template<typename T, M68K::AddressMode TAM>
ROL(HAM<T,TAM> & targ,unsigned count)1676 INLINE void M68K::ROL(HAM<T, TAM> &targ, unsigned count)
1677 {
1678  RotateBase<T, TAM, false, true>(targ, count);
1679 }
1680 
1681 template<typename T, M68K::AddressMode TAM>
ROR(HAM<T,TAM> & targ,unsigned count)1682 INLINE void M68K::ROR(HAM<T, TAM> &targ, unsigned count)
1683 {
1684  RotateBase<T, TAM, false, false>(targ, count);
1685 }
1686 
1687 template<typename T, M68K::AddressMode TAM>
ROXL(HAM<T,TAM> & targ,unsigned count)1688 INLINE void M68K::ROXL(HAM<T, TAM> &targ, unsigned count)
1689 {
1690  RotateBase<T, TAM, true, true>(targ, count);
1691 }
1692 
1693 template<typename T, M68K::AddressMode TAM>
ROXR(HAM<T,TAM> & targ,unsigned count)1694 INLINE void M68K::ROXR(HAM<T, TAM> &targ, unsigned count)
1695 {
1696  RotateBase<T, TAM, true, false>(targ, count);
1697 }
1698 
1699 //
1700 // TAS
1701 //
TAS_Callback(M68K * zptr,uint8 data)1702 static MDFN_FASTCALL uint8 TAS_Callback(M68K* zptr, uint8 data)
1703 {
1704  zptr->CalcZN<uint8>(data);
1705  zptr->SetC(false);
1706  zptr->SetV(false);
1707 
1708  data |= 0x80;
1709  return data;
1710 }
1711 
1712 template<typename T, M68K::AddressMode DAM>
TAS(HAM<T,DAM> & dst)1713 INLINE void M68K::TAS(HAM<T, DAM> &dst)
1714 {
1715  static_assert(std::is_same<T, uint8>::value, "Wrong type");
1716 
1717  dst.rmw(TAS_Callback);
1718 }
1719 
1720 //
1721 // TST
1722 //
1723 template<typename T, M68K::AddressMode DAM>
TST(HAM<T,DAM> & dst)1724 INLINE void M68K::TST(HAM<T, DAM> &dst)
1725 {
1726  T const dst_data = dst.read();
1727 
1728  CalcZN<T>(dst_data);
1729 
1730  SetC(false);
1731  SetV(false);
1732 }
1733 
1734 
1735 //
1736 // CLR
1737 //
1738 template<typename T, M68K::AddressMode DAM>
CLR(HAM<T,DAM> & dst)1739 INLINE void M68K::CLR(HAM<T, DAM> &dst)
1740 {
1741  dst.read();
1742 
1743  if(sizeof(T) == 4 && DAM == DATA_REG_DIR)
1744   timestamp += 2;
1745 
1746  SetZ(true);
1747  SetN(false);
1748 
1749  SetC(false);
1750  SetV(false);
1751 
1752  dst.write(0);
1753 }
1754 
1755 //
1756 // NOT
1757 //
1758 template<typename T, M68K::AddressMode DAM>
NOT(HAM<T,DAM> & dst)1759 INLINE void M68K::NOT(HAM<T, DAM> &dst)
1760 {
1761  T result = dst.read();
1762 
1763  if(sizeof(T) == 4 && DAM == DATA_REG_DIR)
1764   timestamp += 2;
1765 
1766  result = ~result;
1767 
1768  CalcZN<T>(result);
1769  SetC(false);
1770  SetV(false);
1771 
1772  dst.write(result);
1773 }
1774 
1775 
1776 //
1777 // EXT
1778 //
1779 template<typename T, M68K::AddressMode DAM>
EXT(HAM<T,DAM> & dst)1780 INLINE void M68K::EXT(HAM<T, DAM> &dst)
1781 {
1782  static_assert(std::is_same<T, uint16>::value || std::is_same<T, uint32>::value, "Wrong type");
1783  T result = dst.read();
1784 
1785  if(std::is_same<T, uint16>::value)
1786   result = (int8)result;
1787  else
1788   result = (int16)result;
1789 
1790  CalcZN<T>(result);
1791  SetC(false);
1792  SetV(false);
1793 
1794  dst.write(result);
1795 }
1796 
1797 //
1798 // SWAP
1799 //
SWAP(const unsigned dr)1800 INLINE void M68K::SWAP(const unsigned dr)
1801 {
1802  D[dr] = (D[dr] << 16) | (D[dr] >> 16);
1803 
1804  CalcZN<uint32>(D[dr]);
1805  SetC(false);
1806  SetV(false);
1807 }
1808 
1809 
1810 //
1811 // EXG (doesn't affect flags)
1812 //
EXG(uint32 * a,uint32 * b)1813 INLINE void M68K::EXG(uint32* a, uint32* b)
1814 {
1815  timestamp += 2;
1816 
1817  std::swap(*a, *b);
1818 }
1819 
1820 //
1821 //
1822 //
1823 
1824 template<unsigned cc>
TestCond(void)1825 INLINE bool M68K::TestCond(void)
1826 {
1827  static_assert(cc < 0x10, "Invalid CC");
1828 
1829  switch(cc)
1830  {
1831   case 0x00:	// TRUE
1832 	return true;
1833 
1834   case 0x01:	// FALSE
1835 	return false;
1836 
1837   case 0x02:	// HI
1838 	return !GetC() && !GetZ();
1839 
1840   case 0x03:	// LS
1841 	return GetC() || GetZ();
1842 
1843   case 0x04:	// CC/HS
1844 	return !GetC();
1845 
1846   case 0x05:	// CS/LO
1847 	return GetC();
1848 
1849   case 0x06:	// NE
1850 	return !GetZ();
1851 
1852   case 0x07:	// EQ
1853 	return GetZ();
1854 
1855   case 0x08:	// VC
1856 	return !GetV();
1857 
1858   case 0x09:	// VS
1859 	return GetV();
1860 
1861   case 0x0A:	// PL
1862 	return !GetN();
1863 
1864   case 0x0B:	// MI
1865 	return GetN();
1866 
1867   case 0x0C:	// GE
1868 	return GetN() == GetV();
1869 
1870   case 0x0D:	// LT
1871 	return GetN() != GetV();
1872 
1873   case 0x0E:	// GT
1874 	return GetN() == GetV() && !GetZ();
1875 
1876   case 0x0F:	// LE
1877 	return GetN() != GetV() || GetZ();
1878  }
1879 }
1880 
1881 //
1882 // Bcc, BRA, BSR
1883 //
1884 //  (caller of this function should sign-extend the 8-bit displacement)
1885 //
1886 template<unsigned cc>
Bxx(uint32 disp)1887 INLINE void M68K::Bxx(uint32 disp)
1888 {
1889  const uint32 BPC = PC;
1890 
1891  if(TestCond<(cc == 0x01) ? 0x00 : cc>())
1892  {
1893   const uint16 disp16 = (int16)ReadOp();
1894 
1895   if(!disp)
1896    disp = (int16)disp16;
1897   else
1898    PC -= 2;
1899 
1900   if(cc == 0x01)
1901    Push<uint32>(PC);
1902 
1903   timestamp += 2;
1904   PC = BPC + disp;
1905  }
1906  else
1907  {
1908   if(!disp)
1909    ReadOp();
1910 
1911   timestamp += 4;
1912  }
1913 }
1914 
1915 template<unsigned cc>
DBcc(const unsigned dr)1916 INLINE void M68K::DBcc(const unsigned dr)
1917 {
1918  const uint32 BPC = PC;
1919  uint32 disp;
1920 
1921  disp = (int16)ReadOp();
1922 
1923  if(!TestCond<cc>())
1924  {
1925   const uint16 result = D[dr] - 1;
1926 
1927   timestamp += 2;
1928   D[dr] = (D[dr] & 0xFFFF0000) | result;
1929 
1930   if(result != 0xFFFF)
1931    PC = BPC + disp;
1932   else
1933    timestamp += 4;
1934  }
1935  else
1936   timestamp += 4;
1937 }
1938 
1939 
1940 //
1941 // Scc
1942 //
1943 template<unsigned cc, typename T, M68K::AddressMode DAM>
Scc(HAM<T,DAM> & dst)1944 INLINE void M68K::Scc(HAM<T, DAM> &dst)
1945 {
1946  static_assert(std::is_same<T, uint8>::value, "Wrong type");
1947 
1948  T const result = TestCond<cc>() ? ~(T)0 : 0;
1949 
1950  if(DAM == DATA_REG_DIR && result)
1951   timestamp += 2;
1952 
1953  dst.write(result);
1954 }
1955 
1956 
1957 //
1958 // JSR
1959 //
1960 template<typename T, M68K::AddressMode TAM>
JSR(HAM<T,TAM> & targ)1961 INLINE void M68K::JSR(HAM<T, TAM> &targ)
1962 {
1963  Push<uint32>(PC);
1964  targ.jump();
1965 }
1966 
1967 
1968 //
1969 // JMP
1970 //
1971 template<typename T, M68K::AddressMode TAM>
JMP(HAM<T,TAM> & targ)1972 INLINE void M68K::JMP(HAM<T, TAM> &targ)
1973 {
1974  targ.jump();
1975 }
1976 
1977 
1978 //
1979 // MOVE from SR
1980 //
1981 template <typename T, M68K::AddressMode DAM>
MOVE_from_SR(HAM<T,DAM> & dst)1982 INLINE void M68K::MOVE_from_SR(HAM<T, DAM> &dst)
1983 {
1984  static_assert(std::is_same<T, uint16>::value, "Wrong type");
1985 
1986  dst.read();
1987 
1988  if(DAM == DATA_REG_DIR)
1989   timestamp += 2;
1990 
1991  dst.write(GetSR());
1992 }
1993 
1994 
1995 //
1996 // MOVE to CCR
1997 //
1998 template<typename T, M68K::AddressMode SAM>
MOVE_to_CCR(HAM<T,SAM> & src)1999 INLINE void M68K::MOVE_to_CCR(HAM<T, SAM> &src)
2000 {
2001  static_assert(std::is_same<T, uint16>::value, "Wrong type");
2002 
2003  SetCCR(src.read());
2004 
2005  timestamp += 8;
2006 }
2007 
2008 //
2009 // MOVE to SR
2010 //
2011 template<typename T, M68K::AddressMode SAM>
MOVE_to_SR(HAM<T,SAM> & src)2012 INLINE void M68K::MOVE_to_SR(HAM<T, SAM> &src)
2013 {
2014  static_assert(std::is_same<T, uint16>::value, "Wrong type");
2015 
2016  SetSR(src.read());
2017 
2018  timestamp += 8;
2019 }
2020 
2021 
2022 //
2023 // MOVE to/from USP
2024 //
2025 template<bool direction>
MOVE_USP(const unsigned ar)2026 INLINE void M68K::MOVE_USP(const unsigned ar)
2027 {
2028  if(!direction)
2029   SP_Inactive = A[ar];
2030  else
2031   A[ar] = SP_Inactive;
2032 }
2033 
2034 
2035 //
2036 // LEA
2037 //
2038 template<typename T, M68K::AddressMode SAM>
LEA(HAM<T,SAM> & src,const unsigned ar)2039 INLINE void M68K::LEA(HAM<T, SAM> &src, const unsigned ar)
2040 {
2041  const uint32 ea = src.getea();
2042 
2043  A[ar] = ea;
2044 }
2045 
2046 
2047 //
2048 // PEA
2049 //
2050 template<typename T, M68K::AddressMode SAM>
PEA(HAM<T,SAM> & src)2051 INLINE void M68K::PEA(HAM<T, SAM> &src)
2052 {
2053  const uint32 ea = src.getea();
2054 
2055  Push<uint32>(ea);
2056 }
2057 
2058 //
2059 // UNLK
2060 //
UNLK(const unsigned ar)2061 INLINE void M68K::UNLK(const unsigned ar)
2062 {
2063  A[7] = A[ar];
2064  A[ar] = Pull<uint32>();
2065 }
2066 
2067 
2068 //
2069 // LINK
2070 //
LINK(const unsigned ar)2071 INLINE void M68K::LINK(const unsigned ar)
2072 {
2073  const uint32 disp = (int16)ReadOp();
2074 
2075  Push<uint32>(A[ar]);
2076  A[ar] = A[7];
2077  A[7] += disp;
2078 }
2079 
2080 
2081 
2082 
2083 
2084 //
2085 // RTE
2086 //
RTE(void)2087 INLINE void M68K::RTE(void)
2088 {
2089  uint16 new_SR;
2090 
2091  new_SR = Pull<uint16>();
2092  PC = Pull<uint32>();
2093 
2094  SetSR(new_SR);
2095 }
2096 
2097 
2098 //
2099 // RTR
2100 //
RTR(void)2101 INLINE void M68K::RTR(void)
2102 {
2103  SetCCR(Pull<uint16>());
2104  PC = Pull<uint32>();
2105 }
2106 
2107 
2108 //
2109 // RTS
2110 //
RTS(void)2111 INLINE void M68K::RTS(void)
2112 {
2113  PC = Pull<uint32>();
2114 }
2115 
2116 
2117 //
2118 // TRAP
2119 //
TRAP(const unsigned vf)2120 INLINE void M68K::TRAP(const unsigned vf)
2121 {
2122  Exception(EXCEPTION_TRAP, VECNUM_TRAP_BASE + vf);
2123 }
2124 
2125 
2126 //
2127 // TRAPV
2128 //
TRAPV(void)2129 INLINE void M68K::TRAPV(void)
2130 {
2131  if(GetV())
2132   Exception(EXCEPTION_TRAPV, VECNUM_TRAPV);
2133 }
2134 
2135 
2136 //
2137 // ILLEGAL
2138 //
ILLEGAL(const uint16 instr)2139 INLINE void M68K::ILLEGAL(const uint16 instr)
2140 {
2141  //printf("ILLEGAL: %04x\n", instr);
2142 
2143  PC -= 2;
2144  Exception(EXCEPTION_ILLEGAL, VECNUM_ILLEGAL);
2145 }
2146 
2147 
LINEA(void)2148 INLINE void M68K::LINEA(void)
2149 {
2150  PC -= 2;
2151  Exception(EXCEPTION_ILLEGAL, VECNUM_LINEA);
2152 }
2153 
LINEF(void)2154 INLINE void M68K::LINEF(void)
2155 {
2156  PC -= 2;
2157  Exception(EXCEPTION_ILLEGAL, VECNUM_LINEF);
2158 }
2159 
2160 
2161 //
2162 // NOP
2163 //
NOP(void)2164 INLINE void M68K::NOP(void)
2165 {
2166 
2167 }
2168 
2169 
2170 //
2171 // RESET
2172 //
RESET(void)2173 INLINE void M68K::RESET(void)
2174 {
2175  timestamp += 2;
2176  //
2177  BusRESET(true);
2178  timestamp += 124;
2179  BusRESET(false);
2180  //
2181  timestamp += 2;
2182 }
2183 
2184 
2185 //
2186 // STOP
2187 //
STOP(void)2188 INLINE void M68K::STOP(void)
2189 {
2190  uint16 new_SR = ReadOp();
2191 
2192  SetSR(new_SR);
2193  XPending |= XPENDING_MASK_STOPPED;
2194 }
2195 
2196 
CheckPrivilege(void)2197 INLINE bool M68K::CheckPrivilege(void)
2198 {
2199  if(MDFN_UNLIKELY(!GetSVisor()))
2200  {
2201   PC -= 2;
2202   Exception(EXCEPTION_PRIVILEGE, VECNUM_PRIVILEGE);
2203   return false;
2204  }
2205 
2206  return true;
2207 }
2208 
2209 //
2210 //
InternalStep(void)2211 INLINE void M68K::InternalStep(void)
2212 {
2213  if(MDFN_UNLIKELY(XPending))
2214  {
2215   if(MDFN_LIKELY(!(XPending & XPENDING_MASK_EXTHALTED)))
2216   {
2217    if(MDFN_UNLIKELY(XPending & XPENDING_MASK_RESET))
2218    {
2219     XPending &= ~XPENDING_MASK_RESET;
2220 
2221     SetSVisor(true);
2222     SetTrace(false);
2223     SetIMask(0x7);
2224 
2225     A[7] = Read<uint32>(VECNUM_RESET_SSP << 2);
2226     PC = Read<uint32>(VECNUM_RESET_PC << 2);
2227 
2228     return;
2229    }
2230    else if(XPending & (XPENDING_MASK_INT | XPENDING_MASK_NMI))
2231    {
2232     assert(IPL == 0x7 || IPL > ((GetSR() >> 8) & 0x7));
2233     XPending &= ~(XPENDING_MASK_STOPPED | XPENDING_MASK_INT | XPENDING_MASK_NMI);
2234 
2235     Exception(EXCEPTION_INT, VECNUM_INT_BASE);
2236 
2237     return;
2238    }
2239   }
2240 
2241   // STOP and ExtHalted fallthrough:
2242   timestamp += 4;
2243   return;
2244  }
2245  //
2246  //
2247  //
2248  uint16 instr = ReadOp();
2249  const unsigned instr_b11_b9 = (instr >> 9) & 0x7;
2250  const unsigned instr_b2_b0 = instr & 0x7;
2251 
2252 #if 0
2253   printf("PC=%08x: %04x ---", PC - 2, instr);
2254 
2255   for(unsigned i = 0; i < 8; i++)
2256    printf(" A%u=0x%08x", i, A[i]);
2257 
2258   for(unsigned i = 0; i < 8; i++)
2259    printf(" D%u=0x%08x", i, D[i]);
2260 
2261   printf("\n");
2262 #endif
2263  switch(instr)
2264  {
2265   default: ILLEGAL(instr); break;
2266   #include "m68k_instr.inc"
2267  }
2268 }
2269 
2270 
Run(int32 run_until_time)2271 void NO_INLINE M68K::Run(int32 run_until_time)
2272 {
2273  while(MDFN_LIKELY(timestamp < run_until_time))
2274   InternalStep();
2275 }
2276 
Step(void)2277 void NO_INLINE M68K::Step(void)
2278 {
2279  //printf("%08x\n", PC);
2280  InternalStep();
2281 }
2282 
2283 //
2284 // Reset() may be called from BusRESET, which is called from RESET, so ensure it continues working for that case.
2285 //
Reset(bool powering_up)2286 void M68K::Reset(bool powering_up)
2287 {
2288  if(powering_up)
2289  {
2290   PC = 0;
2291 
2292   for(unsigned i = 0; i < 8; i++)
2293    D[i] = 0;
2294 
2295   for(unsigned i = 0; i < 8; i++)
2296    A[i] = 0;
2297 
2298   SP_Inactive = 0;
2299 
2300   SetSR(0);
2301  }
2302  XPending = (XPending & ~(XPENDING_MASK_STOPPED | XPENDING_MASK_NMI)) | XPENDING_MASK_RESET;
2303 }
2304 
2305 
2306 //
2307 //
2308 //
GetRegister(unsigned which,char * special,const uint32 special_len)2309 uint32 M68K::GetRegister(unsigned which, char* special, const uint32 special_len)
2310 {
2311  switch(which)
2312  {
2313   default:
2314 	return 0xDEADBEEF;
2315 
2316   case GSREG_D0: case GSREG_D1: case GSREG_D2: case GSREG_D3:
2317   case GSREG_D4: case GSREG_D5: case GSREG_D6: case GSREG_D7:
2318 	return D[which - GSREG_D0];
2319 
2320   case GSREG_A0: case GSREG_A1: case GSREG_A2: case GSREG_A3:
2321   case GSREG_A4: case GSREG_A5: case GSREG_A6: case GSREG_A7:
2322 	return A[which - GSREG_A0];
2323 
2324   case GSREG_PC:
2325 	return PC;
2326 
2327   case GSREG_SR:
2328 	return GetSR();
2329 
2330   case GSREG_SSP:
2331 	if(GetSVisor())
2332 	 return A[7];
2333 	else
2334 	 return SP_Inactive;
2335 
2336   case GSREG_USP:
2337 	if(!GetSVisor())
2338 	 return A[7];
2339 	else
2340 	 return SP_Inactive;
2341  }
2342 }
2343 
SetRegister(unsigned which,uint32 value)2344 void M68K::SetRegister(unsigned which, uint32 value)
2345 {
2346  switch(which)
2347  {
2348   case GSREG_D0: case GSREG_D1: case GSREG_D2: case GSREG_D3:
2349   case GSREG_D4: case GSREG_D5: case GSREG_D6: case GSREG_D7:
2350 	D[which - GSREG_D0] = value;
2351 	break;
2352 
2353   case GSREG_A0: case GSREG_A1: case GSREG_A2: case GSREG_A3:
2354   case GSREG_A4: case GSREG_A5: case GSREG_A6: case GSREG_A7:
2355 	A[which - GSREG_A0] = value;
2356 	break;
2357 
2358   case GSREG_PC:
2359 	PC = value;
2360 	break;
2361 
2362   case GSREG_SR:
2363 	SetSR(value);
2364 	break;
2365 
2366   case GSREG_SSP:
2367 	if(GetSVisor())
2368 	 A[7] = value;
2369 	else
2370 	 SP_Inactive = value;
2371 	break;
2372 
2373   case GSREG_USP:
2374 	if(!GetSVisor())
2375 	 A[7] = value;
2376 	else
2377 	 SP_Inactive = value;
2378 	break;
2379  }
2380 }
2381 
2382 }
2383