// instructions.c // Definition of all instruction functions, handling effect of instruction and flags. #include"instructions.h" struct State state; // Load and Store Instructions void PageBoundary(Addressing r) { switch(r) { case eAbsoluteIndexedX: if ((state.address & 0xFF00) != ((state.address + X) & 0xFF00)) state.cycles++; break; case eAbsoluteIndexedY: if ((state.address & 0xFF00) != ((state.address + Y) & 0xFF00)) state.cycles++; break; case eIndirectIndexed: if ((state.address & 0xFF00) != (state.address - Y & 0xFF00)) state.cycles++; break; case eRelative: // Assuming that this goes at the end of the break function. if ((PC & 0xFF00) != ((PC - (char)state.value) & 0xFF00)) state.cycles++; break; } } void LDA(Addressing addr){ acc = state.value; SetFlag_N(acc); SetFlag_Z(acc); PageBoundary(addr); } void LDX(Addressing addr){ X = state.value; SetFlag_N(X); SetFlag_Z(X); PageBoundary(addr); } void LDY(Addressing addr){ Y = state.value; SetFlag_N(Y); SetFlag_Z(Y); PageBoundary(addr); } void STA(Addressing addr){ SetMemory(state.address, acc); } void STX(Addressing addr){ SetMemory(state.address, X); } void STY(Addressing addr){ SetMemory(state.address, Y); } // Arithmetic Instructions // TODO: Add BCD arithmetic modes. void ADC(Addressing addr){ byte buffer = acc + state.value + GetFlag(flag_C); SetFlag_V(buffer, acc); SetFlag(flag_C, (buffer < acc) ? 1 : 0); acc = buffer; SetFlag_N(acc); SetFlag_Z(acc); PageBoundary(addr); } void SBC(Addressing addr){ byte buffer = acc - state.value - !GetFlag(flag_C); SetFlag_V(buffer, acc); SetFlag(flag_C, (buffer > acc) ? 0 : 1); acc = buffer; SetFlag_N(acc); SetFlag_Z(acc); PageBoundary(addr); } //Increment and Decrement Instructions void INC(Addressing addr){ byte a = state.value; SetMemory(state.address, ++a); SetFlag_N(a); SetFlag_Z(a); } void INX(Addressing addr){ X++; SetFlag_N(X); SetFlag_Z(X); } void INY(Addressing addr){ Y++; SetFlag_N(Y); SetFlag_Z(Y); } void DEC(Addressing addr){ byte a = state.value; SetMemory(state.address, --a); SetFlag_N(a); SetFlag_Z(a); } void DEX(Addressing addr){ X--; SetFlag_N(X); SetFlag_Z(X); } void DEY(Addressing addr){ Y--; SetFlag_N(Y); SetFlag_Z(Y); } // Logical Instructions void AND(Addressing addr){ acc &= state.value; SetFlag_N(acc); SetFlag_Z(acc); PageBoundary(addr); } void ORA(Addressing addr){ acc |= state.value; SetFlag_N(acc); SetFlag_Z(acc); PageBoundary(addr); } void EOR(Addressing addr){ acc ^= state.value; SetFlag_N(acc); SetFlag_Z(acc); PageBoundary(addr); } // Jump, Branch, Compare, and Test Bits void JMP(Addressing addr){ PC = state.address - state.length; } void BCC(Addressing addr){ if (GetFlag(flag_C) == 0) { PC += (char)state.value; state.cycles++; PageBoundary(addr); } } void BCS(Addressing addr){ if (GetFlag(flag_C) == 1) { PC += (char)state.value; state.cycles++; PageBoundary(addr); } } void BEQ(Addressing addr){ if (GetFlag(flag_Z) == 1) { PC += (char)state.value; state.cycles++; PageBoundary(addr); } } void BNE(Addressing addr){ if (GetFlag(flag_Z) == 0) { PC += (char)state.value; state.cycles++; PageBoundary(addr); } } void BMI(Addressing addr){ if (GetFlag(flag_N) == 1) { PC += (char)state.value; state.cycles++; PageBoundary(addr); } } void BPL(Addressing addr){ if (GetFlag(flag_N) == 0) { PC += (char)state.value; state.cycles++; PageBoundary(addr); } } void BVS(Addressing addr){ if (GetFlag(flag_V) == 1) { PC += (char)state.value; state.cycles++; PageBoundary(addr); } } void BVC(Addressing addr){ if (GetFlag(flag_V) == 0) { PC += (char)state.value; state.cycles++; PageBoundary(addr); } } void CMP(Addressing addr){ SetFlag(flag_C, (acc >= state.value) ? 1 : 0); SetFlag(flag_Z, (acc == state.value) ? 1 : 0); SetFlag(flag_N, (acc < state.value) ? 1 : 0); PageBoundary(addr); } void CPX(Addressing addr){ SetFlag(flag_C, (X >= state.value) ? 1 : 0); SetFlag(flag_Z, (X == state.value) ? 1 : 0); SetFlag(flag_N, (X < state.value) ? 1 : 0); } void CPY(Addressing addr){ SetFlag(flag_C, (Y >= state.value) ? 1 : 0); SetFlag(flag_Z, (Y == state.value) ? 1 : 0); SetFlag(flag_N, (Y < state.value) ? 1 : 0); } void BIT(Addressing addr){ SetFlag(flag_N, ((state.value & flag_N) != 0)); SetFlag(flag_V, ((state.value & flag_V) != 0)); SetFlag(flag_Z, ((state.value & acc) == 0)); } // Shift and Rotate Instructions void ASL(Addressing addr){ byte m = (addr == eAccumulator) ? acc : state.value; SetFlag(flag_C, (m & 0b10000000)); m = (m << 1) & 0b11111110; SetFlag_N(m); SetFlag_Z(m); (addr == eAccumulator) ? acc = m : SetMemory(state.address, m); } void LSR(Addressing addr) { byte m = (addr == eAccumulator) ? acc : state.value; SetFlag(flag_C, (m & 0b00000001)); m = (m >> 1) & 0b01111111; SetFlag_N(m); SetFlag_Z(m); (addr == eAccumulator) ? acc = m : SetMemory(state.address, m); } void ROL(Addressing addr){ byte m = (addr == eAccumulator) ? acc : state.value; byte flag_store = (m & 0b10000000); m = (m << 1) & 0b11111110; m |= (GetFlag(flag_C)) ? 0b00000001 : 0; SetFlag(flag_C, flag_store); SetFlag_N(m); SetFlag_Z(m); (addr == eAccumulator) ? acc = m : SetMemory(state.address, m); } void ROR(Addressing addr){ byte m = (addr == eAccumulator) ? acc : state.value; byte flag_store = (m & 0b00000001); m = (m >> 1) & 0b01111111; m |= (GetFlag(flag_C)) ? 0b10000000 : 0; SetFlag(flag_C, flag_store); SetFlag_N(m); SetFlag_Z(m); (addr == eAccumulator) ? acc = m : SetMemory(state.address, m); } // Transfer Instructions void TAX(Addressing addr){ X = acc; SetFlag_N(X); SetFlag_Z(X); } void TAY(Addressing addr){ Y = acc; SetFlag_N(Y); SetFlag_Z(Y); } void TXA(Addressing addr){ acc = X; SetFlag_N(acc); SetFlag_Z(acc); } void TYA(Addressing addr){ acc = Y; SetFlag_N(acc); SetFlag_Z(acc); } // Stack Instructions void TSX(Addressing addr){ X = S; } void TXS(Addressing addr){ S = X; } void PHA(Addressing addr){ SetStack(acc); } void PHP(Addressing addr){ SetStack(P); } void PLA(Addressing addr){ acc = GetStack(); } void PLP(Addressing addr){ P = GetStack(); } // Subroutine Instructions void JSR(Addressing addr){ SetStack ((PC+state.length) >> 8); SetStack(((PC+state.length) & 0x00FF) - 1); PC = state.address; PC -= state.length; } void RTS(Addressing addr){ PC = (address)(GetStack()) + 1; PC += ((address)(GetStack())) << 8; PC -= state.length; } void RTI(Addressing addr){ P = GetStack(); PC = (address)(GetStack()); PC += (address)(GetStack() << 8); } // Set/Reset Insutrctions void CLC(Addressing addr){ SetFlag(flag_C, 0); } void CLD(Addressing addr){ SetFlag(flag_D, 0); } void CLI(Addressing addr){ SetFlag(flag_I, 0); } void CLV(Addressing addr){ SetFlag(flag_V, 0); } void SEC(Addressing addr){ SetFlag(flag_C, 1); } void SED(Addressing addr){ SetFlag(flag_D, 1); } void SEI(Addressing addr){ SetFlag(flag_I, 1); } // NOP/BRK Instructions void NOP(Addressing addr){ } void BRK(Addressing addr){ SetStack((((PC+2) & 0xFF00) >> 8)); SetStack((PC+2) & 0x00FF); SetStack(P); PC = (address)(GetMemory(0xFFFE)); PC += ((address)(GetMemory(0xFFFF)) << 8); }