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