#pragma once

#include "CPU.h"
//чисто теоретическая модель
//ни одна функция не протестирована
// и что-то незнай как скомбинировать CPU и FPU


class CFPU
{
		CCPU    *m_pCPU;
		uint16_t $FPSR;         // регистр состояния FPP
		enum FSR_BITS : uint16_t
		{
			$FER   = 0100000,   //Floating ERror
			$FID   = 040000,    //Interrupt Disable
			$FPRES = 030020,    //reserved bits
			$FIUV  = 04000,     //Interrupt on Undefined Variable
			$FIU   = 02000,     //Interrupt on Underflow
			$FIV   = 01000,     //Interrupt on oVerflow
			$FIC   = 0400,      //Interrupt on integer Conversion error
			$FD    = 0200,      //floating Double precision mode
			$FL    = 0100,      //floating Long integer mode
			$FT    = 040,       //floating chop mode
			$FMM   = 020,       // Floating Maintenance Mode
			$FN    = 010,       //floating Negative
			$FZ    = 04,        //floating Zero
			$FV    = 02,        //floating oVerflow
			$FC    = 01         //floating Carry
		};

		uint16_t $FEC;          //Floating Exception Code register
		enum FEC_CODES : uint16_t
		{
			$FOP    = 2,        // floating opcode error
			$FDIVZ  = 4,        // floating divide by 0
			$FINT   = 6,        // floating to integer conversion error
			$FOVER  = 8,        // floating overflow
			$FUNDER = 10,       // floating underflow
			$FUNDF  = 12,       // floating undefined variable
			$FMMT   = 14        // Maintenance trap
		};

		uint16_t $FEA;          // Floating Exception Address register

		uint64_t $AC[6];        //storage for floating ACcumulators

		uint16_t        m_instruction;  //текущая инструкция
		int             m_nMeth;
		int             m_nReg;
		int             m_nAc;

		struct UnpackedFLT
		{
			bool     bSign; //знак, true - минус, false - плюс
			int      nExp;  //порядок числа
			uint64_t nFrac; //мантисса числа
		};

		//тут собирается результат
		UnpackedFLT     m_sRes;

		uint16_t        m_nOldPC;
		uint16_t        m_nDSTEA;

		void ExecuteUNKNOWN();
		//инструкции класса 0
		void ExecuteCFCC(); //170000
		void ExecuteSETF(); //170001
		void ExecuteSETI(); //170002
		void ExecuteSETD(); //170011
		void ExecuteSETL(); //170012

		//инструкции класса 1
		void ExecuteLDFPS(); //1701XX
		void ExecuteSTFPS(); //1702XX
		void ExecuteSTST(); //1703XX
		void ExecuteCLRX(); //1704XX
		void ExecuteTSTX(); //1705XX
		void ExecuteABSX(); //1706XX
		void ExecuteNEGX(); //1707XX

		//инструкции класса 2
		void ExecuteMULX();  //1710XX
		void ExecuteMODX();  //1714XX
		void ExecuteADDX();  //1720XX
		void ExecuteLDX();   //1724XX
		void ExecuteSUBX();  //1730XX
		void ExecuteCMPX();  //1734XX
		void ExecuteSTX();   //1740XX
		void ExecuteDIVX();  //1744XX
		void ExecuteSTEXP(); //1750XX
		void ExecuteSTCJ();  //1754XX
		void ExecuteSTCY();  //1760XX
		void ExecuteLDEXP(); //1764XX
		void ExecuteLDCJX(); //1770XX
		void ExecuteLDCYX(); //1774XX

		uint16_t GetArgAddr(int &len);

		uint32_t GetInt(int len);
		uint32_t GetI();
		uint32_t GetL();
		uint32_t GetSrc();

		uint64_t GetX();

		void    PutInt(uint32_t arg, int len);
		void    PutI(uint32_t arg);
		void    PutL(uint32_t arg);
		void    PutDst(uint32_t arg);

		void    PutX(uint64_t arg);

		bool    Over();
		bool    Under();
		bool    DivZer();
		bool    BADFP();
		bool    FPEXC();

		void    SFCC(uint64_t arg);
		void    CFCC();

		void    PutZer();

		uint64_t GetAC();
		void    PutAC(uint64_t arg);

		void    Unpack(uint64_t d, UnpackedFLT *nArg);
		uint64_t Pack(UnpackedFLT *nArg);

		void    I_add(uint64_t f, UnpackedFLT &fsrc);
		void    I_mul(uint64_t fsrc);
		void    Saret();
		void    Norm();

		using ExecuteMethodRef = void (CFPU::*)();
		ExecuteMethodRef *m_pExecuteMethodMap;
		void            RegisterMethodRef(uint16_t start, uint16_t end, ExecuteMethodRef methodref);
		void            PrepareCPU();   // Инициализация таблицы декодирования команд
		void            DoneCPU();      // удаление таблицы декодирования команд и освобождение памяти

	public:
		CFPU(CCPU *pCPU);
		~CFPU();
		void init();
		int TranslateInstruction();

};
