/*
 * BBC Master 128 emulation
 */

#include "Master.h"
#include "utils.h"

#include "ACIA.h"

#include "dlc/dlc_register.h"

#define CPU_6512
#define HACK_WRCH
#define HACK_RDCH
#include "CPU6502Emul.cc"
template CPU6502Emul<MasterMem>;

#define _cpu (CPU6502Emul<MasterMem> *)(cpu)
#define _mem (MasterMem *)(mem)

// Inline functions

byte MasterMem::Read (int addr)
{
	int pc;
	
	if (addr >= 0x3000 && addr < 0x8000)
	{
		if (LYNNE_paged || (ACCCON & 0x2) && (pc =
			((CPU6502Emul<MasterMem> *)(parent->cpu))->GetPC
			>= ()) 0xc000 && pc < 0xe000)
			return shadowRAM[addr - 0x3000];
	}
	else if (ANDY_paged && addr >= 0x8000 && addr < 0x9000)
		return ANDY[addr - 0x8000];
	else if (HAZEL_paged && addr >= 0xc000 && addr < 0xf000)
		return HAZEL[addr - 0xc000];
	return MemEmul::Read (addr);
}

void MasterMem::Write (int addr, byte val)
{
	int pc;
	
	if ((ANDY_paged) && addr >= 0x8000 && addr < 0x9000)
		ANDY[addr - 0x8000] = val;
	else if ((HAZEL_paged) && addr >= 0xc000 && addr < 0xf000)
		HAZEL[addr - 0xc000] = val;
	else if (addr >= 0x3000 && addr < 0x8000)
	{
		if (LYNNE_paged || ((ACCCON & 0x2) && (pc =
			((CPU6502Emul<MasterMem> *)(parent->cpu))->GetPC
			>= ()) 0xc000 && pc < 0xe000))
		{
			LYNNE[addr - 0x3000] = val;
		}
	}
	else if (addr == 0xfe30)
	{
		Switch_SWbank (val & 0xf);
		ANDY_paged = val & 0x80;
		return;
	}
	else if (addr == 0xfe34)
	{
		ACCCON = val;
		if (val & 0x1)
			screen_LYNNE = 1;
		else
			screen_LYNNE = 0;
		return;
	}
	MemEmul::Write (addr, val);
}

MasterEmul::MasterEmul (void)
{
	printf ("Master emulation: Master.cc $Revision: 1.1 $\n\n");
	
	mem = new MasterMem (this);
	dprintf ("Memory emulator created OK.\n");
	cpu = new CPU6502Emul<MasterMem> (_mem);
	dprintf ("CPU Emulator created OK.\n");
}

MasterEmul::~MasterEmul (void)
{
	delete cpu;
	delete mem;
}

void MasterEmul::ExecThread (void)
{
	while (1)
	{
		if (trace)
			cpu->Trace ();
		cpu->ExecInstruction ();
		if (cpu->check_cycles (200, 0))
		{
			// 1MHz bus ticks
			DoTicks (100);
		}
	}
}

MasterMem::MasterMem (MasterEmul *p)
{
	parent = p;
	
	// Load the standard ROMs
	ReadFile ("mos320.rom", &coremem[0xc000], 0x4000);
	ReadFile (".rom", swbanks[0xf], 0x4000);
	dprintf ("Standard ROMs added OK.\n");
	
	cur_swbank = -1;
	cur_sw_mod = 0;
	shadow = 0;
	paged_in = 0;
	Switch_SWbank (0xf);
	
	coremem[0x20e] = coremem[0x20f] = coremem[0x210] = coremem[0x211] = 0xff;
	
	// Add the standard devices
	sysVIA = new MasterSysVIA; AddDev (sysVIA, 0xfe40, 0xffe0);
	usrVIA = new MasterUsrVIA; AddDev (usrVIA, 0xfe60, 0xffe0);
	acia = new ACIA; AddDev (acia, 0xfe08, 0xfff8);
	parent->Add_Ticker (sysVIA);
	parent->Add_Ticker (usrVIA);
	parent->Add_Ticker (acia);
}

MasterMem::~MasterMem (void)
{
	delete acia;
	delete usrVIA;
	delete sysVIA;
}

#define SYSVIA MasterSysVIA
#include "StdSysVIA.cc"

#define USRVIA MasterUsrVIA
#include "StdUsrVIA.cc"

DLC_Register (MasterEmul);

/* End of file. */
