Lib65816/src/CpuStatus.cpp

256 lines
6.3 KiB
C++

/*
* 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 <http://www.gnu.org/licenses/>.
*/
#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);
}