/** fMSX: portable MSX emulator ******************************/
/**                                                         **/
/**                          Lame.h                         **/
/**                                                         **/
/** This file contains simplified version of Z80 emulation  **/
/** which can be used if your compiler can't handle the     **/
/** original version. Simplified code is going to be        **/
/** slightly slower, although optimization may improve its  **/
/** perfomance. In this version, M_WRMEM() is implemented   **/
/** as a function [instead of a macro] and each subset of   **/
/** Z80 commands is also made into a separate function      **/
/** called when appropriate prefix appears.                 **/
/**                                                         **/
/** Copyright (C) Marat Fayzullin 1994,1995                 **/
/**     You are not allowed to distribute this software     **/
/**     commercially. Please, notify me, if you make any    **/
/**     changes to this file.                               **/
/*************************************************************/


#include <time.h>
//#include <iostream.h>
#include <conio.h>

reg R;
byte *Addr;
byte FLAG;

#ifdef INTERRUPTS
word Cnt;
#endif

inline void M_WRMEM(register word A,register byte V)
{
	if (!(A&0x8000))
	{ cprintf("wrote to rom, %x,%x",A,R.PC.W); TI85Exit();}
	else
	{*(Addr+A)=V;}
}

void CodesCBf(void)
{
  register byte I;

  switch(*(Addr+(R.PC.W++)))
	{
#include "CodesCB.h"
    default:
      printf("Unrecognized CB instruction at PC=%hX\n",R.PC.W-=2);
      FLAG=0;
  }
}

void CodesDDCB(register pair J)
{
	register byte I;

#define XX IX
	switch(*(Addr+long(R.PC.W++)))
	{
#include "CodesXCB.h"
		default:
			printf("Unrecognized DD CB instruction at PC=%hX\n",R.PC.W-=3);
			FLAG=0;
	}
#undef XX
}

void CodesFDCB(register pair J)
{
	register byte I;

#define XX IY
	switch(*(Addr+(R.PC.W++)))
	{
#include "CodesXCB.h"
		default:
			printf("Unrecognized FD CB instruction at PC=%hX\n",R.PC.W-=3);
			FLAG=0;
	}
#undef XX
}

void CodesEDf(void)
{
	register byte I;
	register pair J;

	switch(*(Addr+(R.PC.W++)))
	{
#include "CodesED.h"
    default:
      printf("Unrecognized ED instruction at PC=%hX\n",R.PC.W-=2);
      FLAG=0;
  }
}

void CodesDD(void)
{
  register byte I;
	register pair J;

#define XX IX
	switch(*(Addr+(R.PC.W++)))
  {
#include "CodesXX.h"
    case PFX_FD:
    case PFX_DD:
			R.PC.W--;break;
		case PFX_CB:
			J.W=R.XX.W+(*(char *)(Addr+(R.PC.W++)));
			CodesDDCB(J);break;
		case HALT:
#ifdef INTERRUPTS
			if(R.IFF&1) { if(Cnt) R.PC.W--; }
			else
#endif
			{
				printf("CPU HALTed and stuck at PC=%hX\n",R.PC.W-=2);
				FLAG=0;
			}
			break;
		default:
			printf("Unrecognized DD instruction at PC=%hX\n",R.PC.W-=2);
      FLAG=0;
  }
#undef XX
}

void CodesFD(void)
{
  register byte I;
  register pair J;

#define XX IY
	switch(*(Addr+(R.PC.W++)))
  {
#include "CodesXX.h"
    case PFX_FD:
    case PFX_DD:
			R.PC.W--;break;
    case PFX_CB:
			J.W=R.XX.W+(*(char *)(Addr+(R.PC.W++)));
			CodesFDCB(J);break;
		case HALT:
#ifdef INTERRUPTS
      if(R.IFF&1) { if(Cnt) R.PC.W--; }
      else
#endif
			{
				printf("CPU HALTed and stuck at PC=%hX\n",R.PC.W-=2);
				FLAG=0;
			}
			break;
		default:
			printf("Unrecognized FD instruction at PC=%hX\n",R.PC.W-=2);
			FLAG=0;
	}
#undef XX
}

word Z80(register byte *A,reg Regs)
{
	register byte I;
	register pair J;
	R=Regs;Addr=A;
	clock_t start;

	start=clock();

#ifdef INTERRUPTS
	Cnt=IPeriod;
#endif

	for(FLAG=1;FLAG;)
	{
		switch(*(Addr+(R.PC.W++)))
		{
#include "Codes.h"
			case PFX_CB: CodesCBf();break;
			case PFX_ED: CodesEDf();break;
			case PFX_FD: CodesFD();break;
			case PFX_DD: CodesDD();break;
			case HALT:
#ifdef INTERRUPTS
				if(R.IFF&1) { if(Cnt) R.PC.W--; }
				else
#endif
				{
					//printf("CPU HALTed and stuck at PC=%hX\n",--R.PC.W);
				 // FLAG=0;
				}
				break;
			default:
				printf("Unrecognized instruction at PC=%hX\n",--R.PC.W);
				FLAG=0;
		}

#ifdef INTERRUPTS
		if(!Cnt--)
		{
			Cnt=IPeriod;
			if(IntSync) IFlag=1;
		 //	printf("time for 10000 instructions = %f",(clock()-start)/CLK_TCK);
		 //	start=clock();

		}
		if(IFlag)
		{
			IFlag=0;Interrupt();
			if(R.IFF&1)
			{ M_PUSH(PC);R.PC.W=0x0038; }
		}
#endif

#ifdef DEBUG
		if(R.PC.W==Trap) Trace=1;  /*** Turn tracing on if trapped ***/
		if(Trace) Debug(Addr,R);   /*** Call single-step debugger  ***/
#endif


	}
	return(R.PC.W);
}
