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::bits() -> uint { return 8; } template<> auto M68K::bits() -> uint { return 16; } template<> auto M68K::bits() -> uint { return 32; } 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; } template auto M68K::carry(uint32 result, uint32 source) -> bool { return clip(result) < clip(source); } template auto M68K::overflow(uint32 result, uint32 source, uint32 target) -> bool { return sign((target ^ source) & (target ^ result)) < 0; } template auto M68K::zero(uint32 result) -> bool { return clip(result) == 0; } template auto M68K::negative(uint32 result) -> bool { return sign(result) < 0; } // template auto M68K::instructionADD(DataRegister dr, uint1 direction, EffectiveAddress ea) -> void { uint32 source; uint32 target; uint32 result; if(direction == 0) { source = read(ea); target = read(dr); result = source + target; write(dr, result); } else { source = read(dr); target = read(ea); result = source + target; write(ea, result); } r.c = carry(result, source); r.v = overflow(result, source, target); r.z = zero(result); r.n = negative(result); r.x = r.c; } template auto M68K::instructionANDI(EffectiveAddress ea) -> void { auto source = readPC(); auto target = read(ea); auto result = target & source; write(ea, result); r.c = 0; r.v = 0; r.z = zero(result); r.n = negative(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); } auto M68K::instructionBCC(uint4 condition, uint8 displacement) -> void { auto extension = readPC(); if(condition == 1) push(r.pc); r.pc -= 2; if(condition >= 2 && !testCondition(condition)) return; //0 = BRA; 1 = BSR r.pc += displacement ? sign(displacement) : sign(extension); } template auto M68K::instructionBTST(DataRegister dr, EffectiveAddress ea) -> void { auto bit = read(dr); auto test = read(ea); bit &= bits() - 1; r.z = test.bit(bit) == 0; } template auto M68K::instructionBTST(EffectiveAddress ea) -> void { auto bit = (uint8)readPC(); auto test = read(ea); bit &= bits() - 1; r.z = test.bit(bit) == 0; } 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::instructionCMP(DataRegister dr, EffectiveAddress ea) -> void { auto source = read(ea); auto target = read(dr); auto result = target - source; r.c = carry(result, source); r.v = overflow(result, source, target); r.z = zero(result); r.n = negative(result); } auto M68K::instructionDBCC(uint4 condition, DataRegister dr) -> void { auto displacement = (int16)readPC(); if(!testCondition(condition)) { uint16 result = read(dr); write(dr, result - 1); if(result) r.pc -= 2, r.pc += displacement; } } 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::instructionLEA(AddressRegister ar, EffectiveAddress ea) -> void { write(ar, fetch(ea)); } template auto M68K::instructionMOVE(EffectiveAddress to, EffectiveAddress from) -> void { auto data = read(from); write(to, data); r.c = 0; r.v = 0; r.z = zero(data); r.n = negative(data); } template auto M68K::instructionMOVEA(AddressRegister ar, EffectiveAddress ea) -> void { auto data = read(ea); write(ar, data); } template auto M68K::instructionMOVEM(uint1 direction, EffectiveAddress ea) -> void { auto list = readPC(); auto addr = fetch(ea); for(uint n : range(8)) { if(!list.bit(0 + n)) continue; write(DataRegister{n}, read(addr)); addr += Size == Long ? 4 : 2; } for(uint n : range(8)) { if(!list.bit(8 + n)) continue; write(AddressRegister{n}, read(addr)); addr += Size == Long ? 4 : 2; } flush(ea, addr); } auto M68K::instructionMOVEQ(DataRegister dr, uint8 immediate) -> void { write(dr, immediate); r.c = 0; r.v = 0; r.z = zero(immediate); r.n = negative(immediate); } 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_USP(uint1 direction, AddressRegister ar) -> void { if(!supervisor()) return; if(direction == 0) { r.sp = read(ar); } else { write(ar, r.sp); } } auto M68K::instructionNOP() -> void { } 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::instructionRTS() -> void { r.pc = pop(); } template auto M68K::instructionTST(EffectiveAddress ea) -> void { auto data = read(ea); r.c = 0; r.v = 0; r.z = zero(data); r.n = negative(data); }