/*
 *   engine.c
 *
 *   This file is part of Emu48
 *
 *   Copyright (C) 1995 Sebastien Carlier
 *
 */
#include "pch.h"
#include "Emu48.h"

// HST bits
#define XM 1
#define SB 2
#define SR 4
#define MP 8

#pragma intrinsic(memset,memcpy)

#define w Chipset
#define PCHANGED  ((void)(F_s[0]=w.P,F_l[1]=w.P+1))
#define GOYES3    {if(w.carry)goto o_goyes3;else{w.pc+=2;continue;}}
#define GOYES5    {if(w.carry)goto o_goyes5;else{w.pc+=2;continue;}}
#define INTERRUPT ((void)(w.SoftInt=TRUE,bInterrupt=TRUE))

//#define FASTPTR(d) (RMap[d>>12]+(d&0xFFF))
static __inline LPBYTE FASTPTR(DWORD d)
{
	return RMap[d>>12]+(d&0xFFF);
}

#include "Ops.h"

BOOL     bInterrupt = FALSE;
UINT     nState = 1;
UINT     nNextState = 0;
CHIPSET  Chipset;

UINT SwitchToState(UINT nNewState)
{
	UINT nOldState = nState;

	if (nState == nNewState) return nOldState;
	switch (nState)
	{
	case 0: // Run
		switch (nNewState)
		{
		case 1: // -> Invalid
			nNextState = 1;
			if (Chipset.Shutdn)
				ResumeThread(hThread);
			else
				bInterrupt = TRUE;
			while (nState!=nNextState) Sleep(0);
			UpdateWindowStatus();
			break;
		case 2: // -> Return
			nNextState = 1;
			if (Chipset.Shutdn)
				ResumeThread(hThread);
			else
				bInterrupt = TRUE;
			while (nState!=nNextState) Sleep(0);
			nNextState = 2;
			ResumeThread(hThread);
			while (nState!=nNextState) Sleep(0);
			UpdateWindowStatus();
			break;
		case 3: // -> Sleep
			nNextState = 3;
			if (Chipset.Shutdn)
				ResumeThread(hThread);
			else
				bInterrupt = TRUE;
			while (nState!=nNextState) Sleep(0);
			break;
		}
		break;
	case 1: // Invalid
		switch (nNewState)
		{
		case 0: // -> Run
			nNextState = 0;
			bInterrupt = FALSE;
			ResumeThread(hThread);
			while (nState!=nNextState) Sleep(0);
			UpdateWindowStatus();
			break;
		case 2: // -> Return
			nNextState = 2;
			ResumeThread(hThread);
			while (nState!=nNextState) Sleep(0);
			break;
		case 3: // -> Sleep
			nNextState = 3;
			ResumeThread(hThread);
			while (nState!=nNextState) Sleep(0);
			UpdateWindowStatus();
			break;
		}
		break;
	case 3: // Sleep
		switch (nNewState)
		{
		case 0: // -> Run
			nNextState = 0;
			if (Chipset.Shutdn) bInterrupt=TRUE;
			ResumeThread(hThread);
			//while (nState!=nNextState) Sleep(0);
			break;
		case 1: // -> Invalid
			nNextState = 1;
			ResumeThread(hThread);
			while (nState!=nNextState) Sleep(0);
			UpdateWindowStatus();
			break;
		case 2: // -> Return
			nNextState = 1;
			ResumeThread(hThread);
			while (nState!=nNextState) Sleep(0);
			nNextState = 2;
			ResumeThread(hThread);
			while (nState!=nNextState) Sleep(0);
			UpdateWindowStatus();
			break;
		}
		break;
	}
	return nOldState;
}

UINT WorkerThread(LPVOID pParam)
{
loop:
	while (nNextState == 1)
	{
		nState = 1;
		SuspendThread(hThread);
		if (nNextState == 2)
		{
			nState = 2;
			return 0;
		}
	}
	while (nNextState == 0)
	{
		if (nState!=0)
		{
			nState = 0;
			if (Chipset.type == 'S')
			{
				Chipset.cards_status &= 0x5;
				if (pbyPort2) Chipset.cards_status |= 0x2;
				if (bPort2Writeable) Chipset.cards_status |= 0x8;
			}
			else
			{
				Chipset.cards_status &= 0xA;
				if (pbyPort2) Chipset.cards_status |= 0x1;
				if (bPort2Writeable) Chipset.cards_status |= 0x4;
			}
			UpdateDisplayPointers();
			UpdateMainDisplay();
			UpdateMenuDisplay();
			UpdateAnnunciators();
			StartTimers();
		}
		PCHANGED;
		while (!bInterrupt)
		{
			LPBYTE I = FASTPTR(w.pc);
/**/#include "Fetch.h"
/**/#include "Opcodes.h"
		}
		if (Chipset.Shutdn)
		{
			bInterrupt = FALSE;
			SuspendThread(hThread);
			Chipset.Shutdn = FALSE;
		}
		if (Chipset.SoftInt)
		{
			bInterrupt = FALSE;
			Chipset.SoftInt = FALSE;
			if (Chipset.inte)
			{
				Chipset.inte = FALSE;
				rstkpush(Chipset.pc);
				Chipset.pc = 0xf;
			}
		}
		if (nNextState != 0)
		{
			StopTimers();
			Chipset.cards_status &= (Chipset.type=='S')?0x5:0xA;
		}
	}
	while (nNextState == 3)
	{
		nState = 3;
		SuspendThread(hThread);
	}
	goto loop;
	UNREFERENCED_PARAMETER(pParam);
}
