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