<repo_name>TomKauffeld/NES-Emulator<file_sep>/Emulator.core/src/emulator/car/core/Cartridge.h
#ifndef __EMULATOR_CAR_CORE_CARTRIDGE_H__
#define __EMULATOR_CAR_CORE_CARTRIDGE_H__
#include "CartridgeHeader.h"
#include <emulator/car/core/cartridge.h>
#include <emulator/car/mappers/mapperProvider.h>
#include <emulator/car/mappers/mapper.h>
#include <inttypes.h>

#define CARTRIDGE_MIRROR_HORIZONTAL   0x00
#define CARTRIDGE_MIRROR_VERTICAL     0x01
#define CARTRIDGE_MIRROR_ONESCREEN_LO 0x02
#define CARTRIDGE_MIRROR_ONESCREEN_HI 0x03

typedef struct cartridge {
	CartridgeHeader header;
	uint8_t trainer[512];
	uint16_t mapper_id;
	uint8_t* prg;
	uint8_t* chr;
	Mapper* mapper;
	uint8_t mirror;
} Cartridge;




uint8_t cartridge_read_prg(Cartridge* cartridge, uint16_t addr);
void cartridge_write_prg(Cartridge* cartridge, uint16_t addr, uint8_t value);
uint8_t cartridge_read_chr(Cartridge* cartridge, uint16_t addr);
void cartridge_write_chr(Cartridge* cartridge, uint16_t addr, uint8_t value);

#endif<file_sep>/Emulator.core/src/emulator/ppu/core/palScreen.h
#ifndef __EMULATOR_PPU_CORE_PAL_SCREEN_H__
#define __EMULATOR_PPU_CORE_PAL_SCREEN_H__
#include <inttypes.h>

//#define to_color(r, g, b) ((r << 24) + (g << 16) + (b << 8) + 255)
#define to_color(r, g, b) ((255 << 24) + (b << 16) + (g << 8) + r)

uint32_t palScreen[0x40] = {
	to_color(84, 84, 84),
	to_color(0, 30, 116),
	to_color(8, 16, 144),
	to_color(48, 0, 136),
	to_color(68, 0, 100),
	to_color(92, 0, 48),
	to_color(84, 4, 0),
	to_color(60, 24, 0),
	to_color(32, 42, 0),
	to_color(8, 58, 0),
	to_color(0, 64, 0),
	to_color(0, 60, 0),
	to_color(0, 50, 60),
	to_color(0, 0, 0),
	to_color(0, 0, 0),
	to_color(0, 0, 0),
	to_color(152, 150, 152),
	to_color(8, 76, 196),
	to_color(48, 50, 236),
	to_color(92, 30, 228),
	to_color(136, 20, 176),
	to_color(160, 20, 100),
	to_color(152, 34, 32),
	to_color(120, 60, 0),
	to_color(84, 90, 0),
	to_color(40, 114, 0),
	to_color(8, 124, 0),
	to_color(0, 118, 40),
	to_color(0, 102, 120),
	to_color(0, 0, 0),
	to_color(0, 0, 0),
	to_color(0, 0, 0),
	to_color(236, 238, 236),
	to_color(76, 154, 236),
	to_color(120, 124, 236),
	to_color(176, 98, 236),
	to_color(228, 84, 236),
	to_color(236, 88, 180),
	to_color(236, 106, 100),
	to_color(212, 136, 32),
	to_color(160, 170, 0),
	to_color(116, 196, 0),
	to_color(76, 208, 32),
	to_color(56, 204, 108),
	to_color(56, 180, 204),
	to_color(60, 60, 60),
	to_color(0, 0, 0),
	to_color(0, 0, 0),
	to_color(236, 238, 236),
	to_color(168, 204, 236),
	to_color(188, 188, 236),
	to_color(212, 178, 236),
	to_color(236, 174, 236),
	to_color(236, 174, 212),
	to_color(236, 180, 176),
	to_color(228, 196, 144),
	to_color(204, 210, 120),
	to_color(180, 222, 120),
	to_color(168, 226, 144),
	to_color(152, 226, 180),
	to_color(160, 214, 228),
	to_color(160, 162, 160),
	to_color(0, 0, 0),
	to_color(0, 0, 0)
};

#endif<file_sep>/Emulator.core/src/emulator/Emulator.c
#include "Emulator.h"

#include <stdlib.h>
#include <string.h>


Emulator* emulator_init()
{
	Emulator* emulator = (Emulator*)malloc(sizeof(Emulator));
	if (emulator == NULL)
		return NULL;
	emulator->cpu_timer = 0;
	emulator->cpu = cpu_init();
	if (emulator->cpu == NULL)
	{
		free(emulator);
		return NULL;
	}
	return emulator;
}

void emulator_destroy(Emulator* emulator)
{
	if (emulator == NULL)
		return;
	cpu_destroy(emulator->cpu);
	free(emulator);
}

Cartridge* emulator_insert_cartridge(Emulator* emulator, Cartridge* car)
{
	return bus_insert_cartridge(emulator->cpu->bus, car);
}

Cartridge* emulator_remove_cartridge(Emulator* emulator)
{
	return bus_remove_cartridge(emulator->cpu->bus);
}

void emulator_signal_reset(Emulator* emulator)
{
	cpu_signal_reset(emulator->cpu);
}

void emulator_tick(Emulator* emulator)
{
	emulator->cpu_timer++;
	bus_tick(emulator->cpu->bus);
	if (emulator->cpu_timer > 3)
	{
		cpu_clock(emulator->cpu);
		emulator->cpu_timer = 0;
	}
}

uint8_t emulator_get_cpu_bus(Emulator* emulator, uint16_t addr)
{
	return cpu_bus_read(emulator->cpu, addr);
}

uint8_t emulator_get_ppu_bus(Emulator* emulator, uint16_t addr)
{
	return ppu_bus_read(emulator->cpu->bus->ppu, addr);
}

uint16_t emulator_get_pc(Emulator* emulator)
{
	return emulator->cpu->registery->pc;
}

uint8_t emulator_get_cpu_reg_a(Emulator* emulator)
{
	return emulator->cpu->registery->a;
}

uint8_t emulator_get_cpu_reg_x(Emulator* emulator)
{
	return emulator->cpu->registery->x;
}

uint8_t emulator_get_cpu_reg_y(Emulator* emulator)
{
	return emulator->cpu->registery->y;
}

uint8_t emulator_get_cpu_reg_sp(Emulator* emulator)
{
	return emulator->cpu->registery->sp;
}

void emulator_set_pc(Emulator* emulator, uint16_t pc)
{
	emulator->cpu->registery->pc = pc;
}

void emulator_get_screen(Emulator* emulator, uint32_t* screen, size_t size)
{
	memcpy_s(screen, size * sizeof(uint32_t), emulator->cpu->bus->ppu->screen, sizeof(uint32_t) * 256 * 240);
}

uint8_t emulator_get_screen_pixel(Emulator* emulator, int x, int y)
{
	if (x >= 256 || y >= 240)
		return;
	uint32_t index = y * 256 + x;
	return emulator->cpu->bus->ppu->screen[index];
}

bool emulator_is_screen_ready(Emulator* emulator)
{
	return emulator->cpu->bus->ppu->frame;
}

void emulator_get_pattern_table(Emulator* emulator, uint8_t i, uint8_t palette, uint32_t* data)
{
	ppu_get_pattern_table(emulator->cpu->bus->ppu, i, palette, data);
}

void emulator_get_palette_table(Emulator* emulator, uint8_t palette, uint32_t* data)
{
	ppu_get_palette_table(emulator->cpu->bus->ppu, palette, data);
}
<file_sep>/Emulator/src/main.c
#include <emulator/emulator.h>
#include <emulator/car/core/cartridge.h>
#include <emulator/car/mappers/mapperDllProvider.h>
#include <utils/boolean.h>
#include <stdlib.h>
#include <stdio.h>
#include <SDL.h>

#define WIDTH 256
#define HEIGHT 240


int main(int argc, char ** argv)
{
	if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
		return -4;
	SDL_Window* window;
	SDL_Renderer* renderer;
	if (SDL_CreateWindowAndRenderer(WIDTH, HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE, &window, &renderer) != 0)
	{
		SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Couldn't init screen/renderer");
		SDL_LogError(SDL_LOG_CATEGORY_VIDEO, SDL_GetError());
		SDL_Quit();
		return -5;
	}
	Emulator* emulator = emulator_init();
	if (emulator == NULL)
	{
		SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't init the emulator");
		SDL_DestroyRenderer(renderer);
		SDL_DestroyWindow(window);
		SDL_Quit();
		return -1;
	}
	Cartridge* cartridge = cartridge_load_from_file("nestest.nes ", &mapper_dll_provider);
	if (cartridge == NULL)
	{
		SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load the cartridge");
		emulator_destroy(emulator);
		SDL_DestroyRenderer(renderer);
		SDL_DestroyWindow(window);
		SDL_Quit();
		return -2;
	}
	emulator_insert_cartridge(emulator, cartridge);
	emulator_signal_reset(emulator);
	bool running = TRUE;
	SDL_Texture* buffer = SDL_CreateTexture(renderer,
		SDL_PIXELFORMAT_RGBA32,
		SDL_TEXTUREACCESS_STREAMING,
		WIDTH,
		HEIGHT);
	if (buffer == NULL)
	{
		SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Couldn't create the buffer");
		SDL_LogError(SDL_LOG_CATEGORY_VIDEO, SDL_GetError());
		cartridge_destroy(emulator_remove_cartridge(emulator));
		emulator_destroy(emulator);
		SDL_DestroyRenderer(renderer);
		SDL_DestroyWindow(window);
		SDL_Quit();
	}
	uint32_t* pixels = (uint32_t*)malloc(sizeof(uint32_t) * WIDTH * HEIGHT);
	if (pixels == NULL)
	{
		cartridge_destroy(emulator_remove_cartridge(emulator));
		emulator_destroy(emulator);
		SDL_DestroyTexture(buffer);
		SDL_DestroyRenderer(renderer);
		SDL_DestroyWindow(window);
		SDL_Quit();
	}
	int pitch = WIDTH * sizeof(uint32_t);
	while (is_true(running))
	{
		SDL_Event event;
		while (SDL_PollEvent(&event) != 0)
		{
			switch (event.type)
			{
			case SDL_QUIT:
				running = FALSE;
				break;
			default:
				break;
			}
		}
		if (emulator_get_pc(emulator) == 0xC28F)
		{
			int i = 0;
		}
		emulator_tick(emulator);
		if (emulator_is_screen_ready(emulator))
		{
			SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
			SDL_RenderClear(renderer);
			emulator_get_screen(emulator, pixels, WIDTH * HEIGHT);
			if (SDL_UpdateTexture(buffer, NULL, pixels, pitch) == 0)
			{
				if (SDL_RenderCopy(renderer, buffer, NULL, NULL) != 0)
				{
					SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Couldn't render the buffer");
					SDL_LogError(SDL_LOG_CATEGORY_RENDER, SDL_GetError());
				}
			}
			else
			{
				SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Couldn't update the buffer");
				SDL_LogError(SDL_LOG_CATEGORY_RENDER, SDL_GetError());
			}
			SDL_RenderPresent(renderer);
		}
	}



	free(pixels);
	cartridge_destroy(emulator_remove_cartridge(emulator));
	emulator_destroy(emulator);
	SDL_DestroyTexture(buffer);
	SDL_DestroyRenderer(renderer);
	SDL_DestroyWindow(window);
	SDL_Quit();
	return 0;
}<file_sep>/Emulator.core/src/emulator/ppu/core/PPU.c
#include "PPU.h"
#include <stdlib.h>
#include <string.h>
#include "palScreen.h"
#include "../../car/core/Cartridge.h"

PPU* ppu_init(Cartridge** car)
{
	PPU* ppu = (PPU*)malloc(sizeof(PPU));
	if (ppu == NULL)
		return NULL;
	memset(ppu, 0x00, sizeof(PPU));
	ppu->screen = (uint32_t*)malloc(sizeof(uint32_t) * 256 * 240);
	if (ppu->screen == NULL)
	{
		free(ppu);
		return NULL;
	}
	memset(ppu->screen, 0x00, sizeof(uint32_t) * 256 * 240);
	ppu->bus = ppu_bus_init(car);
	if (ppu->bus == NULL)
	{
		free(ppu->screen);
		free(ppu);
		return NULL;
	}
	ppu->car = car;
	return ppu;
}

void ppu_destroy(PPU* ppu)
{
	if (ppu == NULL)
		return;
	ppu_bus_destroy(ppu->bus);
	free(ppu->screen);
	free(ppu);
}

uint8_t ppu_read(PPU* ppu, uint16_t addr)
{
	uint8_t data = 0x00;
	switch (addr)
	{
	case 0x0000: // Control
	case 0x0001: // Mask
		break;
	case 0x0002: // Status
		data = (ppu->status.reg & 0xE0) | (ppu->ppu_data_buffer & 0x1F);
		ppu->status.vertical_blank = 0;
		ppu->address_latch = 0;
		break;
	case 0x0003: // OAM Address
	case 0x0004: // OAM Data
	case 0x0005: // Scroll
	case 0x0006: // PPU Address
		break;
	case 0x0007: // PPU Data
		data = ppu->ppu_data_buffer;
		ppu->ppu_data_buffer = ppu_bus_read(ppu->bus, ppu->vram_addr.reg);
		if (ppu->vram_addr.reg >= 0x3F00) 
			data = ppu->ppu_data_buffer;
		ppu->vram_addr.reg += (ppu->control.increment_mode ? 32 : 1);
		break;
	default:
		break;
	}
	return data;
}

void ppu_write(PPU* ppu, uint16_t addr, uint8_t value)
{
	switch (addr)
	{
	case 0x0000: // Control
		ppu->control.reg = value;
		ppu->tram_addr.nametable_x = ppu->control.nametable_x;
		ppu->tram_addr.nametable_y = ppu->control.nametable_y;
		break;
	case 0x0001: // Mask
		ppu->bus->mask.reg = value;
		break;
	case 0x0002: // Status
	case 0x0003: // OAM Address
	case 0x0004: // OAM Data
		break;
	case 0x0005: // Scroll
		if (ppu->address_latch == 0)
		{
			ppu->fine_x = value & 0x07;
			ppu->tram_addr.coarse_x = value >> 3;
			ppu->address_latch = 1;
		}
		else
		{
			ppu->tram_addr.fine_y = value & 0x07;
			ppu->tram_addr.coarse_y = value >> 3;
			ppu->address_latch = 0;
		}
		break;
	case 0x0006: // PPU Address
		if (ppu->address_latch == 0)
		{
			ppu->tram_addr.reg = (uint16_t)((value & 0x3F) << 8) | (ppu->tram_addr.reg & 0x00FF);
			ppu->address_latch = 1;
		}
		else
		{
			ppu->tram_addr.reg = (ppu->tram_addr.reg & 0xFF00) | value;
			ppu->vram_addr = ppu->tram_addr;
			ppu->address_latch = 0;
		}
		break;
	case 0x0007: // PPU Data
		ppu_bus_write(ppu->bus, ppu->vram_addr.reg, value);
		ppu->vram_addr.reg += (ppu->control.increment_mode ? 32 : 1);
		break;
	default:
		return;
	}
}


void ppu_tick(PPU * ppu)
{
	ppu->bus->mask.render_background = 1;
	if (ppu->scanline >= -1 && ppu->scanline < 240)
	{
		if (ppu->scanline == 0 && ppu->cycle == 0)
			ppu->cycle = 1;
		if (ppu->scanline == -1 && ppu->cycle == 1)
			ppu->status.vertical_blank = 0;
		if ((ppu->cycle >= 2 && ppu->cycle < 258) || (ppu->cycle >= 321 && ppu->cycle < 338))
		{
			ppu_update_shifters(ppu); 
			switch ((ppu->cycle - 1) % 8)
			{
			case 0:
				ppu_load_background_shifters(ppu);
				ppu->bg_next_tile_id = ppu_bus_read(ppu->bus, 0x2000 | (ppu->vram_addr.reg & 0x0FFF));
				break; 
			case 2:
				ppu->bg_next_tile_attrib = ppu_bus_read(ppu->bus,
					0x23C0 
					| (ppu->vram_addr.nametable_y << 11)
					| (ppu->vram_addr.nametable_x << 10)
					| ((ppu->vram_addr.coarse_y >> 2) << 3)
					| (ppu->vram_addr.coarse_x >> 2));
				if (ppu->vram_addr.coarse_y & 0x02) 
					ppu->bg_next_tile_attrib >>= 4;
				if (ppu->vram_addr.coarse_x & 0x02) 
					ppu->bg_next_tile_attrib >>= 2;
				ppu->bg_next_tile_attrib &= 0x03;
				break;
			case 4:
				ppu->bg_next_tile_lsb = ppu_bus_read(ppu->bus, (ppu->control.pattern_background << 12) + ((uint16_t)ppu->bg_next_tile_id << 4) + (ppu->vram_addr.fine_y) + 0);

				break;
			case 6:
				ppu->bg_next_tile_msb = ppu_bus_read(ppu->bus, (ppu->control.pattern_background << 12) + ((uint16_t)ppu->bg_next_tile_id << 4) + (ppu->vram_addr.fine_y) + 8);
				break;
			case 7:
				ppu_increment_scroll_x(ppu);
				break;
			}
		}

		if (ppu->cycle == 256)
			ppu_increment_scroll_y(ppu);
		if (ppu->cycle == 257)
		{
			ppu_load_background_shifters(ppu);
			ppu_transfer_address_x(ppu);
		}
		if (ppu->cycle == 338 || ppu->cycle == 340)
			ppu->bg_next_tile_id = ppu_bus_read(ppu->bus, 0x2000 | (ppu->vram_addr.reg & 0x0FFF));
		if (ppu->scanline == -1 && ppu->cycle >= 280 && ppu->cycle < 305)
			ppu_transfer_address_y(ppu);
	}
	if (ppu->scanline >= 241 && ppu->scanline < 261)
	{
		if (ppu->scanline == 241 && ppu->cycle == 1)
		{
			ppu->status.vertical_blank = 1;
			if (ppu->control.enable_nmi)
				ppu->nmi = TRUE;
		}
	}
	uint8_t bg_pixel = 0x00;
	uint8_t bg_palette = 0x00;
	if (ppu->bus->mask.render_background)
	{
		uint16_t bit_mux = 0x8000 >> ppu->fine_x;

		uint8_t p0_pixel = (ppu->bg_shifter_pattern_lo & bit_mux) > 0;
		uint8_t p1_pixel = (ppu->bg_shifter_pattern_hi & bit_mux) > 0;

		bg_pixel = (p1_pixel << 1) | p0_pixel;

		uint8_t bg_pal0 = (ppu->bg_shifter_attrib_lo & bit_mux) > 0;
		uint8_t bg_pal1 = (ppu->bg_shifter_attrib_hi & bit_mux) > 0;
		bg_palette = (bg_pal1 << 1) | bg_pal0;
	}
	uint32_t color = ppu_get_color_from_palette_ram(ppu, bg_palette, bg_pixel);
	ppu_set_pixel(ppu, ppu->cycle - 1, ppu->scanline, color);

	ppu->frame = FALSE;
	ppu->cycle++;
	if (ppu->cycle >= 341)
	{
		ppu->cycle = 0;
		ppu->scanline++;
		if (ppu->scanline >= 261)
		{
			ppu->scanline = -1;
			ppu->frame = TRUE;
		}
	}
}

void ppu_update_shifters(PPU* ppu)
{
	if (ppu->bus->mask.render_background)
	{
		ppu->bg_shifter_attrib_lo <<= 1;
		ppu->bg_shifter_attrib_hi <<= 1;
		ppu->bg_shifter_attrib_lo <<= 1;
		ppu->bg_shifter_attrib_hi <<= 1;
	}
}

void ppu_load_background_shifters(PPU* ppu)
{
	ppu->bg_shifter_pattern_lo = (ppu->bg_shifter_pattern_lo & 0xFF00) |   ppu->bg_next_tile_lsb;
	ppu->bg_shifter_pattern_hi = (ppu->bg_shifter_pattern_hi & 0xFF00) |   ppu->bg_next_tile_msb;
	ppu->bg_shifter_attrib_lo  = (ppu->bg_shifter_attrib_lo  & 0xFF00) | ((ppu->bg_next_tile_attrib & 0b01) ? 0xFF : 0x00);
	ppu->bg_shifter_attrib_hi  = (ppu->bg_shifter_attrib_hi  & 0xFF00) | ((ppu->bg_next_tile_attrib & 0b10) ? 0xFF : 0x00);
}

void ppu_increment_scroll_x(PPU* ppu)
{
	if (ppu->bus->mask.render_background || ppu->bus->mask.render_sprites)
	{
		if (ppu->vram_addr.coarse_x == 31)
		{
			ppu->vram_addr.coarse_x = 0;
			ppu->vram_addr.nametable_x = ~(ppu->vram_addr.nametable_x);
		}
		else
			ppu->vram_addr.coarse_x++;
	}
}

void ppu_increment_scroll_y(PPU* ppu)
{
	if (ppu->bus->mask.render_background || ppu->bus->mask.render_sprites)
	{
		if (ppu->vram_addr.fine_y < 7)
			ppu->vram_addr.fine_y++;
		else
		{
			ppu->vram_addr.fine_y = 0;

			if (ppu->vram_addr.coarse_y == 29)
			{
				ppu->vram_addr.coarse_y = 0;
				ppu->vram_addr.nametable_y = ~ppu->vram_addr.nametable_y;
			}
			else if (ppu->vram_addr.coarse_y == 31)
				ppu->vram_addr.coarse_y = 0;
			else
				ppu->vram_addr.coarse_y++;
		}
	}
}

void ppu_transfer_address_x(PPU* ppu)
{
	if (ppu->bus->mask.render_background || ppu->bus->mask.render_sprites)
	{
		ppu->vram_addr.nametable_x = ppu->tram_addr.nametable_x;
		ppu->vram_addr.coarse_x = ppu->tram_addr.coarse_x;
	}
}

void ppu_transfer_address_y(PPU* ppu)
{
	if (ppu->bus->mask.render_background || ppu->bus->mask.render_sprites)
	{
		ppu->vram_addr.fine_y = ppu->tram_addr.fine_y;
		ppu->vram_addr.nametable_y = ppu->tram_addr.nametable_y;
		ppu->vram_addr.coarse_y = ppu->tram_addr.coarse_y;
	}
}

void ppu_set_pixel(PPU* ppu, uint16_t x, uint16_t y, uint32_t color)
{
	if (x >= 256 || y >= 240)
		return;
	if (color == 0xFF000000)
		return;
	uint32_t index = y * 256 + x;
	ppu->screen[index] = color;
}

uint32_t ppu_get_color_from_palette_ram(PPU* ppu, uint8_t palette, uint8_t pixel)
{
	uint16_t addr = 0x3F00 + ((uint16_t)palette << 2) + pixel;
	uint16_t val = ppu_bus_read(ppu->bus, addr);
	return palScreen[val & 0x3F];
}

#include <stdio.h>
void ppu_get_palette_table(PPU* ppu, uint8_t palette, uint32_t* data)
{
	if (data == NULL)
	{
		printf("%08u %08u %08u %08u\n",
			ppu_get_color_from_palette_ram(ppu, palette, 0),
			ppu_get_color_from_palette_ram(ppu, palette, 1),
			ppu_get_color_from_palette_ram(ppu, palette, 2),
			ppu_get_color_from_palette_ram(ppu, palette, 3)
		);
	}
	else
	{
		data[0] = ppu_get_color_from_palette_ram(ppu, palette, 0);
		data[1] = ppu_get_color_from_palette_ram(ppu, palette, 1);
		data[2] = ppu_get_color_from_palette_ram(ppu, palette, 2);
		data[3] = ppu_get_color_from_palette_ram(ppu, palette, 3);
	}
}

void ppu_get_pattern_table(PPU* ppu, uint8_t i, uint8_t palette, uint32_t* data)
{
	for (uint16_t nTileY = 0; nTileY < 16; nTileY++)
	{
		for (uint16_t nTileX = 0; nTileX < 16; nTileX++)
		{
			// Convert the 2D tile coordinate into a 1D offset into the pattern
			// table memory.
			uint16_t nOffset = nTileY * 256 + nTileX * 16;

			// Now loop through 8 rows of 8 pixels
			for (uint16_t row = 0; row < 8; row++)
			{
				// For each row, we need to read both bit planes of the character
				// in order to extract the least significant and most significant 
				// bits of the 2 bit pixel value. in the CHR ROM, each character
				// is stored as 64 bits of lsb, followed by 64 bits of msb. This
				// conveniently means that two corresponding rows are always 8
				// bytes apart in memory.
				uint8_t tile_lsb = ppu_bus_read(ppu->bus, i * 0x1000 + nOffset + row + 0x0000);
				uint8_t tile_msb = ppu_bus_read(ppu->bus, i * 0x1000 + nOffset + row + 0x0008);


				// Now we have a single row of the two bit planes for the character
				// we need to iterate through the 8-bit words, combining them to give
				// us the final pixel index
				for (uint16_t col = 0; col < 8; col++)
				{
					// We can get the index value by simply adding the bits together
					// but we're only interested in the lsb of the row words because...
					uint8_t pixel = (tile_lsb & 0x01) + (tile_msb & 0x01);

					// ...we will shift the row words 1 bit right for each column of
					// the character.
					tile_lsb >>= 1; tile_msb >>= 1;

					// Now we know the location and NES pixel value for a specific location
					// in the pattern table, we can translate that to a screen colour, and an
					// (x,y) location in the sprite
					data[nTileX * 8 + (7 - col) + (nTileY * 8 + row)* 128] = ppu_get_color_from_palette_ram(ppu, palette, pixel);
				}
			}
		}
	}
}
<file_sep>/Utils/include/utils/utils.h
#ifndef __UTILS_H__
#define __UTILS_H__


#ifdef UTILS_EXPORTS
#define UTILS_API __declspec(dllexport)
#else
#define UTILS_API __declspec(dllimport)
#endif


#endif
<file_sep>/Emulator.core/include/emulator/car/core/cartridge.h
#ifndef __DLL_EMULATOR_CAR_CORE_CARTRIDGE_H__
#define __DLL_EMULATOR_CAR_CORE_CARTRIDGE_H__
#include <emulator/emulator_core.h>
#include <emulator/car/mappers/mapperProvider.h>
typedef struct cartridge Cartridge;


EMULATOR_API Cartridge* cartridge_load_from_file(const char* file, car_mapper_provider provider);
EMULATOR_API void cartridge_destroy(Cartridge* cartridge);

#endif<file_sep>/Emulator.Mapper0/src/emulator/car/mappers/Mapper0.h
#ifndef __EMULATOR_CAR_MAPPERS_MAPPER_0_H__
#define __EMULATOR_CAR_MAPPERS_MAPPER_0_H__
#include <emulator/car/mappers/mapper0.h>
#include <utils/boolean.h>

bool mapper_0_init(Mapper* mapper);
void mapper_0_destroy(Mapper* mapper);
uint32_t mapper_0_prg_read(Mapper* mapper, uint16_t addr);
uint32_t mapper_0_prg_write(Mapper* mapper, uint16_t addr);
uint32_t mapper_0_chr_read(Mapper* mapper, uint16_t addr);
uint32_t mapper_0_chr_write(Mapper* mapper, uint16_t addr);


#endif<file_sep>/Utils/src/utils/Boolean.h
#ifndef __UTILS_BOOLEAN_H__
#define __UTILS_BOOLEAN_H__
#include <utils/boolean.h>

#endif
<file_sep>/Emulator.core/src/emulator/ppu/bus/PPU_Bus.h
#ifndef __EMULATOR_PPU_BUS_H__
#define __EMULATOR_PPU_BUS_H__

#include "../../car/core/Cartridge.h"
#include "TblName.h"


typedef struct ppu_bus
{
	Cartridge** car;
	Tbl_Name* tbl_name;
	uint8_t tblPalette[32];
	union mask_u
	{
		struct
		{
			uint8_t grayscale : 1;
			uint8_t render_background_left : 1;
			uint8_t render_sprites_left : 1;
			uint8_t render_background : 1;
			uint8_t render_sprites : 1;
			uint8_t enhance_red : 1;
			uint8_t enhance_green : 1;
			uint8_t enhance_blue : 1;
		};
		uint8_t reg;
	} mask;
} PPU_Bus;

PPU_Bus* ppu_bus_init(Cartridge**car);
void ppu_bus_destroy(PPU_Bus* bus);
uint8_t ppu_bus_read(PPU_Bus* bus, uint16_t addr);
void ppu_bus_write(PPU_Bus* bus, uint16_t addr, uint8_t value);





#endif<file_sep>/Emulator.core/src/emulator/ppu/bus/PPU_Bus.c
#include "PPU_Bus.h"
#include <stdlib.h>
#include <string.h>

PPU_Bus* ppu_bus_init(Cartridge** car)
{
	PPU_Bus* bus = (PPU_Bus*)malloc(sizeof(PPU_Bus));
	if (bus == NULL)
		return NULL;
	bus->car = car;
	bus->tbl_name = tbl_name_init();
	if (bus->tbl_name == NULL)
	{
		free(bus);
		return NULL;
	}
	memset(bus->tblPalette, 0x00, 32 * sizeof(uint8_t));
	return bus;
}

void ppu_bus_destroy(PPU_Bus* bus)
{
	if (bus == NULL)
		return;
	tbl_name_destroy(bus->tbl_name);
	free(bus);
}

uint8_t ppu_bus_read(PPU_Bus* bus, uint16_t addr)
{
	addr &= 0x3FFF;
	if (addr >= 0x0000 && addr <= 0x1FFF)
		return cartridge_read_chr(*(bus->car), addr);
	if (addr >= 0x2000 && addr <= 0x3EFF)
		return tbl_name_read(bus->tbl_name, addr, (*bus->car)->mirror);
	if (addr >= 0x3F00 && addr <= 0x3FFF)
	{
		addr &= 0x001F;
		if (addr == 0x0010)
			addr = 0x0000;
		if (addr == 0x0014)
			addr = 0x0004;
		if (addr == 0x0018)
			addr = 0x0008;
		if (addr == 0x001C)
			addr = 0x000C;
		return bus->tblPalette[addr] &(bus->mask.grayscale ? 0x30 : 0x3F);
	}
	return 0x00;
}

void ppu_bus_write(PPU_Bus* bus, uint16_t addr, uint8_t value)
{
	addr &= 0x3FFF;
	if (addr >= 0x0000 && addr <= 0x1FFF)
		cartridge_write_chr(*(bus->car), addr, value);
	if (addr >= 0x2000 && addr <= 0x3EFF)
		tbl_name_write(bus->tbl_name, addr, value, (*bus->car)->mirror);
	if (addr >= 0x3F00 && addr <= 0x3FFF)
	{
		addr &= 0x001F;
		if (addr == 0x0010)
			addr = 0x0000;
		if (addr == 0x0014)
			addr = 0x0004;
		if (addr == 0x0018)
			addr = 0x0008;
		if (addr == 0x001C)
			addr = 0x000C;
		bus->tblPalette[addr] = value;
	}
}<file_sep>/Emulator.MapperProvider/include/emulator/car/mappers/mapperDllProvider.h
#ifndef __DLL_EMULATOR_MAPPER_DLL_PROVIDER__
#define __DLL_EMULATOR_MAPPER_DLL_PROVIDER__

#ifndef EMULATOR_MAPPER_DLL_PROVIDER_API
#ifdef EMULATORMAPPERPROVIDER_EXPORTS
#define EMULATOR_MAPPER_DLL_PROVIDER_API __declspec(dllexport)
#else
#define EMULATOR_MAPPER_DLL_PROVIDER_API __declspec(dllimport)
#endif
#endif

#include <emulator/car/mappers/mapperProvider.h>

EMULATOR_MAPPER_DLL_PROVIDER_API Mapper* mapper_dll_provider(uint16_t mapper_id);


#endif<file_sep>/Emulator.core/src/emulator/cpu/core/CPU.c
#include "CPU.h"
#include "instructions/cpu_instructions.h"

#include <stdlib.h>
#include <string.h>


CPU* cpu_init()
{
	CPU* cpu = (CPU*)malloc(sizeof(CPU));
	if (cpu == NULL)
		return NULL;

	memset(cpu, 0x00, sizeof(CPU));

	cpu->registery = registery_init();
	if (cpu->registery == NULL)
	{
		free(cpu);
		return NULL;
	}
	cpu->bus = bus_init();
	if (cpu->bus == NULL) {
		registery_destroy(cpu->registery);
		free(cpu);
		return NULL;
	}

	cpu->registery->sp = STACK_POINTER_INIT;

	return cpu;
}

void cpu_destroy(CPU* cpu)
{
	if (cpu == NULL)
		return;
	bus_destroy(cpu->bus);
	registery_destroy(cpu->registery);
	free(cpu);
}

void cpu_status_set(const CPU* cpu, flag flag, bool value)
{
	status_set(cpu->registery, flag, value);
}

bool cpu_status_get(const CPU* cpu, flag flag)
{
	return status_get(cpu->registery, flag);
}

uint8_t cpu_bus_read(const CPU* cpu, uint16_t address)
{
	return bus_read(cpu->bus, address);
}

void cpu_bus_write(const CPU* cpu, uint16_t address, uint8_t value)
{
	bus_write(cpu->bus, address, value);
}

uint8_t cpu_bus_read_pc(const CPU* cpu)
{
	uint8_t value = cpu_bus_read(cpu, cpu->registery->pc);
	cpu->registery->pc++;
	return value;
}

void cpu_stack_push(const CPU* cpu, uint8_t value)
{
	cpu_bus_write(cpu, STACK_POSITION_START + cpu->registery->sp, value);
	cpu->registery->sp--;
}

uint8_t cpu_stack_pop(const CPU* cpu)
{
	cpu->registery->sp++;
	uint8_t value = cpu_bus_read(cpu, STACK_POSITION_START + cpu->registery->sp);
	return value;
}


// Reset Interrupt - Forces CPU into known state
//
// in core, the core to send the reset interrupt
void cpu_signal_reset(CPU* cpu)
{
	cpu->addr_abs = RESET_ADDRESS;
	uint16_t lo = cpu_bus_read(cpu, cpu->addr_abs);
	uint16_t hi = cpu_bus_read(cpu, cpu->addr_abs + 1);

	cpu->registery->pc = (hi << 8) | lo;
	cpu->registery->a = 0x00;
	cpu->registery->x = 0x00;
	cpu->registery->y = 0x00;
	cpu->registery->sp = STACK_POINTER_INIT;
	cpu->registery->s = 0x00 | FLAG_U;

	cpu->addr_rel = 0x0000;
	cpu->addr_abs = 0x0000;
	cpu->alu = 0x00;
	cpu->cycles = 0x00;
}

// Interrupt Request - Executes an instruction at a specific location
//
// in core, the core to send the interrupt request
void cpu_signal_irq(CPU* cpu)
{
	if (cpu_status_get(cpu, FLAG_I) == TRUE)
		return;
	cpu_stack_push(cpu, (cpu->registery->pc >> 8) & 0x00ff);
	cpu_stack_push(cpu, cpu->registery->pc & 0x00ff);

	cpu_status_set(cpu, FLAG_B, FALSE);
	cpu_status_set(cpu, FLAG_U, TRUE);
	cpu_status_set(cpu, FLAG_I, TRUE);
	cpu_stack_push(cpu, cpu->registery->s);

	cpu->addr_abs = IRQ_ADDRESS;
	uint16_t lo = cpu_bus_read(cpu, cpu->addr_abs);
	uint16_t hi = cpu_bus_read(cpu, cpu->addr_abs + 1);
	cpu->registery->pc = (hi << 8) | lo;

	cpu->cycles = 7;
}

// Non-Maskable Interrupt Request - Executes an instruction at a specific
// location, but cannot be disabled
//
// in core, the core to send the interrupt request
void cpu_signal_nmi(CPU * cpu)
{
	cpu_stack_push(cpu, (cpu->registery->pc >> 8) & 0x00ff);
	cpu_stack_push(cpu, cpu->registery->pc & 0x00ff);

	cpu_status_set(cpu, FLAG_B, FALSE);
	cpu_status_set(cpu, FLAG_U, TRUE);
	cpu_status_set(cpu, FLAG_I, TRUE);
	cpu_stack_push(cpu, cpu->registery->s);

	cpu->addr_abs = NMI_ADDRESS;
	uint16_t lo = cpu_bus_read(cpu, cpu->addr_abs);
	uint16_t hi = cpu_bus_read(cpu, cpu->addr_abs + 1);
	cpu->registery->pc = (hi << 8) | lo;

	cpu->cycles = 8;
}

// Perform one clock cycle's worth of update
//
// in core, the core to tick
void cpu_clock(CPU* cpu)
{
#ifdef COUNT_CYCLES
	cpu->clock_count++;
#endif
	if (cpu_clock_complete(cpu) == FALSE) {
		cpu->cycles--;
		return;
	}
	if (cpu->registery->pc == 0x0C6BD)
	{
		int i = 0;
	}
	cpu->opt_code = cpu_bus_read_pc(cpu);
	cpu_status_set(cpu, FLAG_U, TRUE);

	cpu->cycles = lookup[cpu->opt_code].cycles;

	uint8_t extra_addr = (*lookup[cpu->opt_code].addr_mode)(cpu);
	uint8_t extra_oper = (*lookup[cpu->opt_code].operation)(cpu);

	cpu->cycles += extra_addr & extra_oper;

	cpu_status_set(cpu, FLAG_U, TRUE);

	cpu->cycles--;
}

bool cpu_clock_complete(const CPU * cpu)
{
	if (cpu->cycles == 0)
		return TRUE;
	return FALSE;
}

<file_sep>/Emulator.core/include/emulator/emulator.h
#ifndef __EMULATOR_H__
#define __EMULATOR_H__

#include "emulator_core.h"
#include <utils/boolean.h>
#include <inttypes.h>

typedef struct cartridge Cartridge;
typedef struct emulator Emulator;



EMULATOR_API Emulator* emulator_init();


EMULATOR_API void emulator_destroy(Emulator* emulator);

EMULATOR_API Cartridge* emulator_insert_cartridge(Emulator* emulator, Cartridge* car);

EMULATOR_API Cartridge* emulator_remove_cartridge(Emulator* emulator);

EMULATOR_API void emulator_signal_reset(Emulator* emulator);

EMULATOR_API void emulator_tick(Emulator* emulator);

EMULATOR_API uint8_t emulator_get_cpu_bus(Emulator* emulator, uint16_t addr);

EMULATOR_API uint8_t emulator_get_ppu_bus(Emulator* emulator, uint16_t addr);

EMULATOR_API uint16_t emulator_get_pc(Emulator* emulator);

EMULATOR_API uint8_t emulator_get_cpu_reg_a(Emulator* emulator);

EMULATOR_API uint8_t emulator_get_cpu_reg_x(Emulator* emulator);

EMULATOR_API uint8_t emulator_get_cpu_reg_y(Emulator* emulator);

EMULATOR_API uint8_t emulator_get_cpu_reg_sp(Emulator* emulator);

EMULATOR_API void emulator_set_pc(Emulator* emulator, uint16_t pc);

EMULATOR_API void emulator_get_screen(Emulator* emulator, uint32_t* screen, size_t size);

EMULATOR_API uint8_t emulator_get_screen_pixel(Emulator* emulator, int x, int y);

EMULATOR_API bool emulator_is_screen_ready(Emulator* emulator);

EMULATOR_API void emulator_get_pattern_table(Emulator* emulator, uint8_t i, uint8_t palette, uint32_t* data);

EMULATOR_API void emulator_get_palette_table(Emulator* emulator, uint8_t palette, uint32_t* data);

#endif<file_sep>/Emulator.core/src/emulator/Emulator.h
#ifndef __EMULATOR_EMULATOR_H__
#define __EMULATOR_EMULATOR_H__
#include "cpu/core/CPU.h"


struct emulator
{
	CPU* cpu;
	uint8_t cpu_timer;
};



#include <emulator/emulator.h>
#endif<file_sep>/Emulator.core/src/emulator/ppu/core/PPU.h
#ifndef __EMULATOR_PPU_CORE_PPU_H__
#define __EMULATOR_PPU_CORE_PPU_H__
#include <inttypes.h>
#include "../../car/core/Cartridge.h"
#include "../bus/PPU_Bus.h"

typedef union loopy_register_u
{
	// Source OneLoneCoder
	// Credit to Loopy for working this out
	struct
	{
		uint16_t coarse_x : 5;
		uint16_t coarse_y : 5;
		uint16_t nametable_x : 1;
		uint16_t nametable_y : 1;
		uint16_t fine_y : 3;
		uint16_t unused : 1;
	};
	uint16_t reg;
} loopy_register;


typedef struct ppu {
	PPU_Bus* bus;
	Cartridge ** car;
	//uint8_t tblPattern[2][4096];
	int16_t scanline;
	int16_t cycle;
	bool frame;
	union status_u
	{
		struct {
			uint8_t unused : 5;
			uint8_t sprite_overflow : 1;
			uint8_t sprite_zero_hit : 1;
			uint8_t vertical_blank : 1;
		};
		uint8_t reg;
	} status;
	union PPUCTRL
	{
		struct
		{
			uint8_t nametable_x : 1;
			uint8_t nametable_y : 1;
			uint8_t increment_mode : 1;
			uint8_t pattern_sprite : 1;
			uint8_t pattern_background : 1;
			uint8_t sprite_size : 1;
			uint8_t slave_mode : 1; // unused
			uint8_t enable_nmi : 1;
		};
		uint8_t reg;
	} control;
	loopy_register vram_addr;
	loopy_register tram_addr; 
	uint8_t fine_x;
	uint8_t address_latch;
	uint8_t ppu_data_buffer;
	uint8_t bg_next_tile_id;
	uint8_t bg_next_tile_attrib;
	uint8_t bg_next_tile_lsb;
	uint8_t bg_next_tile_msb;
	uint16_t bg_shifter_pattern_lo;
	uint16_t bg_shifter_pattern_hi;
	uint16_t bg_shifter_attrib_lo;
	uint16_t bg_shifter_attrib_hi;
	bool nmi;
	uint32_t* screen;
} PPU;

PPU* ppu_init(Cartridge** car);

void ppu_destroy(PPU* ppu);

uint8_t ppu_read(PPU* ppu, uint16_t addr);

void ppu_write(PPU* ppu, uint16_t addr, uint8_t value);

void ppu_tick(PPU* ppu);

void ppu_update_shifters(PPU* ppu);

void ppu_load_background_shifters(PPU* ppu);

void ppu_increment_scroll_x(PPU* ppu);

void ppu_increment_scroll_y(PPU* ppu);

void ppu_transfer_address_x(PPU* ppu);

void ppu_transfer_address_y(PPU* ppu);

void ppu_set_pixel(PPU* ppu, uint16_t x, uint16_t y, uint32_t color);

uint32_t ppu_get_color_from_palette_ram(PPU* ppu, uint8_t palette, uint8_t pixel);

void ppu_get_palette_table(PPU* ppu, uint8_t palette, uint32_t* data);

void ppu_get_pattern_table(PPU* ppu, uint8_t i, uint8_t palette, uint32_t* data);

#endif<file_sep>/Emulator.core/src/emulator/cpu/core/CPU.h
#ifndef __EMULATOR_CPU_CORE_CPU_H__
#define __EMULATOR_CPU_CORE_CPU_H__

#include "Registery.h"
#include "settings.h"
#include "../bus/Bus.h"

typedef struct cpu {
	Registery * registery;
	uint8_t alu; // Represents the working input value to the ALU
	uint16_t temp; // A convenience variable used everywhere
	uint16_t addr_abs; // All used memory addresses end up in here
	uint16_t addr_rel; // Represents absolute address following a branch
	uint8_t opt_code; // Is the instruction byte
	uint8_t cycles; // Counts how many cycles the instruction has remaining
#ifdef COUNT_CYCLES
	uint64_t clock_count; //  global accumulation of the number of clocks
#endif
	Bus* bus;
} CPU;

CPU* cpu_init();

void cpu_destroy(CPU* cpu);

void cpu_status_set(const CPU* cpu, flag flag, bool value);

bool cpu_status_get(const CPU* cpu, flag flag);

uint8_t cpu_bus_read(const CPU* cpu, uint16_t address);

void cpu_bus_write(const CPU* cpu, uint16_t address, uint8_t value);

uint8_t cpu_bus_read_pc(const CPU* cpu);

void cpu_stack_push(const CPU* cpu, uint8_t value);

uint8_t cpu_stack_pop(const CPU* cpu);

// Reset Interrupt - Forces CPU into known state
//
// in core, the core to send the reset interrupt
void cpu_signal_reset(CPU* cpu);

// Interrupt Request - Executes an instruction at a specific location
//
// in core, the core to send the interrupt request
void cpu_signal_irq(CPU* cpu);

// Non-Maskable Interrupt Request - Executes an instruction at a specific
// location, but cannot be disabled
//
// in core, the core to send the interrupt request
void cpu_signal_nmi(CPU* cpu);

// Perform one clock cycle's worth of update
//
// in core, the core to tick
void cpu_clock(CPU* cpu);

bool cpu_clock_complete(const CPU* cpu);

#endif
<file_sep>/Emulator.core/src/emulator/car/core/CartridgeHeader.h
#ifndef __EMULATOR_CAR_CORE_CARTRIDGE_HEADER__H__
#define __EMULATOR_CAR_CORE_CARTRIDGE_HEADER_H__
#include <inttypes.h>


typedef struct cartridge_header {
	char name[4];
	uint8_t size_prg_rom;
	uint8_t size_chr_rom;
	uint8_t mapper_1;
	uint8_t mapper_2;
	uint8_t size_prg_ram;
	uint8_t tv_system_1;
	uint8_t tv_system_2;
	uint8_t unused_1;
	uint8_t unused_2;
	uint8_t unused_3;
	uint8_t unused_4;
	uint8_t unused_5;
} CartridgeHeader;




#endif<file_sep>/Emulator.core/src/main.c
#include "emulator/cpu/core/CPU.h"

int main(int argv, char** args)
{
	CPU* cpu = cpu_init();
	
	cpu_destroy(cpu);
	return cpu != NULL ? 0 : 1;
}<file_sep>/Emulator.core/src/emulator/cpu/core/settings.h
#ifndef __EMULATOR_CPU_CORE_SETTINGS_H__
#define __EMULATOR_CPU_CORE_SETTINGS_H__


#define INCLUDE_HARDWARE_BUG_IND

#define RAM_START       0x0000
#define RAM_END         0x07ff

#define RAM_CLONE_START 0x0800
#define RAM_CLONE_END   0x1fff

#define PPU_START       0x2000
#define PPU_END         0x2007

#define PPU_CLONE_START 0x2008
#define PPU_CLONE_END   0x3fff

#define APU_START       0x4000
#define APU_END         0x4017

#define DIS_START       0x4018
#define DIS_END         0x401f

#define ROM_START       0x4020
#define ROM_END         0xffff


#define CAR_PRG_START   0x8000
#define CAR_PRG_END     0xffff

#define RESET_ADDRESS 0xFFFC // the address where the pc will be fetched after a reset signal
#define IRQ_ADDRESS 0xFFFE // the address where the pc will be fetched after a irq signal
#define NMI_ADDRESS 0xFFFA // the address where the pc will be fetched after a nmi signal

#define STACK_POINTER_INIT 0x00FD // the stack pointer initial value
#define STACK_POSITION_START 0x0100 // the starting position of the stack


#endif<file_sep>/Emulator.MapperProvider/src/emulator/car/mappers/MapperDllProvider.h
#ifndef __EMULATOR_CAR_MAPPERS_MAPPER_DLL_PROVIDER_H__
#define __EMULATOR_CAR_MAPPERS_MAPPER_DLL_PROVIDER_H__
#include <emulator/car/mappers/mapperDllProvider.h>


#endif<file_sep>/Emulator.core/src/emulator/cpu/bus/Bus.h
#ifndef __EMULATOR_CPU_BUS_BUS_H__
#define __EMULATOR_CPU_BUS_BUS_H__
#include "../../ppu/core/PPU.h"
#include "../../car/core/Cartridge.h"
#include <inttypes.h>

typedef struct bus {
	uint8_t* ram;
	PPU* ppu;
	Cartridge* car;
} Bus;

Bus* bus_init();

uint8_t bus_read(const Bus* bus, uint16_t addr);

void bus_write(const Bus* bus, uint16_t addr, uint8_t value);

Cartridge* bus_destroy(Bus* bus);

Cartridge* bus_insert_cartridge(Bus* bus, Cartridge* car);

Cartridge* bus_remove_cartridge(Bus* bus);

void bus_tick(Bus* bus);

#endif
<file_sep>/Emulator.Mapper0/include/emulator/car/mappers/mapper0.h
#ifndef __DLL_MAPPER0__
#define __DLL_MAPPER0__

#ifndef EMULATOR_MAPPER0_API
#ifdef EMULATORMAPPER0_EXPORTS
#define EMULATOR_MAPPER0_API __declspec(dllexport)
#else
#define EMULATOR_MAPPER0_API __declspec(dllimport)
#endif
#endif

#include <emulator/car/mappers/mapperProvider.h>

EMULATOR_MAPPER0_API Mapper* mapper_0_provider(uint16_t mapper_id);


#endif<file_sep>/Emulator.core/src/emulator/cpu/core/instructions/addressing.c
#include "addressing.h"
#include "../settings.h"

// Address Mode: Implied
// There is no additional data required for this instruction. The instruction
// does something very simple like like sets a status bit. However, we will
// target the accumulator, for instructions like PHA
uint8_t cpu_instruction_addressing_imp(CPU* core)
{
	core->alu = core->registery->a;
	return 0;
}

// Address Mode: Immediate
// The instruction expects the next byte to be used as a value, so we'll prep
// the read address to point to the next byte
uint8_t cpu_instruction_addressing_imm(CPU* core)
{
	core->addr_abs = core->registery->pc++;
	return 0;
}

// Address Mode: Zero Page
// To save program bytes, zero page addressing allows you to absolutely address
// a location in first 0xFF bytes of address range. Clearly this only requires
// one byte instead of the usual two.
uint8_t cpu_instruction_addressing_zp0(CPU* core)
{
	core->addr_abs = cpu_bus_read_pc(core);
	core->addr_abs &= 0x00ff;
	return 0;
}

// Address Mode: Zero Page with X Offset
// Fundamentally the same as Zero Page addressing, but the contents of the X Register
// is added to the supplied single byte address. This is useful for iterating through
// ranges within the first page.
uint8_t cpu_instruction_addressing_zpx(CPU* core)
{
	core->addr_abs = cpu_bus_read_pc(core);
	core->addr_abs += core->registery->x;
	core->addr_abs &= 0x00ff;
	return 0;
}

// Address Mode: Zero Page with Y Offset
// Fundamentally the same as Zero Page addressing, but the contents of the Y Register
// is added to the supplied single byte address. This is useful for iterating through
// ranges within the first page.
uint8_t cpu_instruction_addressing_zpy(CPU* core)
{
	core->addr_abs = cpu_bus_read_pc(core);
	core->addr_abs += core->registery->y;
	core->addr_abs &= 0x00ff;
	return 0;
}

// Address Mode: Relative
// This address mode is exclusive to branch instructions. The address
// must reside within -128 to +127 of the branch instruction, i.e.
// you cant directly branch to any address in the addressable range.
uint8_t cpu_instruction_addressing_rel(CPU* core)
{
	core->addr_rel = cpu_bus_read_pc(core);
	if (core->addr_rel & 0x80)
		core->addr_rel |= 0xff00;
	return 0;
}

// Address Mode: Absolute 
// A full 16-bit address is loaded and used
uint8_t cpu_instruction_addressing_abs(CPU* core)
{
	uint16_t lo = cpu_bus_read_pc(core);
	uint16_t hi = cpu_bus_read_pc(core);
	core->addr_abs = (hi << 8) | lo;
	return 0;
}

// Address Mode: Absolute with X Offset
// Fundamentally the same as absolute addressing, but the contents of the X Register
// is added to the supplied two byte address. If the resulting address changes
// the page, an additional clock cycle is required
uint8_t cpu_instruction_addressing_abx(CPU* core)
{
	uint16_t lo = cpu_bus_read_pc(core);
	uint16_t hi = cpu_bus_read_pc(core);
	core->addr_abs = (hi << 8) | lo;
	core->addr_abs += core->registery->x;
	if ((core->addr_abs & 0xff00) != (hi << 8))
		return 1;
	return 0;
}

// Address Mode: Absolute with Y Offset
// Fundamentally the same as absolute addressing, but the contents of the Y Register
// is added to the supplied two byte address. If the resulting address changes
// the page, an additional clock cycle is required
uint8_t cpu_instruction_addressing_aby(CPU* core)
{
	uint16_t lo = cpu_bus_read_pc(core);
	uint16_t hi = cpu_bus_read_pc(core);
	core->addr_abs = (hi << 8) | lo;
	core->addr_abs += core->registery->y;
	if ((core->addr_abs & 0xff00) != (hi << 8))
		return 1;
	return 0;
}

// Address Mode: Indirect
// The supplied 16-bit address is read to get the actual 16-bit address. This is
// instruction is unusual in that it has a bug in the hardware! To emulate its
// function accurately, we also need to emulate this bug. If the low byte of the
// supplied address is 0xFF, then to read the high byte of the actual address
// we need to cross a page boundary. This doesnt actually work on the chip as 
// designed, instead it wraps back around in the same page, yielding an 
// invalid actual address
uint8_t cpu_instruction_addressing_ind(CPU* core)
{
	uint16_t ptr_lo = cpu_bus_read_pc(core);
	uint16_t ptr_hi = cpu_bus_read_pc(core);
	uint16_t ptr = (ptr_hi << 8) | ptr_lo;
	uint16_t addr_lo = cpu_bus_read(core, ptr);
#ifdef INCLUDE_HARDWARE_BUG_IND
	if (ptr_lo == 0x00ff)
		ptr &= 0xff00;
	else
		ptr++;
#else
	ptr++;
#endif
	uint16_t addr_hi = cpu_bus_read(core, ptr);;
	core->addr_abs = (addr_hi << 8) | addr_lo;
	return 0;
}

// Address Mode: Indirect X
// The supplied 8-bit address is offset by X Register to index
// a location in page 0x00. The actual 16-bit address is read 
// from this location
uint8_t cpu_instruction_addressing_izx(CPU* core)
{
	uint16_t ptr = cpu_bus_read_pc(core);
	ptr += core->registery->x;
	uint16_t lo = cpu_bus_read(core, ptr & 0x00ff);
	ptr++;
	uint16_t hi = cpu_bus_read(core, ptr & 0x00ff);
	core->addr_abs = (hi << 8) | lo;
	return 0;
}

// Address Mode: Indirect Y
// The supplied 8-bit address indexes a location in page 0x00. From 
// here the actual 16-bit address is read, and the contents of
// Y Register is added to it to offset it. If the offset causes a
// change in page then an additional clock cycle is required.
uint8_t cpu_instruction_addressing_izy(CPU* core)
{
	uint16_t ptr = cpu_bus_read_pc(core);

	uint16_t lo = cpu_bus_read(core, ptr & 0x00ff);
	ptr++;
	uint16_t hi = cpu_bus_read(core, ptr & 0x00ff);
	core->addr_abs = (hi << 8) | lo;
	core->addr_abs += core->registery->y;
	if ((core->addr_abs & 0xff00) != (hi << 8))
		return 1;
	return 0;
}
<file_sep>/Emulator.Mapper0/src/emulator/car/mappers/Mapper0.c
#include "Mapper0.h"
#include <emulator/car/mappers/mapper.h>
#include <stdlib.h>

Mapper* mapper_0_provider(uint16_t mapper_id)
{
	if (mapper_id != 0)
		return NULL;
	Mapper* mapper = (Mapper*)malloc(sizeof(Mapper));
	if (mapper == NULL)
		return NULL;
	mapper->type = mapper_id;
	mapper->init = &mapper_0_init;
	mapper->destroy = &mapper_0_destroy;
	mapper->prg_read = &mapper_0_prg_read;
	mapper->prg_write = &mapper_0_prg_write;
	mapper->chr_read = &mapper_0_chr_read;
	mapper->chr_write = &mapper_0_chr_write;

	return mapper;
}

bool mapper_0_init(Mapper* mapper)
{
	if (mapper->prg_banks < 1 || mapper->prg_banks > 2)
		return FALSE;
	return TRUE;
}

void mapper_0_destroy(Mapper* mapper)
{
}

uint32_t mapper_0_prg_read(Mapper* mapper, uint16_t addr)
{
	if (mapper->prg_banks == 2 || addr < PRG_BANK_SIZE)
		return addr;
	return addr - PRG_BANK_SIZE;
}

uint32_t mapper_0_prg_write(Mapper* mapper, uint16_t addr)
{
	if (mapper->prg_banks == 2 || addr < PRG_BANK_SIZE)
		return addr;
	return addr - PRG_BANK_SIZE;
}

uint32_t mapper_0_chr_read(Mapper* mapper, uint16_t addr)
{
	return addr;
}

uint32_t mapper_0_chr_write(Mapper* mapper, uint16_t addr)
{
	return addr;
}
<file_sep>/Emulator.core/src/emulator/cpu/core/Flags.c
#include "Flags.h"


bool flag_read(flags flags, flag flag)
{
	return is_true(flags & flag);
}

void flag_write(flags* flags, flag flag, bool value)
{
	if (is_true(value))
		(*flags) |= flag;
	else
		(*flags) &= ~flag;
}


void flag_set_active(flags* flags, flag flag)
{
	flag_write(flags, flag, TRUE);
}

void flag_set_inactive(flags* flags, flag flag)
{

	flag_write(flags, flag, FALSE);
}<file_sep>/Emulator.core/src/emulator/car/core/Cartridge.c
#include "Cartridge.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>


Cartridge* cartridge_load_from_file(const char* file, car_mapper_provider provider)
{
	FILE* f;
	errno_t err = fopen_s(&f, file, "rb");
	if (f == NULL || err != 0)
	{
#ifdef _DEBUG
		printf("Error, couldn't open the file : %s\n", file);
#endif
		return NULL;
	}
	Cartridge* cartridge = (Cartridge*)malloc(sizeof(Cartridge));
	if (cartridge == NULL)
	{
#ifdef _DEBUG
		printf("Error, couldn't allocate memory for the cartridge\n");
#endif
		fclose(f);
		return NULL;
	}
	cartridge->mirror = CARTRIDGE_MIRROR_HORIZONTAL;
	fread_s(&(cartridge->header), sizeof(CartridgeHeader), sizeof(uint8_t), 16, f);

	if (cartridge->header.mapper_1 & 0x04)
		fread_s(cartridge->trainer, sizeof(uint8_t) * 512, sizeof(uint8_t), 512, f);
	else
		memset(cartridge->trainer, 0x00, sizeof(uint8_t) * 512);
	cartridge->mapper_id = ((cartridge->header.mapper_2 >> 4) << 4) | (cartridge->header.mapper_1 >> 4);

#ifdef _DEBUG
	printf("PRG : %u  CHR : %u\n", cartridge->header.size_prg_rom, cartridge->header.size_chr_rom);
#endif
	uint8_t nFileType = 1;
	uint16_t size_prg, size_chr;
	switch (nFileType)
	{
	case 1:
		size_prg = cartridge->header.size_prg_rom * PRG_BANK_SIZE;
		size_chr = cartridge->header.size_chr_rom * CHR_BANK_SIZE;
		cartridge->prg = (uint8_t*)malloc(sizeof(uint8_t) * size_prg);
		if (cartridge->prg == NULL)
		{
			free(cartridge);
			fclose(f);
#ifdef _DEBUG
			printf("Error, couldn't allocate memory for the cartridge PGR\n");
#endif
			return NULL;
		}
		cartridge->chr = (uint8_t*)malloc(sizeof(uint8_t) * size_chr);
		if (cartridge->chr == NULL)
		{
			free(cartridge->prg);
			free(cartridge);
			fclose(f);
#ifdef _DEBUG
			printf("Error, couldn't allocate memory for the cartridge CHR\n");
#endif
			return NULL;
		}
		fread_s(cartridge->prg, sizeof(uint8_t) * size_prg, sizeof(uint8_t), size_prg, f);
		fread_s(cartridge->chr, sizeof(uint8_t) * size_chr, sizeof(uint8_t), size_chr, f);
		break;
	default:
		free(cartridge);
		fclose(f);
#ifdef _DEBUG
		printf("Error, incorrect file type : %u\n", nFileType);
#endif
		return NULL;
	}
	fclose(f);
	cartridge->mapper = (*provider)(cartridge->mapper_id);
	if (cartridge->mapper != NULL)
	{
		cartridge->mapper->chr_banks = cartridge->header.size_chr_rom;
		cartridge->mapper->prg_banks = cartridge->header.size_prg_rom;
		if (is_false((*cartridge->mapper->init)(cartridge->mapper)))
		{
#ifdef _DEBUG
			printf("Error, couldn't initialize mapper %u\n", cartridge->mapper_id);
#endif
			free(cartridge->mapper);
			cartridge->mapper = NULL;
		}
	}
	if (cartridge->mapper == NULL)
	{
#ifdef _DEBUG
		printf("Error, couldn't load mapper %u\n", cartridge->mapper_id);
#endif
		free(cartridge->chr);
		free(cartridge->prg);
		free(cartridge);
		return NULL;
	}
	return cartridge;
}

void cartridge_destroy(Cartridge* cartridge)
{
	if (cartridge == NULL)
		return;
	if (cartridge->mapper != NULL)
	{
		(*cartridge->mapper->destroy)(cartridge->mapper);
		free(cartridge->mapper);
	}
	free(cartridge->chr);
	free(cartridge->prg);
	cartridge->mapper = NULL;
	cartridge->chr = NULL;
	cartridge->prg = NULL;
	free(cartridge);
}

uint8_t cartridge_read_prg(Cartridge* cartridge, uint16_t addr)
{
	uint32_t realAddr = (*cartridge->mapper->prg_read)(cartridge->mapper, addr);
	if (realAddr < UINT32_MAX)
		return cartridge->prg[realAddr];
	return 0x00;
}

void cartridge_write_prg(Cartridge* cartridge, uint16_t addr, uint8_t value)
{
	uint32_t realAddr = (*cartridge->mapper->prg_write)(cartridge->mapper, addr);
	if (realAddr < UINT32_MAX)
		cartridge->prg[realAddr] = value;
}

uint8_t cartridge_read_chr(Cartridge* cartridge, uint16_t addr)
{
	uint32_t realAddr = (*cartridge->mapper->chr_read)(cartridge->mapper, addr);
	if (realAddr < UINT32_MAX)
		return cartridge->chr[realAddr];
	return 0x00;
}

void cartridge_write_chr(Cartridge* cartridge, uint16_t addr, uint8_t value)
{
	uint32_t realAddr = (*cartridge->mapper->chr_write)(cartridge->mapper, addr);
	if (realAddr < UINT32_MAX)
		cartridge->chr[realAddr] = value;
}<file_sep>/Utils/src/utils/Boolean.c
#include "Boolean.h"

bool is_true(bool b) {
	return b != FALSE;
}

bool is_false(bool b) {
	return !is_true(b);
}<file_sep>/Utils/include/utils/boolean.h
#ifndef __UTILS_CORE_BOOLEAN_H__
#define __UTILS_CORE_BOOLEAN_H__
#include <inttypes.h>
#include "utils.h"


#ifndef bool
typedef uint8_t bool;
#endif

#define TRUE  0x01
#define FALSE 0x00

UTILS_API bool is_true(bool b);

UTILS_API bool is_false(bool b);

#endif
<file_sep>/Emulator.core/src/emulator/cpu/bus/Bus.c
#include "Bus.h"
#include <stdlib.h>
#include <string.h>
#include "../core/settings.h"

Bus* bus_init()
{
	Bus* bus = (Bus*)malloc(sizeof(Bus));
	if (bus == NULL)
		return NULL;
	
	memset(bus, 0x00, sizeof(Bus));

	size_t ram_size = RAM_END - RAM_START + 1;

	bus->ram = (uint8_t*)malloc(sizeof(uint8_t) * ram_size);
	if (bus->ram == NULL)
	{
		free(bus);
		return NULL;
	}
	memset(bus->ram, 0x00, sizeof(uint8_t)* ram_size);
	bus->car = NULL;
	bus->ppu = ppu_init(&(bus->car));
	if (bus->ppu == NULL)
	{
		free(bus->ram);
		free(bus);
		return NULL;
	}
	return bus;
}

uint8_t bus_read(const Bus* bus, uint16_t addr)
{
	if (addr >= RAM_START && addr <= RAM_END)
		return bus->ram[addr - RAM_START];
	if (addr >= RAM_CLONE_START && addr <= RAM_CLONE_END)
		return bus_read(bus, (addr & (RAM_END - RAM_START)) + RAM_START);
	if (addr >= PPU_START && addr <= PPU_END)
		return ppu_read(bus->ppu, addr - PPU_START);
	if (addr >= PPU_CLONE_START && addr <= PPU_CLONE_END)
		return bus_read(bus, (addr % (PPU_END - PPU_START )) + PPU_START);
	if (addr >= CAR_PRG_START && addr <= CAR_PRG_END)
		return cartridge_read_prg(bus->car, addr - CAR_PRG_START);
	return 0x00;
}

void bus_write(const Bus* bus, uint16_t addr, uint8_t value)
{
	if (addr >= RAM_START && addr <= RAM_END)
		bus->ram[addr - RAM_START] = value;
	else if (addr >= RAM_CLONE_START && addr <= RAM_CLONE_END)
		bus_write(bus, (addr & (RAM_END - RAM_START)) + RAM_START, value);
	else if (addr >= PPU_START && addr <= PPU_END)
		ppu_write(bus->ppu, addr - PPU_START, value);
	else if (addr >= PPU_CLONE_START && addr <= PPU_CLONE_END)
		bus_write(bus, (addr % (PPU_END - PPU_START)) + PPU_START, value);
	else if (addr >= CAR_PRG_START && addr <= CAR_PRG_END)
		cartridge_write_prg(bus->car, addr - CAR_PRG_START, value);
}

Cartridge* bus_destroy(Bus* bus)
{
	if (bus == NULL)
		return;
	Cartridge* car = bus->car;
	bus->car = NULL;
	free(bus->ram);
	free(bus);
	return car;
}

Cartridge* bus_insert_cartridge(Bus* bus, Cartridge* car)
{
	Cartridge* old = bus->car;
	bus->car = car;
	return old;
}

Cartridge* bus_remove_cartridge(Bus* bus)
{
	Cartridge* old = bus->car;
	bus->car = NULL;
	return old;
}

void bus_tick(Bus* bus)
{
	ppu_tick(bus->ppu);
}
<file_sep>/Emulator.MapperProvider/src/emulator/car/mappers/MapperDllprovider.c
#include "MapperDllProvider.h"
#include <emulator/car/mappers/mapper0.h>

Mapper* mapper_dll_provider(uint16_t mapper_id)
{
	switch (mapper_id)
	{
	case 0:
		return mapper_0_provider(mapper_id);
	default:
		return NULL;
	}
}<file_sep>/Emulator.core/src/emulator/cpu/core/instructions/operations.h
#ifndef __EMULATOR_CPU_CORE_INSTRUCTIONS_OPERATIONS__
#define __EMULATOR_CPU_CORE_INSTRUCTIONS_OPERATIONS__
#include "../CPU.h"

// Instruction: Add with Carry In
// Function:    A = A + M + C
// Flags Out:   C, V, N, Z
uint8_t cpu_instruction_operation_adc(CPU* cpu);

// Instruction: Subtraction with Borrow In
// Function:    A = A - M - (1 - C)
// Flags Out:   C, V, N, Z
uint8_t cpu_instruction_operation_sbc(CPU* cpu);

// Instruction: Bitwise Logic AND
// Function:    A = A & M
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_and(CPU* cpu);

// Instruction: Arithmetic Shift Left
// Function:    A = C <- (A << 1) <- 0
// Flags Out:   N, Z, C
uint8_t cpu_instruction_operation_asl(CPU* cpu);

// Instruction: Branch if Carry Clear
// Function:    if(C == 0) pc = address 
uint8_t cpu_instruction_operation_bcc(CPU* cpu);

// Instruction: Branch if Carry Set
// Function:    if(C == 1) pc = address
uint8_t cpu_instruction_operation_bcs(CPU* cpu);

// Instruction: Branch if Equal
// Function:    if(Z == 1) pc = address
uint8_t cpu_instruction_operation_beq(CPU* cpu);

// Instruction: Test Bits in Memory with Accumulator
// Function:    A AND M, M7 -> N, M6 -> V
uint8_t cpu_instruction_operation_bit(CPU* cpu);

// Instruction: Branch if Negative
// Function:    if(N == 1) pc = address
uint8_t cpu_instruction_operation_bmi(CPU* cpu);

// Instruction: Branch if Not Equal
// Function:    if(Z == 0) pc = addres
uint8_t cpu_instruction_operation_bne(CPU* cpu);

// Instruction: Branch if Positive
// Function:    if(N == 0) pc = address
uint8_t cpu_instruction_operation_bpl(CPU* cpu);

// Instruction: Break
// Function:    Program Sourced Interrupt
uint8_t cpu_instruction_operation_brk(CPU* cpu);

// Instruction: Branch if Overflow Clear
// Function:    if(V == 0) pc = address
uint8_t cpu_instruction_operation_bvc(CPU* cpu);

// Instruction: Branch if Overflow Set
// Function:    if(V == 1) pc = address
uint8_t cpu_instruction_operation_bvs(CPU* cpu);

// Instruction: Clear Carry Flag
// Function:    C = 0
uint8_t cpu_instruction_operation_clc(CPU* cpu);

// Instruction: Clear Decimal Flag
// Function:    D = 0
uint8_t cpu_instruction_operation_cld(CPU* cpu);

// Instruction: Disable Interrupts / Clear Interrupt Flag
// Function:    I = 0
uint8_t cpu_instruction_operation_cli(CPU* cpu);

// Instruction: Clear Overflow Flag
// Function:    V = 0
uint8_t cpu_instruction_operation_clv(CPU* cpu);

// Instruction: Compare Accumulator
// Function:    C <- A >= M      Z <- (A - M) == 0
// Flags Out:   N, C, Z
uint8_t cpu_instruction_operation_cmp(CPU* cpu);

// Instruction: Compare X Register
// Function:    C <- X >= M      Z <- (X - M) == 0
// Flags Out:   N, C, Z
uint8_t cpu_instruction_operation_cpx(CPU* cpu);

// Instruction: Compare Y Register
// Function:    C <- Y >= M      Z <- (Y - M) == 0
// Flags Out:   N, C, Z
uint8_t cpu_instruction_operation_cpy(CPU* cpu);

// Instruction: Decrement Value at Memory Location
// Function:    M = M - 1
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_dec(CPU* cpu);

// Instruction: Decrement X Register
// Function:    X = X - 1
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_dex(CPU* cpu);

// Instruction: Decrement Y Register
// Function:    Y = Y - 1
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_dey(CPU* cpu);

// Instruction: Bitwise Logic XOR
// Function:    A = A xor M
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_eor(CPU* cpu);

// Instruction: Increment Value at Memory Location
// Function:    M = M + 1
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_inc(CPU* cpu);

// Instruction: Increment X Register
// Function:    X = X + 1
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_inx(CPU* cpu);

// Instruction: Increment Y Register
// Function:    Y = Y + 1
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_iny(CPU* cpu);

// Instruction: Jump To Location
// Function:    pc = address
uint8_t cpu_instruction_operation_jmp(CPU* cpu);

// Instruction: Jump To Sub-Routine
// Function:    Push current pc to stack, pc = address
uint8_t cpu_instruction_operation_jsr(CPU* cpu);

// Instruction: Load The Accumulator
// Function:    A = M
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_lda(CPU* cpu);

// Instruction: Load The X Register
// Function:    X = M
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_ldx(CPU* cpu);

// Instruction: Load The Y Register
// Function:    Y = M
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_ldy(CPU* cpu);

// Instruction: Shift One Bit Right (Memory or Accumulator)
// Function:    0 -> [76543210] -> C
uint8_t cpu_instruction_operation_lsr(CPU* cpu);

// Instruction: No Operation
uint8_t cpu_instruction_operation_nop(CPU* cpu);

// Instruction: Bitwise Logic OR
// Function:    A = A | M
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_ora(CPU* cpu);

// Instruction: Push Accumulator to Stack
// Function:    A -> stack
uint8_t cpu_instruction_operation_pha(CPU* cpu);

// Instruction: Push Status Register to Stack
// Function:    status -> stack
// Note:        Break flag is set to 1 before push
uint8_t cpu_instruction_operation_php(CPU* cpu);

// Instruction: Pop Accumulator off Stack
// Function:    A <- stack
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_pla(CPU* cpu);

// Instruction: Pop Status Register off Stack
// Function:    Status <- stack
uint8_t cpu_instruction_operation_plp(CPU* cpu);

// Instruction: Rotate One Bit Left (Memory or Accumulator)
// C <- [76543210] <- C
uint8_t cpu_instruction_operation_rol(CPU* cpu);

// Instruction: Rotate One Bit Right (Memory or Accumulator)
// C -> [76543210] -> C
uint8_t cpu_instruction_operation_ror(CPU* cpu);

// Instruction: Return from Interrupt
// Function:    pull SR, pull PC
uint8_t cpu_instruction_operation_rti(CPU* cpu);

// Instruction: Return from Subroutine
// Function:    pull PC, PC+1 -> PC
uint8_t cpu_instruction_operation_rts(CPU* cpu);

// Instruction: Set Carry Flag
// Function:    C = 1
uint8_t cpu_instruction_operation_sec(CPU* cpu);

// Instruction: Set Decimal Flag
// Function:    D = 1
uint8_t cpu_instruction_operation_sed(CPU* cpu);

// Instruction: Set Interrupt Flag / Enable Interrupts
// Function:    I = 1
uint8_t cpu_instruction_operation_sei(CPU* cpu);

// Instruction: Store Accumulator at Address
// Function:    M = A
uint8_t cpu_instruction_operation_sta(CPU* cpu);

// Instruction: Store X Register at Address
// Function:    M = X
uint8_t cpu_instruction_operation_stx(CPU* cpu);

// Instruction: Store Y Register at Address
// Function:    M = Y
uint8_t cpu_instruction_operation_sty(CPU* cpu);

// Instruction: Transfer Accumulator to X Register
// Function:    X = A
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_tax(CPU* cpu);

// Instruction: Transfer Accumulator to Y Register
// Function:    Y = A
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_tay(CPU* cpu);

// Instruction: Transfer Stack Pointer to X Register
// Function:    X = stack pointer
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_tsx(CPU* cpu);

// Instruction: Transfer X Register to Accumulator
// Function:    A = X
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_txa(CPU* cpu);

// Instruction: Transfer X Register to Stack Pointer
// Function:    stack pointer = X
uint8_t cpu_instruction_operation_txs(CPU* cpu);

// Instruction: Transfer Y Register to Accumulator
// Function:    A = Y
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_tya(CPU* cpu);

uint8_t cpu_instruction_operation_lax(CPU* cpu);
uint8_t cpu_instruction_operation_sax(CPU* cpu);
uint8_t cpu_instruction_operation_dcp(CPU* cpu);
uint8_t cpu_instruction_operation_isc(CPU* cpu);
uint8_t cpu_instruction_operation_rla(CPU* cpu);
uint8_t cpu_instruction_operation_rra(CPU* cpu);
uint8_t cpu_instruction_operation_slo(CPU* cpu);
uint8_t cpu_instruction_operation_sre(CPU* cpu);

// This function captures illegal opcodes
uint8_t cpu_instruction_operation_xxx(CPU* cpu);

#endif<file_sep>/Emulator.core/include/emulator/emulator_core.h
#ifndef EMULATOR_API
#ifdef EMULATOR_CORE_DLL
#define EMULATOR_API __declspec(dllexport)
#else
#define EMULATOR_API __declspec(dllimport)
#endif
#endif<file_sep>/Emulator.core/include/emulator/car/mappers/mapperProvider.h
#ifndef __DLL_EMULATOR_CAR_MAPPERS_MAPPER_PROVIDER_H__
#define __DLL_EMULATOR_CAR_MAPPERS_MAPPER_PROVIDER_H__

#include <emulator/emulator_core.h>
#include <inttypes.h>

typedef struct mapper Mapper;

typedef Mapper* (*car_mapper_provider)(uint16_t mapper_id);

#endif<file_sep>/Emulator.core/src/utils/boolean.h
#ifndef __UTILS_BOOLEAN_H__
#define __UTILS_BOOLEAN_H__
#include <inttypes.h>

#ifndef bool
typedef uint8_t bool;
#endif

#define TRUE  0x01
#define FALSE 0x00

bool is_true(bool b);

bool is_false(bool b);

#endif
<file_sep>/Emulator.core/include/emulator/car/mappers/mapper.h
#ifndef __DLL_EMULATOR_CAR_MAPPERS_MAPPER_H__
#define __DLL_EMULATOR_CAR_MAPPERS_MAPPER_H__

#include <emulator/emulator_core.h>
#include <utils/boolean.h>
#include <inttypes.h>

#define PRG_BANK_SIZE 16384
#define CHR_BANK_SIZE 8192

typedef struct mapper Mapper;

typedef bool(*car_mapper_init)(Mapper* mapper);
typedef void(*car_mapper_destroy)(Mapper* mapper);
typedef uint32_t(*car_mapper_map)(Mapper* mapper, uint16_t address);

typedef struct mapper {
	uint16_t type;
	uint8_t prg_banks;
	uint8_t chr_banks;
	void* user_ptr;
	car_mapper_init init;
	car_mapper_destroy destroy;
	car_mapper_map prg_read;
	car_mapper_map prg_write;
	car_mapper_map chr_read;
	car_mapper_map chr_write;
} Mapper;


#endif<file_sep>/Emulator.core/src/emulator/cpu/core/instructions/cpu_instructions.h
#ifndef __EMULATOR_CPU_CORE_INSTRUCTIONS_INSTRUCTIONS_H__
#define __EMULATOR_CPU_CORE_INSTRUCTIONS_INSTRUCTIONS_H__

#include "operations.h"
#include "addressing.h"

typedef uint8_t(*cpu_instruction_addressing)(CPU*);
typedef uint8_t(*cpu_instruction_operation)(CPU*);

static const struct instruction {
	cpu_instruction_addressing addr_mode;
	cpu_instruction_operation operation;
	uint8_t cycles;
} lookup[256] = {
	{ &cpu_instruction_addressing_imm, &cpu_instruction_operation_brk, 7 }, //00
	{ &cpu_instruction_addressing_izx, &cpu_instruction_operation_ora, 6 }, //01
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //02
	{ &cpu_instruction_addressing_izx, &cpu_instruction_operation_slo, 8 }, //03
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_nop, 3 }, //04
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_ora, 3 }, //05
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_asl, 5 }, //06
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_slo, 5 }, //07
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_php, 3 }, //08
	{ &cpu_instruction_addressing_imm, &cpu_instruction_operation_ora, 2 }, //09
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_asl, 2 }, //0A
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //0B
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_nop, 4 }, //0C
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_ora, 4 }, //0D
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_asl, 6 }, //0E
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_slo, 6 }, //0F
	{ &cpu_instruction_addressing_rel, &cpu_instruction_operation_bpl, 2 }, //10
	{ &cpu_instruction_addressing_izy, &cpu_instruction_operation_ora, 5 }, //11
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //12
	{ &cpu_instruction_addressing_izy, &cpu_instruction_operation_slo, 8 }, //13
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_nop, 4 }, //14
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_ora, 4 }, //15
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_asl, 6 }, //16
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_slo, 6 }, //17
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_clc, 2 }, //18
	{ &cpu_instruction_addressing_aby, &cpu_instruction_operation_ora, 4 }, //19
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_nop, 2 }, //1A
	{ &cpu_instruction_addressing_aby, &cpu_instruction_operation_slo, 7 }, //1B
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_nop, 4 }, //1C
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_ora, 4 }, //1D
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_asl, 7 }, //1E
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_slo, 7 }, //1F
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_jsr, 6 }, //20
	{ &cpu_instruction_addressing_izx, &cpu_instruction_operation_and, 6 }, //21
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //22
	{ &cpu_instruction_addressing_izx, &cpu_instruction_operation_rla, 8 }, //23
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_bit, 3 }, //24
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_and, 3 }, //25
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_rol, 5 }, //26
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_rla, 5 }, //27
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_plp, 4 }, //28
	{ &cpu_instruction_addressing_imm, &cpu_instruction_operation_and, 2 }, //29
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_rol, 2 }, //2A
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //2B
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_bit, 4 }, //2C
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_and, 4 }, //2D
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_rol, 6 }, //2E
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_rla, 6 }, //2F
	{ &cpu_instruction_addressing_rel, &cpu_instruction_operation_bmi, 2 }, //30
	{ &cpu_instruction_addressing_izy, &cpu_instruction_operation_and, 5 }, //31
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //32
	{ &cpu_instruction_addressing_izy, &cpu_instruction_operation_rla, 8 }, //33
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_nop, 4 }, //34
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_and, 4 }, //35
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_rol, 6 }, //36
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_rla, 6 }, //37
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_sec, 2 }, //38
	{ &cpu_instruction_addressing_aby, &cpu_instruction_operation_and, 4 }, //39
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_nop, 2 }, //3A
	{ &cpu_instruction_addressing_aby, &cpu_instruction_operation_rla, 7 }, //3B
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_nop, 4 }, //3C
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_and, 4 }, //3D
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_rol, 7 }, //3E
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_rla, 7 }, //3F
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_rti, 6 }, //40
	{ &cpu_instruction_addressing_izx, &cpu_instruction_operation_eor, 6 }, //41
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //42
	{ &cpu_instruction_addressing_izx, &cpu_instruction_operation_sre, 8 }, //43
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_nop, 3 }, //44
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_eor, 3 }, //45
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_lsr, 5 }, //46
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_sre, 5 }, //47
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_pha, 3 }, //48
	{ &cpu_instruction_addressing_imm, &cpu_instruction_operation_eor, 2 }, //49
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_lsr, 2 }, //4A
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //4B
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_jmp, 3 }, //4C
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_eor, 4 }, //4D
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_lsr, 6 }, //4E
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_sre, 6 }, //4F
	{ &cpu_instruction_addressing_rel, &cpu_instruction_operation_bvc, 2 }, //50
	{ &cpu_instruction_addressing_izy, &cpu_instruction_operation_eor, 5 }, //51
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //52
	{ &cpu_instruction_addressing_izy, &cpu_instruction_operation_sre, 8 }, //53
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_nop, 4 }, //54
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_eor, 4 }, //55
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_lsr, 6 }, //56
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_sre, 6 }, //57
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_cli, 2 }, //58
	{ &cpu_instruction_addressing_aby, &cpu_instruction_operation_eor, 4 }, //59
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_nop, 2 }, //5A
	{ &cpu_instruction_addressing_aby, &cpu_instruction_operation_sre, 7 }, //5B
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_nop, 4 }, //5C
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_eor, 4 }, //5D
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_lsr, 7 }, //5E
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_sre, 7 }, //5F
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_rts, 6 }, //60
	{ &cpu_instruction_addressing_izx, &cpu_instruction_operation_adc, 6 }, //61
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //62
	{ &cpu_instruction_addressing_izx, &cpu_instruction_operation_rra, 8 }, //63
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_nop, 3 }, //64
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_adc, 3 }, //65
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_ror, 5 }, //66
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_rra, 5 }, //67
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_pla, 4 }, //68
	{ &cpu_instruction_addressing_imm, &cpu_instruction_operation_adc, 2 }, //69
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_ror, 2 }, //6A
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //6B
	{ &cpu_instruction_addressing_ind, &cpu_instruction_operation_jmp, 5 }, //6C
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_adc, 4 }, //6D
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_ror, 6 }, //6E
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_rra, 6 }, //6F
	{ &cpu_instruction_addressing_rel, &cpu_instruction_operation_bvs, 2 }, //70
	{ &cpu_instruction_addressing_izy, &cpu_instruction_operation_adc, 5 }, //71
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //72
	{ &cpu_instruction_addressing_izy, &cpu_instruction_operation_rra, 8 }, //73
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_nop, 4 }, //74
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_adc, 4 }, //75
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_ror, 6 }, //76
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_rra, 6 }, //77
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_sei, 2 }, //78
	{ &cpu_instruction_addressing_aby, &cpu_instruction_operation_adc, 4 }, //79
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_nop, 2 }, //7A
	{ &cpu_instruction_addressing_aby, &cpu_instruction_operation_rra, 7 }, //7B
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_nop, 4 }, //7C
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_adc, 4 }, //7D
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_ror, 7 }, //7E
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_rra, 7 }, //7F
	{ &cpu_instruction_addressing_rel, &cpu_instruction_operation_nop, 2 }, //80
	{ &cpu_instruction_addressing_izx, &cpu_instruction_operation_sta, 6 }, //81
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_nop, 2 }, //82
	{ &cpu_instruction_addressing_izx, &cpu_instruction_operation_sax, 6 }, //83
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_sty, 3 }, //84
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_sta, 3 }, //85
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_stx, 3 }, //86
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_sax, 3 }, //87
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_dey, 2 }, //88
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_nop, 2 }, //89
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_txa, 2 }, //8A
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //8B
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_sty, 4 }, //8C
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_sta, 4 }, //8D
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_stx, 4 }, //8E
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_sax, 4 }, //8F
	{ &cpu_instruction_addressing_rel, &cpu_instruction_operation_bcc, 2 }, //90
	{ &cpu_instruction_addressing_izy, &cpu_instruction_operation_sta, 6 }, //91
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //92
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_xxx, 6 }, //93
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_sty, 4 }, //94
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_sta, 4 }, //95
	{ &cpu_instruction_addressing_zpy, &cpu_instruction_operation_stx, 4 }, //96
	{ &cpu_instruction_addressing_zpy, &cpu_instruction_operation_sax, 4 }, //97
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_tya, 2 }, //98
	{ &cpu_instruction_addressing_aby, &cpu_instruction_operation_sta, 5 }, //99
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_txs, 2 }, //9A
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 5 }, //9B
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_nop, 5 }, //9C
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_sta, 5 }, //9D
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 5 }, //9E
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 5 }, //9F
	{ &cpu_instruction_addressing_imm, &cpu_instruction_operation_ldy, 2 }, //A0
	{ &cpu_instruction_addressing_izx, &cpu_instruction_operation_lda, 6 }, //A1
	{ &cpu_instruction_addressing_imm, &cpu_instruction_operation_ldx, 2 }, //A2
	{ &cpu_instruction_addressing_izx, &cpu_instruction_operation_lax, 6 }, //A3
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_ldy, 3 }, //A4
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_lda, 3 }, //A5
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_ldx, 3 }, //A6
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_lax, 3 }, //A7
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_tay, 2 }, //A8
	{ &cpu_instruction_addressing_imm, &cpu_instruction_operation_lda, 2 }, //A9
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_tax, 2 }, //AA
	{ &cpu_instruction_addressing_imm, &cpu_instruction_operation_lax, 2 }, //AB
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_ldy, 4 }, //AC
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_lda, 4 }, //AD
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_ldx, 4 }, //AE
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_lax, 4 }, //AF
	{ &cpu_instruction_addressing_rel, &cpu_instruction_operation_bcs, 2 }, //B0
	{ &cpu_instruction_addressing_izy, &cpu_instruction_operation_lda, 5 }, //B1
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //B2
	{ &cpu_instruction_addressing_izy, &cpu_instruction_operation_lax, 5 }, //B3
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_ldy, 4 }, //B4
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_lda, 4 }, //B5
	{ &cpu_instruction_addressing_zpy, &cpu_instruction_operation_ldx, 4 }, //B6
	{ &cpu_instruction_addressing_zpy, &cpu_instruction_operation_lax, 4 }, //B7
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_clv, 2 }, //B8
	{ &cpu_instruction_addressing_aby, &cpu_instruction_operation_lda, 4 }, //B9
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_tsx, 2 }, //BA
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 4 }, //BB
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_ldy, 4 }, //BC
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_lda, 4 }, //BD
	{ &cpu_instruction_addressing_aby, &cpu_instruction_operation_ldx, 4 }, //BE
	{ &cpu_instruction_addressing_aby, &cpu_instruction_operation_lax, 4 }, //BF
	{ &cpu_instruction_addressing_imm, &cpu_instruction_operation_cpy, 2 }, //C0
	{ &cpu_instruction_addressing_izx, &cpu_instruction_operation_cmp, 6 }, //C1
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_nop, 2 }, //C2
	{ &cpu_instruction_addressing_izx, &cpu_instruction_operation_dcp, 8 }, //C3
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_cpy, 3 }, //C4
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_cmp, 3 }, //C5
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_dec, 5 }, //C6
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_dcp, 5 }, //C7
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_iny, 2 }, //C8
	{ &cpu_instruction_addressing_imm, &cpu_instruction_operation_cmp, 2 }, //C9
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_dex, 2 }, //CA
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //CB
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_cpy, 4 }, //CC
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_cmp, 4 }, //CD
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_dec, 6 }, //CE
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_dcp, 6 }, //CF
	{ &cpu_instruction_addressing_rel, &cpu_instruction_operation_bne, 2 }, //D0
	{ &cpu_instruction_addressing_izy, &cpu_instruction_operation_cmp, 5 }, //D1
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //D2
	{ &cpu_instruction_addressing_izy, &cpu_instruction_operation_dcp, 8 }, //D3
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_nop, 4 }, //D4
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_cmp, 4 }, //D5
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_dec, 6 }, //D6
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_dcp, 6 }, //D7
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_cld, 2 }, //D8
	{ &cpu_instruction_addressing_aby, &cpu_instruction_operation_cmp, 4 }, //D9
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_nop, 2 }, //DA
	{ &cpu_instruction_addressing_aby, &cpu_instruction_operation_dcp, 7 }, //DB
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_nop, 4 }, //DC
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_cmp, 4 }, //DD
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_dec, 7 }, //DE
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_dcp, 7 }, //DF
	{ &cpu_instruction_addressing_imm, &cpu_instruction_operation_cpx, 2 }, //E0
	{ &cpu_instruction_addressing_izx, &cpu_instruction_operation_sbc, 6 }, //E1
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_nop, 2 }, //E2
	{ &cpu_instruction_addressing_izx, &cpu_instruction_operation_isc, 8 }, //E3
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_cpx, 3 }, //E4
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_sbc, 3 }, //E5
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_inc, 5 }, //E6
	{ &cpu_instruction_addressing_zp0, &cpu_instruction_operation_isc, 5 }, //E7
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_inx, 2 }, //E8
	{ &cpu_instruction_addressing_imm, &cpu_instruction_operation_sbc, 2 }, //E9
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_nop, 2 }, //EA
	{ &cpu_instruction_addressing_imm, &cpu_instruction_operation_sbc, 2 }, //EB
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_cpx, 4 }, //EC
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_sbc, 4 }, //ED
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_inc, 6 }, //EE
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_isc, 6 }, //EF
	{ &cpu_instruction_addressing_rel, &cpu_instruction_operation_beq, 2 }, //F0
	{ &cpu_instruction_addressing_izy, &cpu_instruction_operation_sbc, 5 }, //F1
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_xxx, 2 }, //F2
	{ &cpu_instruction_addressing_izy, &cpu_instruction_operation_isc, 8 }, //F3
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_nop, 4 }, //F4
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_sbc, 4 }, //F5
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_inc, 6 }, //F6
	{ &cpu_instruction_addressing_zpx, &cpu_instruction_operation_isc, 6 }, //F7
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_sed, 2 }, //F8
	{ &cpu_instruction_addressing_aby, &cpu_instruction_operation_sbc, 4 }, //F9
	{ &cpu_instruction_addressing_imp, &cpu_instruction_operation_nop, 2 }, //FA
	{ &cpu_instruction_addressing_aby, &cpu_instruction_operation_isc, 7 }, //FB
	{ &cpu_instruction_addressing_abs, &cpu_instruction_operation_nop, 4 }, //FC
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_sbc, 4 }, //FD
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_inc, 7 }, //FE
	{ &cpu_instruction_addressing_abx, &cpu_instruction_operation_isc, 7 }  //FF
};

#endif<file_sep>/Emulator.core/src/emulator/ppu/bus/TblName.c
#include "TblName.h"
#include <stdlib.h>
#include "../../car/core/Cartridge.h"

Tbl_Name* tbl_name_init()
{
	Tbl_Name* tbl_name = (Tbl_Name*)malloc(sizeof(Tbl_Name));
	if (tbl_name == NULL)
		return NULL;
	tbl_name->table_1 = (uint8_t*)malloc(sizeof(uint8_t) * 1024);
	if (tbl_name->table_1 == NULL)
	{
		free(tbl_name);
		return NULL;
	}
	tbl_name->table_2 = (uint8_t*)malloc(sizeof(uint8_t) * 1024);
	if (tbl_name->table_2 == NULL)
	{
		free(tbl_name->table_1);
		free(tbl_name);
		return NULL;
	}
	return tbl_name;
}

void tbl_name_destroy(Tbl_Name* tbl_name)
{
	if (tbl_name == NULL)
		return;
	free(tbl_name->table_1);
	free(tbl_name->table_2);
	free(tbl_name);
}

uint8_t tbl_name_read(Tbl_Name* tbl_name, uint16_t addr, uint8_t mirror)
{
	addr &= 0x0FFF;
	if (mirror == CARTRIDGE_MIRROR_VERTICAL)
	{
		if (addr >= 0x0000 && addr <= 0x03FF)
			return tbl_name->table_1[addr & 0x03FF];
		if (addr >= 0x0400 && addr <= 0x07FF)
			return tbl_name->table_2[addr & 0x03FF];
		if (addr >= 0x0800 && addr <= 0x0BFF)
			return tbl_name->table_1[addr & 0x03FF];
		if (addr >= 0x0C00 && addr <= 0x0FFF)
			return tbl_name->table_2[addr & 0x03FF];
	}
	else if (mirror == CARTRIDGE_MIRROR_HORIZONTAL)
	{
		if (addr >= 0x0000 && addr <= 0x03FF)
			return tbl_name->table_1[addr & 0x03FF];
		if (addr >= 0x0400 && addr <= 0x07FF)
			return tbl_name->table_1[addr & 0x03FF];
		if (addr >= 0x0800 && addr <= 0x0BFF)
			return tbl_name->table_2[addr & 0x03FF];
		if (addr >= 0x0C00 && addr <= 0x0FFF)
			return tbl_name->table_2[addr & 0x03FF];
	}
}

void tbl_name_write(Tbl_Name* tbl_name, uint16_t addr, uint8_t value, uint8_t mirror)
{
	addr &= 0x0FFF;
	if (mirror == CARTRIDGE_MIRROR_VERTICAL)
	{
		if (addr >= 0x0000 && addr <= 0x03FF)
			tbl_name->table_1[addr & 0x03FF] = value;
		if (addr >= 0x0400 && addr <= 0x07FF)
			tbl_name->table_2[addr & 0x03FF] = value;
		if (addr >= 0x0800 && addr <= 0x0BFF)
			tbl_name->table_1[addr & 0x03FF] = value;
		if (addr >= 0x0C00 && addr <= 0x0FFF)
			tbl_name->table_2[addr & 0x03FF] = value;
	}
	else if (mirror == CARTRIDGE_MIRROR_HORIZONTAL)
	{
		if (addr >= 0x0000 && addr <= 0x03FF)
			tbl_name->table_1[addr & 0x03FF] = value;
		if (addr >= 0x0400 && addr <= 0x07FF)
			tbl_name->table_1[addr & 0x03FF] = value;
		if (addr >= 0x0800 && addr <= 0x0BFF)
			tbl_name->table_2[addr & 0x03FF] = value;
		if (addr >= 0x0C00 && addr <= 0x0FFF)
			tbl_name->table_2[addr & 0x03FF] = value;
	}
}
<file_sep>/Emulator.core/src/emulator/cpu/core/Registery.c
#include "Registery.h"

#include <stdlib.h>
#include <string.h>

Registery* registery_init()
{
	Registery* registery = (Registery*)malloc(sizeof(Registery));
	if (registery == NULL)
		return NULL;

	memset(registery, 0x00, sizeof(Registery));

	return registery;
}

void registery_destroy(Registery* registery)
{
	if (registery == NULL)
		return;
	free(registery);
}

void status_set(Registery* registery, flag flag, bool value)
{
	flag_write(&(registery->s), flag, value);
}

bool status_get(const Registery* registery, flag flag)
{
	return flag_read(registery->s, flag);
}<file_sep>/Emulator.core/src/emulator/cpu/core/Flags.h
#ifndef __EMULATOR_CPU_CORE_FLAGS__
#define __EMULATOR_CPU_CORE_FLAGS__

#include <inttypes.h>
#include <utils/boolean.h>


typedef uint8_t flag;
typedef uint8_t flags;

#define FLAG_C 0x01 // Carry Bit
#define FLAG_Z 0x02 // Zero
#define FLAG_I 0x04 // Disable Interrupts
#define FLAG_D 0x08 // Decimal Mode (unused in this implementation)
#define FLAG_B 0x10 // Break
#define FLAG_U 0x20 // Unused
#define FLAG_V 0x40 // Overflow
#define FLAG_N 0x80 // Negative



bool flag_read(flags flags, flag flag);

void flag_write(flags* flags, flag flag, bool value);

void flag_set_active(flags* flags, flag flag);

void flag_set_inactive(flags* flags, flag flag);


#endif<file_sep>/Emulator.core/src/emulator/ppu/bus/TblName.h
#ifndef __EMULATOR_PPU_BUS_TBL_NAME_H__
#define __EMULATOR_PPU_BUS_TBL_NAME_H__

#include <inttypes.h>

typedef struct tbl_name
{
	uint8_t * table_1;
	uint8_t * table_2;
}Tbl_Name;

Tbl_Name * tbl_name_init();
void tbl_name_destroy(Tbl_Name* tbl_name);
uint8_t tbl_name_read(Tbl_Name* tbl_name, uint16_t addr, uint8_t mirror);
void tbl_name_write(Tbl_Name* tbl_name, uint16_t addr, uint8_t value, uint8_t mirror);

#endif<file_sep>/Emulator.core/src/emulator/cpu/core/instructions/operations.c
#include "operations.h"
#include "addressing.h"
#include "cpu_instructions.h"
#include "../settings.h"

// helper function
// fetches the value from the bus into the alu
void fetch(CPU* cpu)
{
	if (!(lookup[cpu->opt_code].addr_mode == &cpu_instruction_addressing_imp))
		cpu->alu = cpu_bus_read(cpu, cpu->addr_abs);
}

// Instruction: Add with Carry In
// Function:    A = A + M + C
// Flags Out:   C, V, N, Z
uint8_t cpu_instruction_operation_adc(CPU* cpu)
{
	fetch(cpu);
	cpu->temp = (uint16_t)cpu->registery->a + (uint16_t)cpu->alu;
	if (is_true(cpu_status_get(cpu, FLAG_C)))
		cpu->temp += 1;
	cpu_status_set(cpu, FLAG_C, cpu->temp > 255);
	cpu_status_set(cpu, FLAG_Z, (cpu->temp & 0x00ff) == 0);
	cpu_status_set(cpu, FLAG_V, ((~((uint16_t)cpu->registery->a ^ (uint16_t)cpu->alu) & ((uint16_t)cpu->registery->a ^ (uint16_t)cpu->temp)) & 0x0080) > 0);
	cpu_status_set(cpu, FLAG_N, (cpu->temp & 0x80) > 0);
	cpu->registery->a = cpu->temp & 0x00ff;
	return 1;
}

// Instruction: Subtraction with Borrow In
// Function:    A = A - M - (1 - C)
// Flags Out:   C, V, N, Z
uint8_t cpu_instruction_operation_sbc(CPU* cpu)
{
	fetch(cpu);
	uint16_t value = ((uint16_t)cpu->alu) ^ 0x00ff;
	cpu->temp = (uint16_t)cpu->registery->a + (uint16_t)value;
	if (is_true(cpu_status_get(cpu, FLAG_C)))
		cpu->temp += 1;
	cpu_status_set(cpu, FLAG_C, (cpu->temp & 0xff00) > 0);
	cpu_status_set(cpu, FLAG_Z, (cpu->temp & 0x00ff) == 0);
	cpu_status_set(cpu, FLAG_V, ((cpu->temp ^ (uint16_t)cpu->registery->a) & (cpu->temp ^ value) & 0x0080) > 0);
	cpu_status_set(cpu, FLAG_N, (cpu->temp & 0x80) > 0);
	cpu->registery->a = cpu->temp & 0x00ff;
	return 1;
}

// Instruction: Bitwise Logic AND
// Function:    A = A & M
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_and(CPU* cpu)
{
	fetch(cpu);
	cpu->registery->a &= cpu->alu;
	cpu_status_set(cpu, FLAG_Z, cpu->registery->a == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->registery->a & 0x80) > 0);
	return 1;
}

// Instruction: Arithmetic Shift Left
// Function:    A = C <- (A << 1) <- 0
// Flags Out:   N, Z, C
uint8_t cpu_instruction_operation_asl(CPU* cpu)
{
	fetch(cpu);
	cpu->temp = ((uint16_t)cpu->alu) << 1;
	cpu_status_set(cpu, FLAG_C, (cpu->temp & 0xff00) > 0);
	cpu_status_set(cpu, FLAG_Z, (cpu->temp & 0x00ff) == 0x0000);
	cpu_status_set(cpu, FLAG_N, (cpu->temp & 0x0080) > 0);
	if (lookup[cpu->opt_code].addr_mode == &cpu_instruction_addressing_imp)
		cpu->registery->a = cpu->temp & 0x00ff;
	else
		cpu_bus_write(cpu, cpu->addr_abs, cpu->temp & 0x00ff);
	return 0;

}

// Instruction: Branch if Carry Clear
// Function:    if(C == 0) pc = address 
uint8_t cpu_instruction_operation_bcc(CPU* cpu)
{
	if (is_true(cpu_status_get(cpu, FLAG_C)))
		return 0;
	cpu->cycles++;
	cpu->addr_abs = cpu->registery->pc + cpu->addr_rel;
	if ((cpu->addr_abs & 0xff00) != (cpu->registery->pc & 0xff00))
		cpu->cycles++;
	cpu->registery->pc = cpu->addr_abs;
	return 0;
}

// Instruction: Branch if Carry Set
// Function:    if(C == 1) pc = address
uint8_t cpu_instruction_operation_bcs(CPU* cpu)
{
	if (is_false(cpu_status_get(cpu, FLAG_C)))
		return 0;
	cpu->cycles++;
	cpu->addr_abs = cpu->registery->pc + cpu->addr_rel;
	if ((cpu->addr_abs & 0xff00) != (cpu->registery->pc & 0xff00))
		cpu->cycles++;
	cpu->registery->pc = cpu->addr_abs;
	return 0;
}

// Instruction: Branch if Equal
// Function:    if(Z == 1) pc = address
uint8_t cpu_instruction_operation_beq(CPU* cpu)
{
	if (is_false(cpu_status_get(cpu, FLAG_Z)))
		return 0;
	cpu->cycles++;
	cpu->addr_abs = cpu->registery->pc + cpu->addr_rel;
	if ((cpu->addr_abs & 0xff00) != (cpu->registery->pc & 0xff00))
		cpu->cycles++;
	cpu->registery->pc = cpu->addr_abs;
	return 0;
}

// Instruction: Test Bits in Memory with Accumulator
// Function:    A AND M, M7 -> N, M6 -> V
uint8_t cpu_instruction_operation_bit(CPU* cpu)
{
	fetch(cpu);
	cpu->temp = cpu->registery->a & cpu->alu;
	cpu_status_set(cpu, FLAG_Z, (cpu->temp & 0x00ff) == 0x0000);
	cpu_status_set(cpu, FLAG_N, (cpu->alu & (1 << 7)) > 0);
	cpu_status_set(cpu, FLAG_V, (cpu->alu & (1 << 6)) > 0);
	return 0;
}

// Instruction: Branch if Negative
// Function:    if(N == 1) pc = address
uint8_t cpu_instruction_operation_bmi(CPU* cpu)
{
	if (is_false(cpu_status_get(cpu, FLAG_N)))
		return 0;
	cpu->cycles++;
	cpu->addr_abs = cpu->registery->pc + cpu->addr_rel;
	if ((cpu->addr_abs & 0xff00) != (cpu->registery->pc & 0xff00))
		cpu->cycles++;
	cpu->registery->pc = cpu->addr_abs;
	return 0;
}

// Instruction: Branch if Not Equal
// Function:    if(Z == 0) pc = addres
uint8_t cpu_instruction_operation_bne(CPU* cpu)
{
	if (is_true(cpu_status_get(cpu, FLAG_Z)))
		return 0;
	cpu->cycles++;
	cpu->addr_abs = cpu->registery->pc + cpu->addr_rel;
	if ((cpu->addr_abs & 0xff00) != (cpu->registery->pc & 0xff00))
		cpu->cycles++;
	cpu->registery->pc = cpu->addr_abs;
	return 0;
}

// Instruction: Branch if Not Equal
// Function:    if(Z == 0) pc = address
uint8_t cpu_instruction_operation_bpl(CPU* cpu)
{
	if (is_true(cpu_status_get(cpu, FLAG_N)))
		return 0;
	cpu->cycles++;
	cpu->addr_abs = cpu->registery->pc + cpu->addr_rel;
	if ((cpu->addr_abs & 0xff00) != (cpu->registery->pc & 0xff00))
		cpu->cycles++;
	cpu->registery->pc = cpu->addr_abs;
	return 0;
}

// Instruction: Break
// Function:    Program Sourced Interrupt
uint8_t cpu_instruction_operation_brk(CPU* cpu)
{
	cpu->registery->pc++;
	cpu_status_set(cpu, FLAG_I, TRUE);
	cpu_stack_push(cpu, (cpu->registery->pc >> 8) & 0x00ff);
	cpu_stack_push(cpu, cpu->registery->pc & 0x00ff);
	cpu_status_set(cpu, FLAG_B, TRUE);
	cpu_stack_push(cpu, cpu->registery->s);
	cpu_status_set(cpu, FLAG_B, FALSE);
	uint16_t lo = cpu_bus_read(cpu, IRQ_ADDRESS);
	uint16_t hi = cpu_bus_read(cpu, IRQ_ADDRESS + 1);
	cpu->registery->pc = (hi << 8) | lo;
	return 0;
}

// Instruction: Branch if Overflow Clear
// Function:    if(V == 0) pc = address
uint8_t cpu_instruction_operation_bvc(CPU* cpu)
{
	if (is_true(cpu_status_get(cpu, FLAG_V)))
		return 0;
	cpu->cycles++;
	cpu->addr_abs = cpu->registery->pc + cpu->addr_rel;
	if ((cpu->addr_abs & 0xff00) != (cpu->registery->pc & 0xff00))
		cpu->cycles++;
	cpu->registery->pc = cpu->addr_abs;
	return 0;
}

// Instruction: Branch if Overflow Set
// Function:    if(V == 1) pc = address
uint8_t cpu_instruction_operation_bvs(CPU* cpu)
{
	if (is_false(cpu_status_get(cpu, FLAG_V)))
		return 0;
	cpu->cycles++;
	cpu->addr_abs = cpu->registery->pc + cpu->addr_rel;
	if ((cpu->addr_abs & 0xff00) != (cpu->registery->pc & 0xff00))
		cpu->cycles++;
	cpu->registery->pc = cpu->addr_abs;
	return 0;
}

// Instruction: Clear Carry Flag
// Function:    C = 0
uint8_t cpu_instruction_operation_clc(CPU* cpu)
{
	cpu_status_set(cpu, FLAG_C, FALSE);
	return 0;
}

// Instruction: Clear Decimal Flag
// Function:    D = 0
uint8_t cpu_instruction_operation_cld(CPU* cpu)
{
	cpu_status_set(cpu, FLAG_D, FALSE);
	return 0;
}

// Instruction: Disable Interrupts / Clear Interrupt Flag
// Function:    I = 0
uint8_t cpu_instruction_operation_cli(CPU* cpu)
{
	cpu_status_set(cpu, FLAG_I, FALSE);
	return 0;
}

// Instruction: Clear Overflow Flag
// Function:    V = 0
uint8_t cpu_instruction_operation_clv(CPU* cpu)
{
	cpu_status_set(cpu, FLAG_V, FALSE);
	return 0;
}

// Instruction: Compare Accumulator
// Function:    C <- A >= M      Z <- (A - M) == 0
// Flags Out:   N, C, Z
uint8_t cpu_instruction_operation_cmp(CPU* cpu)
{
	fetch(cpu);
	cpu->temp = cpu->registery->a;
	cpu->temp -= cpu->alu;
	cpu_status_set(cpu, FLAG_C, cpu->registery->a >= cpu->alu);
	cpu_status_set(cpu, FLAG_Z, (cpu->temp & 0x00ff) == 0x0000);
	cpu_status_set(cpu, FLAG_N, (cpu->temp & 0x0080) > 0);
	return 1;
}

// Instruction: Compare X Register
// Function:    C <- X >= M      Z <- (X - M) == 0
// Flags Out:   N, C, Z
uint8_t cpu_instruction_operation_cpx(CPU* cpu)
{
	fetch(cpu);
	cpu->temp = cpu->registery->x;
	cpu->temp -= cpu->alu;
	cpu_status_set(cpu, FLAG_C, cpu->registery->x >= cpu->alu);
	cpu_status_set(cpu, FLAG_Z, (cpu->temp & 0x00ff) == 0x0000);
	cpu_status_set(cpu, FLAG_N, (cpu->temp & 0x0080) > 0);
	return 0;
}

// Instruction: Compare Y Register
// Function:    C <- Y >= M      Z <- (Y - M) == 0
// Flags Out:   N, C, Z
uint8_t cpu_instruction_operation_cpy(CPU* cpu)
{
	fetch(cpu);
	cpu->temp = cpu->registery->y;
	cpu->temp -= cpu->alu;
	cpu_status_set(cpu, FLAG_C, cpu->registery->y >= cpu->alu);
	cpu_status_set(cpu, FLAG_Z, (cpu->temp & 0x00ff) == 0x0000);
	cpu_status_set(cpu, FLAG_N, (cpu->temp & 0x0080) > 0);
	return 0;
}

// Instruction: Decrement Value at Memory Location
// Function:    M = M - 1
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_dec(CPU* cpu)
{
	fetch(cpu);
	cpu->temp = cpu->alu - 1;
	cpu_bus_write(cpu, cpu->addr_abs, cpu->temp & 0x00ff);
	cpu_status_set(cpu, FLAG_Z, (cpu->temp & 0x00ff) == 0x0000);
	cpu_status_set(cpu, FLAG_N, (cpu->temp & 0x0080) > 0);
	return 0;
}

// Instruction: Decrement X Register
// Function:    X = X - 1
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_dex(CPU* cpu)
{
	cpu->registery->x--;
	cpu_status_set(cpu, FLAG_Z, cpu->registery->x == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->registery->x & 0x80) > 0);
	return 0;
}

// Instruction: Decrement Y Register
// Function:    Y = Y - 1
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_dey(CPU* cpu)
{
	cpu->registery->y--;
	cpu_status_set(cpu, FLAG_Z, cpu->registery->y == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->registery->y & 0x80) > 0);
	return 0;
}

// Instruction: Bitwise Logic XOR
// Function:    A = A xor M
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_eor(CPU* cpu)
{
	fetch(cpu);
	cpu->registery->a ^= cpu->alu;
	cpu_status_set(cpu, FLAG_Z, cpu->registery->a == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->registery->a & 0x80) > 0);
	return 1;

}

// Instruction: Increment Value at Memory Location
// Function:    M = M + 1
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_inc(CPU* cpu)
{
	fetch(cpu);
	cpu->temp = cpu->alu + 1;
	cpu_bus_write(cpu, cpu->addr_abs, cpu->temp & 0x00ff);
	cpu_status_set(cpu, FLAG_Z, (cpu->temp & 0x00ff) == 0x0000);
	cpu_status_set(cpu, FLAG_N, (cpu->temp & 0x0080) > 0);
	return 0;
}

// Instruction: Increment X Register
// Function:    X = X + 1
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_inx(CPU* cpu)
{
	cpu->registery->x++;
	cpu_status_set(cpu, FLAG_Z, cpu->registery->x == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->registery->x & 0x80) > 0);
	return 0;
}

// Instruction: Increment Y Register
// Function:    Y = Y + 1
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_iny(CPU* cpu)
{
	cpu->registery->y++;
	cpu_status_set(cpu, FLAG_Z, cpu->registery->y == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->registery->y & 0x80) > 0);
	return 0;
}

// Instruction: Jump To Location
// Function:    pc = address
uint8_t cpu_instruction_operation_jmp(CPU* cpu)
{
	cpu->registery->pc = cpu->addr_abs;
	return 0;
}

// Instruction: Jump To Sub-Routine
// Function:    Push current pc to stack, pc = address
uint8_t cpu_instruction_operation_jsr(CPU* cpu)
{
	cpu->registery->pc--;
	cpu_stack_push(cpu, (cpu->registery->pc >> 8) & 0x00ff);
	cpu_stack_push(cpu, cpu->registery->pc & 0x00ff);
	cpu->registery->pc = cpu->addr_abs;
	return 0;
}

// Instruction: Load The Accumulator
// Function:    A = M
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_lda(CPU* cpu)
{
	fetch(cpu);
	cpu->registery->a = cpu->alu;
	cpu_status_set(cpu, FLAG_Z, cpu->registery->a == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->registery->a & 0x80) > 0);
	return 1;
}

// Instruction: Load The X Register
// Function:    X = M
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_ldx(CPU* cpu)
{
	fetch(cpu);
	cpu->registery->x = cpu->alu;
	cpu_status_set(cpu, FLAG_Z, cpu->registery->x == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->registery->x & 0x80) > 0);
	return 1;
}

// Instruction: Load The Y Register
// Function:    Y = M
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_ldy(CPU* cpu)
{
	fetch(cpu);
	cpu->registery->y = cpu->alu;
	cpu_status_set(cpu, FLAG_Z, cpu->registery->y == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->registery->y & 0x80) > 0);
	return 1;
}

// Instruction: Shift One Bit Right (Memory or Accumulator)
// Function:    0 -> [76543210] -> C
uint8_t cpu_instruction_operation_lsr(CPU* cpu)
{
	fetch(cpu);
	cpu_status_set(cpu, FLAG_C, (cpu->alu & 0x0001) > 0);
	cpu->temp = cpu->alu >> 1;
	cpu_status_set(cpu, FLAG_Z, (cpu->temp & 0x00ff) == 0x0000);
	cpu_status_set(cpu, FLAG_N, (cpu->temp & 0x0080) > 0);
	if (lookup[cpu->opt_code].addr_mode == &cpu_instruction_addressing_imp)
		cpu->registery->a = cpu->temp & 0x00ff;
	else
		cpu_bus_write(cpu, cpu->addr_abs, cpu->temp & 0x00ff);
	return 0;
}

// Instruction: No Operation
uint8_t cpu_instruction_operation_nop(CPU* cpu)
{
	switch (cpu->opt_code) {
	case 0x1C:
	case 0x3C:
	case 0x5C:
	case 0x7C:
	case 0xDC:
	case 0xFC:
		return 1;
	}
	return 0;
}

// Instruction: Bitwise Logic OR
// Function:    A = A | M
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_ora(CPU* cpu)
{
	fetch(cpu);
	cpu->registery->a |= cpu->alu;
	cpu_status_set(cpu, FLAG_Z, cpu->registery->a == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->registery->a & 0x80) > 0);
	return 1;
}

// Instruction: Push Accumulator to Stack
// Function:    A -> stack
uint8_t cpu_instruction_operation_pha(CPU* cpu)
{
	cpu_stack_push(cpu, cpu->registery->a);
	return 0;
}

// Instruction: Push Status Register to Stack
// Function:    status -> stack
// Note:        Break flag is set to 1 before push
uint8_t cpu_instruction_operation_php(CPU* cpu)
{
	cpu_bus_write(cpu, STACK_POSITION_START + cpu->registery->sp, cpu->registery->s | FLAG_B | FLAG_U);
	cpu_status_set(cpu, FLAG_B, FALSE);
	cpu_status_set(cpu, FLAG_U, FALSE);
	cpu->registery->sp--;
	return 0;
}

// Instruction: Pop Accumulator off Stack
// Function:    A <- stack
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_pla(CPU* cpu)
{
	cpu->registery->a = cpu_stack_pop(cpu);
	cpu_status_set(cpu, FLAG_U, TRUE);
	cpu_status_set(cpu, FLAG_Z, cpu->registery->a == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->registery->a & 0x80) > 0);
	return 0;
}

// Instruction: Pop Status Register off Stack
// Function:    Status <- stack
uint8_t cpu_instruction_operation_plp(CPU* cpu)
{
	cpu->registery->s = cpu_stack_pop(cpu);
	cpu_status_set(cpu, FLAG_U, TRUE);
	return 0;
}

// Instruction: Rotate One Bit Left (Memory or Accumulator)
// C <- [76543210] <- C
uint8_t cpu_instruction_operation_rol(CPU* cpu)
{
	fetch(cpu);
	cpu->temp = cpu->alu << 1;
	if (is_true(cpu_status_get(cpu, FLAG_C)))
		cpu->temp |= 0x01;
	cpu_status_set(cpu, FLAG_C, (cpu->temp & 0xff00) > 0);
	cpu_status_set(cpu, FLAG_Z, (cpu->temp & 0x00ff) == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->temp & 0x0080) > 0);
	if (lookup[cpu->opt_code].addr_mode == &cpu_instruction_addressing_imp)
		cpu->registery->a = cpu->temp & 0x00ff;
	else
		cpu_bus_write(cpu, cpu->addr_abs, cpu->temp & 0x00ff);
	return 0;
}

// Instruction: Rotate One Bit Right (Memory or Accumulator)
// C -> [76543210] -> C
uint8_t cpu_instruction_operation_ror(CPU* cpu)
{
	fetch(cpu);
	cpu->temp = cpu->alu >> 1;
	if (is_true(cpu_status_get(cpu, FLAG_C)))
		cpu->temp |= 0x0080;
	cpu_status_set(cpu, FLAG_C, (cpu->alu & 0x01) > 0);
	cpu_status_set(cpu, FLAG_Z, (cpu->temp & 0x00ff) == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->temp & 0x0080) > 0);
	if (lookup[cpu->opt_code].addr_mode == &cpu_instruction_addressing_imp)
		cpu->registery->a = cpu->temp & 0x00ff;
	else
		cpu_bus_write(cpu, cpu->addr_abs, cpu->temp & 0x00ff);
	return 0;
}

// Instruction: Return from Interrupt
// Function:    pull SR, pull PC
uint8_t cpu_instruction_operation_rti(CPU* cpu)
{
	cpu->registery->s = cpu_stack_pop(cpu);
	cpu->registery->s &= ~FLAG_B;
	cpu->registery->s &= ~FLAG_U;
	cpu->registery->pc = cpu_stack_pop(cpu);
	cpu->registery->pc |= cpu_stack_pop(cpu) << 8;
	return 0;
}

// Instruction: Return from Subroutine
// Function:    pull PC, PC+1 -> PC
uint8_t cpu_instruction_operation_rts(CPU* cpu)
{
	cpu->registery->pc = cpu_stack_pop(cpu);
	cpu->registery->pc |= cpu_stack_pop(cpu) << 8;
	cpu->registery->pc++;
	return 0;
}

// Instruction: Set Carry Flag
// Function:    C = 1
uint8_t cpu_instruction_operation_sec(CPU* cpu)
{
	cpu_status_set(cpu, FLAG_C, TRUE);
	return 0;
}

// Instruction: Set Decimal Flag
// Function:    D = 1
uint8_t cpu_instruction_operation_sed(CPU* cpu)
{
	cpu_status_set(cpu, FLAG_D, TRUE);
	return 0;
}

// Instruction: Set Interrupt Flag / Enable Interrupts
// Function:    I = 1
uint8_t cpu_instruction_operation_sei(CPU* cpu)
{
	cpu_status_set(cpu, FLAG_I, TRUE);
	return 0;
}

// Instruction: Store Accumulator at Address
// Function:    M = A
uint8_t cpu_instruction_operation_sta(CPU* cpu)
{
	cpu_bus_write(cpu, cpu->addr_abs, cpu->registery->a);
	return 0;
}

// Instruction: Store X Register at Address
// Function:    M = X
uint8_t cpu_instruction_operation_stx(CPU* cpu)
{
	cpu_bus_write(cpu, cpu->addr_abs, cpu->registery->x);
	return 0;
}

// Instruction: Store Y Register at Address
// Function:    M = Y
uint8_t cpu_instruction_operation_sty(CPU* cpu)
{
	cpu_bus_write(cpu, cpu->addr_abs, cpu->registery->y);
	return 0;
}

// Instruction: Transfer Accumulator to X Register
// Function:    X = A
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_tax(CPU* cpu)
{
	cpu->registery->x = cpu->registery->a;
	cpu_status_set(cpu, FLAG_Z, cpu->registery->x == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->registery->x & 0x80) > 0);
	return 0;
}

// Instruction: Transfer Accumulator to Y Register
// Function:    Y = A
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_tay(CPU* cpu)
{
	cpu->registery->y = cpu->registery->a;
	cpu_status_set(cpu, FLAG_Z, cpu->registery->y == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->registery->y & 0x80) > 0);
	return 0;
}

// Instruction: Transfer Stack Pointer to X Register
// Function:    X = stack pointer
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_tsx(CPU* cpu)
{
	cpu->registery->x = cpu->registery->sp;
	cpu_status_set(cpu, FLAG_Z, cpu->registery->x == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->registery->x & 0x80) > 0);
	return 0;
}

// Instruction: Transfer X Register to Accumulator
// Function:    A = X
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_txa(CPU* cpu)
{
	cpu->registery->a = cpu->registery->x;
	cpu_status_set(cpu, FLAG_Z, cpu->registery->a == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->registery->a & 0x80) > 0);
	return 0;
}

// Instruction: Transfer X Register to Stack Pointer
// Function:    stack pointer = X
uint8_t cpu_instruction_operation_txs(CPU* cpu)
{
	cpu->registery->sp = cpu->registery->x;
	return 0;
}

// Instruction: Transfer Y Register to Accumulator
// Function:    A = Y
// Flags Out:   N, Z
uint8_t cpu_instruction_operation_tya(CPU* cpu)
{
	cpu->registery->a = cpu->registery->y;
	cpu_status_set(cpu, FLAG_Z, cpu->registery->a == 0x00);
	cpu_status_set(cpu, FLAG_N, (cpu->registery->a & 0x80) > 0);
	return 0;
}

uint8_t cpu_instruction_operation_lax(CPU* cpu)
{
	cpu_instruction_operation_lda(cpu);
	cpu_instruction_operation_tax(cpu);
	return 0;
}

uint8_t cpu_instruction_operation_sax(CPU* cpu)
{
	cpu_bus_write(cpu, cpu->addr_abs, cpu->registery->a & cpu->registery->x);
	return 0;
}

uint8_t cpu_instruction_operation_dcp(CPU* cpu)
{
	cpu_instruction_operation_dec(cpu);
	cpu_instruction_operation_cmp(cpu);
}

uint8_t cpu_instruction_operation_isc(CPU* cpu)
{
	cpu_instruction_operation_inc(cpu);
	cpu_instruction_operation_sbc(cpu);
}

uint8_t cpu_instruction_operation_rla(CPU* cpu)
{
	cpu_instruction_operation_rol(cpu);
	cpu_instruction_operation_and(cpu);
}

uint8_t cpu_instruction_operation_rra(CPU* cpu)
{
	cpu_instruction_operation_ror(cpu);
	cpu_instruction_operation_adc(cpu);
}

uint8_t cpu_instruction_operation_slo(CPU* cpu)
{
	cpu_instruction_operation_asl(cpu);
	cpu_instruction_operation_ora(cpu);
}

uint8_t cpu_instruction_operation_sre(CPU* cpu)
{
	cpu_instruction_operation_lsr(cpu);
	cpu_instruction_operation_eor(cpu);
}

// This function captures illegal opcodes
uint8_t cpu_instruction_operation_xxx(CPU* cpu)
{
	return 0;
}
<file_sep>/Emulator.core/src/emulator/cpu/core/Registery.h
#ifndef __EMULATOR_CPU_REGISTRY_H__
#define __EMULATOR_CPU_REGISTRY_H__

#include <inttypes.h>
#include "Flags.h"

typedef struct registery
{
	uint8_t  a;  // accumulator
	uint8_t  x;  // x register
	uint8_t  y;  // y register
	flags    s;  // status register
	uint8_t  sp; // stack pointer
	uint16_t pc; // program counter
} Registery;


Registery* registery_init();

void registery_destroy(Registery* registery);

void status_set(Registery* registery, flag flag, bool value);

bool status_get(const Registery* registery, flag flag);

#endif