/* * This file is part of the 65816 Emulator Library. * Copyright (c) 2018 Francesco Rigoni. * * https://github.com/FrancescoRigoni/Lib65816 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "CpuStatus.hpp" #include "Log.hpp" #include "Binary.hpp" #define LOG_TAG "CpuStatus" /* ********************************************** * * Flags: * * b flag: the break flag * c flag: the carry flag * d flag: the decimal mode flag * e flag: the emulation mode flag * i flag: the interrupt disable flag * m flag: the accumulator and memory width flag * n flag: the negative flag * v flag: the overflow flag * x flag: the index register width flag * z flag: the zero flag * * **********************************************/ #define STATUS_CARRY 0x01 #define STATUS_ZERO 0x02 #define STATUS_INTERRUPT_DISABLE 0x04 #define STATUS_DECIMAL 0x08 // In emulation mode #define STATUS_BREAK 0X10 // In native mode (x = 0, 16 bit) #define STATUS_INDEX_WIDTH 0X10 // Only used in native mode #define STATUS_ACCUMULATOR_WIDTH 0X20 #define STATUS_OVERFLOW 0X40 #define STATUS_SIGN 0X80 CpuStatus::CpuStatus() { } void CpuStatus::setZeroFlag() { mZeroFlag = true; } void CpuStatus::setSignFlag() { mSignFlag = true; } void CpuStatus::setDecimalFlag() { mDecimalFlag = true; } void CpuStatus::setInterruptDisableFlag() { mInterruptDisableFlag = true; } void CpuStatus::setAccumulatorWidthFlag() { mAccumulatorWidthFlag = true; } void CpuStatus::setIndexWidthFlag() { mIndexWidthFlag = true; } void CpuStatus::setCarryFlag() { mCarryFlag = true; } void CpuStatus::setEmulationFlag() { mEmulationFlag = true; } void CpuStatus::clearZeroFlag() { mZeroFlag = false; } void CpuStatus::clearSignFlag() { mSignFlag = false; } void CpuStatus::clearDecimalFlag() { mDecimalFlag = false; } void CpuStatus::clearInterruptDisableFlag() { mInterruptDisableFlag = false; } void CpuStatus::clearAccumulatorWidthFlag() { mAccumulatorWidthFlag = false; } void CpuStatus::clearIndexWidthFlag() { mIndexWidthFlag = false; } void CpuStatus::clearCarryFlag() { mCarryFlag = false; } void CpuStatus::clearEmulationFlag() { mEmulationFlag = false; } bool CpuStatus::zeroFlag() { return mZeroFlag; } bool CpuStatus::signFlag() { return mSignFlag; } bool CpuStatus::decimalFlag() { return mDecimalFlag; } bool CpuStatus::interruptDisableFlag() { return mInterruptDisableFlag; } bool CpuStatus::accumulatorWidthFlag() { return mAccumulatorWidthFlag; } bool CpuStatus::indexWidthFlag() { return mIndexWidthFlag; } bool CpuStatus::carryFlag() { return mCarryFlag; } bool CpuStatus::emulationFlag() { return mEmulationFlag; } void CpuStatus::setBreakFlag() { mBreakFlag = true; } void CpuStatus::clearBreakFlag() { mBreakFlag = false; } bool CpuStatus::breakFlag() { return mBreakFlag; } void CpuStatus::setOverflowFlag() { mOverflowFlag = true; } void CpuStatus::clearOverflowFlag() { mOverflowFlag = false; } bool CpuStatus::overflowFlag() { return mOverflowFlag; } uint8_t CpuStatus::getRegisterValue() { uint8_t value = 0; if (carryFlag()) value |= STATUS_CARRY; if (zeroFlag()) value |= STATUS_ZERO; if (interruptDisableFlag()) value |= STATUS_INTERRUPT_DISABLE; if (decimalFlag()) value |= STATUS_DECIMAL; if (emulationFlag() && breakFlag()) value |= STATUS_BREAK; if (!emulationFlag() && indexWidthFlag()) value |= STATUS_INDEX_WIDTH; if (!emulationFlag() && accumulatorWidthFlag()) value |= STATUS_ACCUMULATOR_WIDTH; if (overflowFlag()) value |= STATUS_OVERFLOW; if (signFlag()) value |= STATUS_SIGN; return value; } void CpuStatus::setRegisterValue(uint8_t value) { if (value & STATUS_CARRY) setCarryFlag(); else clearCarryFlag(); if (value & STATUS_ZERO) setZeroFlag(); else clearZeroFlag(); if (value & STATUS_INTERRUPT_DISABLE) setInterruptDisableFlag(); else clearInterruptDisableFlag(); if (value & STATUS_DECIMAL) setDecimalFlag(); else clearDecimalFlag(); if (emulationFlag()) { if (value & STATUS_BREAK) setBreakFlag(); else clearBreakFlag(); } else { if (value & STATUS_INDEX_WIDTH) setIndexWidthFlag(); else clearIndexWidthFlag(); } if (!emulationFlag() && (value & STATUS_ACCUMULATOR_WIDTH)) setAccumulatorWidthFlag(); else clearAccumulatorWidthFlag(); if (value & STATUS_OVERFLOW) setOverflowFlag(); else clearOverflowFlag(); if (value & STATUS_SIGN) setSignFlag(); else clearSignFlag(); } void CpuStatus::updateZeroFlagFrom8BitValue(uint8_t value) { if (Binary::is8bitValueZero(value)) setZeroFlag(); else clearZeroFlag(); } void CpuStatus::updateZeroFlagFrom16BitValue(uint16_t value) { if (Binary::is16bitValueZero(value)) setZeroFlag(); else clearZeroFlag(); } void CpuStatus::updateSignFlagFrom8BitValue(uint8_t value) { if (Binary::is8bitValueNegative(value)) setSignFlag(); else clearSignFlag(); } void CpuStatus::updateSignFlagFrom16BitValue(uint16_t value) { if (Binary::is16bitValueNegative(value)) setSignFlag(); else clearSignFlag(); } void CpuStatus::updateSignAndZeroFlagFrom8BitValue(uint8_t value) { updateSignFlagFrom8BitValue(value); updateZeroFlagFrom8BitValue(value); } void CpuStatus::updateSignAndZeroFlagFrom16BitValue(uint16_t value) { updateSignFlagFrom16BitValue(value); updateZeroFlagFrom16BitValue(value); }