text: #pragma once
  
  #include "Types.h"
  #include "Convertible.h"
  #include "../uint128.h"
  #include "../Profiler.h"
  #include "zip/ZipArchiveWriter.h"
  #include "zip/ZipArchiveReader.h"
  
  //#define DELAYED_MSCAL
  
  class CVpu;
  
  class CVif
  {
  public:
  	enum
  	{
  		REGS0_START		= 0x10003800,
  		VIF0_STAT		= 0x10003800,
  		VIF0_FBRST		= 0x10003810,
  		VIF0_MARK		= 0x10003830,
  		VIF0_CYCLE		= 0x10003840,
  		VIF0_MODE		= 0x10003850,
  		VIF0_NUM		= 0x10003860,
  		VIF0_CODE		= 0x10003880,
  		VIF0_R0			= 0x10003900,
  		VIF0_R1			= 0x10003910,
  		VIF0_R2			= 0x10003920,
  		VIF0_R3			= 0x10003930,
  		REGS0_END		= 0x10003A00,
  
  		REGS1_START		= 0x10003C00,
  		VIF1_STAT		= 0x10003C00,
  		VIF1_FBRST		= 0x10003C10,
  		VIF1_MARK		= 0x10003C30,
  		VIF1_CYCLE		= 0x10003C40,
  		VIF1_MODE		= 0x10003C50,
  		VIF1_NUM		= 0x10003C60,
  		VIF1_CODE		= 0x10003C80,
  		VIF1_R0			= 0x10003D00,
  		VIF1_R1			= 0x10003D10,
  		VIF1_R2			= 0x10003D20,
  		VIF1_R3			= 0x10003D30,
  		REGS1_END		= 0x10003E00,
  
  		VIF0_FIFO_START	= 0x10004000,
  		VIF0_FIFO_END	= 0x10004FFF,
  		VIF1_FIFO_START	= 0x10005000,
  		VIF1_FIFO_END	= 0x10005FFF,
  	};
  
  								CVif(unsigned int, CVpu&, uint8*, uint8*);
  	virtual						~CVif();
  
  	virtual void				Reset();
  	uint32						GetRegister(uint32);
  	void						SetRegister(uint32, uint32);
  	virtual void				SaveState(Framework::CZipArchiveWriter&);
  	virtual void				LoadState(Framework::CZipArchiveReader&);
  
  	virtual uint32				GetTOP() const;
  	virtual uint32				GetITOP() const;
  
  	virtual uint32				ReceiveDMA(uint32, uint32, uint32, bool);
  
  	bool						IsWaitingForProgramEnd() const;
  	bool						IsStalledByInterrupt() const;
  
  protected:
  	enum
  	{
  		FBRST_RST = 0x01,
  		FBRST_STC = 0x08
  	};
  
  	enum
  	{
  		STAT_FDR = 0x00800000,
  	};
  
  	enum
  	{
  		FIFO_SIZE = 0x100
  	};
  
  	class CFifoStream
  	{
  	public:
  								CFifoStream(uint8*, uint8*);
  		virtual					~CFifoStream();
  
  		void					Reset();
  
  		uint32					GetAvailableReadBytes() const;
  		uint32					GetRemainingDmaTransferSize() const;
  		void					Read(void*, uint32);
  		void					Flush();
  		void					Align32();
  		void					SetDmaParams(uint32, uint32, bool);
  		void					SetFifoParams(uint8*, uint32);
  
  	private:
  		void					SyncBuffer();
  
  		enum
  		{
  			BUFFERSIZE = 0x10
  		};
  
  		uint8*					m_ram = nullptr;
  		uint8*					m_spr = nullptr;
  
  		uint128					m_buffer;
  		uint32					m_bufferPosition = BUFFERSIZE;
  		uint32					m_nextAddress = 0;
  		uint32					m_endAddress = 0;
  		bool					m_tagIncluded = false;
  		uint8*					m_source = nullptr;
  	};
  
  	typedef CFifoStream StreamType;
  
  	struct STAT : public convertible<uint32>
  	{
  		unsigned int	nVPS		: 2;
  		unsigned int	nVEW		: 1;
  		unsigned int	nReserved0	: 3;
  		unsigned int	nMRK		: 1;
  		unsigned int	nDBF		: 1;
  		unsigned int	nVSS		: 1;
  		unsigned int	nVFS		: 1;
  		unsigned int	nVIS		: 1;
  		unsigned int	nINT		: 1;
  		unsigned int	nER0		: 1;
  		unsigned int	nER1		: 1;
  		unsigned int	nReserved2	: 9;
  		unsigned int	nFDR		: 1;  //VIF1 only
  		unsigned int	nFQC		: 4;
  		unsigned int	nReserved3	: 4;
  	};
  	static_assert(sizeof(STAT) == sizeof(uint32), "Size of STAT struct must be 4 bytes.");
  
  	struct CYCLE : public convertible<uint32>
  	{
  		unsigned int	nCL			: 8;
  		unsigned int	nWL			: 8;
  		unsigned int	reserved	: 16;
  	};
  	static_assert(sizeof(CYCLE) == sizeof(uint32), "Size of CYCLE struct must be 4 bytes.");
  
  	struct CODE : public convertible<uint32>
  	{
  		unsigned int	nIMM	: 16;
  		unsigned int	nNUM	: 8;
  		unsigned int	nCMD	: 7;
  		unsigned int	nI		: 1;
  	};
  	static_assert(sizeof(CODE) == sizeof(uint32), "Size of CODE struct must be 4 bytes.");
  
  	enum ADDMODE
  	{
  		MODE_NORMAL = 0,
  		MODE_OFFSET = 1,
  		MODE_DIFFERENCE = 2
  	};
  
  	enum MASKOP
  	{
  		MASK_DATA = 0,
  		MASK_ROW = 1,
  		MASK_COL = 2,
  		MASK_MASK = 3
  	};
  
  	void				ProcessFifoWrite(uint32, uint32);
  
  	void				ProcessPacket(StreamType&);
  	virtual void		ExecuteCommand(StreamType&, CODE);
  	virtual void		Cmd_UNPACK(StreamType&, CODE, uint32);
  
  	void				Cmd_MPG(StreamType&, CODE);
  	void				Cmd_STROW(StreamType&, CODE);
  	void				Cmd_STCOL(StreamType&, CODE);
  	void				Cmd_STMASK(StreamType&, CODE);
  
  	bool				Unpack_ReadValue(const CODE&, StreamType&, uint128&, bool);
  	bool				Unpack_S32(StreamType&, uint128&);
  	bool				Unpack_S16(StreamType&, uint128&, bool);
  	bool				Unpack_S8(StreamType&, uint128&, bool);
  	bool				Unpack_V16(StreamType&, uint128&, unsigned int, bool);
  	bool				Unpack_V8(StreamType&, uint128&, unsigned int, bool);
  	bool				Unpack_V32(StreamType&, uint128&, unsigned int);
  	bool				Unpack_V45(StreamType&, uint128&);
  
  	uint32				GetMaskOp(unsigned int, unsigned int) const;
  
  	virtual void		PrepareMicroProgram();
  	void				StartMicroProgram(uint32);
  #ifdef DELAYED_MSCAL
  	void				StartDelayedMicroProgram(uint32);
  	bool				ResumeDelayedMicroProgram();
  #endif
  
  	void				DisassembleCommand(CODE);
  	void				DisassembleGet(uint32);
  	void				DisassembleSet(uint32, uint32);
  
  	unsigned int		m_number = 0;
  	CVpu&				m_vpu;
  	uint8*				m_ram = nullptr;
  	uint8*				m_spr = nullptr;
  	CFifoStream			m_stream;
  
  	uint8				m_fifoBuffer[FIFO_SIZE];
  	uint32				m_fifoIndex = 0;
  
  	STAT				m_STAT;
  	CYCLE				m_CYCLE;
  	CODE				m_CODE;
  	uint8				m_NUM;
  	uint32				m_MODE;
  	uint32				m_R[4];
  	uint32				m_C[4];
  	uint32				m_MASK;
  	uint32				m_MARK;
  	uint32				m_ITOP;
  	uint32				m_ITOPS;
  	uint32				m_readTick;
  	uint32				m_writeTick;
  #ifdef DELAYED_MSCAL
  	uint32				m_pendingMicroProgram;
  	CODE				m_previousCODE;
  #endif
  
  	CProfiler::ZoneHandle	m_vifProfilerZone = 0;
  };
  