mirror of
				https://github.com/TomHarte/CLK.git
				synced 2025-11-04 00:16:26 +00:00 
			
		
		
		
	Merge branch 'master' into BBCNew6502
This commit is contained in:
		@@ -120,7 +120,7 @@ void testExecution(NSDictionary *test, BusHandler &handler) {
 | 
				
			|||||||
				instruction.operation == CPU::MOS6502Mk2::Operation::SBC
 | 
									instruction.operation == CPU::MOS6502Mk2::Operation::SBC
 | 
				
			||||||
			) &&
 | 
								) &&
 | 
				
			||||||
			instruction.mode == CPU::MOS6502Mk2::AddressingMode::Immediate &&
 | 
								instruction.mode == CPU::MOS6502Mk2::AddressingMode::Immediate &&
 | 
				
			||||||
			processor.registers().flags.decimal;
 | 
								processor.registers().flags.template get<CPU::MOS6502Mk2::Flag::Decimal>();
 | 
				
			||||||
		ignore_addresses[3] = instruction.mode == CPU::MOS6502Mk2::AddressingMode::JMPAbsoluteIndexedIndirect;
 | 
							ignore_addresses[3] = instruction.mode == CPU::MOS6502Mk2::AddressingMode::JMPAbsoluteIndexedIndirect;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -169,7 +169,7 @@ void testExecution(NSDictionary *test, BusHandler &handler) {
 | 
				
			|||||||
		auto repeat_processor = make_processor<model>(test, handler);
 | 
							auto repeat_processor = make_processor<model>(test, handler);
 | 
				
			||||||
		const bool should_interrupt =
 | 
							const bool should_interrupt =
 | 
				
			||||||
			instruction.operation != CPU::MOS6502Mk2::Operation::BRK &&
 | 
								instruction.operation != CPU::MOS6502Mk2::Operation::BRK &&
 | 
				
			||||||
			repeat_processor.registers().flags.inverse_interrupt;
 | 
								!repeat_processor.registers().flags.template get<CPU::MOS6502Mk2::Flag::Interrupt>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			repeat_processor.run_for(Cycles(last_length - 1));
 | 
								repeat_processor.run_for(Cycles(last_length - 1));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,11 +42,12 @@ void Processor<model, Traits>::run_for(const Cycles cycles) {
 | 
				
			|||||||
	};
 | 
						};
 | 
				
			||||||
	const auto check_interrupt = [&] {
 | 
						const auto check_interrupt = [&] {
 | 
				
			||||||
		Storage::captured_interrupt_requests_ =
 | 
							Storage::captured_interrupt_requests_ =
 | 
				
			||||||
			Storage::inputs_.interrupt_requests &
 | 
								Storage::inputs_.interrupt_requests & Storage::registers_.flags.interrupt_mask();
 | 
				
			||||||
				(Storage::registers_.flags.inverse_interrupt | ~InterruptRequest::IRQ);
 | 
					 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	#define restore_point()	(__COUNTER__ + int(ResumePoint::Max) + int(AddressingMode::Max))
 | 
						// This is a header file, so exclusive use of the counter can't be guaranteed; adjust for that via FirstCounter.
 | 
				
			||||||
 | 
						static constexpr auto FirstCounter = __COUNTER__;
 | 
				
			||||||
 | 
						#define restore_point()	(__COUNTER__ - FirstCounter + int(ResumePoint::Max) + int(AddressingMode::Max))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	#define join(a, b)			a##b
 | 
						#define join(a, b)			a##b
 | 
				
			||||||
	#define attach(a, b)		join(a, b)
 | 
						#define attach(a, b)		join(a, b)
 | 
				
			||||||
@@ -109,12 +110,12 @@ void Processor<model, Traits>::run_for(const Cycles cycles) {
 | 
				
			|||||||
			(
 | 
								(
 | 
				
			||||||
				Storage::decoded_.operation == Operation::ADC ||
 | 
									Storage::decoded_.operation == Operation::ADC ||
 | 
				
			||||||
				Storage::decoded_.operation == Operation::SBC
 | 
									Storage::decoded_.operation == Operation::SBC
 | 
				
			||||||
			) && registers.flags.decimal;
 | 
								) && registers.flags.template get<Flag::Decimal>();
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	const auto set_interrupt_flag = [&] {
 | 
						const auto set_interrupt_flag = [&] {
 | 
				
			||||||
		registers.flags.inverse_interrupt = 0;
 | 
							registers.flags.template set_per<Flag::InverseInterrupt>(0);
 | 
				
			||||||
		if constexpr (is_65c02(model)) {
 | 
							if constexpr (is_65c02(model)) {
 | 
				
			||||||
			registers.flags.decimal = 0;
 | 
								registers.flags.template set_per<Flag::Decimal>(0);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,29 +21,30 @@ namespace Operations {
 | 
				
			|||||||
template <typename RegistersT>
 | 
					template <typename RegistersT>
 | 
				
			||||||
void ane(RegistersT ®isters, const uint8_t operand) {
 | 
					void ane(RegistersT ®isters, const uint8_t operand) {
 | 
				
			||||||
	registers.a = (registers.a | 0xee) & operand & registers.x;
 | 
						registers.a = (registers.a | 0xee) & operand & registers.x;
 | 
				
			||||||
	registers.flags.set_nz(registers.a);
 | 
						registers.flags.template set_per<Flag::NegativeZero>(registers.a);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename RegistersT>
 | 
					template <typename RegistersT>
 | 
				
			||||||
void anc(RegistersT ®isters, const uint8_t operand) {
 | 
					void anc(RegistersT ®isters, const uint8_t operand) {
 | 
				
			||||||
	registers.a &= operand;
 | 
						registers.a &= operand;
 | 
				
			||||||
	registers.flags.set_nz(registers.a);
 | 
						registers.flags.template set_per<Flag::NegativeZero>(registers.a);
 | 
				
			||||||
	registers.flags.carry = registers.a >> 7;
 | 
						registers.flags.template set_per<Flag::Carry>(registers.a >> 7);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <Model model, typename RegistersT>
 | 
					template <Model model, typename RegistersT>
 | 
				
			||||||
void adc(RegistersT ®isters, const uint8_t operand) {
 | 
					void adc(RegistersT ®isters, const uint8_t operand) {
 | 
				
			||||||
	uint8_t result = registers.a + operand + registers.flags.carry;
 | 
						uint8_t result = registers.a + operand + registers.flags.carry_value();
 | 
				
			||||||
	registers.flags.carry = result < registers.a + registers.flags.carry;
 | 
						uint8_t carry = result < registers.a + registers.flags.carry_value();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(!has_decimal_mode(model) || !registers.flags.decimal) {
 | 
						if(!has_decimal_mode(model) || !registers.flags.template get<Flag::Decimal>()) {
 | 
				
			||||||
		registers.flags.set_v(result, registers.a, operand);
 | 
							registers.flags.set_overflow(result, registers.a, operand);
 | 
				
			||||||
		registers.flags.set_nz(registers.a = result);
 | 
							registers.flags.template set_per<Flag::NegativeZero>(registers.a = result);
 | 
				
			||||||
 | 
							registers.flags.template set_per<Flag::Carry>(carry);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if constexpr (!is_65c02(model)) {
 | 
						if constexpr (!is_65c02(model)) {
 | 
				
			||||||
		registers.flags.zero_result = result;
 | 
							registers.flags.template set_per<Flag::Zero>(result);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// General ADC logic:
 | 
						// General ADC logic:
 | 
				
			||||||
@@ -60,46 +61,47 @@ void adc(RegistersT ®isters, const uint8_t operand) {
 | 
				
			|||||||
	if(Numeric::carried_in<4>(registers.a, operand, result)) {
 | 
						if(Numeric::carried_in<4>(registers.a, operand, result)) {
 | 
				
			||||||
		result = (result & 0xf0) | ((result + 0x06) & 0x0f);
 | 
							result = (result & 0xf0) | ((result + 0x06) & 0x0f);
 | 
				
			||||||
	} else if((result & 0xf) > 0x9) {
 | 
						} else if((result & 0xf) > 0x9) {
 | 
				
			||||||
		registers.flags.carry |= result >= 0x100 - 0x6;
 | 
							carry |= result >= 0x100 - 0x6;
 | 
				
			||||||
		result += 0x06;
 | 
							result += 0x06;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 6502 quirk: N and V are set before the full result is computed but
 | 
						// 6502 quirk: N and V are set before the full result is computed but
 | 
				
			||||||
	// after the low nibble has been corrected.
 | 
						// after the low nibble has been corrected.
 | 
				
			||||||
	if constexpr (!is_65c02(model)) {
 | 
						if constexpr (!is_65c02(model)) {
 | 
				
			||||||
		registers.flags.negative_result = result;
 | 
							registers.flags.template set_per<Flag::Negative>(result);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	registers.flags.set_v(result, registers.a, operand);
 | 
						registers.flags.set_overflow(result, registers.a, operand);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// i.e. fix high nibble if there was carry out of bit 7 already, or if the
 | 
						// i.e. fix high nibble if there was carry out of bit 7 already, or if the
 | 
				
			||||||
	// top nibble is too large (in which case there will be carry after the fix-up).
 | 
						// top nibble is too large (in which case there will be carry after the fix-up).
 | 
				
			||||||
	registers.flags.carry |= result >= 0xa0;
 | 
						carry |= result >= 0xa0;
 | 
				
			||||||
	if(registers.flags.carry) {
 | 
						if(carry) {
 | 
				
			||||||
		result += 0x60;
 | 
							result += 0x60;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	registers.a = result;
 | 
						registers.a = result;
 | 
				
			||||||
 | 
						registers.flags.template set_per<Flag::Carry>(carry);
 | 
				
			||||||
	if constexpr (is_65c02(model)) {
 | 
						if constexpr (is_65c02(model)) {
 | 
				
			||||||
		registers.flags.set_nz(registers.a);
 | 
							registers.flags.template set_per<Flag::NegativeZero>(registers.a);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <Model model, typename RegistersT>
 | 
					template <Model model, typename RegistersT>
 | 
				
			||||||
void sbc(RegistersT ®isters, const uint8_t operand) {
 | 
					void sbc(RegistersT ®isters, const uint8_t operand) {
 | 
				
			||||||
	if(!has_decimal_mode(model) || !registers.flags.decimal) {
 | 
						if(!has_decimal_mode(model) || !registers.flags.template get<Flag::Decimal>()) {
 | 
				
			||||||
		adc<Model::NES6502>(registers, ~operand);	// Lie about the model to carry forward the fact of not-decimal.
 | 
							adc<Model::NES6502>(registers, ~operand);	// Lie about the model to carry forward the fact of not-decimal.
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const uint8_t operand_complement = ~operand;
 | 
						const uint8_t operand_complement = ~operand;
 | 
				
			||||||
	uint8_t result = registers.a + operand_complement + registers.flags.carry;
 | 
						uint8_t result = registers.a + operand_complement + registers.flags.carry_value();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// All flags are set based only on the decimal result.
 | 
						// All flags are set based only on the decimal result.
 | 
				
			||||||
	registers.flags.carry = result < registers.a + registers.flags.carry;
 | 
						uint8_t carry = result < registers.a + registers.flags.carry_value();
 | 
				
			||||||
	if constexpr (!is_65c02(model)) {
 | 
						if constexpr (!is_65c02(model)) {
 | 
				
			||||||
		registers.flags.set_nz(result);
 | 
							registers.flags.template set_per<Flag::NegativeZero>(result);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	registers.flags.set_v(result, registers.a, operand_complement);
 | 
						registers.flags.set_overflow(result, registers.a, operand_complement);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// General SBC logic:
 | 
						// General SBC logic:
 | 
				
			||||||
	//
 | 
						//
 | 
				
			||||||
@@ -122,13 +124,14 @@ void sbc(RegistersT ®isters, const uint8_t operand) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// The top nibble is adjusted only if there was borrow out of the whole byte.
 | 
						// The top nibble is adjusted only if there was borrow out of the whole byte.
 | 
				
			||||||
	if(!registers.flags.carry) {
 | 
						if(!carry) {
 | 
				
			||||||
		result += 0xa0;
 | 
							result += 0xa0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	registers.a = result;
 | 
						registers.a = result;
 | 
				
			||||||
 | 
						registers.flags.template set_per<Flag::Carry>(carry);
 | 
				
			||||||
	if constexpr (is_65c02(model)) {
 | 
						if constexpr (is_65c02(model)) {
 | 
				
			||||||
		registers.flags.set_nz(registers.a);
 | 
							registers.flags.template set_per<Flag::NegativeZero>(registers.a);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -136,123 +139,124 @@ template <Model model, typename RegistersT>
 | 
				
			|||||||
void arr(RegistersT ®isters, const uint8_t operand) {
 | 
					void arr(RegistersT ®isters, const uint8_t operand) {
 | 
				
			||||||
	registers.a &= operand;
 | 
						registers.a &= operand;
 | 
				
			||||||
	const uint8_t unshifted_a = registers.a;
 | 
						const uint8_t unshifted_a = registers.a;
 | 
				
			||||||
	registers.a = uint8_t((registers.a >> 1) | (registers.flags.carry << 7));
 | 
						registers.a = uint8_t((registers.a >> 1) | (registers.flags.carry_value() << 7));
 | 
				
			||||||
	registers.flags.set_nz(registers.a);
 | 
						registers.flags.template set_per<Flag::NegativeZero>(registers.a);
 | 
				
			||||||
	registers.flags.overflow = (registers.a^(registers.a << 1))&Flag::Overflow;
 | 
						registers.flags.template set_per<Flag::Overflow>(uint8_t(registers.a ^ (registers.a << 1)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(registers.flags.decimal && has_decimal_mode(model)) {
 | 
						if(registers.flags.template get<Flag::Decimal>() && has_decimal_mode(model)) {
 | 
				
			||||||
		if((unshifted_a&0xf) + (unshifted_a&0x1) > 5) registers.a = ((registers.a + 6)&0xf) | (registers.a & 0xf0);
 | 
							if((unshifted_a&0xf) + (unshifted_a&0x1) > 5) registers.a = ((registers.a + 6)&0xf) | (registers.a & 0xf0);
 | 
				
			||||||
		registers.flags.carry = ((unshifted_a&0xf0) + (unshifted_a&0x10) > 0x50) ? 1 : 0;
 | 
							const uint8_t carry = ((unshifted_a&0xf0) + (unshifted_a&0x10) > 0x50) ? 1 : 0;
 | 
				
			||||||
		if(registers.flags.carry) registers.a += 0x60;
 | 
							if(carry) registers.a += 0x60;
 | 
				
			||||||
 | 
							registers.flags.template set_per<Flag::Carry>(carry);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		registers.flags.carry = (registers.a >> 6)&1;
 | 
							registers.flags.template set_per<Flag::Carry>((registers.a >> 6)&1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename RegistersT>
 | 
					template <typename RegistersT>
 | 
				
			||||||
void sbx(RegistersT ®isters, const uint8_t operand) {
 | 
					void sbx(RegistersT ®isters, const uint8_t operand) {
 | 
				
			||||||
	registers.x &= registers.a;
 | 
						registers.x &= registers.a;
 | 
				
			||||||
	registers.flags.carry = operand <= registers.x;
 | 
						registers.flags.template set_per<Flag::Carry>(operand <= registers.x);
 | 
				
			||||||
	registers.x -= operand;
 | 
						registers.x -= operand;
 | 
				
			||||||
	registers.flags.set_nz(registers.x);
 | 
						registers.flags.template set_per<Flag::NegativeZero>(registers.x);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename RegistersT>
 | 
					template <typename RegistersT>
 | 
				
			||||||
void asl(RegistersT ®isters, uint8_t &operand) {
 | 
					void asl(RegistersT ®isters, uint8_t &operand) {
 | 
				
			||||||
	registers.flags.carry = operand >> 7;
 | 
						registers.flags.template set_per<Flag::Carry>(operand >> 7);
 | 
				
			||||||
	operand <<= 1;
 | 
						operand <<= 1;
 | 
				
			||||||
	registers.flags.set_nz(operand);
 | 
						registers.flags.template set_per<Flag::NegativeZero>(operand);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename RegistersT>
 | 
					template <typename RegistersT>
 | 
				
			||||||
void aso(RegistersT ®isters, uint8_t &operand) {
 | 
					void aso(RegistersT ®isters, uint8_t &operand) {
 | 
				
			||||||
	registers.flags.carry = operand >> 7;
 | 
						registers.flags.template set_per<Flag::Carry>(operand >> 7);
 | 
				
			||||||
	operand <<= 1;
 | 
						operand <<= 1;
 | 
				
			||||||
	registers.a |= operand;
 | 
						registers.a |= operand;
 | 
				
			||||||
	registers.flags.set_nz(registers.a);
 | 
						registers.flags.template set_per<Flag::NegativeZero>(registers.a);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename RegistersT>
 | 
					template <typename RegistersT>
 | 
				
			||||||
void rol(RegistersT ®isters, uint8_t &operand) {
 | 
					void rol(RegistersT ®isters, uint8_t &operand) {
 | 
				
			||||||
	const uint8_t temp8 = uint8_t((operand << 1) | registers.flags.carry);
 | 
						const uint8_t temp8 = uint8_t((operand << 1) | registers.flags.carry_value());
 | 
				
			||||||
	registers.flags.carry = operand >> 7;
 | 
						registers.flags.template set_per<Flag::Carry>(operand >> 7);
 | 
				
			||||||
	registers.flags.set_nz(operand = temp8);
 | 
						registers.flags.template set_per<Flag::NegativeZero>(operand = temp8);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename RegistersT>
 | 
					template <typename RegistersT>
 | 
				
			||||||
void rla(RegistersT ®isters, uint8_t &operand) {
 | 
					void rla(RegistersT ®isters, uint8_t &operand) {
 | 
				
			||||||
	const uint8_t temp8 = uint8_t((operand << 1) | registers.flags.carry);
 | 
						const uint8_t temp8 = uint8_t((operand << 1) | registers.flags.carry_value());
 | 
				
			||||||
	registers.flags.carry = operand >> 7;
 | 
						registers.flags.template set_per<Flag::Carry>(operand >> 7);
 | 
				
			||||||
	operand = temp8;
 | 
						operand = temp8;
 | 
				
			||||||
	registers.a &= operand;
 | 
						registers.a &= operand;
 | 
				
			||||||
	registers.flags.set_nz(registers.a);
 | 
						registers.flags.template set_per<Flag::NegativeZero>(registers.a);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename RegistersT>
 | 
					template <typename RegistersT>
 | 
				
			||||||
void lsr(RegistersT ®isters, uint8_t &operand) {
 | 
					void lsr(RegistersT ®isters, uint8_t &operand) {
 | 
				
			||||||
	registers.flags.carry = operand & 1;
 | 
						registers.flags.template set_per<Flag::Carry>(operand & 1);
 | 
				
			||||||
	operand >>= 1;
 | 
						operand >>= 1;
 | 
				
			||||||
	registers.flags.set_nz(operand);
 | 
						registers.flags.template set_per<Flag::NegativeZero>(operand);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename RegistersT>
 | 
					template <typename RegistersT>
 | 
				
			||||||
void lse(RegistersT ®isters, uint8_t &operand) {
 | 
					void lse(RegistersT ®isters, uint8_t &operand) {
 | 
				
			||||||
	registers.flags.carry = operand & 1;
 | 
						registers.flags.template set_per<Flag::Carry>(operand & 1);
 | 
				
			||||||
	operand >>= 1;
 | 
						operand >>= 1;
 | 
				
			||||||
	registers.a ^= operand;
 | 
						registers.a ^= operand;
 | 
				
			||||||
	registers.flags.set_nz(registers.a);
 | 
						registers.flags.template set_per<Flag::NegativeZero>(registers.a);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename RegistersT>
 | 
					template <typename RegistersT>
 | 
				
			||||||
void asr(RegistersT ®isters, uint8_t &operand) {
 | 
					void asr(RegistersT ®isters, uint8_t &operand) {
 | 
				
			||||||
	registers.a &= operand;
 | 
						registers.a &= operand;
 | 
				
			||||||
	registers.flags.carry = registers.a & 1;
 | 
						registers.flags.template set_per<Flag::Carry>(registers.a & 1);
 | 
				
			||||||
	registers.a >>= 1;
 | 
						registers.a >>= 1;
 | 
				
			||||||
	registers.flags.set_nz(registers.a);
 | 
						registers.flags.template set_per<Flag::NegativeZero>(registers.a);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename RegistersT>
 | 
					template <typename RegistersT>
 | 
				
			||||||
void ror(RegistersT ®isters, uint8_t &operand) {
 | 
					void ror(RegistersT ®isters, uint8_t &operand) {
 | 
				
			||||||
	const uint8_t temp8 = uint8_t((operand >> 1) | (registers.flags.carry << 7));
 | 
						const uint8_t temp8 = uint8_t((operand >> 1) | (registers.flags.carry_value() << 7));
 | 
				
			||||||
	registers.flags.carry = operand & 1;
 | 
						registers.flags.template set_per<Flag::Carry>(operand & 1);
 | 
				
			||||||
	registers.flags.set_nz(operand = temp8);
 | 
						registers.flags.template set_per<Flag::NegativeZero>(operand = temp8);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <Model model, typename RegistersT>
 | 
					template <Model model, typename RegistersT>
 | 
				
			||||||
void rra(RegistersT ®isters, uint8_t &operand) {
 | 
					void rra(RegistersT ®isters, uint8_t &operand) {
 | 
				
			||||||
	const uint8_t temp8 = uint8_t((operand >> 1) | (registers.flags.carry << 7));
 | 
						const uint8_t temp8 = uint8_t((operand >> 1) | (registers.flags.carry_value() << 7));
 | 
				
			||||||
	registers.flags.carry = operand & 1;
 | 
						registers.flags.template set_per<Flag::Carry>(operand & 1);
 | 
				
			||||||
	Operations::adc<model>(registers, temp8);
 | 
						Operations::adc<model>(registers, temp8);
 | 
				
			||||||
	operand = temp8;
 | 
						operand = temp8;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename RegistersT>
 | 
					template <typename RegistersT>
 | 
				
			||||||
void compare(RegistersT ®isters, const uint8_t lhs, const uint8_t rhs) {
 | 
					void compare(RegistersT ®isters, const uint8_t lhs, const uint8_t rhs) {
 | 
				
			||||||
	registers.flags.carry = rhs <= lhs;
 | 
						registers.flags.template set_per<Flag::Carry>(rhs <= lhs);
 | 
				
			||||||
	registers.flags.set_nz(lhs - rhs);
 | 
						registers.flags.template set_per<Flag::NegativeZero>(lhs - rhs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename RegistersT>
 | 
					template <typename RegistersT>
 | 
				
			||||||
void bit(RegistersT ®isters, const uint8_t operand) {
 | 
					void bit(RegistersT ®isters, const uint8_t operand) {
 | 
				
			||||||
	registers.flags.zero_result = operand & registers.a;
 | 
						registers.flags.template set_per<Flag::Zero>(operand & registers.a);
 | 
				
			||||||
	registers.flags.negative_result = operand;
 | 
						registers.flags.template set_per<Flag::Negative>(operand);
 | 
				
			||||||
	registers.flags.overflow = operand & Flag::Overflow;
 | 
						registers.flags.template set_per<Flag::Overflow>(operand);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename RegistersT>
 | 
					template <typename RegistersT>
 | 
				
			||||||
void bit_no_nv(RegistersT ®isters, const uint8_t operand) {
 | 
					void bit_no_nv(RegistersT ®isters, const uint8_t operand) {
 | 
				
			||||||
	registers.flags.zero_result = operand & registers.a;
 | 
						registers.flags.template set_per<Flag::Zero>(operand & registers.a);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename RegistersT>
 | 
					template <typename RegistersT>
 | 
				
			||||||
void trb(RegistersT ®isters, uint8_t &operand) {
 | 
					void trb(RegistersT ®isters, uint8_t &operand) {
 | 
				
			||||||
	registers.flags.zero_result = operand & registers.a;
 | 
						registers.flags.template set_per<Flag::Zero>(operand & registers.a);
 | 
				
			||||||
	operand &= ~registers.a;
 | 
						operand &= ~registers.a;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename RegistersT>
 | 
					template <typename RegistersT>
 | 
				
			||||||
void tsb(RegistersT ®isters, uint8_t &operand) {
 | 
					void tsb(RegistersT ®isters, uint8_t &operand) {
 | 
				
			||||||
	registers.flags.zero_result = operand & registers.a;
 | 
						registers.flags.template set_per<Flag::Zero>(operand & registers.a);
 | 
				
			||||||
	operand |= registers.a;
 | 
						operand |= registers.a;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -309,14 +313,14 @@ bool test(const Operation operation, RegistersT ®isters) {
 | 
				
			|||||||
		default:
 | 
							default:
 | 
				
			||||||
			__builtin_unreachable();
 | 
								__builtin_unreachable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case Operation::BPL: return !(registers.flags.negative_result & 0x80);
 | 
							case Operation::BPL: return !registers.flags.template get<Flag::Negative>();
 | 
				
			||||||
		case Operation::BMI: return registers.flags.negative_result & 0x80;
 | 
							case Operation::BMI: return registers.flags.template get<Flag::Negative>();
 | 
				
			||||||
		case Operation::BVC: return !registers.flags.overflow;
 | 
							case Operation::BVC: return !registers.flags.template get<Flag::Overflow>();
 | 
				
			||||||
		case Operation::BVS: return registers.flags.overflow;
 | 
							case Operation::BVS: return registers.flags.template get<Flag::Overflow>();
 | 
				
			||||||
		case Operation::BCC: return !registers.flags.carry;
 | 
							case Operation::BCC: return !registers.flags.template get<Flag::Carry>();
 | 
				
			||||||
		case Operation::BCS: return registers.flags.carry;
 | 
							case Operation::BCS: return registers.flags.template get<Flag::Carry>();
 | 
				
			||||||
		case Operation::BNE: return registers.flags.zero_result;
 | 
							case Operation::BNE: return !registers.flags.template get<Flag::Zero>();
 | 
				
			||||||
		case Operation::BEQ: return !registers.flags.zero_result;
 | 
							case Operation::BEQ: return registers.flags.template get<Flag::Zero>();
 | 
				
			||||||
		case Operation::BRA: return true;
 | 
							case Operation::BRA: return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -335,112 +339,116 @@ void perform(
 | 
				
			|||||||
	const uint8_t opcode
 | 
						const uint8_t opcode
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
	switch(operation) {
 | 
						switch(operation) {
 | 
				
			||||||
 | 
							using enum Operation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			__builtin_unreachable();
 | 
								__builtin_unreachable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case Operation::NOP:	break;
 | 
							case NOP:	break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// MARK: - Bitwise logic.
 | 
							// MARK: - Bitwise logic.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case Operation::ORA:	registers.flags.set_nz(registers.a |= operand);		break;
 | 
							case ORA:	registers.flags.template set_per<Flag::NegativeZero>(registers.a |= operand);	break;
 | 
				
			||||||
		case Operation::AND:	registers.flags.set_nz(registers.a &= operand);		break;
 | 
							case AND:	registers.flags.template set_per<Flag::NegativeZero>(registers.a &= operand);	break;
 | 
				
			||||||
		case Operation::EOR:	registers.flags.set_nz(registers.a ^= operand);		break;
 | 
							case EOR:	registers.flags.template set_per<Flag::NegativeZero>(registers.a ^= operand);	break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// MARK: - Loads and stores.
 | 
							// MARK: - Loads and stores.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case Operation::LDA:	registers.flags.set_nz(registers.a = operand);					break;
 | 
							case LDA:	registers.flags.template set_per<Flag::NegativeZero>(registers.a = operand);	break;
 | 
				
			||||||
		case Operation::LDX:	registers.flags.set_nz(registers.x = operand);					break;
 | 
							case LDX:	registers.flags.template set_per<Flag::NegativeZero>(registers.x = operand);	break;
 | 
				
			||||||
		case Operation::LDY:	registers.flags.set_nz(registers.y = operand);					break;
 | 
							case LDY:	registers.flags.template set_per<Flag::NegativeZero>(registers.y = operand);	break;
 | 
				
			||||||
		case Operation::LAX:	registers.flags.set_nz(registers.a = registers.x = operand);	break;
 | 
							case LAX:
 | 
				
			||||||
		case Operation::LXA:
 | 
								registers.flags.template set_per<Flag::NegativeZero>(registers.a = registers.x = operand);
 | 
				
			||||||
			registers.a = registers.x = (registers.a | 0xee) & operand;
 | 
					 | 
				
			||||||
			registers.flags.set_nz(registers.a);
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
		case Operation::PLP:	registers.flags = Flags(operand);								break;
 | 
							case LXA:
 | 
				
			||||||
 | 
								registers.a = registers.x = (registers.a | 0xee) & operand;
 | 
				
			||||||
 | 
								registers.flags.template set_per<Flag::NegativeZero>(registers.a);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
							case PLP:	registers.flags = Flags(operand);								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case Operation::STA:	operand = registers.a;											break;
 | 
							case STA:	operand = registers.a;											break;
 | 
				
			||||||
		case Operation::STX:	operand = registers.x;											break;
 | 
							case STX:	operand = registers.x;											break;
 | 
				
			||||||
		case Operation::STY:	operand = registers.y;											break;
 | 
							case STY:	operand = registers.y;											break;
 | 
				
			||||||
		case Operation::STZ:	operand = 0;													break;
 | 
							case STZ:	operand = 0;													break;
 | 
				
			||||||
		case Operation::SAX:	operand = registers.a & registers.x;							break;
 | 
							case SAX:	operand = registers.a & registers.x;							break;
 | 
				
			||||||
		case Operation::PHP:	operand = static_cast<uint8_t>(registers.flags) | Flag::Break;	break;
 | 
							case PHP:	operand = static_cast<uint8_t>(registers.flags) | Flag::Break;	break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case Operation::CLC:	registers.flags.carry = 0;								break;
 | 
							case CLC:	registers.flags.template set_per<Flag::Carry>(0);					break;
 | 
				
			||||||
		case Operation::CLI:	registers.flags.inverse_interrupt = Flag::Interrupt;	break;
 | 
							case CLI:	registers.flags.template set_per<Flag::Interrupt>(0);				break;
 | 
				
			||||||
		case Operation::CLV:	registers.flags.overflow = 0;							break;
 | 
							case CLV:	registers.flags.template set_per<Flag::Overflow>(0);				break;
 | 
				
			||||||
		case Operation::CLD:	registers.flags.decimal = 0;							break;
 | 
							case CLD:	registers.flags.template set_per<Flag::Decimal>(0);					break;
 | 
				
			||||||
		case Operation::SEC:	registers.flags.carry = Flag::Carry;					break;
 | 
							case SEC:	registers.flags.template set_per<Flag::Carry>(Flag::Carry);			break;
 | 
				
			||||||
		case Operation::SEI:	registers.flags.inverse_interrupt = 0;					break;
 | 
							case SEI:	registers.flags.template set_per<Flag::Interrupt>(Flag::Interrupt);	break;
 | 
				
			||||||
		case Operation::SED:	registers.flags.decimal = Flag::Decimal;				break;
 | 
							case SED:	registers.flags.template set_per<Flag::Decimal>(Flag::Decimal);		break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case Operation::ANE:	Operations::ane(registers, operand);	break;
 | 
							case ANE:	Operations::ane(registers, operand);	break;
 | 
				
			||||||
		case Operation::ANC:	Operations::anc(registers, operand);	break;
 | 
							case ANC:	Operations::anc(registers, operand);	break;
 | 
				
			||||||
		case Operation::LAS:
 | 
							case LAS:
 | 
				
			||||||
			registers.a = registers.x = registers.s = registers.s & operand;
 | 
								registers.a = registers.x = registers.s = registers.s & operand;
 | 
				
			||||||
			registers.flags.set_nz(registers.a);
 | 
								registers.flags.template set_per<Flag::NegativeZero>(registers.a);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// MARK: - Transfers.
 | 
							// MARK: - Transfers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case Operation::TXA:	registers.flags.set_nz(registers.a = registers.x);	break;
 | 
							case TXA:	registers.flags.template set_per<Flag::NegativeZero>(registers.a = registers.x);	break;
 | 
				
			||||||
		case Operation::TYA:	registers.flags.set_nz(registers.a = registers.y);	break;
 | 
							case TYA:	registers.flags.template set_per<Flag::NegativeZero>(registers.a = registers.y);	break;
 | 
				
			||||||
		case Operation::TXS:	registers.s = registers.x;							break;
 | 
							case TXS:	registers.s = registers.x;															break;
 | 
				
			||||||
		case Operation::TAY:	registers.flags.set_nz(registers.y = registers.a);	break;
 | 
							case TAY:	registers.flags.template set_per<Flag::NegativeZero>(registers.y = registers.a);	break;
 | 
				
			||||||
		case Operation::TAX:	registers.flags.set_nz(registers.x = registers.a);	break;
 | 
							case TAX:	registers.flags.template set_per<Flag::NegativeZero>(registers.x = registers.a);	break;
 | 
				
			||||||
		case Operation::TSX:	registers.flags.set_nz(registers.x = registers.s);	break;
 | 
							case TSX:	registers.flags.template set_per<Flag::NegativeZero>(registers.x = registers.s);	break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// MARK: - Increments and decrements.
 | 
							// MARK: - Increments and decrements.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case Operation::INC:	registers.flags.set_nz(++operand);		break;
 | 
							case INC:	registers.flags.template set_per<Flag::NegativeZero>(++operand);		break;
 | 
				
			||||||
		case Operation::DEC:	registers.flags.set_nz(--operand);		break;
 | 
							case DEC:	registers.flags.template set_per<Flag::NegativeZero>(--operand);		break;
 | 
				
			||||||
		case Operation::INA:	registers.flags.set_nz(++registers.a);	break;
 | 
							case INA:	registers.flags.template set_per<Flag::NegativeZero>(++registers.a);	break;
 | 
				
			||||||
		case Operation::DEA:	registers.flags.set_nz(--registers.a);	break;
 | 
							case DEA:	registers.flags.template set_per<Flag::NegativeZero>(--registers.a);	break;
 | 
				
			||||||
		case Operation::INX:	registers.flags.set_nz(++registers.x);	break;
 | 
							case INX:	registers.flags.template set_per<Flag::NegativeZero>(++registers.x);	break;
 | 
				
			||||||
		case Operation::DEX:	registers.flags.set_nz(--registers.x);	break;
 | 
							case DEX:	registers.flags.template set_per<Flag::NegativeZero>(--registers.x);	break;
 | 
				
			||||||
		case Operation::INY:	registers.flags.set_nz(++registers.y);	break;
 | 
							case INY:	registers.flags.template set_per<Flag::NegativeZero>(++registers.y);	break;
 | 
				
			||||||
		case Operation::DEY:	registers.flags.set_nz(--registers.y);	break;
 | 
							case DEY:	registers.flags.template set_per<Flag::NegativeZero>(--registers.y);	break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// MARK: - Shifts and rolls.
 | 
							// MARK: - Shifts and rolls.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case Operation::ASL:	Operations::asl(registers, operand);		break;
 | 
							case ASL:	Operations::asl(registers, operand);		break;
 | 
				
			||||||
		case Operation::ASO:	Operations::aso(registers, operand);		break;
 | 
							case ASO:	Operations::aso(registers, operand);		break;
 | 
				
			||||||
		case Operation::ROL:	Operations::rol(registers, operand);		break;
 | 
							case ROL:	Operations::rol(registers, operand);		break;
 | 
				
			||||||
		case Operation::RLA: 	Operations::rla(registers, operand);		break;
 | 
							case RLA: 	Operations::rla(registers, operand);		break;
 | 
				
			||||||
		case Operation::LSR:	Operations::lsr(registers, operand);		break;
 | 
							case LSR:	Operations::lsr(registers, operand);		break;
 | 
				
			||||||
		case Operation::LSE:	Operations::lse(registers, operand);		break;
 | 
							case LSE:	Operations::lse(registers, operand);		break;
 | 
				
			||||||
		case Operation::ASR:	Operations::asr(registers, operand);		break;
 | 
							case ASR:	Operations::asr(registers, operand);		break;
 | 
				
			||||||
		case Operation::ROR:	Operations::ror(registers, operand);		break;
 | 
							case ROR:	Operations::ror(registers, operand);		break;
 | 
				
			||||||
		case Operation::RRA:	Operations::rra<model>(registers, operand);	break;
 | 
							case RRA:	Operations::rra<model>(registers, operand);	break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// MARK: - Bit logic.
 | 
							// MARK: - Bit logic.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case Operation::BIT:		Operations::bit(registers, operand);			break;
 | 
							case BIT:		Operations::bit(registers, operand);			break;
 | 
				
			||||||
		case Operation::BITNoNV:	Operations::bit_no_nv(registers, operand);		break;
 | 
							case BITNoNV:	Operations::bit_no_nv(registers, operand);		break;
 | 
				
			||||||
		case Operation::TRB:		Operations::trb(registers, operand);			break;
 | 
							case TRB:		Operations::trb(registers, operand);			break;
 | 
				
			||||||
		case Operation::TSB:		Operations::tsb(registers, operand);			break;
 | 
							case TSB:		Operations::tsb(registers, operand);			break;
 | 
				
			||||||
		case Operation::RMB:		Operations::rmb(operand, opcode);				break;
 | 
							case RMB:		Operations::rmb(operand, opcode);				break;
 | 
				
			||||||
		case Operation::SMB:		Operations::smb(operand, opcode);				break;
 | 
							case SMB:		Operations::smb(operand, opcode);				break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// MARK: - Compare
 | 
							// MARK: - Compare
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case Operation::DCP:
 | 
							case DCP:
 | 
				
			||||||
			--operand;
 | 
								--operand;
 | 
				
			||||||
			Operations::compare(registers, registers.a, operand);
 | 
								Operations::compare(registers, registers.a, operand);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
		case Operation::CMP:	Operations::compare(registers, registers.a, operand);	break;
 | 
							case CMP:	Operations::compare(registers, registers.a, operand);	break;
 | 
				
			||||||
		case Operation::CPX:	Operations::compare(registers, registers.x, operand);	break;
 | 
							case CPX:	Operations::compare(registers, registers.x, operand);	break;
 | 
				
			||||||
		case Operation::CPY:	Operations::compare(registers, registers.y, operand);	break;
 | 
							case CPY:	Operations::compare(registers, registers.y, operand);	break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// MARK: - Arithmetic.
 | 
							// MARK: - Arithmetic.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case Operation::INS:
 | 
							case INS:
 | 
				
			||||||
			++operand;
 | 
								++operand;
 | 
				
			||||||
			Operations::sbc<model>(registers, operand);
 | 
								Operations::sbc<model>(registers, operand);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
		case Operation::SBC:	Operations::sbc<model>(registers, operand);		break;
 | 
							case SBC:	Operations::sbc<model>(registers, operand);		break;
 | 
				
			||||||
		case Operation::ADC:	Operations::adc<model>(registers, operand);		break;
 | 
							case ADC:	Operations::adc<model>(registers, operand);		break;
 | 
				
			||||||
		case Operation::ARR:	Operations::arr<model>(registers, operand);		break;
 | 
							case ARR:	Operations::arr<model>(registers, operand);		break;
 | 
				
			||||||
		case Operation::SBX: 	Operations::sbx(registers, operand);			break;
 | 
							case SBX: 	Operations::sbx(registers, operand);			break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "Numeric/RegisterSizes.hpp"
 | 
					#include "Numeric/RegisterSizes.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cassert>
 | 
				
			||||||
#include <compare>
 | 
					#include <compare>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
@@ -37,7 +38,7 @@ enum class Register {
 | 
				
			|||||||
	the corresponding set.
 | 
						the corresponding set.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
enum Flag: uint8_t {
 | 
					enum Flag: uint8_t {
 | 
				
			||||||
	Sign		= 0b1000'0000,
 | 
						Negative	= 0b1000'0000,
 | 
				
			||||||
	Overflow	= 0b0100'0000,
 | 
						Overflow	= 0b0100'0000,
 | 
				
			||||||
	Always		= 0b0010'0000,
 | 
						Always		= 0b0010'0000,
 | 
				
			||||||
	Break		= 0b0001'0000,
 | 
						Break		= 0b0001'0000,
 | 
				
			||||||
@@ -46,6 +47,12 @@ enum Flag: uint8_t {
 | 
				
			|||||||
	Zero		= 0b0000'0010,
 | 
						Zero		= 0b0000'0010,
 | 
				
			||||||
	Carry		= 0b0000'0001,
 | 
						Carry		= 0b0000'0001,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Psuedo-flags, for convenience setting and getting.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						NegativeZero		= 0b00,
 | 
				
			||||||
 | 
						InverseInterrupt	= 0b11,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//
 | 
						//
 | 
				
			||||||
	// 65816 only.
 | 
						// 65816 only.
 | 
				
			||||||
	//
 | 
						//
 | 
				
			||||||
@@ -53,36 +60,89 @@ enum Flag: uint8_t {
 | 
				
			|||||||
	IndexSize	= Break,
 | 
						IndexSize	= Break,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr bool is_stored(const Flag flag) {
 | 
				
			||||||
 | 
						switch(flag) {
 | 
				
			||||||
 | 
							case Flag::Negative:
 | 
				
			||||||
 | 
							case Flag::Overflow:
 | 
				
			||||||
 | 
							case Flag::Decimal:
 | 
				
			||||||
 | 
							case Flag::Interrupt:
 | 
				
			||||||
 | 
							case Flag::InverseInterrupt:
 | 
				
			||||||
 | 
							case Flag::Zero:
 | 
				
			||||||
 | 
							case Flag::Carry:
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr bool is_settable(const Flag flag) {
 | 
				
			||||||
 | 
						switch(flag) {
 | 
				
			||||||
 | 
							case Flag::NegativeZero:	return true;
 | 
				
			||||||
 | 
							default:					return is_stored(flag);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Flags {
 | 
					struct Flags {
 | 
				
			||||||
	/// Sets N and Z flags per the 8-bit value @c value.
 | 
						template <Flag flag>
 | 
				
			||||||
	void set_nz(const uint8_t value) {
 | 
						requires(is_stored(flag))
 | 
				
			||||||
		zero_result = negative_result = value;
 | 
						bool get() const {
 | 
				
			||||||
 | 
							switch(flag) {
 | 
				
			||||||
 | 
								default:						__builtin_unreachable();
 | 
				
			||||||
 | 
								case Flag::Negative:			return negative_result & Flag::Negative;
 | 
				
			||||||
 | 
								case Flag::Overflow:			return overflow;
 | 
				
			||||||
 | 
								case Flag::Decimal:				return decimal;
 | 
				
			||||||
 | 
								case Flag::Interrupt:			return !(inverse_interrupt & Flag::Interrupt);
 | 
				
			||||||
 | 
								case Flag::InverseInterrupt:	return inverse_interrupt & Flag::Interrupt;
 | 
				
			||||||
 | 
								case Flag::Zero:				return !zero_result;
 | 
				
			||||||
 | 
								case Flag::Carry:				return carry & Flag::Carry;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Sets N and Z flags per the 8- or 16-bit value @c value; @c shift should be 0 to indicate an 8-bit value or 8 to indicate a 16-bit value.
 | 
						/// Sets a flag based on an 8-bit ALU result.
 | 
				
			||||||
	void set_nz(const uint16_t value, const int shift) {
 | 
						template <Flag flag>
 | 
				
			||||||
		negative_result = uint8_t(value >> shift);
 | 
						requires(is_settable(flag))
 | 
				
			||||||
		zero_result = uint8_t(value | (value >> shift));
 | 
						void set_per(const uint8_t result) {
 | 
				
			||||||
 | 
							switch(flag) {
 | 
				
			||||||
 | 
								default:	__builtin_unreachable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								case Flag::Negative:			negative_result = result;											break;
 | 
				
			||||||
 | 
								case Flag::Overflow:			overflow = result & Flag::Overflow;									break;
 | 
				
			||||||
 | 
								case Flag::Decimal:				decimal = result & Flag::Decimal;									break;
 | 
				
			||||||
 | 
								case Flag::Interrupt:			inverse_interrupt = uint8_t(~Flag::Interrupt) | uint8_t(~result);	break;
 | 
				
			||||||
 | 
								case Flag::InverseInterrupt:	inverse_interrupt = uint8_t(~Flag::Interrupt) | result;				break;
 | 
				
			||||||
 | 
								case Flag::Zero:				zero_result = result;												break;
 | 
				
			||||||
 | 
								case Flag::Carry:
 | 
				
			||||||
 | 
									assert(!(result & ~Flag::Carry));
 | 
				
			||||||
 | 
									carry = result;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
								case Flag::NegativeZero:		zero_result = negative_result = result;								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Sets the Z flag per the 8- or 16-bit value @c value; @c shift should be 0 to indicate an 8-bit value or 8 to indicate a 16-bit value.
 | 
						template <Flag flag>
 | 
				
			||||||
	void set_z(const uint16_t value, const int shift) {
 | 
						requires(is_settable(flag))
 | 
				
			||||||
		zero_result = uint8_t(value | (value >> shift));
 | 
						void set(const bool result) {
 | 
				
			||||||
 | 
							set_per<flag>(result ? flag : 0x00);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Sets the N flag per the 8- or 16-bit value @c value; @c shift should be 0 to indicate an 8-bit value or 8 to indicate a 16-bit value.
 | 
						uint8_t carry_value() const {
 | 
				
			||||||
	void set_n(const uint16_t value, const int shift) {
 | 
							return carry;
 | 
				
			||||||
		negative_result = uint8_t(value >> shift);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void set_v(const uint8_t result, const uint8_t lhs, const uint8_t rhs) {
 | 
						uint8_t interrupt_mask() const {
 | 
				
			||||||
 | 
							return inverse_interrupt;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_overflow(const uint8_t result, const uint8_t lhs, const uint8_t rhs) {
 | 
				
			||||||
		// TODO: can this be done lazily?
 | 
							// TODO: can this be done lazily?
 | 
				
			||||||
		overflow = (( (result^lhs) & (result^rhs) ) & 0x80) >> 1;
 | 
							overflow = (( (result^lhs) & (result^rhs) ) & 0x80) >> 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	explicit operator uint8_t() const {
 | 
						explicit operator uint8_t() const {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
			carry | overflow | (inverse_interrupt ^ Flag::Interrupt) | (negative_result & 0x80) |
 | 
								carry | overflow | ((~inverse_interrupt) & Flag::Interrupt) | (negative_result & 0x80) |
 | 
				
			||||||
			(zero_result ? 0 : Flag::Zero) | Flag::Always | Flag::Break | decimal;
 | 
								(zero_result ? 0 : Flag::Zero) | Flag::Always | Flag::Break | decimal;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -95,23 +155,26 @@ struct Flags {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Flags(const uint8_t flags) {
 | 
						Flags(const uint8_t flags) {
 | 
				
			||||||
		carry				= flags		& Flag::Carry;
 | 
							set_per<Flag::Carry>(flags & Flag::Carry);
 | 
				
			||||||
		negative_result		= flags		& Flag::Sign;
 | 
							set_per<Flag::Negative>(flags);
 | 
				
			||||||
		zero_result			= (~flags)	& Flag::Zero;
 | 
							set_per<Flag::Zero>((~flags) & Flag::Zero);
 | 
				
			||||||
		overflow			= flags		& Flag::Overflow;
 | 
							set_per<Flag::Overflow>(flags);
 | 
				
			||||||
		inverse_interrupt	= (~flags)	& Flag::Interrupt;
 | 
							set_per<Flag::Interrupt>(flags);
 | 
				
			||||||
		decimal				= flags		& Flag::Decimal;
 | 
							set_per<Flag::Decimal>(flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							assert((flags | Flag::Always | Flag::Break) == static_cast<uint8_t>(*this));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto operator <=> (const Flags &rhs) const {
 | 
						auto operator <=> (const Flags &rhs) const {
 | 
				
			||||||
		return static_cast<uint8_t>(*this) <=> static_cast<uint8_t>(rhs);
 | 
							return static_cast<uint8_t>(*this) <=> static_cast<uint8_t>(rhs);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						uint8_t overflow = 0;			/// Contains Flag::Overflow.
 | 
				
			||||||
 | 
						uint8_t carry = 0;				/// Contains Flag::Carry.
 | 
				
			||||||
	uint8_t negative_result = 0;	/// Bit 7 = the negative flag.
 | 
						uint8_t negative_result = 0;	/// Bit 7 = the negative flag.
 | 
				
			||||||
	uint8_t zero_result = 0;		/// Non-zero if the zero flag is clear, zero if it is set.
 | 
						uint8_t zero_result = 0;		/// Non-zero if the zero flag is clear, zero if it is set.
 | 
				
			||||||
	uint8_t carry = 0;				/// Contains Flag::Carry.
 | 
					 | 
				
			||||||
	uint8_t decimal = 0;			/// Contains Flag::Decimal.
 | 
						uint8_t decimal = 0;			/// Contains Flag::Decimal.
 | 
				
			||||||
	uint8_t overflow = 0;			/// Contains Flag::Overflow.
 | 
					 | 
				
			||||||
	uint8_t inverse_interrupt = 0;	/// Contains Flag::Interrupt, complemented.
 | 
						uint8_t inverse_interrupt = 0;	/// Contains Flag::Interrupt, complemented.
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user