1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-23 20:29:42 +00:00

Makes an effort to factor out the 6502's [lazy] flags.

This is preparatory to deciding which instructions, if any, are worth factoring out.
This commit is contained in:
Thomas Harte 2020-10-05 22:23:33 -04:00
parent b7ba0d4327
commit 18e8d6ce06
12 changed files with 262 additions and 179 deletions

View File

@ -210,9 +210,9 @@
4B4B1A3D200198CA00A0F866 /* KonamiSCC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4B1A3A200198C900A0F866 /* KonamiSCC.cpp */; };
4B4DC8211D2C2425003C5BF8 /* Vic20.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DC81F1D2C2425003C5BF8 /* Vic20.cpp */; };
4B4DC82B1D2C27A4003C5BF8 /* SerialBus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DC8291D2C27A4003C5BF8 /* SerialBus.cpp */; };
4B4DEBED2522C03F004583AC /* 65816Base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DEBEC2522C03F004583AC /* 65816Base.cpp */; };
4B4DEBEE2522C03F004583AC /* 65816Base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DEBEC2522C03F004583AC /* 65816Base.cpp */; };
4B4DEBEF2522C03F004583AC /* 65816Base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DEBEC2522C03F004583AC /* 65816Base.cpp */; };
4B4DEC06252BFA56004583AC /* 65816Base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DEC05252BFA56004583AC /* 65816Base.cpp */; };
4B4DEC07252BFA56004583AC /* 65816Base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DEC05252BFA56004583AC /* 65816Base.cpp */; };
4B4DEC08252BFA56004583AC /* 65816Base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DEC05252BFA56004583AC /* 65816Base.cpp */; };
4B50AF80242817F40099BBD7 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B50AF7F242817F40099BBD7 /* QuartzCore.framework */; };
4B54C0BC1F8D8E790050900F /* KeyboardMachine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B54C0BB1F8D8E790050900F /* KeyboardMachine.cpp */; };
4B54C0BF1F8D8F450050900F /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B54C0BD1F8D8F450050900F /* Keyboard.cpp */; };
@ -1122,7 +1122,11 @@
4B4DC8271D2C2470003C5BF8 /* C1540.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = C1540.hpp; sourceTree = "<group>"; };
4B4DC8291D2C27A4003C5BF8 /* SerialBus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SerialBus.cpp; sourceTree = "<group>"; };
4B4DC82A1D2C27A4003C5BF8 /* SerialBus.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SerialBus.hpp; sourceTree = "<group>"; };
4B4DEBEC2522C03F004583AC /* 65816Base.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = 65816Base.cpp; path = ../../Processors/65816/Implementation/65816Base.cpp; sourceTree = "<group>"; };
4B4DEC04252BFA56004583AC /* 65816Implementation.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 65816Implementation.hpp; sourceTree = "<group>"; };
4B4DEC05252BFA56004583AC /* 65816Base.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 65816Base.cpp; sourceTree = "<group>"; };
4B4DEC16252BFA9C004583AC /* 6502Selector.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6502Selector.hpp; sourceTree = "<group>"; };
4B4DEC18252BFA9C004583AC /* 6502Esque.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6502Esque.hpp; sourceTree = "<group>"; };
4B4DEC19252BFB5A004583AC /* LazyFlags.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = LazyFlags.hpp; sourceTree = "<group>"; };
4B4F2B7024DF99D4000DA6B0 /* CSScanTarget+CppScanTarget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CSScanTarget+CppScanTarget.h"; sourceTree = "<group>"; };
4B50AF7F242817F40099BBD7 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
4B51F70920A521D700AFA2C1 /* Source.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Source.hpp; sourceTree = "<group>"; };
@ -1346,9 +1350,6 @@
4BAB62AE1D32730D00DF5BA0 /* Storage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Storage.hpp; sourceTree = "<group>"; };
4BAF2B4C2004580C00480230 /* DMK.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DMK.cpp; sourceTree = "<group>"; };
4BAF2B4D2004580C00480230 /* DMK.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = DMK.hpp; sourceTree = "<group>"; };
4BB023FF25212888009F8D90 /* 65816Implementation.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = 65816Implementation.hpp; path = ../../Processors/65816/Implementation/65816Implementation.hpp; sourceTree = "<group>"; };
4BB0240425229C6E009F8D90 /* 6502Esque.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = 6502Esque.hpp; sourceTree = "<group>"; };
4BB024092522B7BE009F8D90 /* 6502Selector.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = 6502Selector.hpp; sourceTree = "<group>"; };
4BB06B211F316A3F00600C7A /* ForceInline.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ForceInline.hpp; sourceTree = "<group>"; };
4BB0A6592044FD3000FB3688 /* SN76489.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SN76489.cpp; sourceTree = "<group>"; };
4BB0A65A2044FD3000FB3688 /* SN76489.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SN76489.hpp; sourceTree = "<group>"; };
@ -2463,6 +2464,24 @@
path = 1540;
sourceTree = "<group>";
};
4B4DEC15252BFA9C004583AC /* 6502Esque */ = {
isa = PBXGroup;
children = (
4B4DEC18252BFA9C004583AC /* 6502Esque.hpp */,
4B4DEC16252BFA9C004583AC /* 6502Selector.hpp */,
4B4DEC17252BFA9C004583AC /* Implementation */,
);
path = 6502Esque;
sourceTree = "<group>";
};
4B4DEC17252BFA9C004583AC /* Implementation */ = {
isa = PBXGroup;
children = (
4B4DEC19252BFB5A004583AC /* LazyFlags.hpp */,
);
path = Implementation;
sourceTree = "<group>";
};
4B51F70820A521D700AFA2C1 /* Activity */ = {
isa = PBXGroup;
children = (
@ -3337,8 +3356,6 @@
4BB73E951B587A5100552FC2 = {
isa = PBXGroup;
children = (
4B4DEBEC2522C03F004583AC /* 65816Base.cpp */,
4BB023FF25212888009F8D90 /* 65816Implementation.hpp */,
4B51F70820A521D700AFA2C1 /* Activity */,
4B8944E2201967B4007DE474 /* Analyser */,
4BB73EA01B587A5100552FC2 /* Clock Signal */,
@ -3496,11 +3513,10 @@
isa = PBXGroup;
children = (
4BFCA1211ECBDCAF00AC40C1 /* AllRAMProcessor.cpp */,
4BB0240425229C6E009F8D90 /* 6502Esque.hpp */,
4BB024092522B7BE009F8D90 /* 6502Selector.hpp */,
4BFCA1221ECBDCAF00AC40C1 /* AllRAMProcessor.hpp */,
4B2C455C1EC9442600FC74DD /* RegisterSizes.hpp */,
4B1414561B58879D00E04248 /* 6502 */,
4B4DEC15252BFA9C004583AC /* 6502Esque */,
4BF8D4CC251C0C9C00BBE21B /* 65816 */,
4BFF1D332233778C00838EA1 /* 68000 */,
4B77069E1EC9045B0053B588 /* Z80 */,
@ -3921,8 +3937,10 @@
4BF8D4D2251C0D9F00BBE21B /* Implementation */ = {
isa = PBXGroup;
children = (
4BF8D4D3251C0D9F00BBE21B /* 65816Storage.hpp */,
4B4DEC05252BFA56004583AC /* 65816Base.cpp */,
4BF8D4D4251C11DD00BBE21B /* 65816Storage.cpp */,
4B4DEC04252BFA56004583AC /* 65816Implementation.hpp */,
4BF8D4D3251C0D9F00BBE21B /* 65816Storage.hpp */,
);
path = Implementation;
sourceTree = "<group>";
@ -4503,7 +4521,7 @@
4BDACBED22FFA5D20045EF7E /* ncr5380.cpp in Sources */,
4BC131772346DE9100E4FF3D /* StaticAnalyser.cpp in Sources */,
4B055ACF1FAE9B030060FFFF /* SoundGenerator.cpp in Sources */,
4B4DEBEF2522C03F004583AC /* 65816Base.cpp in Sources */,
4B4DEC08252BFA56004583AC /* 65816Base.cpp in Sources */,
4B894519201967B4007DE474 /* ConfidenceCounter.cpp in Sources */,
4B055AEE1FAE9BBF0060FFFF /* Keyboard.cpp in Sources */,
4B055AED1FAE9BA20060FFFF /* Z80Storage.cpp in Sources */,
@ -4786,7 +4804,7 @@
4BEBFB4D2002C4BF000708CC /* MSXDSK.cpp in Sources */,
4BBFBB6C1EE8401E00C01E7A /* ZX8081.cpp in Sources */,
4B83348A1F5DB94B0097E338 /* IRQDelegatePortHandler.cpp in Sources */,
4B4DEBED2522C03F004583AC /* 65816Base.cpp in Sources */,
4B4DEC06252BFA56004583AC /* 65816Base.cpp in Sources */,
4B894524201967B4007DE474 /* Tape.cpp in Sources */,
4B7136891F78725F008B8ED9 /* Shifter.cpp in Sources */,
4BDB61EB2032806E0048AF91 /* CSAtari2600.mm in Sources */,
@ -4934,7 +4952,7 @@
4B778F4123A5F19A0000D260 /* MemoryPacker.cpp in Sources */,
4B778F4423A5F1BE0000D260 /* CommodoreGCR.cpp in Sources */,
4B778EF923A5EB740000D260 /* MSA.cpp in Sources */,
4B4DEBEE2522C03F004583AC /* 65816Base.cpp in Sources */,
4B4DEC07252BFA56004583AC /* 65816Base.cpp in Sources */,
4B778F2323A5EDE40000D260 /* Tape.cpp in Sources */,
4B778F4F23A5F21C0000D260 /* StaticAnalyser.cpp in Sources */,
4B778EEF23A5D6680000D260 /* AsyncTaskQueue.cpp in Sources */,

View File

@ -13,16 +13,19 @@
#include <cstdio>
#include <cstdint>
#include "../6502Esque/6502Esque.hpp"
#include "../6502Esque/Implementation/LazyFlags.hpp"
#include "../RegisterSizes.hpp"
#include "../../ClockReceiver/ClockReceiver.hpp"
#include "../6502Esque.hpp"
namespace CPU {
namespace MOS6502 {
// Adopt a bunch of things from MOS6502Esque.
using BusOperation = CPU::MOS6502Esque::BusOperation;
using BusHandler = CPU::MOS6502Esque::BusHandler<uint16_t>;
using Register = CPU::MOS6502Esque::Register;
using Flag = CPU::MOS6502Esque::Flag;
/*
The list of 6502 variants supported by this implementation.
@ -40,21 +43,6 @@ enum Personality {
#define has_bbrbbsrmbsmb(p) ((p) >= Personality::PRockwell65C02)
#define has_stpwai(p) ((p) >= Personality::PWDC65C02)
/*
Flags as defined on the 6502; can be used to decode the result of @c get_value_of_register(Flags) or to form a value for
the corresponding set.
*/
enum Flag: uint8_t {
Sign = 0x80,
Overflow = 0x40,
Always = 0x20,
Break = 0x10,
Decimal = 0x08,
Interrupt = 0x04,
Zero = 0x02,
Carry = 0x01
};
/*!
An opcode that is guaranteed to cause the CPU to jam.
*/

View File

@ -9,7 +9,7 @@
#ifndef MOS6502AllRAM_cpp
#define MOS6502AllRAM_cpp
#include "../../6502Selector.hpp"
#include "../../6502Esque/6502Selector.hpp"
#include "../../AllRAMProcessor.hpp"
namespace CPU {

View File

@ -13,7 +13,7 @@
*/
template <Personality personality, typename T, bool uses_ready_line> void Processor<personality, T, uses_ready_line>::run_for(const Cycles cycles) {
static uint8_t throwaway_target;
uint8_t throwaway_target;
// These plus program below act to give the compiler permission to update these values
// without touching the class storage (i.e. it explicitly says they need be completely up
@ -42,7 +42,7 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
#define bus_access() \
interrupt_requests_ = (interrupt_requests_ & ~InterruptRequestFlags::IRQ) | irq_request_history_; \
irq_request_history_ = irq_line_ & inverse_interrupt_flag_; \
irq_request_history_ = irq_line_ & flags_.inverse_interrupt; \
number_of_cycles -= bus_handler_.perform_bus_operation(nextBusOperation, busAddress, busValue); \
nextBusOperation = BusOperation::None; \
if(number_of_cycles <= Cycles(0)) break;
@ -70,7 +70,7 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
// Deal with a potential WAI state, if this 6502 implements WAI.
while(has_stpwai(personality) && wait_is_active_ && number_of_cycles > Cycles(0)) {
number_of_cycles -= bus_handler_.perform_bus_operation(BusOperation::Ready, busAddress, busValue);
interrupt_requests_ |= (irq_line_ & inverse_interrupt_flag_);
interrupt_requests_ |= (irq_line_ & flags_.inverse_interrupt);
if(interrupt_requests_ & InterruptRequestFlags::NMI || irq_line_) {
wait_is_active_ = false;
checkSchedule();
@ -167,25 +167,25 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
case CycleReadVectorLow: read_mem(pc_.halves.low, nextAddress.full); break;
case CycleReadVectorHigh: read_mem(pc_.halves.high, nextAddress.full+1); break;
case OperationSetIRQFlags:
inverse_interrupt_flag_ = 0;
if(is_65c02(personality)) decimal_flag_ = false;
flags_.inverse_interrupt = 0;
if(is_65c02(personality)) flags_.decimal = 0;
continue;
case OperationSetNMIRSTFlags:
if(is_65c02(personality)) decimal_flag_ = false;
if(is_65c02(personality)) flags_.decimal = 0;
continue;
case CyclePullPCL: s_++; read_mem(pc_.halves.low, s_ | 0x100); break;
case CyclePullPCH: s_++; read_mem(pc_.halves.high, s_ | 0x100); break;
case CyclePullA: s_++; read_mem(a_, s_ | 0x100); break;
case CyclePullX: s_++; read_mem(x_, s_ | 0x100); break;
case CyclePullY: s_++; read_mem(y_, s_ | 0x100); break;
case CyclePullOperand: s_++; read_mem(operand_, s_ | 0x100); break;
case OperationSetFlagsFromOperand: set_flags(operand_); continue;
case OperationSetOperandFromFlagsWithBRKSet: operand_ = get_flags() | Flag::Break; continue;
case OperationSetOperandFromFlags: operand_ = get_flags(); continue;
case OperationSetFlagsFromA: zero_result_ = negative_result_ = a_; continue;
case OperationSetFlagsFromX: zero_result_ = negative_result_ = x_; continue;
case OperationSetFlagsFromY: zero_result_ = negative_result_ = y_; continue;
case CyclePullPCL: s_++; read_mem(pc_.halves.low, s_ | 0x100); break;
case CyclePullPCH: s_++; read_mem(pc_.halves.high, s_ | 0x100); break;
case CyclePullA: s_++; read_mem(a_, s_ | 0x100); break;
case CyclePullX: s_++; read_mem(x_, s_ | 0x100); break;
case CyclePullY: s_++; read_mem(y_, s_ | 0x100); break;
case CyclePullOperand: s_++; read_mem(operand_, s_ | 0x100); break;
case OperationSetFlagsFromOperand: set_flags(operand_); continue;
case OperationSetOperandFromFlagsWithBRKSet: operand_ = flags_.get() | Flag::Break; continue;
case OperationSetOperandFromFlags: operand_ = flags_.get(); continue;
case OperationSetFlagsFromA: flags_.set_nz(a_); continue;
case OperationSetFlagsFromX: flags_.set_nz(x_); continue;
case OperationSetFlagsFromY: flags_.set_nz(y_); continue;
case CycleIncrementPCAndReadStack: pc_.full++; throwaway_read(s_ | 0x100); break;
case CycleReadPCLFromAddress: read_mem(pc_.halves.low, address_.full); break;
@ -216,17 +216,17 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
// MARK: - Bitwise
case OperationORA: a_ |= operand_; negative_result_ = zero_result_ = a_; continue;
case OperationAND: a_ &= operand_; negative_result_ = zero_result_ = a_; continue;
case OperationEOR: a_ ^= operand_; negative_result_ = zero_result_ = a_; continue;
case OperationORA: a_ |= operand_; flags_.set_nz(a_); continue;
case OperationAND: a_ &= operand_; flags_.set_nz(a_); continue;
case OperationEOR: a_ ^= operand_; flags_.set_nz(a_); continue;
// MARK: - Load and Store
case OperationLDA: a_ = negative_result_ = zero_result_ = operand_; continue;
case OperationLDX: x_ = negative_result_ = zero_result_ = operand_; continue;
case OperationLDY: y_ = negative_result_ = zero_result_ = operand_; continue;
case OperationLAX: a_ = x_ = negative_result_ = zero_result_ = operand_; continue;
case OperationCopyOperandToA: a_ = operand_; continue;
case OperationLDA: flags_.set_nz(a_ = operand_); continue;
case OperationLDX: flags_.set_nz(x_ = operand_); continue;
case OperationLDY: flags_.set_nz(y_ = operand_); continue;
case OperationLAX: flags_.set_nz(a_ = x_ = operand_); continue;
case OperationCopyOperandToA: a_ = operand_; continue;
case OperationSTA: operand_ = a_; continue;
case OperationSTX: operand_ = x_; continue;
@ -240,43 +240,43 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
case OperationLXA:
a_ = x_ = (a_ | 0xee) & operand_;
negative_result_ = zero_result_ = a_;
flags_.set_nz(a_);
continue;
// MARK: - Compare
case OperationCMP: {
const uint16_t temp16 = a_ - operand_;
negative_result_ = zero_result_ = uint8_t(temp16);
carry_flag_ = ((~temp16) >> 8)&1;
flags_.set_nz(uint8_t(temp16));
flags_.carry = ((~temp16) >> 8)&1;
} continue;
case OperationCPX: {
const uint16_t temp16 = x_ - operand_;
negative_result_ = zero_result_ = uint8_t(temp16);
carry_flag_ = ((~temp16) >> 8)&1;
flags_.set_nz(uint8_t(temp16));
flags_.carry = ((~temp16) >> 8)&1;
} continue;
case OperationCPY: {
const uint16_t temp16 = y_ - operand_;
negative_result_ = zero_result_ = uint8_t(temp16);
carry_flag_ = ((~temp16) >> 8)&1;
flags_.set_nz(uint8_t(temp16));
flags_.carry = ((~temp16) >> 8)&1;
} continue;
// MARK: - BIT, TSB, TRB
case OperationBIT:
zero_result_ = operand_ & a_;
negative_result_ = operand_;
overflow_flag_ = operand_&Flag::Overflow;
flags_.zero_result = operand_ & a_;
flags_.negative_result = operand_;
flags_.overflow = operand_ & Flag::Overflow;
continue;
case OperationBITNoNV:
zero_result_ = operand_ & a_;
flags_.zero_result = operand_ & a_;
continue;
case OperationTRB:
zero_result_ = operand_ & a_;
flags_.zero_result = operand_ & a_;
operand_ &= ~a_;
continue;
case OperationTSB:
zero_result_ = operand_ & a_;
flags_.zero_result = operand_ & a_;
operand_ |= a_;
continue;
@ -295,8 +295,8 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
operand_++;
[[fallthrough]];
case OperationSBC:
if(decimal_flag_ && has_decimal_mode(personality)) {
const uint16_t notCarry = carry_flag_ ^ 0x1;
if(flags_.decimal && has_decimal_mode(personality)) {
const uint16_t notCarry = flags_.carry ^ 0x1;
const uint16_t decimalResult = uint16_t(a_) - uint16_t(operand_) - notCarry;
uint16_t temp16;
@ -305,17 +305,17 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
temp16 = (temp16&0x0f) | ((temp16 > 0x0f) ? 0xfff0 : 0x00);
temp16 += (a_&0xf0) - (operand_&0xf0);
overflow_flag_ = ( ( (decimalResult^a_)&(~decimalResult^operand_) )&0x80) >> 1;
negative_result_ = uint8_t(temp16);
zero_result_ = uint8_t(decimalResult);
flags_.overflow = ( ( (decimalResult^a_)&(~decimalResult^operand_) )&0x80) >> 1;
flags_.negative_result = uint8_t(temp16);
flags_.zero_result = uint8_t(decimalResult);
if(temp16 > 0xff) temp16 -= 0x60;
carry_flag_ = (temp16 > 0xff) ? 0 : Flag::Carry;
flags_.carry = (temp16 > 0xff) ? 0 : Flag::Carry;
a_ = uint8_t(temp16);
if(is_65c02(personality)) {
negative_result_ = zero_result_ = a_;
flags_.set_nz(a_);
read_mem(operand_, address_.full);
break;
}
@ -326,30 +326,30 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
[[fallthrough]];
case OperationADC:
if(decimal_flag_ && has_decimal_mode(personality)) {
const uint16_t decimalResult = uint16_t(a_) + uint16_t(operand_) + uint16_t(carry_flag_);
if(flags_.decimal && has_decimal_mode(personality)) {
const uint16_t decimalResult = uint16_t(a_) + uint16_t(operand_) + uint16_t(flags_.carry);
uint8_t low_nibble = (a_ & 0xf) + (operand_ & 0xf) + carry_flag_;
uint8_t low_nibble = (a_ & 0xf) + (operand_ & 0xf) + flags_.carry;
if(low_nibble >= 0xa) low_nibble = ((low_nibble + 0x6) & 0xf) + 0x10;
uint16_t result = uint16_t(a_ & 0xf0) + uint16_t(operand_ & 0xf0) + uint16_t(low_nibble);
negative_result_ = uint8_t(result);
overflow_flag_ = (( (result^a_)&(result^operand_) )&0x80) >> 1;
flags_.negative_result = uint8_t(result);
flags_.overflow = (( (result^a_)&(result^operand_) )&0x80) >> 1;
if(result >= 0xa0) result += 0x60;
carry_flag_ = (result >> 8) ? 1 : 0;
flags_.carry = (result >> 8) ? 1 : 0;
a_ = uint8_t(result);
zero_result_ = uint8_t(decimalResult);
flags_.zero_result = uint8_t(decimalResult);
if(is_65c02(personality)) {
negative_result_ = zero_result_ = a_;
flags_.set_nz(a_);
read_mem(operand_, address_.full);
break;
}
} else {
const uint16_t result = uint16_t(a_) + uint16_t(operand_) + uint16_t(carry_flag_);
overflow_flag_ = (( (result^a_)&(result^operand_) )&0x80) >> 1;
negative_result_ = zero_result_ = a_ = uint8_t(result);
carry_flag_ = (result >> 8)&1;
const uint16_t result = uint16_t(a_) + uint16_t(operand_) + uint16_t(flags_.carry);
flags_.overflow = (( (result^a_)&(result^operand_) )&0x80) >> 1;
flags_.set_nz(a_ = uint8_t(result));
flags_.carry = (result >> 8)&1;
}
// fix up in case this was INS
@ -359,99 +359,99 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
// MARK: - Shifts and Rolls
case OperationASL:
carry_flag_ = operand_ >> 7;
flags_.carry = operand_ >> 7;
operand_ <<= 1;
negative_result_ = zero_result_ = operand_;
flags_.set_nz(operand_);
continue;
case OperationASO:
carry_flag_ = operand_ >> 7;
flags_.carry = operand_ >> 7;
operand_ <<= 1;
a_ |= operand_;
negative_result_ = zero_result_ = a_;
flags_.set_nz(a_);
continue;
case OperationROL: {
const uint8_t temp8 = uint8_t((operand_ << 1) | carry_flag_);
carry_flag_ = operand_ >> 7;
operand_ = negative_result_ = zero_result_ = temp8;
const uint8_t temp8 = uint8_t((operand_ << 1) | flags_.carry);
flags_.carry = operand_ >> 7;
flags_.set_nz(operand_ = temp8);
} continue;
case OperationRLA: {
const uint8_t temp8 = uint8_t((operand_ << 1) | carry_flag_);
carry_flag_ = operand_ >> 7;
const uint8_t temp8 = uint8_t((operand_ << 1) | flags_.carry);
flags_.carry = operand_ >> 7;
operand_ = temp8;
a_ &= operand_;
negative_result_ = zero_result_ = a_;
flags_.set_nz(a_);
} continue;
case OperationLSR:
carry_flag_ = operand_ & 1;
flags_.carry = operand_ & 1;
operand_ >>= 1;
negative_result_ = zero_result_ = operand_;
flags_.set_nz(operand_);
continue;
case OperationLSE:
carry_flag_ = operand_ & 1;
flags_.carry = operand_ & 1;
operand_ >>= 1;
a_ ^= operand_;
negative_result_ = zero_result_ = a_;
flags_.set_nz(a_);
continue;
case OperationASR:
a_ &= operand_;
carry_flag_ = a_ & 1;
flags_.carry = a_ & 1;
a_ >>= 1;
negative_result_ = zero_result_ = a_;
flags_.set_nz(a_);
continue;
case OperationROR: {
const uint8_t temp8 = uint8_t((operand_ >> 1) | (carry_flag_ << 7));
carry_flag_ = operand_ & 1;
operand_ = negative_result_ = zero_result_ = temp8;
const uint8_t temp8 = uint8_t((operand_ >> 1) | (flags_.carry << 7));
flags_.carry = operand_ & 1;
flags_.set_nz(operand_ = temp8);
} continue;
case OperationRRA: {
const uint8_t temp8 = uint8_t((operand_ >> 1) | (carry_flag_ << 7));
carry_flag_ = operand_ & 1;
const uint8_t temp8 = uint8_t((operand_ >> 1) | (flags_.carry << 7));
flags_.carry = operand_ & 1;
operand_ = temp8;
} continue;
case OperationDecrementOperand: operand_--; continue;
case OperationIncrementOperand: operand_++; continue;
case OperationCLC: carry_flag_ = 0; continue;
case OperationCLI: inverse_interrupt_flag_ = Flag::Interrupt; continue;
case OperationCLV: overflow_flag_ = 0; continue;
case OperationCLD: decimal_flag_ = 0; continue;
case OperationCLC: flags_.carry = 0; continue;
case OperationCLI: flags_.inverse_interrupt = Flag::Interrupt; continue;
case OperationCLV: flags_.overflow = 0; continue;
case OperationCLD: flags_.decimal = 0; continue;
case OperationSEC: carry_flag_ = Flag::Carry; continue;
case OperationSEI: inverse_interrupt_flag_ = 0; continue;
case OperationSED: decimal_flag_ = Flag::Decimal; continue;
case OperationSEC: flags_.carry = Flag::Carry; continue;
case OperationSEI: flags_.inverse_interrupt = 0; continue;
case OperationSED: flags_.decimal = Flag::Decimal; continue;
case OperationINC: operand_++; negative_result_ = zero_result_ = operand_; continue;
case OperationDEC: operand_--; negative_result_ = zero_result_ = operand_; continue;
case OperationINA: a_++; negative_result_ = zero_result_ = a_; continue;
case OperationDEA: a_--; negative_result_ = zero_result_ = a_; continue;
case OperationINX: x_++; negative_result_ = zero_result_ = x_; continue;
case OperationDEX: x_--; negative_result_ = zero_result_ = x_; continue;
case OperationINY: y_++; negative_result_ = zero_result_ = y_; continue;
case OperationDEY: y_--; negative_result_ = zero_result_ = y_; continue;
case OperationINC: operand_++; flags_.set_nz(operand_); continue;
case OperationDEC: operand_--; flags_.set_nz(operand_); continue;
case OperationINA: a_++; flags_.set_nz(a_); continue;
case OperationDEA: a_--; flags_.set_nz(a_); continue;
case OperationINX: x_++; flags_.set_nz(x_); continue;
case OperationDEX: x_--; flags_.set_nz(x_); continue;
case OperationINY: y_++; flags_.set_nz(y_); continue;
case OperationDEY: y_--; flags_.set_nz(y_); continue;
case OperationANE:
a_ = (a_ | 0xee) & operand_ & x_;
negative_result_ = zero_result_ = a_;
flags_.set_nz(a_);
continue;
case OperationANC:
a_ &= operand_;
negative_result_ = zero_result_ = a_;
carry_flag_ = a_ >> 7;
flags_.set_nz(a_);
flags_.carry = a_ >> 7;
continue;
case OperationLAS:
a_ = x_ = s_ = s_ & operand_;
negative_result_ = zero_result_ = a_;
flags_.set_nz(a_);
continue;
// MARK: - Addressing Mode Work
@ -548,7 +548,7 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
throwaway_read(operand_);
break;
case OperationIncrementPC: pc_.full++; continue;
case OperationIncrementPC: pc_.full++; continue;
case CycleFetchOperandFromAddress: read_mem(operand_, address_.full); break;
case CycleWriteOperandToAddress: write_mem(operand_, address_.full); break;
@ -560,14 +560,14 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
scheduled_program_counter_ = operations_[size_t(OperationsSlot::DoBRA)]; \
}
case OperationBPL: BRA(!(negative_result_&0x80)); continue;
case OperationBMI: BRA(negative_result_&0x80); continue;
case OperationBVC: BRA(!overflow_flag_); continue;
case OperationBVS: BRA(overflow_flag_); continue;
case OperationBCC: BRA(!carry_flag_); continue;
case OperationBCS: BRA(carry_flag_); continue;
case OperationBNE: BRA(zero_result_); continue;
case OperationBEQ: BRA(!zero_result_); continue;
case OperationBPL: BRA(!(flags_.negative_result&0x80)); continue;
case OperationBMI: BRA(flags_.negative_result&0x80); continue;
case OperationBVC: BRA(!flags_.overflow); continue;
case OperationBVS: BRA(flags_.overflow); continue;
case OperationBCC: BRA(!flags_.carry); continue;
case OperationBCS: BRA(flags_.carry); continue;
case OperationBNE: BRA(flags_.zero_result); continue;
case OperationBEQ: BRA(!flags_.zero_result); continue;
case OperationBRA: BRA(true); continue;
#undef BRA
@ -610,31 +610,31 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
// MARK: - Transfers
case OperationTXA: zero_result_ = negative_result_ = a_ = x_; continue;
case OperationTYA: zero_result_ = negative_result_ = a_ = y_; continue;
case OperationTXS: s_ = x_; continue;
case OperationTAY: zero_result_ = negative_result_ = y_ = a_; continue;
case OperationTAX: zero_result_ = negative_result_ = x_ = a_; continue;
case OperationTSX: zero_result_ = negative_result_ = x_ = s_; continue;
case OperationTXA: flags_.set_nz(a_ = x_); continue;
case OperationTYA: flags_.set_nz(a_ = y_); continue;
case OperationTXS: s_ = x_; continue;
case OperationTAY: flags_.set_nz(y_ = a_); continue;
case OperationTAX: flags_.set_nz(x_ = a_); continue;
case OperationTSX: flags_.set_nz(x_ = s_); continue;
case OperationARR:
if(decimal_flag_) {
if(flags_.decimal) {
a_ &= operand_;
uint8_t unshiftedA = a_;
a_ = uint8_t((a_ >> 1) | (carry_flag_ << 7));
zero_result_ = negative_result_ = a_;
overflow_flag_ = (a_^(a_ << 1))&Flag::Overflow;
a_ = uint8_t((a_ >> 1) | (flags_.carry << 7));
flags_.set_nz(a_);
flags_.overflow = (a_^(a_ << 1))&Flag::Overflow;
if((unshiftedA&0xf) + (unshiftedA&0x1) > 5) a_ = ((a_ + 6)&0xf) | (a_ & 0xf0);
carry_flag_ = ((unshiftedA&0xf0) + (unshiftedA&0x10) > 0x50) ? 1 : 0;
if(carry_flag_) a_ += 0x60;
flags_.carry = ((unshiftedA&0xf0) + (unshiftedA&0x10) > 0x50) ? 1 : 0;
if(flags_.carry) a_ += 0x60;
} else {
a_ &= operand_;
a_ = uint8_t((a_ >> 1) | (carry_flag_ << 7));
negative_result_ = zero_result_ = a_;
carry_flag_ = (a_ >> 6)&1;
overflow_flag_ = (a_^(a_ << 1))&Flag::Overflow;
a_ = uint8_t((a_ >> 1) | (flags_.carry << 7));
flags_.set_nz(a_);
flags_.carry = (a_ >> 6)&1;
flags_.overflow = (a_^(a_ << 1))&Flag::Overflow;
}
continue;
@ -642,8 +642,8 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
x_ &= a_;
uint16_t difference = x_ - operand_;
x_ = uint8_t(difference);
negative_result_ = zero_result_ = x_;
carry_flag_ = ((difference >> 8)&1)^1;
flags_.set_nz(x_);
flags_.carry = ((difference >> 8)&1)^1;
continue;
}
@ -691,13 +691,13 @@ void ProcessorBase::set_power_on(bool active) {
}
void ProcessorBase::set_irq_line(bool active) {
irq_line_ = active ? Flag::Interrupt : 0;
irq_line_ = active ? MOS6502Esque::Flag::Interrupt : 0;
}
void ProcessorBase::set_overflow_line(bool active) {
// a leading edge will set the overflow flag
if(active && !set_overflow_line_is_enabled_)
overflow_flag_ = Flag::Overflow;
flags_.overflow = MOS6502Esque::Flag::Overflow;
set_overflow_line_is_enabled_ = active;
}
@ -709,14 +709,9 @@ void ProcessorBase::set_nmi_line(bool active) {
}
uint8_t ProcessorStorage::get_flags() const {
return carry_flag_ | overflow_flag_ | (inverse_interrupt_flag_ ^ Flag::Interrupt) | (negative_result_ & 0x80) | (zero_result_ ? 0 : Flag::Zero) | Flag::Always | decimal_flag_;
return flags_.get();
}
void ProcessorStorage::set_flags(uint8_t flags) {
carry_flag_ = flags & Flag::Carry;
negative_result_ = flags & Flag::Sign;
zero_result_ = (~flags) & Flag::Zero;
overflow_flag_ = flags & Flag::Overflow;
inverse_interrupt_flag_ = (~flags) & Flag::Interrupt;
decimal_flag_ = flags & Flag::Decimal;
flags_.set(flags);
}

View File

@ -76,12 +76,6 @@ using namespace CPU::MOS6502;
#define JAM {CycleFetchOperand, OperationScheduleJam}
ProcessorStorage::ProcessorStorage(Personality personality) {
// only the interrupt flag is defined upon reset but get_flags isn't going to
// mask the other flags so we need to do that, at least
carry_flag_ &= Flag::Carry;
decimal_flag_ &= Flag::Decimal;
overflow_flag_ &= Flag::Overflow;
const InstructionList operations_6502[] = {
/* 0x00 BRK */ Program(CycleIncPCPushPCH, CyclePushPCL, OperationBRKPickVector, OperationSetOperandFromFlagsWithBRKSet, CyclePushOperand, OperationSetIRQFlags, CycleReadVectorLow, CycleReadVectorHigh),
/* 0x01 ORA x, ind */ IndexedIndirectRead(OperationORA),

View File

@ -228,7 +228,7 @@ class ProcessorStorage {
*/
RegisterPair16 pc_, last_operation_pc_;
uint8_t a_, x_, y_, s_ = 0;
uint8_t carry_flag_, negative_result_, zero_result_, decimal_flag_, overflow_flag_, inverse_interrupt_flag_ = 0;
MOS6502Esque::LazyFlags flags_;
/*
Temporary state for the micro programs.
@ -267,7 +267,7 @@ class ProcessorStorage {
enum InterruptRequestFlags: uint8_t {
Reset = 0x80,
IRQ = Flag::Interrupt,
IRQ = MOS6502Esque::Flag::Interrupt,
NMI = 0x20,
PowerOn = 0x10,

View File

@ -9,6 +9,8 @@
#ifndef m6502Esque_h
#define m6502Esque_h
#include "../../ClockReceiver/ClockReceiver.hpp"
/*
This file defines how the CPU-controlled part of a bus looks for the 6502 and
for other processors with a sufficiently-similar bus.
@ -35,6 +37,21 @@ enum Register {
Y
};
/*
Flags as defined on the 6502; can be used to decode the result of @c get_value_of_register(Flags) or to form a value for
the corresponding set.
*/
enum Flag: uint8_t {
Sign = 0x80,
Overflow = 0x40,
Always = 0x20,
Break = 0x10,
Decimal = 0x08,
Interrupt = 0x04,
Zero = 0x02,
Carry = 0x01
};
/*!
Bus handlers will be given the task of performing bus operations, allowing them to provide whatever interface they like
between a 6502 and the rest of the system. @c BusOperation lists the types of bus operation that may be requested.

View File

@ -9,8 +9,8 @@
#ifndef _502Selector_h
#define _502Selector_h
#include "6502/6502.hpp"
#include "65816/65816.hpp"
#include "../6502/6502.hpp"
#include "../65816/65816.hpp"
namespace CPU {
namespace MOS6502Esque {

View File

@ -0,0 +1,66 @@
//
// LazyFlags.hpp
// Clock Signal
//
// Created by Thomas Harte on 05/10/2020.
// Copyright © 2020 Thomas Harte. All rights reserved.
//
#ifndef LazyFlags_h
#define LazyFlags_h
#include "../6502Esque.hpp"
namespace CPU {
namespace MOS6502Esque {
struct LazyFlags {
/// Bit 7 is set if the negative flag is set; otherwise it is clear.
uint8_t negative_result;
/// Non-zero if the zero flag is clear, zero if it is set.
uint8_t zero_result;
/// Contains Flag::Carry.
uint8_t carry;
/// Contains Flag::Decimal.
uint8_t decimal;
/// Contains Flag::Overflow.
uint8_t overflow;
/// Contains Flag::Interrupt, complemented.
uint8_t inverse_interrupt = 0;
void set_nz(uint8_t value) {
zero_result = negative_result = value;
}
void set(uint8_t flags) {
carry = flags & Flag::Carry;
negative_result = flags & Flag::Sign;
zero_result = (~flags) & Flag::Zero;
overflow = flags & Flag::Overflow;
inverse_interrupt = (~flags) & Flag::Interrupt;
decimal = flags & Flag::Decimal;
}
uint8_t get() const {
return carry | overflow | (inverse_interrupt ^ Flag::Interrupt) | (negative_result & 0x80) | (zero_result ? 0 : Flag::Zero) | Flag::Always | decimal;
}
LazyFlags() {
// Only the interrupt flag is defined upon reset but get_flags isn't going to
// mask the other flags so we need to do that, at least.
carry &= Flag::Carry;
decimal &= Flag::Decimal;
overflow &= Flag::Overflow;
}
};
}
}
#endif /* LazyFlags_h */

View File

@ -0,0 +1,3 @@
# 6502Esque
This folder contains common code for CPUs for a 6502-esque bus interface; it also contains a special template, the 6502Selector, which allows a consumer to select between the 6502-esque chips by enum.

View File

@ -16,7 +16,7 @@
#include "../RegisterSizes.hpp"
#include "../../ClockReceiver/ClockReceiver.hpp"
#include "../6502Esque.hpp"
#include "../6502Esque/6502Esque.hpp"
namespace CPU {
namespace WDC65816 {

View File

@ -372,8 +372,10 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
}
break;
// default:
// assert(false);
// TODO: OperationCopyPBRToData, OperationPrepareException
default:
assert(false);
}
number_of_cycles -= bus_handler_.perform_bus_operation(bus_operation, bus_address, bus_value);