auto M68K::testCondition(uint4 condition) -> bool { switch(condition) { case 0: return true; //T case 1: return false; //F case 2: return !r.c && !r.z; //HI case 3: return r.c || r.z; //LS case 4: return !r.c; //CC,HS case 5: return r.c; //CS,LO case 6: return !r.z; //NE case 7: return r.z; //EQ case 8: return !r.v; //VC case 9: return r.v; //VS case 10: return !r.n; //PL case 11: return r.n; //MI case 12: return r.n == r.v; //GE case 13: return r.n != r.v; //LT case 14: return r.n == r.v && !r.z; //GT case 15: return r.n != r.v || r.z; //LE } unreachable; } // template<> auto M68K::bytes() -> uint { return 1; } template<> auto M68K::bytes() -> uint { return 2; } template<> auto M68K::bytes() -> uint { return 4; } template<> auto M68K::bits() -> uint { return 8; } template<> auto M68K::bits() -> uint { return 16; } template<> auto M68K::bits() -> uint { return 32; } template auto M68K::lsb() -> uint32 { return 1; } template<> auto M68K::msb() -> uint32 { return 0x80; } template<> auto M68K::msb() -> uint32 { return 0x8000; } template<> auto M68K::msb() -> uint32 { return 0x80000000; } template<> auto M68K::mask() -> uint32 { return 0xff; } template<> auto M68K::mask() -> uint32 { return 0xffff; } template<> auto M68K::mask() -> uint32 { return 0xffffffff; } template<> auto M68K::clip(uint32 data) -> uint32 { return data & 0xff; } template<> auto M68K::clip(uint32 data) -> uint32 { return data & 0xffff; } template<> auto M68K::clip(uint32 data) -> uint32 { return data & 0xffffffff; } template<> auto M68K::sign(uint32 data) -> int32 { return (int8)data; } template<> auto M68K::sign(uint32 data) -> int32 { return (int16)data; } template<> auto M68K::sign(uint32 data) -> int32 { return (int32)data; } // auto M68K::instructionABCD(EffectiveAddress with, EffectiveAddress from) -> void { auto source = read(from); auto target = read(with); auto result = source + target + r.x; bool v = false; if(((target ^ source ^ result) & 0x10) || (result & 0x0f) >= 0x0a) { auto previous = result; result += 0x06; v |= ((~previous & 0x80) & (result & 0x80)); } if(result >= 0xa0) { auto previous = result; result += 0x60; v |= ((~previous & 0x80) & (result & 0x80)); } write(with, result); r.c = sign(result >> 1) < 0; r.v = v; r.z = clip(result) ? 0 : r.z; r.n = sign(result) < 0; r.x = r.c; } template auto M68K::ADD(uint32 source, uint32 target) -> uint32 { auto result = (uint64)source + target; if(Extend) result += r.x; r.c = sign(result >> 1) < 0; r.v = sign(~(target ^ source) & (target ^ result)) < 0; r.z = clip(result) ? 0 : (Extend ? r.z : 1); r.n = sign(result) < 0; r.x = r.c; return clip(result); } template auto M68K::instructionADD(EffectiveAddress from, DataRegister with) -> void { auto source = read(from); auto target = read(with); auto result = ADD(source, target); write(with, result); } template auto M68K::instructionADD(DataRegister from, EffectiveAddress with) -> void { auto source = read(from); auto target = read(with); auto result = ADD(source, target); write(with, result); } template auto M68K::instructionADDA(AddressRegister ar, EffectiveAddress ea) -> void { auto source = sign(read(ea)); auto target = read(ar); write(ar, source + target); } template auto M68K::instructionADDI(EffectiveAddress modify) -> void { auto source = readPC(); auto target = read(modify); auto result = ADD(source, target); write(modify, result); } template auto M68K::instructionADDQ(uint4 immediate, EffectiveAddress with) -> void { auto source = immediate; auto target = read(with); auto result = ADD(source, target); write(with, result); } //Size is ignored: always uses Long template auto M68K::instructionADDQ(uint4 immediate, AddressRegister with) -> void { auto result = read(with) + immediate; write(with, result); } template auto M68K::instructionADDX(EffectiveAddress with, EffectiveAddress from) -> void { auto source = read(from); auto target = read(with); auto result = ADD(source, target); write(with, result); } template auto M68K::AND(uint32 source, uint32 target) -> uint32 { uint32 result = target & source; r.c = 0; r.v = 0; r.z = clip(result) == 0; r.n = sign(result) < 0; return clip(result); } template auto M68K::instructionAND(EffectiveAddress from, DataRegister with) -> void { auto source = read(from); auto target = read(with); auto result = AND(source, target); write(with, result); } template auto M68K::instructionAND(DataRegister from, EffectiveAddress with) -> void { auto source = read(from); auto target = read(with); auto result = AND(source, target); write(with, result); } template auto M68K::instructionANDI(EffectiveAddress with) -> void { auto source = readPC(); auto target = read(with); auto result = AND(source, target); write(with, result); } auto M68K::instructionANDI_TO_CCR() -> void { auto data = readPC(); writeCCR(readCCR() & data); } auto M68K::instructionANDI_TO_SR() -> void { if(!supervisor()) return; auto data = readPC(); writeSR(readSR() & data); } template auto M68K::ASL(uint32 result, uint shift) -> uint32 { bool carry = false; uint32 overflow = 0; for(auto _ : range(shift)) { carry = result & msb(); uint32 before = result; result <<= 1; overflow |= before ^ result; } r.c = carry; r.v = sign(overflow) < 0; r.z = clip(result) == 0; r.n = sign(result) < 0; if(shift) r.x = r.c; return clip(result); } template auto M68K::instructionASL(uint4 shift, DataRegister modify) -> void { auto result = ASL(read(modify), shift); write(modify, result); } template auto M68K::instructionASL(DataRegister shift, DataRegister modify) -> void { auto count = read(shift) & 63; auto result = ASL(read(modify), count); write(modify, result); } auto M68K::instructionASL(EffectiveAddress modify) -> void { auto result = ASL(read(modify), 1); write(modify, result); } template auto M68K::ASR(uint32 result, uint shift) -> uint32 { bool carry = false; uint32 overflow = 0; for(auto _ : range(shift)) { carry = result & lsb(); uint32 before = result; result = sign(result) >> 1; overflow |= before ^ result; } r.c = carry; r.v = sign(overflow) < 0; r.z = clip(result) == 0; r.n = sign(result) < 0; if(shift) r.x = r.c; return clip(result); } template auto M68K::instructionASR(uint4 shift, DataRegister modify) -> void { auto result = ASR(read(modify), shift); write(modify, result); } template auto M68K::instructionASR(DataRegister shift, DataRegister modify) -> void { auto count = read(shift) & 63; auto result = ASR(read(modify), count); write(modify, result); } auto M68K::instructionASR(EffectiveAddress modify) -> void { auto result = ASR(read(modify), 1); write(modify, result); } auto M68K::instructionBCC(uint4 condition, uint8 displacement) -> void { auto extension = readPC(); if(displacement) r.pc -= 2; if(condition >= 2 && !testCondition(condition)) return; if(condition == 1) push(r.pc); r.pc += displacement ? (int8_t)displacement : (int16_t)extension - 2; } template auto M68K::instructionBCHG(DataRegister bit, EffectiveAddress with) -> void { auto index = read(bit) & bits() - 1; auto test = read(with); r.z = test.bit(index) == 0; test.bit(index) ^= 1; write(with, test); } template auto M68K::instructionBCHG(EffectiveAddress with) -> void { auto index = readPC() & bits() - 1; auto test = read(with); r.z = test.bit(index) == 0; test.bit(index) ^= 1; write(with, test); } template auto M68K::instructionBCLR(DataRegister bit, EffectiveAddress with) -> void { auto index = read(bit) & bits() - 1; auto test = read(with); r.z = test.bit(index) == 0; test.bit(index) = 0; write(with, test); } template auto M68K::instructionBCLR(EffectiveAddress with) -> void { auto index = readPC() & bits() - 1; auto test = read(with); r.z = test.bit(index) == 0; test.bit(index) = 0; write(with, test); } template auto M68K::instructionBSET(DataRegister bit, EffectiveAddress with) -> void { auto index = read(bit) & bits() - 1; auto test = read(with); r.z = test.bit(index) == 0; test.bit(index) = 1; write(with, test); } template auto M68K::instructionBSET(EffectiveAddress with) -> void { auto index = readPC() & bits() - 1; auto test = read(with); r.z = test.bit(index) == 0; test.bit(index) = 1; write(with, test); } template auto M68K::instructionBTST(DataRegister bit, EffectiveAddress with) -> void { auto index = read(bit) & bits() - 1; auto test = read(with); r.z = test.bit(index) == 0; } template auto M68K::instructionBTST(EffectiveAddress with) -> void { auto index = readPC() & bits() - 1; auto test = read(with); r.z = test.bit(index) == 0; } auto M68K::instructionCHK(DataRegister compare, EffectiveAddress maximum) -> void { auto source = read(maximum); auto target = read(compare); r.z = clip(target) == 0; r.n = sign(target) < 0; if(r.n) return exception(Exception::BoundsCheck, Vector::BoundsCheck); auto result = (uint64)target - source; r.c = sign(result >> 1) < 0; r.v = sign((target ^ source) & (target ^ result)) < 0; r.z = clip(result) == 0; r.n = sign(result) < 0; if(r.n == r.v && !r.z) return exception(Exception::BoundsCheck, Vector::BoundsCheck); } template auto M68K::instructionCLR(EffectiveAddress ea) -> void { read(ea); write(ea, 0); r.c = 0; r.v = 0; r.z = 1; r.n = 0; } template auto M68K::CMP(uint32 source, uint32 target) -> uint32 { auto result = (uint64)target - source; r.c = sign(result >> 1) < 0; r.v = sign((target ^ source) & (target ^ result)) < 0; r.z = clip(result) == 0; r.n = sign(result) < 0; return clip(result); } template auto M68K::instructionCMP(DataRegister dr, EffectiveAddress ea) -> void { auto source = read(ea); auto target = read(dr); CMP(source, target); } template auto M68K::instructionCMPA(AddressRegister ar, EffectiveAddress ea) -> void { auto source = sign(read(ea)); auto target = read(ar); CMP(source, target); } template auto M68K::instructionCMPI(EffectiveAddress ea) -> void { auto source = readPC(); auto target = read(ea); CMP(source, target); } template auto M68K::instructionCMPM(EffectiveAddress ax, EffectiveAddress ay) -> void { auto source = read(ay); auto target = read(ax); CMP(source, target); } auto M68K::instructionDBCC(uint4 condition, DataRegister dr) -> void { auto displacement = readPC(); if(!testCondition(condition)) { uint16 result = read(dr); write(dr, result - 1); if(result) r.pc -= 2, r.pc += sign(displacement); } } template auto M68K::DIV(uint16 divisor, DataRegister with) -> void { auto dividend = read(with); bool negativeQuotient = false; bool negativeRemainder = false; bool overflow = false; if(divisor == 0) return exception(Exception::DivisionByZero, Vector::DivisionByZero); if(Sign) { negativeQuotient = (dividend >> 31) ^ (divisor >> 15); if(dividend >> 31) dividend = -dividend, negativeRemainder = true; if(divisor >> 15) divisor = -divisor; } auto result = dividend; for(auto _ : range(16)) { bool lb = false; if(result >= (uint32)divisor << 15) result -= divisor << 15, lb = true; bool ob = result >> 31; result = result << 1 | lb; if(ob) overflow = true; } if(Sign) { if((uint16)result > 0x7fff + negativeQuotient) overflow = true; } if(result >> 16 >= divisor) overflow = true; if(Sign && !overflow) { if(negativeQuotient) result = ((-result) & 0xffff) | (result & 0xffff0000); if(negativeRemainder) result = (((-(result >> 16)) << 16) & 0xffff0000) | (result & 0xffff); } if(!overflow) write(with, result); r.c = 0; r.v = overflow; r.z = clip(result) == 0; r.n = sign(result) < 0; } auto M68K::instructionDIVS(DataRegister with, EffectiveAddress from) -> void { auto divisor = read(from); DIV<1>(divisor, with); } auto M68K::instructionDIVU(DataRegister with, EffectiveAddress from) -> void { auto divisor = read(from); DIV<0>(divisor, with); } template auto M68K::EOR(uint32 source, uint32 target) -> uint32 { uint32 result = target ^ source; r.c = 0; r.v = 0; r.z = clip(result) == 0; r.n = sign(result) < 0; return clip(result); } template auto M68K::instructionEOR(DataRegister from, EffectiveAddress with) -> void { auto source = read(from); auto target = read(with); auto result = EOR(source, target); write(with, result); } template auto M68K::instructionEORI(EffectiveAddress with) -> void { auto source = readPC(); auto target = read(with); auto result = EOR(source, target); write(with, result); } auto M68K::instructionEORI_TO_CCR() -> void { auto data = readPC(); writeCCR(readCCR() ^ data); } auto M68K::instructionEORI_TO_SR() -> void { if(!supervisor()) return; auto data = readPC(); writeSR(readSR() ^ data); } auto M68K::instructionEXG(DataRegister x, DataRegister y) -> void { auto z = read(x); write(x, read(y)); write(y, z); } auto M68K::instructionEXG(AddressRegister x, AddressRegister y) -> void { auto z = read(x); write(x, read(y)); write(y, z); } auto M68K::instructionEXG(DataRegister x, AddressRegister y) -> void { auto z = read(x); write(x, read(y)); write(y, z); } template<> auto M68K::instructionEXT(DataRegister with) -> void { auto result = (int8)read(with); write(with, result); r.c = 0; r.v = 0; r.z = clip(result) == 0; r.n = sign(result) < 0; } template<> auto M68K::instructionEXT(DataRegister with) -> void { auto result = (int16)read(with); write(with, result); r.c = 0; r.v = 0; r.z = clip(result) == 0; r.n = sign(result) < 0; } auto M68K::instructionILLEGAL() -> void { r.pc -= 2; if(opcode >> 12 == 0xa) return exception(Exception::Illegal, Vector::IllegalLineA); if(opcode >> 12 == 0xf) return exception(Exception::Illegal, Vector::IllegalLineF); return exception(Exception::Illegal, Vector::Illegal); } auto M68K::instructionJMP(EffectiveAddress target) -> void { r.pc = fetch(target); } auto M68K::instructionJSR(EffectiveAddress target) -> void { auto pc = fetch(target); push(r.pc); r.pc = pc; } auto M68K::instructionLEA(AddressRegister ar, EffectiveAddress ea) -> void { write(ar, fetch(ea)); } auto M68K::instructionLINK(AddressRegister with) -> void { auto displacement = (int16)readPC(); auto sp = AddressRegister{7}; push(read(with)); write(with, read(sp)); write(sp, read(sp) + displacement); } template auto M68K::LSL(uint32 result, uint shift) -> uint32 { bool carry = false; for(auto _ : range(shift)) { carry = result & msb(); result <<= 1; } r.c = carry; r.v = 0; r.z = clip(result) == 0; r.n = sign(result) < 0; if(shift) r.x = r.c; return clip(result); } template auto M68K::instructionLSL(uint4 immediate, DataRegister dr) -> void { auto result = LSL(read(dr), immediate); write(dr, result); } template auto M68K::instructionLSL(DataRegister sr, DataRegister dr) -> void { auto shift = read(sr) & 63; auto result = LSL(read(dr), shift); write(dr, result); } auto M68K::instructionLSL(EffectiveAddress ea) -> void { auto result = LSL(read(ea), 1); write(ea, result); } template auto M68K::LSR(uint32 result, uint shift) -> uint32 { bool carry = false; for(auto _ : range(shift)) { carry = result & lsb(); result >>= 1; } r.c = carry; r.v = 0; r.z = clip(result) == 0; r.n = sign(result) < 0; if(shift) r.x = r.c; return clip(result); } template auto M68K::instructionLSR(uint4 immediate, DataRegister dr) -> void { auto result = LSR(read(dr), immediate); write(dr, result); } template auto M68K::instructionLSR(DataRegister shift, DataRegister dr) -> void { auto count = read(shift) & 63; auto result = LSR(read(dr), count); write(dr, result); } auto M68K::instructionLSR(EffectiveAddress ea) -> void { auto result = LSR(read(ea), 1); write(ea, result); } template auto M68K::instructionMOVE(EffectiveAddress to, EffectiveAddress from) -> void { auto data = read(from); write(to, data); r.c = 0; r.v = 0; r.z = clip(data) == 0; r.n = sign(data) < 0; } template auto M68K::instructionMOVEA(AddressRegister ar, EffectiveAddress ea) -> void { auto data = sign(read(ea)); write(ar, data); } template auto M68K::instructionMOVEM_TO_MEM(EffectiveAddress to) -> void { auto list = readPC(); auto addr = fetch(to); for(uint n : range(16)) { if(!list.bit(n)) continue; //pre-decrement mode traverses registers in reverse order {A7-A0, D7-D0} uint index = to.mode == AddressRegisterIndirectWithPreDecrement ? 15 - n : n; if(to.mode == AddressRegisterIndirectWithPreDecrement) addr -= bytes(); auto data = index < 8 ? read(DataRegister{index}) : read(AddressRegister{index}); write(addr, data); if(to.mode != AddressRegisterIndirectWithPreDecrement) addr += bytes(); } AddressRegister with{to.reg}; if(to.mode == AddressRegisterIndirectWithPreDecrement ) write(with, addr); if(to.mode == AddressRegisterIndirectWithPostIncrement) write(with, addr); } template auto M68K::instructionMOVEM_TO_REG(EffectiveAddress from) -> void { auto list = readPC(); auto addr = fetch(from); for(uint n : range(16)) { if(!list.bit(n)) continue; uint index = from.mode == AddressRegisterIndirectWithPreDecrement ? 15 - n : n; if(from.mode == AddressRegisterIndirectWithPreDecrement) addr -= bytes(); auto data = read(addr); data = sign(data); index < 8 ? write(DataRegister{index}, data) : write(AddressRegister{index}, data); if(from.mode != AddressRegisterIndirectWithPreDecrement) addr += bytes(); } AddressRegister with{from.reg}; if(from.mode == AddressRegisterIndirectWithPreDecrement ) write(with, addr); if(from.mode == AddressRegisterIndirectWithPostIncrement) write(with, addr); } template auto M68K::instructionMOVEP(DataRegister from, EffectiveAddress to) -> void { auto address = fetch(to); auto data = read(from); uint shift = bits(); for(auto _ : range(bytes())) { shift -= 8; write(address, data >> shift); address += 2; } } template auto M68K::instructionMOVEP(EffectiveAddress from, DataRegister to) -> void { auto address = fetch(from); auto data = read(to); uint shift = bits(); for(auto _ : range(bytes())) { shift -= 8; data &= ~(0xff << shift); data |= read(address) << shift; address += 2; } write(to, data); } auto M68K::instructionMOVEQ(DataRegister dr, uint8 immediate) -> void { write(dr, sign(immediate)); r.c = 0; r.v = 0; r.z = clip(immediate) == 0; r.n = sign(immediate) < 0; } auto M68K::instructionMOVE_FROM_SR(EffectiveAddress ea) -> void { auto data = readSR(); write(ea, data); } auto M68K::instructionMOVE_TO_CCR(EffectiveAddress ea) -> void { auto data = read(ea); writeCCR(data); } auto M68K::instructionMOVE_TO_SR(EffectiveAddress ea) -> void { if(!supervisor()) return; auto data = read(ea); writeSR(data); } auto M68K::instructionMOVE_FROM_USP(AddressRegister to) -> void { if(!supervisor()) return; write(to, r.sp); } auto M68K::instructionMOVE_TO_USP(AddressRegister from) -> void { if(!supervisor()) return; r.sp = read(from); } auto M68K::instructionMULS(DataRegister with, EffectiveAddress from) -> void { auto source = read(from); auto target = read(with); auto result = (int16)source * (int16)target; write(with, result); r.c = 0; r.v = 0; r.z = clip(result) == 0; r.n = sign(result) < 0; } auto M68K::instructionMULU(DataRegister with, EffectiveAddress from) -> void { auto source = read(from); auto target = read(with); auto result = source * target; write(with, result); r.c = 0; r.v = 0; r.z = clip(result) == 0; r.n = sign(result) < 0; } auto M68K::instructionNBCD(EffectiveAddress with) -> void { auto source = 0u; auto target = read(with); auto result = target - source - r.x; bool v = false; const bool adjustLo = (target ^ source ^ result) & 0x10; const bool adjustHi = result & 0x100; if(adjustLo) { auto previous = result; result -= 0x06; v |= (previous & 0x80) & (~result & 0x80); } if(adjustHi) { auto previous = result; result -= 0x60; v |= (previous & 0x80) & (~result & 0x80); } write(with, result); r.c = sign(result >> 1) < 0; r.v = v; r.z = clip(result) ? 0 : r.z; r.n = sign(result) < 0; } template auto M68K::instructionNEG(EffectiveAddress with) -> void { auto result = SUB(read(with), 0); write(with, result); } template auto M68K::instructionNEGX(EffectiveAddress with) -> void { auto result = SUB(read(with), 0); write(with, result); } auto M68K::instructionNOP() -> void { } template auto M68K::instructionNOT(EffectiveAddress with) -> void { auto result = ~read(with); write(with, result); r.c = 0; r.v = 0; r.z = clip(result) == 0; r.n = sign(result) < 0; } template auto M68K::OR(uint32 source, uint32 target) -> uint32 { auto result = target | source; r.c = 0; r.v = 0; r.z = clip(result) == 0; r.n = sign(result) < 0; return clip(result); } template auto M68K::instructionOR(EffectiveAddress from, DataRegister with) -> void { auto source = read(from); auto target = read(with); auto result = OR(source, target); write(with, result); } template auto M68K::instructionOR(DataRegister from, EffectiveAddress with) -> void { auto source = read(from); auto target = read(with); auto result = OR(source, target); write(with, result); } template auto M68K::instructionORI(EffectiveAddress with) -> void { auto source = readPC(); auto target = read(with); auto result = OR(source, target); write(with, result); } auto M68K::instructionORI_TO_CCR() -> void { auto data = readPC(); writeCCR(readCCR() | data); } auto M68K::instructionORI_TO_SR() -> void { if(!supervisor()) return; auto data = readPC(); writeSR(readSR() | data); } auto M68K::instructionPEA(EffectiveAddress from) -> void { auto data = fetch(from); push(data); } auto M68K::instructionRESET() -> void { if(!supervisor()) return; r.reset = true; } template auto M68K::ROL(uint32 result, uint shift) -> uint32 { bool carry = false; for(auto _ : range(shift)) { carry = result & msb(); result = result << 1 | carry; } r.c = carry; r.v = 0; r.z = clip(result) == 0; r.n = sign(result) < 0; return clip(result); } template auto M68K::instructionROL(uint4 shift, DataRegister modify) -> void { auto result = ROL(read(modify), shift); write(modify, result); } template auto M68K::instructionROL(DataRegister shift, DataRegister modify) -> void { auto count = read(shift) & 63; auto result = ROL(read(modify), count); write(modify, result); } auto M68K::instructionROL(EffectiveAddress modify) -> void { auto result = ROL(read(modify), 1); write(modify, result); } template auto M68K::ROR(uint32 result, uint shift) -> uint32 { bool carry = false; for(auto _ : range(shift)) { carry = result & lsb(); result >>= 1; if(carry) result |= msb(); } r.c = carry; r.v = 0; r.z = clip(result) == 0; r.n = sign(result) < 0; return clip(result); } template auto M68K::instructionROR(uint4 shift, DataRegister modify) -> void { auto result = ROR(read(modify), shift); write(modify, result); } template auto M68K::instructionROR(DataRegister shift, DataRegister modify) -> void { auto count = read(shift) & 63; auto result = ROR(read(modify), count); write(modify, result); } auto M68K::instructionROR(EffectiveAddress modify) -> void { auto result = ROR(read(modify), 1); write(modify, result); } template auto M68K::ROXL(uint32 result, uint shift) -> uint32 { bool carry = r.x; for(auto _ : range(shift)) { bool extend = carry; carry = result & msb(); result = result << 1 | extend; } r.c = carry; r.v = 0; r.z = clip(result) == 0; r.n = sign(result) < 0; r.x = r.c; return clip(result); } template auto M68K::instructionROXL(uint4 shift, DataRegister modify) -> void { auto result = ROXL(read(modify), shift); write(modify, result); } template auto M68K::instructionROXL(DataRegister shift, DataRegister modify) -> void { auto count = read(shift) & 63; auto result = ROXL(read(modify), count); write(modify, result); } auto M68K::instructionROXL(EffectiveAddress modify) -> void { auto result = ROXL(read(modify), 1); write(modify, result); } template auto M68K::ROXR(uint32 result, uint shift) -> uint32 { bool carry = r.x; for(auto _ : range(shift)) { bool extend = carry; carry = result & lsb(); result >>= 1; if(extend) result |= msb(); } r.c = carry; r.v = 0; r.z = clip(result) == 0; r.n = sign(result) < 0; r.x = r.c; return clip(result); } template auto M68K::instructionROXR(uint4 shift, DataRegister modify) -> void { auto result = ROXR(read(modify), shift); write(modify, result); } template auto M68K::instructionROXR(DataRegister shift, DataRegister modify) -> void { auto count = read(shift) & 63; auto result = ROXR(read(modify), count); write(modify, result); } auto M68K::instructionROXR(EffectiveAddress modify) -> void { auto result = ROXR(read(modify), 1); write(modify, result); } auto M68K::instructionRTE() -> void { if(!supervisor()) return; auto sr = pop(); r.pc = pop(); writeSR(sr); } auto M68K::instructionRTR() -> void { writeCCR(pop()); r.pc = pop(); } auto M68K::instructionRTS() -> void { r.pc = pop(); } auto M68K::instructionSBCD(EffectiveAddress with, EffectiveAddress from) -> void { auto source = read(from); auto target = read(with); auto result = target - source - r.x; bool v = false; const bool adjustLo = (target ^ source ^ result) & 0x10; const bool adjustHi = result & 0x100; if(adjustLo) { auto previous = result; result -= 0x06; v |= (previous & 0x80) & (~result & 0x80); } if(adjustHi) { auto previous = result; result -= 0x60; v |= (previous & 0x80) & (~result & 0x80); } write(with, result); r.c = sign(result >> 1) < 0; r.v = v; r.z = clip(result) ? 0 : r.z; r.n = sign(result) < 0; } auto M68K::instructionSCC(uint4 condition, EffectiveAddress to) -> void { uint8 result = testCondition(condition) ? ~0 : 0; write(to, result); } auto M68K::instructionSTOP() -> void { if(!supervisor()) return; auto sr = readPC(); writeSR(sr); r.stop = true; } template auto M68K::SUB(uint32 source, uint32 target) -> uint32 { auto result = (uint64)target - source; if(Extend) result -= r.x; r.c = sign(result >> 1) < 0; r.v = sign((target ^ source) & (target ^ result)) < 0; r.z = clip(result) ? 0 : (Extend ? r.z : 1); r.n = sign(result) < 0; r.x = r.c; return result; } template auto M68K::instructionSUB(EffectiveAddress source_, DataRegister target_) -> void { auto source = read(source_); auto target = read(target_); auto result = SUB(source, target); write(target_, result); } template auto M68K::instructionSUB(DataRegister source_, EffectiveAddress target_) -> void { auto source = read(source_); auto target = read(target_); auto result = SUB(source, target); write(target_, result); } template auto M68K::instructionSUBA(AddressRegister to, EffectiveAddress from) -> void { auto source = sign(read(from)); auto target = read(to); write(to, target - source); } template auto M68K::instructionSUBI(EffectiveAddress with) -> void { auto source = readPC(); auto target = read(with); auto result = SUB(source, target); write(with, result); } template auto M68K::instructionSUBQ(uint4 immediate, EffectiveAddress with) -> void { auto source = immediate; auto target = read(with); auto result = SUB(source, target); write(with, result); } //Size is ignored: always uses Long template auto M68K::instructionSUBQ(uint4 immediate, AddressRegister with) -> void { auto result = read(with) - immediate; write(with, result); } template auto M68K::instructionSUBX(EffectiveAddress with, EffectiveAddress from) -> void { auto source = read(from); auto target = read(with); auto result = SUB(source, target); write(with, result); } auto M68K::instructionSWAP(DataRegister with) -> void { auto result = read(with); result = result >> 16 | result << 16; write(with, result); r.c = 0; r.v = 0; r.z = clip(result) == 0; r.n = sign(result) < 0; } auto M68K::instructionTAS(EffectiveAddress with) -> void { //auto data = read(with); //write(with, data | 0x80); //Mega Drive models 1&2 have a bug that prevents TAS write cycle from completing //this bugged behavior is required for certain software to function correctly auto data = read(with); r.c = 0; r.v = 0; r.z = clip(data) == 0; r.n = sign(data) < 0; } auto M68K::instructionTRAP(uint4 vector) -> void { exception(Exception::Trap, 32 + vector, r.i); } auto M68K::instructionTRAPV() -> void { if(r.v) exception(Exception::Overflow, Vector::Overflow); } template auto M68K::instructionTST(EffectiveAddress ea) -> void { auto data = read(ea); r.c = 0; r.v = 0; r.z = clip(data) == 0; r.n = sign(data) < 0; } auto M68K::instructionUNLK(AddressRegister with) -> void { auto sp = AddressRegister{7}; write(sp, read(with)); write(with, pop()); }