#include "nes.h"

struct nes_emu_t
{
	cpu6502_t* cpu;
	mapper_t* mapper;
	
	int memory[0x10000];
	
	int running;
};

void nes_init(nes_emu_t** nes)
{
	nes_emu_t* pThis = NULL;

	(*nes) = (nes_emu_t*)malloc(sizeof(nes_emu_t));
	assert((*nes));
	pThis = (*nes);
	
	cpu_init(&pThis->cpu);
	cpu_reset(pThis->cpu);
	
	pThis->running = 0;
	
	/*cpu_dump_instructiontable(pThis->cpu);*/	
}

void nes_kill(nes_emu_t* nes)
{
	nes_emu_t* pThis = nes;
	
	assert(pThis);

	mapper_kill(pThis->mapper);
	cpu_kill(pThis->cpu);
	
	free(pThis);
}

void nes_start(nes_emu_t* nes)
{
	nes_emu_t* pThis = nes;
	
	assert(pThis);

	pThis->running = 1;
}

void nes_step(nes_emu_t* nes)
{
	nes_emu_t* pThis = nes;
	
	assert(pThis);

	if (!cpu_emulate(pThis->cpu)) {
		pThis->running = 0;
	}
}

void nes_stop(nes_emu_t* nes)
{
	nes_emu_t* pThis = nes;
	
	assert(pThis);
	
	pThis->running = 0;
}

void nes_reset(nes_emu_t* nes)
{
	nes_emu_t* pThis = nes;
	
	assert(pThis);
	
	cpu_reset(pThis->cpu);
}

int nes_running(nes_emu_t* nes)
{
	nes_emu_t* pThis = nes;
	
	assert(pThis);
	
	return pThis->running;
}

cpu6502_t* nes_get_cpu(nes_emu_t* nes)
{
	nes_emu_t* pThis = nes;
	
	assert(pThis);
	
	return pThis->cpu;
}

mapper_t* nes_get_mapper(nes_emu_t* nes)
{
	nes_emu_t* pThis = nes;
	
	assert(pThis);
	
	return pThis->mapper;
}

void nes_load_rom(nes_emu_t* nes)
{
	nes_emu_t* pThis = nes;
	
	assert(pThis);

	/* DEBUG CODE */
	mapper_init(&pThis->mapper, pThis->memory, MAPPER_DIRECT);
	cpu_set_mapper(pThis->cpu, pThis->mapper);

	/* PRGROM */
	pThis->memory[0x8000] = 0xA9; /* LDA */
	pThis->memory[0x8001] = 0x02;
	
	pThis->memory[0x8002] = 0x38; /* SEC */

	pThis->memory[0x8003] = 0xE9; /* SBC */
	pThis->memory[0x8004] = 0x1;
	
	pThis->memory[0x8005] = 0xD0; /* BNE */
	pThis->memory[0x8006] = 0xFB;
	
	pThis->memory[0x8007] = 0x20; /* JSR */
	pThis->memory[0x8008] = 0x01;
	pThis->memory[0x8009] = 0x00;

	pThis->memory[0x800A] = 0x00; /* BRK */

	pThis->memory[0x800B] = 0xEA; /* NOP */
	pThis->memory[0x800C] = 0xEA; /* NOP */
	
	pThis->memory[0x800D] = 0x85; /* STA ZP*/
	pThis->memory[0x800E] = 0x10;
	
	pThis->memory[0x800F] = 0x95; /* STA ZPX */
	pThis->memory[0x8010] = 0x10;

	pThis->memory[0x8011] = 0x8D; /* STA ABS*/
	pThis->memory[0x8012] = 0x10;
	pThis->memory[0x8013] = 0x00;
	
	pThis->memory[0x8014] = 0x9D; /* STA ABSX*/
	pThis->memory[0x8015] = 0x10;
	pThis->memory[0x8016] = 0x00;
	
	pThis->memory[0x8017] = 0x99; /* STA ABSY*/
	pThis->memory[0x8018] = 0x10;
	pThis->memory[0x8019] = 0x00;

	pThis->memory[0x801A] = 0x81; /* STA INDX */
	pThis->memory[0x801B] = 0x10;

	pThis->memory[0x801C] = 0x91; /* STA INDY */
	pThis->memory[0x801D] = 0x10;

	pThis->memory[0x801E] = 0xEA; /* NOP */
	pThis->memory[0x801F] = 0xEA; /* NOP */

	pThis->memory[0x8020] = 0x6C; /* JMP IND */
	pThis->memory[0x8021] = 0xA0;
	pThis->memory[0x8022] = 0x00;
	
	/* ZERO PAGE */
	/* JSR code */
	pThis->memory[0x0001] = 0x38; /* SEC */
	pThis->memory[0x0002] = 0xA9; /* LDA */
	pThis->memory[0x0003] = 0x6E;
	pThis->memory[0x0004] = 0x6A; /* ROR */
	pThis->memory[0x0005] = 0x60; /* RTS */
	
	/* BRK code */
	pThis->memory[0x000A] = 0xA9; /* LDA */
	pThis->memory[0x000B] = 0x77;
	pThis->memory[0x000C] = 0x40; /* RTI */
	
	/* JMP IND */
	pThis->memory[0x00A0] = 0x00;
	pThis->memory[0x00A1] = 0x80;
	
	/* IRQ */
	pThis->memory[0xFFFE] = 0x0A;
	pThis->memory[0xFFFF] = 0x00;
	/* DEBUG CODE */
}