#include "pch.h"
#include "WS/WsCpuPrefetch.h"
#include "WS/WsMemoryManager.h"
#include "WS/WsCpu.h"

WsCpuPrefetch::WsCpuPrefetch(WsCpu* cpu, WsMemoryManager* memoryManager)
{
	_cpu = cpu;
	_memoryManager = memoryManager;
}

bool WsCpuPrefetch::IsFull()
{
	return _size >= 16;
}

void WsCpuPrefetch::PushByte(uint8_t value)
{
	_data[(_writePos++) & 0x0F] = value;
	_fetchIp++;
	_size++;
}

void WsCpuPrefetch::Prefetch()
{
	_cpu->ProcessCpuCycle();

	_waitCycles++;

	if(IsFull()) {
		return;
	}

	uint32_t addr = ((_fetchCs << 4) + _fetchIp) & 0xFFFFF;
	uint8_t cycles = _memoryManager->GetWaitStates(addr);
	if(_waitCycles < cycles) {
		return;
	}

	_waitCycles = 0;

	bool isWordBus = _memoryManager->IsWordBus(addr);

	//TODOWS debugger can't see these reads
	PushByte(_memoryManager->InternalRead(addr));
	if(!IsFull() && isWordBus && (_fetchIp & 0x01)) {
		PushByte(_memoryManager->InternalRead(((_fetchCs << 4) + _fetchIp)) & 0xFFFFF);
	}
}

void WsCpuPrefetch::ProcessRep(uint8_t opCode)
{
	if(IsFull()) {
		_writePos--;
		_fetchIp--;
		_size--;
	}

	_readPos--;
	_size++;
	_data[_readPos & 0x0F] = opCode;
}

uint8_t WsCpuPrefetch::Read()
{
	while(_size < 2) {
		Prefetch();
	}

	_size--;
	return _data[(_readPos++) & 0x0F];
}

void WsCpuPrefetch::Clear(uint16_t cs, uint16_t ip)
{
	_fetchCs = cs;
	_fetchIp = ip;
	_size = 0;
	_readPos = 0;
	_writePos = 0;
	_waitCycles = 0;
}

void WsCpuPrefetch::Serialize(Serializer& s)
{
	SV(_fetchCs);
	SV(_fetchIp);
	SV(_readPos);
	SV(_writePos);
	SV(_size);
	SV(_waitCycles);
	SVArray(_data, 16);
}