// rev 1.50

#pragma once

// флаг способа опроса периферии, если 1, то каждый такт, если 0 - каждый полутакт.
// затрагивает модель vm1.cpp, и tboard.cpp
#define ONE_CLK_PERIPHERY_PROCESSING 0

//длинные циклы, увеличенные на 1 такт
#define LONG_QBUS_CYCLES 1
//при опросе периферии через каждый такт, необходимы.
#if (ONE_CLK_PERIPHERY_PROCESSING)
#if !(LONG_QBUS_CYCLES)
#define LONG_QBUS_CYCLES 1
#endif
#endif

#include "defmacros.h"
#include "CommonBus.h"
#include "vm1a_pli.h"
#include "vm1a_plm.h"
#include "vm1a_plm2.h"
#include "vm1g_pli.h"
#include "vm1g_plm.h"

#include "vm1_qbus_shared.h"

#include "Debugger.h"

// вывод разных диагностических логов
#define DBG_OUT_PLM_LOG 0
#define DBG_OUT_PLI_LOG 0
#define DBG_OUT_WIRESDIFF 0

class C1801VM1
{
		friend class CDebugger;

		//внутренние переменные
		//триггеры, состояние которых нужно сохранять
		VM1_QBUS_REGS   reg, snap_reg;

		//wires, состояние которых не нужно сохранять, а нужно каждый раз вычислять
		VM1_QBUS_WIRES  wire, prev_wire;

		//подмодули
		vm1a_pli        *pli_matrix_a;
		vm1a_plm        *plm_matrix_a;
		vm1a_plm2       *plm_matrix_a2;
		vm1g_pli        *pli_matrix_g;
		vm1g_plm        *plm_matrix_g;

		int             m_nClk;
		CCommonBus     *m_pCMNB; //указатель на структуру, чтобы не передавать её в качестве параметров постоянно.

	protected:
		CPU_TYPE        m_nCpuType;
		/*преобразование числа в битовый массив
		вход: число
		указатель на массив
		ко-во бит
		*/
		template <typename T> void data2bita(T d, bool *pBa, int nLen)
		{
			register T dd = d;

			for (register int i = 0; i < nLen; ++i)
			{
				*pBa++ = !!(dd & 1);
				dd >>= 1;
			}
		}

		//и наоборот
		template <typename T> void bita2data(bool *pBa, T &d, int nLen)
		{
			register T dd = 0;
			pBa += nLen;

			for (register int i = 0; i < nLen; ++i)
			{
				dd <<= 1;

				if (*--pBa)
				{
					dd++;
				}
			}

			d = dd;
		}

		void initial();

		void assign_in();
		void assign_func();
		void assign_out();
		void assign_all(const char *str = "  ");
		void assign_tve();
		void eval_all_p();
		void eval_all_n();
		// --- ВЕ таймер -------------------------------
		void tve_always_posedge_pin_dclo();
		void tve_always_posedge_tve_reset();
		void tve_always_posedge_pin_clk_p();

		// ---------------------------------------------
		void always_posedge_pin_clk_n();
		void always_posedge_pin_clk_p();

		void always_posedge_mjres();
		void always_posedge_pin_clk_p_or_posedge_mjres();

		void always_negedge_qbus_tena();

		void always_posedge_reset();
		void always_posedge_pin_clk_p_or_posedge_reset();

		void always_posedge_abort();
		void always_posedge_pin_clk_p_or_posedge_abort();

		void vc_always_p();

		bool wire_qbus_tena_prev;
		bool wire_pin_dclo_prev;
		bool wire_tve_reset_prev;

		//вспомогательные средства.
#if (DBG_OUT_PLI_LOG)
		//  1. лог PLI
		FILE *m_PLILog;
		void OutPLILog();
#endif
#if (DBG_OUT_PLM_LOG)
		//  2. лог PLM
		FILE *m_PLMLog;
		void OutPLMLog();
#endif


	public:
		//input-output
		CCommonBus::CMNB_DATASET PIN_nAD;
		CCommonBus::CMNB_LINESET PIN_nSYNC;
		CCommonBus::CMNB_LINESET PIN_nDIN;
		CCommonBus::CMNB_LINESET PIN_nDOUT;
		CCommonBus::CMNB_LINESET PIN_nWTBT;
		CCommonBus::CMNB_LINESET PIN_nIAKO;
		CCommonBus::CMNB_LINESET PIN_nDMGO;

		CCommonBus::CMNB_LINESET PIN_nINIT;
		CCommonBus::CMNB_LINESET PIN_nSACK;
		CCommonBus::CMNB_LINESET PIN_nRPLY;
		CCommonBus::CMNB_LINESET PIN_nDMR;
		CCommonBus::CMNB_LINESET PIN_nBSY;
		CCommonBus::CMNB_LINESET PIN_nSEL1;
		CCommonBus::CMNB_LINESET PIN_nSEL2;
		VM1_IO m_IOPins;    //ножки микросхемы.

		C1801VM1();
		~C1801VM1();

		void SetCpuType(CPU_TYPE nCPUType)
		{
			m_nCpuType = nCPUType;
		}
		CPU_TYPE GetCpuType()
		{
			return m_nCpuType;
		}

		void AttachDebugger(CDebugger *pDbg)
		{
			pDbg->AttachDebugger(this);
		}
		void RegisterDevice(CCommonBus *pMPI);

		void eval_p(int nClk);
		void eval_n(int nClk);

#if (DBG_OUT_WIRESDIFF)
		void Out_Difference(int nClk, int n, const char *str = "  ");
		void compareBool(FILE *f, bool bOrig, bool bTest, const char *str);
		void compareByte(FILE *f, uint8_t bOrig, uint8_t bTest, const char *str);
		void compareWord(FILE *f, uint16_t bOrig, uint16_t bTest, const char *str);
		void compareDWord(FILE *f, uint32_t bOrig, uint32_t bTest, const char *str);
		void compareQWord(FILE *f, uint64_t bOrig, uint64_t bTest, const char *str);
		void compareBoolArray(FILE *f, bool *pOrig, bool *pTest, int nLen, const char *str);
#endif // DBG_OUT_WIRESDIFF

};

