<commit_before>//
//  cpu.c
//  v6502
//
//  Created by <NAME> on H.25/03/28.
//  Copyright (c) 平成25年 Hello-Channel, LLC. All rights reserved.
//

#include <stdlib.h>

#include "cpu.h"

#define	BOTH_BYTES									(high << 8 | low)
#define FLAG_CARRY_WITH_HIGH_BIT(a)					cpu->sr &= (~v6502_cpu_status_carry | (a >> 7)); \
													cpu->sr |= a >> 7;
#define FLAG_CARRY_WITH_LOW_BIT(a)					cpu->sr &= ~v6502_cpu_status_carry | a; \
													cpu->sr |= v6502_cpu_status_carry & a;
#define FLAG_ZERO_WITH_RESULT(a)					cpu->sr &= (a ? ~v6502_cpu_status_zero : ~0); \
													cpu->sr |= (a ? 0 : v6502_cpu_status_zero);
#define FLAG_NEGATIVE_WITH_RESULT(a)				cpu->sr |= ((a & 0x80) ? v6502_cpu_status_negative : 0);
/** FIXME: @bug (a > 0xFF) is always true with uint8_t */
#define FLAG_CARRY_WITH_EXPRESSION(a)				cpu->sr |= ((a > 0xFF) ? v6502_cpu_status_carry : 0);
#define FLAG_OVERFLOW_PREPARE(a)					uint8_t _overflowCheck = a;
#define FLAG_OVERFLOW_CHECK(a)						_overflowCheck ^= a; \
													_overflowCheck >>= 1; /* Shift to overflow flag position */ \
													cpu->sr &= (_overflowCheck | ~v6502_cpu_status_overflow); \
													cpu->sr |= (_overflowCheck & v6502_cpu_status_overflow); \

#define kUnhandledInstructionErrorText				"Unhandled CPU Instruction"

#define STACK_OFFSET								0x0100

#pragma mark -
#pragma mark CPU Internal Instruction Execution

static void _executeInPlaceASL(v6502_cpu *cpu, uint8_t *operand) {
	FLAG_CARRY_WITH_HIGH_BIT(*operand);
	*operand <<= 1;
	FLAG_NEGATIVE_WITH_RESULT(*operand);
	FLAG_ZERO_WITH_RESULT(*operand);
}

static void _executeInPlaceLSR(v6502_cpu *cpu, uint8_t *operand) {
	FLAG_CARRY_WITH_LOW_BIT(*operand);
	*operand >>= 1;
	FLAG_ZERO_WITH_RESULT(*operand);
}

static void _executeInPlaceROL(v6502_cpu *cpu, uint8_t *operand) {
	FLAG_CARRY_WITH_HIGH_BIT(*operand);
	*operand = (*operand << 1) | (*operand >> 7);
	FLAG_NEGATIVE_WITH_RESULT(*operand);
	FLAG_ZERO_WITH_RESULT(*operand);
}

static void _executeInPlaceROR(v6502_cpu *cpu, uint8_t *operand) {
	FLAG_CARRY_WITH_HIGH_BIT(*operand);
	*operand = (*operand >> 1) | (*operand << 7);
	FLAG_NEGATIVE_WITH_RESULT(*operand);
	FLAG_ZERO_WITH_RESULT(*operand);
}

static void _executeInPlaceORA(v6502_cpu *cpu, uint8_t operand) {
	cpu->ac |= operand;
	FLAG_NEGATIVE_WITH_RESULT(cpu->ac);
	FLAG_ZERO_WITH_RESULT(cpu->ac);
}

static void _executeInPlaceAND(v6502_cpu *cpu, uint8_t operand) {
	cpu->ac &= operand;
	FLAG_NEGATIVE_WITH_RESULT(cpu->ac);
	FLAG_ZERO_WITH_RESULT(cpu->ac);
}

static void _executeInPlaceADC(v6502_cpu *cpu, uint8_t operand) {
	FLAG_OVERFLOW_PREPARE(cpu->ac);
	cpu->ac += operand;
	FLAG_CARRY_WITH_EXPRESSION(cpu->ac);
	FLAG_OVERFLOW_CHECK(cpu->ac);
	FLAG_NEGATIVE_WITH_RESULT(cpu->ac);
	FLAG_ZERO_WITH_RESULT(cpu->ac);
}

static void _executeInPlaceSBC(v6502_cpu *cpu, uint8_t operand) {
	FLAG_OVERFLOW_PREPARE(cpu->ac);
	cpu->ac -= operand;
	FLAG_CARRY_WITH_EXPRESSION(cpu->ac);
	FLAG_OVERFLOW_CHECK(cpu->ac);
	FLAG_NEGATIVE_WITH_RESULT(cpu->ac);
	FLAG_ZERO_WITH_RESULT(cpu->ac);
}

static void _executeInPlaceDEC(v6502_cpu *cpu, uint8_t *operand) {
	(*operand)--;
	FLAG_NEGATIVE_WITH_RESULT(*operand);
	FLAG_ZERO_WITH_RESULT(*operand);
}

static void _executeInPlaceINC(v6502_cpu *cpu, uint8_t *operand) {
	(*operand)++;
	FLAG_NEGATIVE_WITH_RESULT(*operand);
	FLAG_ZERO_WITH_RESULT(*operand);
}

static void _executeInPlaceCMP(v6502_cpu *cpu, uint8_t operand) {
	uint8_t result = cpu->ac - operand;
	FLAG_NEGATIVE_WITH_RESULT(result);
	FLAG_ZERO_WITH_RESULT(result);
}

static void _executeInPlaceCPY(v6502_cpu *cpu, uint8_t operand) {
	uint8_t result = cpu->y - operand;
	FLAG_NEGATIVE_WITH_RESULT(result);
	FLAG_ZERO_WITH_RESULT(result);
}

static void _executeInPlaceCPX(v6502_cpu *cpu, uint8_t operand) {
	uint8_t result = cpu->x - operand;
	FLAG_NEGATIVE_WITH_RESULT(result);
	FLAG_ZERO_WITH_RESULT(result);
}

static void _executeInPlaceBIT(v6502_cpu *cpu, uint8_t operand) {
	uint8_t result = cpu->ac & operand;
	cpu->sr &= ~v6502_cpu_status_overflow;
	cpu->sr |= (result & v6502_cpu_status_overflow);
	FLAG_NEGATIVE_WITH_RESULT(result);
	FLAG_ZERO_WITH_RESULT(result);
}

#pragma mark -
#pragma mark CPU Lifecycle

v6502_cpu *v6502_createCPU(void) {
	// Allocate CPU Struct
	v6502_cpu *cpu = malloc(sizeof(v6502_cpu));
	
	if (cpu) {
		cpu->fault_callback = NULL;
		cpu->fault_context = NULL;
	}<commit_msg>Simplified FLAG_CARRY_WITH_EXPRESSION, and improved it’s logic for 8-bit carries. Also simplified FLAG_CARRY_WITH_*_BIT. Created FLAG_NEG_AND_ZERO_WITH_RESULT to consolidate all operations that would check for both potential flags.<commit_after>//
//  cpu.c
//  v6502
//
//  Created by <NAME> on H.25/03/28.
//  Copyright (c) 平成25年 Hello-Channel, LLC. All rights reserved.
//

#include <stdlib.h>

#include "cpu.h"

#define	BOTH_BYTES									(high << 8 | low)
#define FLAG_CARRY_WITH_HIGH_BIT(a)					cpu->sr &= ~v6502_cpu_status_carry; \
													cpu->sr |= a >> 7;
#define FLAG_CARRY_WITH_LOW_BIT(a)					cpu->sr &= ~v6502_cpu_status_carry; \
													cpu->sr |= a & v6502_cpu_status_carry;
#define FLAG_ZERO_WITH_RESULT(a)					cpu->sr &= (a ? ~v6502_cpu_status_zero : ~0); \
													cpu->sr |= (a ? 0 : v6502_cpu_status_zero);
#define FLAG_NEGATIVE_WITH_RESULT(a)				cpu->sr |= ((a & 0x80) ? v6502_cpu_status_negative : 0);
/** FIXME: @bug (a > 0xFF) is always true with uint8_t */
#define FLAG_CARRY_WITH_EXPRESSION(a)				cpu->sr &= ~v6502_cpu_status_carry; \
													cpu->sr |= ((a >= 0x0100 || a < 0) ? v6502_cpu_status_carry : 0);
#define FLAG_OVERFLOW_PREPARE(a)					uint8_t _overflowCheck = a;
#define FLAG_OVERFLOW_CHECK(a)						_overflowCheck ^= a; \
													_overflowCheck >>= 1; /* Shift to overflow flag position */ \
													cpu->sr &= (_overflowCheck | ~v6502_cpu_status_overflow); \
													cpu->sr |= (_overflowCheck & v6502_cpu_status_overflow); \

#define FLAG_NEG_AND_ZERO_WITH_RESULT(a)			FLAG_NEGATIVE_WITH_RESULT(a); \
													FLAG_ZERO_WITH_RESULT(a);

#define kUnhandledInstructionErrorText				"Unhandled CPU Instruction"

#define STACK_OFFSET								0x0100

#pragma mark -
#pragma mark CPU Internal Instruction Execution

static void _executeInPlaceASL(v6502_cpu *cpu, uint8_t *operand) {
	FLAG_CARRY_WITH_HIGH_BIT(*operand);
	*operand <<= 1;
	FLAG_NEGATIVE_WITH_RESULT(*operand);
	FLAG_ZERO_WITH_RESULT(*operand);
}

static void _executeInPlaceLSR(v6502_cpu *cpu, uint8_t *operand) {
	FLAG_CARRY_WITH_LOW_BIT(*operand);
	*operand >>= 1;
	FLAG_ZERO_WITH_RESULT(*operand);
}

static void _executeInPlaceROL(v6502_cpu *cpu, uint8_t *operand) {
	FLAG_CARRY_WITH_HIGH_BIT(*operand);
	*operand = (*operand << 1) | (*operand >> 7);
	FLAG_NEG_AND_ZERO_WITH_RESULT(*operand);
}

static void _executeInPlaceROR(v6502_cpu *cpu, uint8_t *operand) {
	FLAG_CARRY_WITH_HIGH_BIT(*operand);
	*operand = (*operand >> 1) | (*operand << 7);
	FLAG_NEG_AND_ZERO_WITH_RESULT(*operand);
}

static void _executeInPlaceORA(v6502_cpu *cpu, uint8_t operand) {
	cpu->ac |= operand;
	FLAG_NEG_AND_ZERO_WITH_RESULT(cpu->ac);
}

static void _executeInPlaceAND(v6502_cpu *cpu, uint8_t operand) {
	cpu->ac &= operand;
	FLAG_NEG_AND_ZERO_WITH_RESULT(cpu->ac);
}

static void _executeInPlaceADC(v6502_cpu *cpu, uint8_t operand) {
	FLAG_OVERFLOW_PREPARE(cpu->ac);
	cpu->ac += operand;
	FLAG_CARRY_WITH_EXPRESSION(cpu->ac + operand);
	FLAG_OVERFLOW_CHECK(cpu->ac);
	FLAG_NEG_AND_ZERO_WITH_RESULT(cpu->ac);
}

static void _executeInPlaceSBC(v6502_cpu *cpu, uint8_t operand) {
	FLAG_OVERFLOW_PREPARE(cpu->ac);
	cpu->ac -= operand;
	FLAG_CARRY_WITH_EXPRESSION(cpu->ac - operand);
	FLAG_OVERFLOW_CHECK(cpu->ac);
	FLAG_NEG_AND_ZERO_WITH_RESULT(cpu->ac);
}

static void _executeInPlaceDEC(v6502_cpu *cpu, uint8_t *operand) {
	(*operand)--;
	FLAG_NEG_AND_ZERO_WITH_RESULT(*operand);
}

static void _executeInPlaceINC(v6502_cpu *cpu, uint8_t *operand) {
	(*operand)++;
	FLAG_NEG_AND_ZERO_WITH_RESULT(*operand);
}

static void _executeInPlaceCMP(v6502_cpu *cpu, uint8_t operand) {
	uint8_t result = cpu->ac - operand;
	FLAG_CARRY_WITH_EXPRESSION(cpu->ac - operand);
	FLAG_NEG_AND_ZERO_WITH_RESULT(result);
}

static void _executeInPlaceCPY(v6502_cpu *cpu, uint8_t operand) {
	uint8_t result = cpu->y - operand;
	FLAG_CARRY_WITH_EXPRESSION(cpu->y - operand);
	FLAG_NEG_AND_ZERO_WITH_RESULT(result);
}

static void _executeInPlaceCPX(v6502_cpu *cpu, uint8_t operand) {
	uint8_t result = cpu->x - operand;
	FLAG_CARRY_WITH_EXPRESSION(cpu->x - operand);
	FLAG_NEG_AND_ZERO_WITH_RESULT(result);
}

static void _executeInPlaceBIT(v6502_cpu *cpu, uint8_t operand) {
	uint8_t result = cpu->ac & operand;
	cpu->sr &= ~v6502_cpu_status_overflow;
	cpu->sr |= (result & v6502_cpu_status_overflow);
	FLAG_NEG_AND_ZERO_WITH_RESULT(result);
}

#pragma mark -
#pragma mark CPU Lifecycle

v6502_cpu *v6502_createCPU(void) {
	// Allocate CPU Struct
	v6502_cpu *cpu = malloc(sizeof(v6502_cpu));
	
	if (cpu) {
		cpu->fault_callback = NULL;
		cpu->fault_context = NULL;
	}
{'fraction_non_alphanumeric': 0.12699832308552264, 'fraction_numerical': 0.03946338736724427, 'mean_word_length': 5.089857045609258, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 105, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '559419', 'n_tokens_mistral': 4087, 'n_tokens_neox': 3673, 'n_words': 623}