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