// rev 1.50

#include "stdafx.h"
#include "vm1.h"

//#include <ppl.h>


C1801VM1::C1801VM1()
	: m_nClk(0)
	, m_pCMNB(nullptr)
{
	srand((unsigned)time(nullptr));
#if (DBG_OUT_PLI_LOG)
#define DBG_PLI_LOG_NAME "_PLI_log.txt"
	m_PLILog = fopen(DBG_PLI_LOG_NAME, "wt");
	fclose(m_PLILog);
#endif
#if (DBG_OUT_PLM_LOG)
#define DBG_PLM_LOG_NAME "_PLM_log.txt"
	m_PLMLog = fopen(DBG_PLM_LOG_NAME, "wt");
	fclose(m_PLMLog);
#endif
#if (DBG_OUT_WIRESDIFF)
#define DBG_WIRESDIFF_LOG_NAME "_wiresdiff_log.txt"
	FILE *f = fopen(DBG_WIRESDIFF_LOG_NAME, "wt");
	fclose(f);
#endif
	m_IOPins.clear();
	reg.clear();
	wire.clear();
	m_nCpuType = CPU_VM1A;
	pli_matrix_a = new vm1a_pli();
	pli_matrix_g = new vm1g_pli();
	plm_matrix_a = new vm1a_plm();
	plm_matrix_a2 = new vm1a_plm2();
	plm_matrix_g = new vm1g_plm();
	initial();
}

C1801VM1::~C1801VM1()
{
	if (pli_matrix_a)
	{
		delete pli_matrix_a;
	}

	if (pli_matrix_g)
	{
		delete pli_matrix_g;
	}

	if (plm_matrix_a)
	{
		delete plm_matrix_a;
	}

	if (plm_matrix_a2)
	{
		delete plm_matrix_a2;
	}

	if (plm_matrix_g)
	{
		delete plm_matrix_g;
	}

#if (DBG_OUT_PLI_LOG)
	fclose(m_PLILog);
#endif
#if (DBG_OUT_PLM_LOG)
	fclose(m_PLMLog);
#endif
}

void C1801VM1::RegisterDevice(CCommonBus *pCMNB)
{
	m_pCMNB = pCMNB;
	ASSERT(m_pCMNB);
	m_pCMNB->RegisterSignal(&PIN_nAD, CCommonBus::MPI_DATA_nAD);
	m_pCMNB->RegisterSignal(&PIN_nSYNC, CCommonBus::MPI_LINE_nSYNC);
	m_pCMNB->RegisterSignal(&PIN_nDIN, CCommonBus::MPI_LINE_nDIN);
	m_pCMNB->RegisterSignal(&PIN_nDOUT, CCommonBus::MPI_LINE_nDOUT);
	m_pCMNB->RegisterSignal(&PIN_nWTBT, CCommonBus::MPI_LINE_nWTBT);
	m_pCMNB->RegisterSignal(&PIN_nIAKO, CCommonBus::MPI_LINE_nIAK0);
	m_pCMNB->RegisterSignal(&PIN_nDMGO, CCommonBus::MPI_LINE_nDMGO);
	m_pCMNB->RegisterSignal(&PIN_nINIT, CCommonBus::MPI_LINE_nINIT);
	m_pCMNB->RegisterSignal(&PIN_nSACK, CCommonBus::MPI_LINE_nSACK);
	m_pCMNB->RegisterSignal(&PIN_nRPLY, CCommonBus::MPI_LINE_nRPLY);
	m_pCMNB->RegisterSignal(&PIN_nDMR, CCommonBus::MPI_LINE_nDMR);
	m_pCMNB->RegisterSignal(&PIN_nBSY, CCommonBus::CMN_LINE_nBSY);
	m_pCMNB->RegisterSignal(&PIN_nSEL1, CCommonBus::CMN_LINE_nSEL1);
	m_pCMNB->RegisterSignal(&PIN_nSEL2, CCommonBus::CMN_LINE_nSEL2);
}


/* Начальная аппаратная инициализация модели */
void C1801VM1::initial()
{
	//plm[33:0] = 34'o000000000000;
	reg.plm = 0;

	for (uint16_t &i : reg.gpr)
	{
		//инициализация НЕ 0 что-то вообще не понравилась. очень плохо для отладки.
		i = 0; // (uint16_t)((double)rand() / (RAND_MAX + 1) * (65535));
	}

	//reg.gpr[14][15:0] = 16'o000000;
	reg.gpr[14] = 0;
	//reg.tve_count = (uint16_t)((double)rand() / (RAND_MAX + 1) * (65535));
	//reg.tve_limit = (uint16_t)((double)rand() / (RAND_MAX + 1) * (65535));
	wire_qbus_tena_prev = false;
	wire_pin_dclo_prev = false;
	wire_tve_reset_prev = false;
	//
	// Odd address trap detector is blocked on 1801BM1
	//
	wire.exc_oat = false;
}


/* Выполнение модели по переднему фронту ТЧ */
void C1801VM1::eval_p(int nClk)
{
	m_nClk = nClk;
	assign_in();
	assign_all("p>");   //вычисляем все assignы
	eval_all_p();       //выполняем все always для переднего фронта
	assign_all("p<");   //вычисляем все assignы
	assign_out();
}

/* Выполнение модели по заднему фронту ТЧ */
void C1801VM1::eval_n(int nClk)
{
	m_nClk = nClk;
	assign_in();
	assign_all("n>");   //вычисляем все assignы
	eval_all_n();       //выполняем все always для заднего фронта
	assign_all("n<");   //вычисляем все assignы
	assign_out();
}

/* Выполнение назначений assign
 * Функция специально на случай, если все assignы невозможно будет выполнить за один проход.
 *
 * на данный момент эта функция иногда выполняется за 3 прохода, а в основном за 2.
 * причина - ноги процессора inout, выход с которых надо перенаправить на вход модели,
 * если быть ещё точнее - pin_ad_in, всё из-за него.
 */
void C1801VM1::assign_all(const char *str)
{
	int n = 0;
	wire_qbus_tena_prev = wire.qbus_tena;
	wire_pin_dclo_prev = wire.pin_dclo;
	wire_tve_reset_prev = wire.tve_reset;
	assign_func();
#if (ONE_CLK_PERIPHERY_PROCESSING)

	//при опросе периферии каждый такт, этот цикл обязателен
	do
	{
		prev_wire = wire;
		assign_func();

		if (++n > 200)
		{
			//зациклились
			TRACE1("Steps num: %d\n", n);
			ASSERT(false);
			break;
		}

#if (DBG_OUT_WIRESDIFF)

		if (prev_wire != wire)
		{
			Out_Difference(m_nClk, n, str);
		}

#endif
	}
	while (prev_wire != wire);   //крутимся в цикле пока переменные не перестанут меняться.

#else
	//для опроса периферии каждый полутакт, этим циклом можно пренебречь, на работоспособность не влияет
	//но можно и добавить, станет всего лишь медленнее работать
#endif

	if (wire_qbus_tena_prev && !wire.qbus_tena)
	{
		always_negedge_qbus_tena();
		//изменяемый рег используется только в алвайсах
	}

	// -- ВЕ таймер -------------------
	if (!wire_pin_dclo_prev && wire.pin_dclo)
	{
		tve_always_posedge_pin_dclo();
		assign_tve(); //снова переизменим ВЕ переменные
	}

	if (!wire_tve_reset_prev && wire.tve_reset)
	{
		tve_always_posedge_tve_reset();
		assign_tve(); //снова переизменим ВЕ переменные
	}

	//TRACE2("Clock: %d, Steps num: %d\n", m_nClk, n);
}

/* Выполнение всех alwaysов для переднего фронта */
void C1801VM1::eval_all_p()
{
	snap_reg = reg; //делаем снапшот регистров. в левой части выражений используем reg, в правой - snap_reg
	always_posedge_pin_clk_p(); //reg.mjres, reg.reset, reg.abort вычисляются здесь
	//----------------------------------
	vc_always_p();
	// -- ВЕ таймер -------------------
	tve_always_posedge_pin_clk_p();
}

/* Выполнение всех alwaysов для заднего фронта */
void C1801VM1::eval_all_n()
{
	snap_reg = reg;
	always_posedge_pin_clk_n();
}

void C1801VM1::assign_in()
{
	//
	// External connection assignments
	//
	wire.pin_dclo    = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nDCLO);       //input         // processor reset
	wire.pin_aclo    = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nACLO);       //input         // power fail notification
	wire.pin_irq[0]  = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nIRQ0);       //input         // vectored interrupt request
	wire.pin_irq[1]  = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nIRQ1);       //input         // radial interrupt requests
	wire.pin_irq[2]  = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nIRQ2);       //input         // radial interrupt requests
	wire.pin_irq[3]  = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nIRQ3);       //input         // radial interrupt requests
	wire.pin_dmgi    = !m_pCMNB->GetSignal(CCommonBus::CMN_LINE_nDMGI);       //input         // bus granted input
	wire.pin_sync_in = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nSYNC);       //inout         // address strobe
	wire.pin_dout_in = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nDOUT);       //inout         // data output strobe
	wire.pin_din_in  = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nDIN);        //inout         // data input strobe
	wire.pin_rply_in = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nRPLY);       //inout         // transaction reply
	wire.pin_init_in = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nINIT);       //inout         // peripheral reset
	wire.pin_dmr_in  = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nDMR);        //inout         // bus request shared line
	wire.pin_sack_in = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nSACK);       // bus acknowledgement
	wire.pin_ad_in   = ~LOWORD(m_pCMNB->GetSignal(CCommonBus::MPI_DATA_nAD));   //inout[15:0]   // inverted address/data bus
}

void C1801VM1::assign_func()
{
	//______________________________________________________________________________
	//
	// Interrupt controller
	//
	switch (m_nCpuType)
	{
		default:
		case CPU_VM1A:
			wire.pli = pli_matrix_a->eval(reg.rq);   //выполняем матрицу прерываний
			break;

		case CPU_VM1G:
			wire.pli = pli_matrix_g->eval(reg.rq);   //выполняем матрицу прерываний
			break;
	}

#if (DBG_OUT_PLI_LOG)
	OutPLILog();
#endif
	wire.exc_uop = reg.plm_ena && (reg.plr & (1 << 12));

	//______________________________________________________________________________
	//
	// Microcode state machine
	//
	// входной формат mj:
	// 6..0 - адрес ячейки микрокода
	// 11..7 - текущие флаги TNZVC
	// 14..12 - доп. аргументы, либо из матрицы прерываний, либо из второй фазы декодирования инструкции
	switch (m_nCpuType)
	{
		default:
		case CPU_VM1A:
		{
			plm_matrix_a2->eval(reg.ir, reg.mj, wire.plx);
//          static uint64_t plx2=0;
//          plm_matrix_a->eval(reg.ir, reg.mj, plx2);
//          ASSERT(plx2 == wire.plx);
		}
		break;

		case CPU_VM1G:
			plm_matrix_g->eval(reg.ir, reg.mj, wire.plx);
			break;
	}

#if (DBG_OUT_PLM_LOG)
	OutPLMLog();
#endif

	if (reg.qbus_win)
	{
		wire.sync_stb = !(reg.qbus_win_h && reg.sync_out_h);
		wire.pin_ctrl_ena = true;        // enable control outputs
		wire.pin_bsy_out = true;  // bus busy flag
	}
	else
	{
		wire.sync_stb = false;
		wire.pin_ctrl_ena = reg.iako_oe;        // enable control outputs
		wire.pin_bsy_out = wire.pin_ctrl_ena || reg.sync_out;  // bus busy flag
	}

	//______________________________________________________________________________
	//
	// Reset circuits
	//
	wire.reset_rc = wire.pin_dclo || (wire.pin_aclo ? (reg.init_out[0] ? false : reg.init_out[2]) : false);
	wire.abort_rc = (wire.reset_rc || reg.abort_tm) ? false : (wire.exc_oat || wire.exc_uop || reg.qbus_tovf || reg.abort);
	wire.mjres_rc = wire.reset_rc || wire.abort_rc;
	wire.pin_init_out = reg.init_out[0] || reg.reset;   // peripheral reset output
	wire.tve_reset = wire.pin_init_out || wire.pin_init_in;
	//______________________________________________________________________________
	//
	// Qbus logic
	//
	wire.sync_fedge =  reg.sync_ena ? false : reg.sync_out;
#if (LONG_QBUS_CYCLES)
	wire.din_done = reg.din_out_l && reg.rply_ack[3]; //старый вариант
	//работает и каждый такт и каждый полутакт
#else
	wire.din_done = reg.din_out_l && (reg.rply_ack[3] || reg.rply_ack[2]); //новый вариант - сокращает время дин на 1 такт
	//не работает при опросе периферии каждый такт
#endif
	wire.qbus_tena = reg.dout_out || reg.din_out;

	//
	// Reply acknowledgement latches
	// (converted to flip-flops approach)
	//
	if (wire.pin_rply_in)
	{
		wire.rply_ack_fc = wire.pin_bsy_out;
		wire.qbus_nosr_rc = false;
	}
	else
	{
		wire.rply_ack_fc = false;
		wire.qbus_nosr_rc = !wire.pin_sync_in;
	}

	if (reg.dout_done || reg.mjres)
	{
		wire.qbus_done = true;
	}
	else if (wire.din_done)
	{
		wire.qbus_done = !(reg.plrt & (1 << 1));
	}
	else
	{
		wire.qbus_done = false;
	}

	wire.sel_out    = wire.pin_dout_in && reg.sel_xx;
	// Master processor never asserts DMR_OUT
	wire.dmr_out    = m_IOPins.pin_pa && reg.dmr_req;
	wire.dma_in     = wire.pin_dmr_in || wire.pin_sack_in;
	register bool wire3 = (wire.alu_shift == 1) ? reg.ustb : reg.au_alsl;
	//если wire3 и ожидать завершения записи на шине МПИ
	wire.au_astb  = wire3 && wire.wait_write_complete; //признак записи результатов в регистр адреса А
	//если wire3 и ожидать освобождения регистра A
	wire.au_qstbx = wire3 && wire.wait_areg_free; //признак записи результатов в регистр Q
	//______________________________________________________________________________
	//
	// 1801BM1 can issue preliminary transaction address, so the reg.plm->reg.plr strobe
	// should be delayed till current transaction in progress completed
	//
	register bool qbus_nrdy;

	if (wire.au_astb)
	{
		if (reg.qbus_aseq[1] || reg.qbus_aseq[0])
		{
			qbus_nrdy     = !reg.oe_clr;
			wire.uplr_stb =  reg.oe_clr || !reg.qbus_aseq[0];
		}
		else
		{
			qbus_nrdy     = false;
			wire.uplr_stb = !reg.qbus_aseq[0];
		}
	}
	else
	{
		if (reg.qbus_aseq[1])
		{
			qbus_nrdy     = !reg.oe_clr;
			wire.uplr_stb =  reg.oe_clr;
		}
		else
		{
			qbus_nrdy     = false;
			wire.uplr_stb = false;
		}
	}

	wire.qbus_flag_rc = wire.qbus_done ? false : (wire.sync_fedge || reg.qbus_flag);
	wire.dmr_req_rc = (reg.qbus_win ? reg.sync_out : true) ? (wire.au_astb || reg.dmr_req) : false;
	wire.dout_req_rc = ((reg.plrt & (1 << 2)) ? false : (wire.au_qstbx ? (wire.dmr_req_rc || reg.qbus_own_rp) : false)) || (wire.qbus_done ? false : reg.dout_req);
#if (LONG_QBUS_CYCLES)
	//старый вариант
	wire.dout_start = wire.dout_req_rc && (reg.rply_ack[3] ? false : wire.qbus_flag_rc); // originally !reg.rply_ack[1]
#else
	//новый вариант
	wire.dout_start = wire.dout_req_rc && (reg.rply_ack[2] ? false : wire.qbus_flag_rc); // originally !reg.rply_ack[1]
#endif
	//______________________________________________________________________________
	//
	// Control and glue logic
	//

	//wire.tplm_rc bit1 instruction early prefetch
	//wire.tplm_rc bit2 data retrieving
	//wire.tplm_rc bit3 instruction fetch
	if (wire.mjres_rc || reg.mjres)
	{
		wire.ir_seq_rc = false;
		wire.tplm_rc = 0;
	}
	else
	{
		//
		// tplm1 - instruction prefetch
		// tplm3 - instruction fetch
		//
		wire.ir_seq_rc = reg.ir_seq ? !!(reg.tplm & (1 << 1 | 1 << 3)) : reg.plm23_wait;

		if (wire.din_done)
		{
			wire.tplm_rc = 0;
		}
		else
		{
			wire.tplm_rc = ((wire.uplr_stb ? 0xE : 0) & reg.tplmz) | reg.tplm;
		}
	}

	wire.ir_clr     = (~wire.tplm_rc & reg.tplm & (1 << 3)) || (wire.ir_seq_rc ? false : reg.ir_seq);
	wire.plm_ena_fc = (qbus_nrdy || reg.sop_out[0]) ? false : (reg.alu_busy_rp ? (reg.mjres || reg.ustb1_h) : true);
	wire.plm_stb_rc = (reg.sop_out[1] || reg.sop_out[2]) ? (reg.plm_stb ? false : !reg.sop_out[3]) : false;
	//______________________________________________________________________________
	// ВЕ таймер
	//
	assign_tve();
	//______________________________________________________________________________
	//
	// ALU function unit
	//
	//
	// plr[17:13]  cl  alu_a alu_b alu_c alu_d alu_e alu_x   oxy    axy      h     alu
	//    00x00    0   ( 1  |  0 ) ( 1  |  0 )   1     0     x&y    x|y     x^y    x+y  А
	//    00x01 #  0   ( 1  |  0 ) ( 1  |  0 )   1     0     x&y    x|y     x^y    x+y  А #
	//    00x10    0   ( 1  |  0 ) ( 0  |  0 )   0     0     x&y     x      x&~y   x&~y Л
	//    00x11 *  0   ( 1  |  0 ) ( 1  |  0 )   1     0     x&y    x|y     x^y    x+y  А + сдвиг
	//    01x00    1   ( 1  |  0 ) ( 1  |  0 )   1     1    ~x&y   ~x|y   ~(x^y)   y-x  А
	//    01x01 #  1   ( 1  |  0 ) ( 1  |  0 )   1     1    ~x&y   ~x|y   ~(x^y)   y-x  А #
	//    01x10    1   ( 1  |  0 ) ( 1  |  0 )   0     0     x&y    x|y     x^y    x^y  Л
	//    01x11 *  1   ( 1  |  0 ) ( 1  |  0 )   1     1    ~x&y   ~x|y   ~(x^y)   y-x  А + сдвиг
	//    10x00    0   ( 0  |  1 ) ( 1  |  0 )   0     0     x&~y   x|y      y      y   Л
	//    10x01 #  0   ( 0  |  0 ) ( 0  |  0 )   0     0      0      x       x      x   Л #
	//    10x10    0   ( 0  |  0 ) ( 1  |  0 )   0     0      0     x|y     x|y    x|y  Л
	//    10x11 *  0   ( 0  |  0 ) ( 0  |  0 )   0     0      0      x       x      x   Л + сдвиг
	//    11x00    1   ( 0  |  1 ) ( 0  |  1 )   1     0     x&~y   x|~y  ~(x^y)   x-y  А
	//    11x01 #  1   ( 0  |  1 ) ( 0  |  1 )   1     0     x&~y   x|~y  ~(x^y)   x-y  А #
	//    11x10    0   ( 0  |  1 ) ( 0  |  0 )   0     0     x&~y    x      x&y    x&y  Л
	//    11x11 *  1   ( 0  |  1 ) ( 0  |  1 )   1     0     x&~y   x|~y  ~(x^y)   x-y  А + сдвиг
	//# - при этом ещё интерпретировать yreg как вектор или константу, а не номер регистра.
	//
	// ALU controls
	//
	int n = wire.alu_shift | ((reg.plr >> 14) & 0xc);
	static bool a_cl[16]    = { false, false, false, false, true,  true,  true,  true,  false, false, false, false, true,  true,  false, true };
//  static bool a_alu_a[16] = { true,  true,  true,  true,  true,  true,  true,  true,  false, false, false, false, false, false, false, false };
//  static bool a_alu_b[16] = { false, false, false, false, false, false, false, false, true,  false, false, false, true,  true,  true,  true };
//  static bool a_alu_c[16] = { true,  true,  false, true,  true,  true,  true,  true,  true,  false, true,  false, false, false, false, false };
//  static bool a_alu_d[16] = { false, false, false, false, false, false, false, false, false, false, false, false, true,  true,  false, true };
	static bool a_alu_e[16] = { true,  true,  false, true,  true,  true,  false, true,  false, false, false, false, true,  true,  false, true };
	static bool a_alu_x[16] = { false, false, false, false, true,  true,  false, true,  false, false, false, false, false, false, false, false };
	bool &cl    = a_cl[n];      //флаг операции вычитания
//  bool &alu_a = a_alu_a[n];   //флаг прямого y в oxy
//  bool &alu_b = a_alu_b[n];   //флаг инверсного y в oxy
//  bool &alu_c = a_alu_c[n];   //флаг прямого y в axy
//  bool &alu_d = a_alu_d[n];   //флаг инверсного y в axy
	bool &alu_e = a_alu_e[n];   //флаг арифметической, а не логической операции
	bool &alu_x = a_alu_x[n];   //флаг инверсного х
	//
	// ALU and/or products
	//
//  register uint16_t nx = alu_x ? ~reg.xreg : reg.xreg;
//  register uint16_t oxy = (nx & ((alu_a ? reg.yreg : 0) | (alu_b ? ~reg.yreg : 0)));  // OR product
//  register uint16_t axy = (nx | ((alu_c ? reg.yreg : 0) | (alu_d ? ~reg.yreg : 0)));  // AND product
	register uint16_t oxy;
	register uint16_t axy;

	switch (n)
	{
		case 0:
		case 1:
		case 2:
		case 3:
		case 6:
			oxy = reg.xreg & reg.yreg;
			break;

		case 4:
		case 5:
		case 7:
			oxy = ~reg.xreg & reg.yreg;
			break;

		case 9:
		case 10:
		case 11:
			oxy = 0;
			break;

		case 8:
		case 12:
		case 13:
		case 14:
		case 15:
			oxy = reg.xreg & ~reg.yreg;
			break;
	}

	switch (n)
	{
		case 0:
		case 1:
		case 3:
		case 6:
		case 8:
		case 10:
			axy = reg.xreg | reg.yreg;
			break;

		case 4:
		case 5:
		case 7:
			axy = ~reg.xreg | reg.yreg;
			break;

		case 2:
		case 9:
		case 11:
		case 14:
			axy = reg.xreg;
			break;

		case 12:
		case 13:
		case 15:
			axy = reg.xreg | ~reg.yreg;
			break;
	}

	//
	// ALU selectable function
	//
	register uint16_t h = oxy ^ axy;   // half summ
	register uint16_t tmp = ~((axy + oxy) + (cl ? 1 : 0));
	register uint16_t c = (tmp & axy) | oxy; //определяем, будет ли перенос в данном разряде при сложении
	//тут каждый бит в с означает: 1 - при арифметической операции в этом бите будет перенос. 0 - не будет переноса
	register uint16_t cpred = (c << 1) | (cl ? 1 : 0);
	register uint16_t f = alu_e ? (cpred ^ h) : h;    //результат операции ALU, пока без сдвига
	//plr[18] == 1 - словная операция, 0 - байтовая
	register bool bWordOp = !!(reg.plr & (1 << 18));
	//plr[27] == 1 - сдвиг вправо, 0 - влево
	//plr[26:25] - режим сдвига АЛУ
	//     00 - арифметический
	//     01 - ещё какой-то особенный
	//     10 - циклический
	//     11 - нет сдвига, доп. операции
	//общий результат комбинации битов:
	//    000 влево, в младший бит вдвигается 0, ASL
	//    001 влево, в младший бит вдвигается 0, ASL
	//    010 влево, в младший бит вдвигается С, ROL
	//    011 нет сдвига, перестановка байт на входе АЛУ с шины X
	//    100 вправо, старший бит копируется, ASR
	//    101 вправо, в старший бит вдвигается перенос из старшего разряда АЛУ в текущей операции
	//    110 вправо, в старший бит вдвигается C, ROR
	//    111 нет сдвига
	register bool alu_s = (wire.shift_code != 3) && (wire.alu_shift == 3); //признак операции сдвига
	//определяем, будет ли переполнение в арифметической операции
	tmp = c << 1;
	register bool fmuxV = !!(bWordOp ? (tmp ^ c) & 0100000 : (tmp ^ c) & 0200); //register bool fmuxV = bWordOp ? (c[14] ^ c[15]) : (c[6] ^ c[7]);
	//
	// ALU result shifter
	//
	register uint8_t flag = 0;     // Флаги состояния результата операции АЛУ. Заранее обнулим, там по ходу будем устанавливать
	register uint16_t alu;          // ALU output to X/Y bus

	if (alu_s)  //если операция сдвига
	{
		//при байтовой операции старший байт значения не имеет, поэтому
		//корректностью результата fbit15 можно пренебречь
		register uint16_t fbit7 = 0, fbit15 = 0, fbitc = 0;

		switch (wire.shift_code)
		{
			case 0:
				fbit7  = f & 0200;		//арифметический сдвиг, байтовая операция
				fbit15 = f & 0100000;	//арифметический сдвиг, любая операция
				break;

			case 1:
				fbit7  = c & 0200;		//сдвиг код 01, байтовая операция
				fbit15 = c & 0100000;	//сдвиг код 01, любая операция
				//fbitc  = c & 1;		//а не надо ли тут для операции х01 брать c[0]?
				//по аналогии со сдвигом вправо. Если это сделать, ничего не изменится
				//потому что функционал такой не используется нигде
				break;

			case 2:
				//если х10 (ROL,ROR), то fbitc = берём бит C из PSW, иначе 0 (для ASL,ASR и оп. х01)
				fbitc = reg.gpr[14] & 1; //циклический сдвиг, любая операция

				if (fbitc)
				{
					fbit7  = 0200;
					fbit15 = 0100000;
				}

				break;
		}

		register uint16_t fmuxC;

		if (reg.plr & (1 << 27))    //если сдвиг вправо
		{
			if (bWordOp)	//если словная операция
			{
				alu = ((f >> 1) & 0077777) | fbit15;
			}
			else			//если байтовая операция
			{
				alu = ((f >> 1) & 0177577) | fbit7;
			}

			fmuxC = f & 1;
		}
		else    //если сдвиг влево, то двигаем всё слово влево и в мл.бит или С или 0,
		{
			alu = (f << 1) | fbitc;
			fmuxC = bWordOp ? (f & 0100000) : (f & 0200);
		}

		register bool bCf = false; //признак наличия флага С

		//если сдвиг есть, то бит С - из f
		if (fmuxC)
		{
			flag |= (1 << 0);    // C
			bCf = true;
		}

		//если словная операция, проверяем всё слово, иначе - только младший байт
		if ((bWordOp ? alu : (alu & 0377)) == 0)
		{
			flag |= (1 << 2);    // Z
		}

		register bool bNf = false; //признак наличия флага N

		//если словная операция, то бит 15 иначе бит 7 конечного результата
		if (bWordOp ? (alu & (1 << 15)) : (alu & (1 << 7)))
		{
			flag |= (1 << 3);    // N
			bNf = true;
		}

		//если операция сдвига, то по сути C ^ N или арифм переполнение. (как-то странно сложно)
		if ((bCf ^ bNf) || fmuxV)
		{
			flag |= (1 << 1);    // V
		}
	}
	else
	{
		//если сдвига нету, то просто f как есть
		alu = f;
		//если операция арифметическая, то если словная операция, то c[15] иначе c[7], для логической - 0
		register bool fmux0 = alu_e && !!(bWordOp ? (c & 0100000) : (c & 0200));

		//если сдвига нет, то результат арифметической операции
		if (cl ? !fmux0 : fmux0)
		{
			flag |= (1 << 0);    // C
		}

		//если словная операция, проверяем всё слово, иначе - только младший байт
		if ((bWordOp ? alu : (alu & 0377)) == 0)
		{
			flag |= (1 << 2);    // Z
		}

		//если словная операция, то бит 15 иначе бит 7 конечного результата
		if (bWordOp ? (alu & (1 << 15)) : (alu & (1 << 7)))
		{
			flag |= (1 << 3);    // N
		}

		//если не сдвиг, то если есть арифметическая операция, то арифметическое переполнение, иначе 0
		if (alu_e && fmuxV)
		{
			flag |= (1 << 1);    // V
		}
	}

	wire.flag = flag;
	//______________________________________________________________________________
	//
	// Блок регистров
	//
	static uint16_t RegRecode[16] =
	{
		15, 7, 11, 3, 13, 5, 9, 1, 14, 6, 10, 2, 12, 4, 8, 0
	};
	//выбор регистра на шине Y
	register uint16_t rsY = -1; //число должно быть гарантировано за пределами границ массива,

	if (wire.alu_shift == 3)
	{
		//если режим сдвига, то reg.yadr - код сдвига, а не номер регистра, поэтому тогда Y будет R12
		rsY = 12;
	}
	else if (!(reg.plr & (1 << 11 | 1 << 13))) //если Y - регистр
	{
		rsY = RegRecode[reg.yadr];    // register select
	}

	//выбор регистра на шине X
	register uint16_t rsX = RegRecode[reg.xadr];   // register select
	//выбор регистра-приёмника для сохранения результатов
	wire.rsw = -1;

	if (rsX == 12 || !(reg.plr & (1 << 20)))
	{
		//если запись не в конкретно какой-то регистр, значит в R12
		wire.rsw = 12;      // register select
	}
	else if (rsX != 12 && (reg.plr & (1 << 20)))
	{
		if (rsX != 15) //в Q запись делается не так
		{
			wire.rsw = rsX;
		}
	}

	//
	// X bus (12 entries)
	//    AU_RSX0  - general purpose regs
	//    AU_RSX1  - general purpose regs
	//    AU_QSX   - qbus temporary reg
	//    AU_PSWX  - PSW
	//
	//    AU_ALSx  - ALU result strobe     (writeonly)
	//    AU_ASTB  - A address register    (readonly)
	//    AU_ASTB  - A address register    (readonly)
	//    AU_QSTBX - Qbus temporary reg    (readonly)
	//    AU_QSTBX - Qbus temporary reg    (readonly)
	//    AU_IS0   - ALU X argument        (readonly)
	//    AU_IS1   - ALU X argument        (readonly)
	//
	// Y bus, inverted (9 entries)
	//    AU_RSY0  - general purpose regs
	//    AU_RSY1  - general purpose regs
	//    AU_QSY   - Qbus temporary reg
	//    AU_PSWY  - PSW
	//
	//    AU_ALSx  - ALU result strobe     (writeonly))
	//    AU_VSELY - vector generator      (Y-writeonly)
	//    AU_CSELY - constant generator    (Y-writeonly)
	//    ALU_U    - ALU Y argument        (readonly)
	//
	wire.x =  reg.au_alsl ? (reg.au_alsh ? alu : alu & 0377) : ((rsX < 16) ? reg.gpr[rsX] : 0);    //X bus
	wire.y = (rsY < 16) ? reg.gpr[rsY] : ((wire.vc_vsel ? reg.vmux : (wire.vc_csel ? reg.cmux : 0)));    //Y bus
}

void C1801VM1::assign_out()
{
	register bool sel_in        = reg.sel_xx && wire.pin_din_in;
	register bool dout_ext      = reg.dout_out || reg.dout_out_l;
	register uint16_t pin_ad_out    = 0;        // address/data bus output
	register bool pin_ad_ena    = false;    // address/data bus enable

	if (sel_in)
	{
		pin_ad_ena = true;

		switch (reg.sel_reg)
		{
			case 0:
				pin_ad_out = 0177740 | (m_IOPins.pin_pa << 3) | (reg.reg_csr & 7);
				break;

			case 1:
				pin_ad_out = 0177777;
				break;

			case 2:
				pin_ad_out = reg.reg_err & 0377;
				break;

			//
			// Reading the timer registers content to the shared bus
			//
			case 3:
				pin_ad_out = reg.tve_limit;
				break;

			case 4:
				pin_ad_out = reg.tve_count;
				break;

			case 5:
				pin_ad_out = 0177400 | reg.tve_csr;
				break;

			case 6:
			case 7:
				pin_ad_ena = false;
				break;
		}
	}
	else if (wire.sync_stb)
	{
		pin_ad_out = reg.areg;
		pin_ad_ena = true;
	}
	else if (dout_ext)
	{
		pin_ad_out = reg.au_hibyte ? ((reg.gpr[15] & 0377) << 8) : (reg.plrt & (1 << 0) ? (reg.gpr[15] & 0377) : reg.gpr[15]);
		pin_ad_ena = true;
	}

	//
	// External connection assignments
	//
	//--копируем данные из внутренних переменных на МПИ. из-за этого функция иногда выполняется за 3 прохода. -------------
	//тут если Z, то не надо бы значения изменять, это реализовано в функции setPins
	//
	// Shared Qbus lines
	//
	m_pCMNB->SetSignal(&PIN_nAD,   pin_ad_ena        ? ~pin_ad_out        : -1);        //inout[15:0]   // inverted address/data bus
//  register bool pin_sync_ena = reg.sync_ena || reg.sync_out;   // address strobe enable
//  m_pCMNB->SetSignal(&PIN_nSYNC, pin_sync_ena      ? !reg.sync_out      : true);    //inout         // address strobe
//  register bool pin_dout_out = reg.dout_out && reg.dout_out_l; // data output strobe output
//  m_pCMNB->SetSignal(&PIN_nDOUT, wire.pin_ctrl_ena ? !pin_dout_out      : true);    //inout         // data output strobe
//  m_pCMNB->SetSignal(&PIN_nDIN,  wire.pin_ctrl_ena ? !reg.din_out       : true);     //inout         // data input strobe
//  register bool pin_wtbt_out = (wire.sync_stb && !(reg.plrt & (1 << 2))) || (dout_ext && (reg.plrt & (1 << 0)));   // write/byte status
//  m_pCMNB->SetSignal(&PIN_nWTBT, wire.pin_ctrl_ena ? !pin_wtbt_out      : true);    //output        // write/byte status
//  m_pCMNB->SetSignal(&PIN_nIAKO, wire.pin_ctrl_ena ? !reg.iako_out_lh   : true);    //output        // interrupt vector input
//	m_pCMNB->SetSignalOE(&PIN_nAD, pin_ad_ena, ~pin_ad_out);        // а вот это не срабатывает. грязь получается
	register bool pin_sync_ena = reg.sync_ena || reg.sync_out;   // address strobe enable
	register bool sync_oe = pin_sync_ena && reg.sync_out;
	m_pCMNB->SetSignalOE(&PIN_nSYNC, sync_oe);    //inout         // address strobe
	register bool pin_dout_out = reg.dout_out && reg.dout_out_l; // data output strobe output
	register bool dout_oe = wire.pin_ctrl_ena && pin_dout_out;
	m_pCMNB->SetSignalOE(&PIN_nDOUT, dout_oe);    //inout         // data output strobe
	register bool din_oe = wire.pin_ctrl_ena && reg.din_out;
	m_pCMNB->SetSignalOE(&PIN_nDIN, din_oe);     //inout         // data input strobe
	register bool pin_wtbt_out = (wire.sync_stb && !(reg.plrt & (1 << 2))) || (dout_ext && (reg.plrt & (1 << 0)));   // write/byte status
	register bool wtbt_oe = wire.pin_ctrl_ena && pin_wtbt_out;
	m_pCMNB->SetSignalOE(&PIN_nWTBT, wtbt_oe);    //output        // write/byte status
	register bool iako_oe = wire.pin_ctrl_ena && reg.iako_out_lh;
	m_pCMNB->SetSignalOE(&PIN_nIAKO, iako_oe);    //output        // interrupt vector input
	register bool dmgo_out = (wire.pin_dmr_in && m_IOPins.pin_pa && !(reg.qbus_own_fp || reg.qbus_own_rp || reg.iako_oe)) || (!reg.qbus_req && reg.dmgi_in_l);
	m_pCMNB->SetSignalOE(&PIN_nDMGO, dmgo_out);                                        //output        // bus granted output
	//
	// "Open collector" outputs
	//
	m_pCMNB->SetSignalOE(&PIN_nINIT, wire.pin_init_out);    //inout         // peripheral reset
	m_pCMNB->SetSignalOE(&PIN_nSACK, reg.sack_out);         //inout         // bus acknowlegement
	register bool pin_rply_out = (sel_in || wire.sel_out) && (wire.pin_rply_in || (reg.rply_s2 ? (reg.sel_reg != 1) : true));    // transaction reply output
	m_pCMNB->SetSignalOE(&PIN_nRPLY, pin_rply_out);         //inout         // transaction reply
	m_pCMNB->SetSignalOE(&PIN_nDMR,  wire.dmr_out);         //inout         // bus request shared line
	m_pCMNB->SetSignalOE(&PIN_nBSY,  wire.pin_bsy_out);     //output        // bus busy flag
	m_pCMNB->SetSignalOE(&PIN_nSEL1, (reg.sel_reg == 7));    //output        // register select outputs
	m_pCMNB->SetSignalOE(&PIN_nSEL2, (reg.sel_reg == 6));    //output        // register select outputs
}

// --- ВЕ Таймер ---------------------------------------------------------
void C1801VM1::assign_tve()
{
	//
	//
	// Hidden clock prescaler, generates the /4 and /128 frequencies
	//
	wire.tve_tclk128    = (reg.tve_pre & 0177) == 0177;
	wire.pin_spclk      = (reg.tve_edge & (1 << 2 | 1 << 1)) == (1 << 1); //reg.tve_edge[1] && !reg.tve_edge[2];
	wire.tve_zero       = (reg.tve_count == 0) && !(reg.tve_csr & (1 << 1));
	wire.tve_back       = wire.pin_spclk && reg.tve_tclk4 && (reg.tve_csr & (1 << 4 | 1 << 1));
}

void C1801VM1::tve_always_posedge_pin_dclo()
{
	//
	// Asynchronous prescaler reset, no in original 1801VM1,
	// added here to provide the comfortable simulation
	//
	reg.tve_pre   = 0;
	reg.tve_div   = 0;
	//
	// Asynchronous timer counter and preload reset, no in original 1801VM1,
	// added here to provide the comfortable simulation. The control timer
	// register reset is implemented in the original chip
	//
	reg.tve_csr   = 0;
	reg.tve_count = 0;
	reg.tve_limit = 0;
}

void C1801VM1::tve_always_posedge_tve_reset()
{
	//
	// Asynchronous prescaler reset, no in original 1801VM1,
	// added here to provide the comfortable simulation
	//
	reg.tve_tclk4    = false;
	reg.tve_tclk     = false;
	reg.tve_edge     = 0;
	reg.tve_intrq[0] = false;
	reg.tve_intrq[1] = false;
	reg.tve_zprev    = true;
	//
	// The control timer register reset is implemented in the original chip
	//
	reg.tve_csr      = 0;
}



void C1801VM1::tve_always_posedge_pin_clk_p()
{
	if (!wire.pin_dclo)
	{
		if (m_IOPins.pin_ena)
		{
			reg.tve_pre = (snap_reg.tve_pre + 1) & 0177;

			//
			// Documented divisor 1/4, 1/16, 1/64
			//
			if (wire.tve_tclk128)
			{
				reg.tve_div = (snap_reg.tve_div + 1) & 077;
			}
		}
	}

	if (!wire.tve_reset)
	{
		if (m_IOPins.pin_ena)
		{
			//
			// Falling edge detector (raising for the inverted input pin_sp)
			//
			if (snap_reg.tve_tclk4)
			{
				//
				// Input metastability eliminator and synchronizer
				//
				reg.tve_edge = (snap_reg.tve_edge << 1) | (m_IOPins.pin_sp ? 1 : 0);
				//
				// Counter zero flag edge detector
				//
				reg.tve_zprev = wire.tve_zero;
			}

			register bool b = reg.tve_tclk4 = (snap_reg.tve_pre & 3) == 3;

			//
			// Timer clock selector
			//
			/*
			reg.tve_tclk = (snap_reg.tve_csr[0]) ?
			                  ( wire.pin_spclk && ((snap_reg.tve_pre & 3) == 3) ) :
			                  ( wire.tve_tclk128 && ( !snap_reg.tve_csr[6] && !snap_reg.tve_csr[5]
			                                       ||  snap_reg.tve_csr[6] && !snap_reg.tve_csr[5] && ((snap_reg.tve_div & 3) == 3)
			                                       || !snap_reg.tve_csr[6] &&  snap_reg.tve_csr[5] && ((snap_reg.tve_div & 017) == 017)
			                                       ||  snap_reg.tve_csr[6] &&  snap_reg.tve_csr[5] && ((snap_reg.tve_div & 077) == 077) ) );
			*/
			if (snap_reg.tve_csr & (1 << 0))
			{
				reg.tve_tclk = wire.pin_spclk ? b : false;
			}
			else if (wire.tve_tclk128)
			{
				switch (snap_reg.tve_csr & (3 << 5))
				{
					case (0 << 5): reg.tve_tclk = true;
						break;

					case (1 << 5): reg.tve_tclk = ((snap_reg.tve_div & 017) == 017);
						break;

					case (2 << 5): reg.tve_tclk = ((snap_reg.tve_div & 3) == 3);
						break;

					case (3 << 5): reg.tve_tclk = ((snap_reg.tve_div & 077) == 077);
						break;
				}
			}
			else
			{
				reg.tve_tclk = false;
			}
		}

		register bool bCond1 = (snap_reg.tve_csr & (1 << 2)) ? (wire.tve_zero || wire.tve_back) : false;

		if (!bCond1)
		{
			reg.tve_intrq[1] = snap_reg.tve_intrq[0];
		}

		if (m_IOPins.pin_ena)
		{
			//
			// Interrupt flags
			//
			if (bCond1)
			{
				reg.tve_intrq[0] = true;
			}
		}
		else if ((snap_reg.plm1x_hl && !(snap_reg.plr & (1 << 27))) && (snap_reg.plir == 5)) // VE-timer interrupt acknowledgement
		{
			//
			// New timer interrupt request raising while
			// acknowledgement can be missed
			//
			reg.tve_intrq[0] = false;
		}
	}

	//
	// Timer counter, preload/capture and control registers
	//
	if (!(wire.pin_dclo || wire.tve_reset))
	{
		//
		// Timer control register
		//
		// csr[0]   - selects external clock source
		// csr[1]   - selects capture mode
		// csr[2]   - enables interrupt request
		// csr[3]   - selects one-shot mode
		// csr[4]   - timer count enable
		// csr[5]   - 1/16 divider enable
		// csr[6]   - 1/4 divider enable
		// csr[7]   - interrupt overflow flag
		//
		register bool tve_csr_wr, tve_lim_wr;

		if (wire.sel_out)
		{
			tve_csr_wr = (snap_reg.sel_reg == 5);
			tve_lim_wr = (snap_reg.sel_reg == 3);
		}
		else
		{
			tve_csr_wr = false;
			tve_lim_wr = false;
		}

		if (tve_csr_wr)
		{
			//
			// The prioritized CSR write from bus
			// Clocked every system bus cycle
			//
			reg.tve_csr = wire.pin_ad_in & 0377;
			//
			// Counter is written unconditionally at every CSR bus write
			//
			reg.tve_count = snap_reg.tve_limit;
		}

		if (tve_lim_wr)
		{
			//
			// The prioritized register write from bus
			// Clocked every system bus cycle
			//
			reg.tve_limit = wire.pin_ad_in;
		}

		if (m_IOPins.pin_ena)
		{
			//
			// Timer counter, preload/capture and control registers
			//
			if (!tve_csr_wr)
			{
				if (wire.tve_zero && (snap_reg.tve_csr & (1 << 3)))
				{
					//
					// Reset the RUN bit in one-shot mode
					//
					reg.tve_csr &= ~(1 << 4);
				}

				if (snap_reg.tve_intrq[1] && (snap_reg.tve_csr & (1 << 2)) && (wire.tve_zero || wire.tve_back))
				{
					//
					// Set the interrupt overflow flag if enabled
					//
					reg.tve_csr |= (1 << 7);
				}

				//
				// Decrementing counter register
				//
				if (!snap_reg.tve_zprev && wire.tve_zero && snap_reg.tve_tclk4 && !(snap_reg.tve_csr & (1 << 1))) // timer counter load
				{
					//
					// Counter is being reloaded
					//
					reg.tve_count = snap_reg.tve_limit;
				}
				else if (snap_reg.tve_tclk && (snap_reg.tve_csr & (1 << 4)))
				{
					//
					// Count selected clock events if enabled
					//
					reg.tve_count = snap_reg.tve_count - 1;
				}
			}

			//
			// Timer preload and capture value register
			//
			if (!tve_lim_wr && wire.tve_back)
			{
				//
				// Capture the current counter value
				//
				reg.tve_limit = snap_reg.tve_count;
			}
		}
	}
}

//------------------------------------------------------------------------

void C1801VM1::always_posedge_pin_clk_n()
{
	//______________________________________________________________________________
	//
	// Microcode state machine
	//
	//plm23_fc bit   irq check  wait IR  start IR     Note
	//       0          no       yes       no         RTT opcode, wait fetch completion
	//       1          yes      yes       yes        usual IR fetch
	//       2          yes      no        no         WAIT opcode, check irq only
	//       3          yes      yes       no         ~RTT opcode, wait fetch completion
	register uint8_t plm23_fc = 0;   //wire[3:0]
	register bool bTmpB1;

	if (wire.plm_ena_fc)
	{
		reg.tplmz = 0;

		switch (((snap_reg.plm & 0xf) >> 1)) //биты plm 3,2,1
		{
			case 1: plm23_fc = (1 << 0); break;

			case 2: reg.tplmz = (1 << 2); break;

			case 3: plm23_fc = (1 << 1);
				reg.tplmz = (1 << 3); break;

			case 4: reg.tplmz = (1 << 1); break;

			case 5: plm23_fc = (1 << 2); break;

			case 7: plm23_fc = (1 << 3); break;
		}

		bTmpB1 = !(snap_reg.plm & (1 << 12));
	}
	else
	{
		bTmpB1 = false;
	}

	register bool bTmpB2 = (snap_reg.plm & (1 << 11 | 1 << 13)) == (1 << 11 | 1 << 13); //snap_reg.plm[11] && snap_reg.plm[13];
	// main matrix result strobes
	reg.plm1x_hl = snap_reg.plm1x;

	if (bTmpB1)
	{
		reg.plm1x =  bTmpB2;
		reg.plm2x = !bTmpB2;
	}
	else
	{
		reg.plm1x = false;
		reg.plm2x = false;
	}

	reg.ir_set     = !!(plm23_fc & (1 << 3          | 1 << 1 | 1 << 0)); //wire.plm23_fc[0] || wire.plm23_fc[1] || wire.plm23_fc[3];
	reg.plm23_wait = !!(plm23_fc & (1 << 3                   | 1 << 0)); //wire.plm23_fc[0] || wire.plm23_fc[3];
	reg.plm23_ichk = !!(plm23_fc & (1 << 3 | 1 << 2 | 1 << 1));          //wire.plm23_fc[1] || wire.plm23_fc[2] || wire.plm23_fc[3];

	if (wire.plm_ena_fc)
	{
		reg.plr = snap_reg.plm;
		//______________________________________________________________________________
		//делаем вычисления, зависящие от текущего значения reg.plr
		// здесь reg справа так и должен быть, т.к. должен рассматриваться как просто переменная.
		register uint32_t lplr = LODWORD(reg.plr);
		wire.alu_shift  = (lplr >> 13) & 3; //признак режима сдвига АЛУ, и частично - определитель, как интерпретировать шину Y
		wire.shift_code = (lplr >> 25) & 3; //код вида сдвига
		reg.yadr = ((lplr >> 25) & 0xf);
		reg.xadr = ((reg.plr >> 30) & 0xf);
		register bool wire1 = (wire.alu_shift == 1) || (lplr & (1 << 11));
		wire.vc_vsel = (reg.yadr == 2) && wire1;
		wire.vc_csel = (reg.yadr != 2) && wire1;
		//wire.plop[0] = !reg.plr[22] && !reg.plr[21] && !reg.plr[4]; // 000
		//wire.plop[1] = !reg.plr[22] && !reg.plr[21] &&  reg.plr[4]; // 001
		//wire.plop[2] = !reg.plr[22] &&  reg.plr[21] && !reg.plr[4]; // 010
		//wire.plop[3] = !reg.plr[22] &&  reg.plr[21] &&  reg.plr[4]; // 011
		//wire.plop[4] =  reg.plr[22] && !reg.plr[21] && !reg.plr[4]; // 100
		//wire.plop[5] =  reg.plr[22] && !reg.plr[21] &&  reg.plr[4]; // 101
		//wire.plop[6] =  reg.plr[22] &&  reg.plr[21] && !reg.plr[4]; // 110
		//wire.plop[7] =  reg.plr[22] &&  reg.plr[21] &&  reg.plr[4]; // 111
		register int n = ((lplr >> 20) & 6) | ((lplr >> 4) & 1);
		wire.plop = g_WordBitMask[n];
		//wire.au_swapX = !(reg.plr & (1 << 27)) && (shift_code == 3) && (alu_shift == 3); //011 - команда перестановки байтов на шине Х
		wire.au_swapX = (lplr & (1 << 27 | 1 << 26 | 1 << 25 | 1 << 14 | 1 << 13)) == (1 << 26 | 1 << 25 | 1 << 14 | 1 << 13);
		wire1         = !!(lplr & (1 << 8 | 1 << 7));
		wire.wait_areg_free      = !(lplr & (1 << 23)) && !wire1; //ожидать освобождения регистра A
		wire.wait_write_complete = !(lplr & (1 << 23)) &&  wire1; //ожидать завершения записи на шине МПИ
	}

	if (snap_reg.plm_ena)
	{
		//если PLOP != 0 и != 2 и != 7, (т.е. == 1 или 3,4,5,6), то надо сохранять в PSW флаги NZV
		reg.psw_stb  = !(wire.plop & (1 << 0 | 1 << 2 | 1 << 7));
		//если PLOP != 0 и != 1 и != 2 и != 3 и != 7 (т.е. == 4 или 5, 6), то надо сохранять в PSW флаг C
		reg.psw_stbc = !(wire.plop & (1 << 0 | 1 << 2 | 1 << 7 | 1 << 1 | 1 << 3));

		if (wire.plop & (1 << 7))
		{
			//если PLOP == 7, то reg_ir_stb2, иначе (PLOP == 0 или 2,3,4,6)
			reg.mj_stb1 = snap_reg.ir_stb2;
			//если PLOP == 7, то reg_ir_stb2, иначе (PLOP == 0 или 2,4,6)
			reg.mj_stb2 = snap_reg.ir_stb2;
			//если PLOP == 7, то reg_ir_stb2, иначе 0
			reg.psw_mj  = snap_reg.ir_stb2;
		}
		else
		{
			//если PLOP == 7, то reg_ir_stb2, иначе (PLOP == 0 или 2,3,4,6)
			reg.mj_stb1 = !(wire.plop & (1 << 1 | 1 << 5));
			//если PLOP == 7, то reg_ir_stb2, иначе (PLOP == 0 или 2,4,6)
			reg.mj_stb2 = !(wire.plop & (1 << 1 | 1 << 3 | 1 << 5));
			//если PLOP == 7, то reg_ir_stb2, иначе 0
			reg.psw_mj  = false;
		}
	}

	//______________________________________________________________________________
	//
	// ALU function unit
	//
	//
	// ALU input parameters (from X and Y buses) registers
	//
	reg.xreg = wire.au_swapX ? ((wire.x & 0xff) << 8) | ((wire.x >> 8) & 0xff) : wire.x;
	reg.yreg = wire.y;
	//
	// ALU general purpose registers
	//
	register bool alsl = reg.au_alsl = snap_reg.alu_busy_rp && snap_reg.ustb_h;
	//reg.au_alsh = snap_reg.alu_busy_rp && snap_reg.ustb_h && snap_reg.plr[18];
	reg.au_alsh = alsl && (snap_reg.plr & (1 << 18));

	if (wire.au_astb)
	{
		//сохраняем в регистре адреса A текущее содержимое шины X
		reg.areg = wire.x;
	}

	//______________________________________________________________________________
	//
	// Control and glue logic
	//
	reg.plm_ena     = wire.plm_ena_fc;
	reg.sop_out[1]  = snap_reg.sop_out[0];
	reg.sop_out[3]  = snap_reg.ir_stop || snap_reg.pli_req || snap_reg.ir_stb2 || snap_reg.mjres_h || ((wire.plop & (1 << 0 | 1 << 4)) ? snap_reg.alu_nrdy : false);
	reg.ustb1       = snap_reg.ustb_h;
	reg.ustb1_hl    = snap_reg.ustb1_h;
	// always_posedge_pin_clk_n_or_posedge_mjres()
	//______________________________________________________________________________
	//
	// Qbus data ready
	register bool alu_qrdy = !((snap_reg.qbus_adr && wire.wait_write_complete)   // wait for write complete
	                           || (snap_reg.dout_req && wire.wait_areg_free)        // wait for reg.areg free
	                           || (!(snap_reg.plr & (1 << 10)) && (!!(snap_reg.tplm & (1 << 2)) || snap_reg.iak_flag))); // wait for data or vector fetch

	if (snap_reg.ustb_h)
	{
		reg.ustb = false;
	}
	else if (alu_qrdy && (snap_reg.alu_busy_rp || (snap_reg.alu_busy_fp && !snap_reg.ustb1_h)))
	{
		reg.ustb = true;
	}

	reg.alu_busy_fp = snap_reg.alu_busy_rp;
	//______________________________________________________________________________
	//
	// Qbus logic
	//
	reg.rply_ack[2] = snap_reg.rply_ack[1];
	reg.rply_ack[0] =  wire.rply_ack_fc;
	reg.dmr_req_l   =  snap_reg.dmr_req;
	reg.dout_out_l  =  snap_reg.dout_out;
	reg.din_out_l   =  snap_reg.din_out;
	reg.sync_out    =  snap_reg.qbus_win_h;
	reg.sync_ena    =  snap_reg.sync_out_h;
	reg.dmgi_in_l   =  wire.pin_dmgi;
	reg.rply_s2     =  snap_reg.start_irq;
	reg.rply_s3     = !snap_reg.rply_s2;
	register bool qbus_gnt = reg.qbus_gnt_l = (snap_reg.qbus_nosr_h || (snap_reg.qbus_win_h ? false : snap_reg.sync_out_h)) && (snap_reg.qbus_free_h || (wire.dmr_out && snap_reg.sack_out));
	register bool oe_set_fc = reg.oe_set = (snap_reg.dmr_req || snap_reg.qbus_own_fp || snap_reg.qbus_own_rp) ? false : (qbus_gnt && snap_reg.iak_flag);
#if (LONG_QBUS_CYCLES)
	reg.dout_done = wire.dout_start ? false : snap_reg.dout_out_l; //старый вариант
	register bool oe_clr_fc = reg.oe_clr = snap_reg.mjres || ((wire.rply_ack_fc || snap_reg.qbus_flag) ? false : snap_reg.rply_ack[2]); //старый вариант
	//работает и каждый такт и каждый полутакт
#else
	reg.dout_done = snap_reg.rply_ack[1] ? snap_reg.dout_out : false; //новый вариант - сокращает время доут на 1 такт
	register bool oe_clr_fc = reg.oe_clr = snap_reg.mjres || ((wire.rply_ack_fc || snap_reg.qbus_flag) ? false : snap_reg.rply_ack[1]); //новый вариант - сокращает время SYNC на 1 такт
	//не работает при опросе периферии каждый такт
#endif

	if (oe_clr_fc)
	{
		reg.iako_oe = false;
		reg.qbus_win = false;
	}

	if (oe_set_fc)
	{
		reg.iako_oe = true;
	}

	if (snap_reg.dmr_req && qbus_gnt)
	{
		reg.qbus_win = true;
		reg.qbus_own_fp = true;
	}

	if (snap_reg.qbus_own_rp)
	{
		reg.qbus_own_fp = false;
	}

	// always_posedge_pin_clk_n_or_posedge_mjres()
	//______________________________________________________________________________
	// Reset the completed request if it is only one
	// The third request is impossible - the state machine
	// is suspended by qbus_nrdy
	//
	if (wire.au_astb)
	{
		reg.qbus_aseq[0] = true;

		if (snap_reg.qbus_aseq[0])
		{
			reg.qbus_aseq[1] = true;
		}
	}

	if (snap_reg.oe_clr)
	{
		reg.qbus_aseq[1] = false;

		if (!snap_reg.qbus_aseq[1])
		{
			reg.qbus_aseq[0] = false;
		}
	}

	//______________________________________________________________________________
	//
	// Блок регистров
	//
	if (wire.rsw < 14)
	{
		if (snap_reg.au_alsl)
		{
			//заполняем младший байт
			reg.gpr[wire.rsw] &= 0xff00;
			reg.gpr[wire.rsw] |= wire.x & 0xff;
		}

		if (snap_reg.au_alsh)
		{
			//заполняем старший байт
			reg.gpr[wire.rsw] &= 0xff;
			reg.gpr[wire.rsw] |= wire.x & 0xff00;
		}
	}

	// always_posedge_pin_clk_n_or_posedge_reset()
	//
	// ALU result flags and PSW
	//
	//
	// Start microcode correctly sets the PSW
	// But simulator can not calculate ALU function
	// correctly if PSW in initially undefined
	//
	// The PSW is written by microcode with 340 value
	// while executing reset sequence
	//
	//запись в PSW
	if (wire.rsw == 14 && snap_reg.au_alsl) //если выбран для записи PSW, и надо сохранить результат работы АЛУ в мл.байт
	{
		reg.gpr[14] &= 0177400;
		reg.gpr[14] |= wire.x & 0377;   //так и делаем.
	}
	else
	{
		//
		// Latch the ALU flag results immediately after ALU completion
		// Rollback to the original PSW logic
		//
		if (snap_reg.ustb1_hl)
		{
			if (snap_reg.psw_stbc)
			{
				reg.gpr[14] &= ~(1 << 0);
				reg.gpr[14] |= snap_reg.freg & (1 << 0);
			}

			if (snap_reg.psw_stb)
			{
				reg.gpr[14] &= ~(1 << 3 | 1 << 2 | 1 << 1);
				reg.gpr[14] |= snap_reg.freg & (1 << 3 | 1 << 2 | 1 << 1);
			}
		}

//
// This does not work correctly for MUL instruction - result flags are wrong
// due to G-version microcode urges to write flags from ALU bus directly
// (wire.rsw[14] active)
//
//          if (snap_reg.psw_stbc && snap_reg.au_alsl)
//          {
//              reg.gpr[14] &= ~(1 << 0);
//              reg.gpr[14] |= wire.flag & (1 << 0);
//          }
//          if (snap_reg.psw_stb && snap_reg.au_alsl)
//          {
//              reg.gpr[14] &= ~(1 << 3 | 1 << 2 | 1 << 1);
//              reg.gpr[14] |= wire.flag & (1 << 3 | 1 << 2 | 1 << 1);
//          }
	}

	if (wire.rsw == 14 && snap_reg.au_alsh) //если выбран для записи PSW, и надо сохранить результат работы АЛУ в ст.байт
	{
		reg.gpr[14] &= 0377;
		reg.gpr[14] |= (wire.x & 0176000) | (m_IOPins.pin_pa << 8);//так и делаем. за исключением особых битов
	}

	//always_posedge_pin_clk_n_or_negedge_qbus_tena()
	if (wire.qbus_tena)
	{
		if (!snap_reg.qbus_tovf)
		{
			reg.qbus_timer = (snap_reg.qbus_timer + 1) & 077;
		}
	}
}


//
// Qbus timeout counter
//
// original 1801BM1 timer has 1/8 input prescaler which is no reset and
// provides bus timeout in a range 56..63 processor clocks. This model
// emulates the average value 60 clocks.
//
// Timeout exception request should be synchronized with raising clk's edge
//
void C1801VM1::always_negedge_qbus_tena()
{
	reg.qbus_timer = 0;
}

void C1801VM1::always_posedge_pin_clk_p()
{
	//______________________________________________________________________________
	// Interrupt controller
	//
	//
	register int n = (snap_reg.gpr[14] >> 10) & 3; //биты psw 11 10
	static int nRQPSWData[4] =
	{
		(0 << 2) | (0 << 0),
		(0 << 2) | (1 << 0),
		(1 << 2) | (0 << 0),
		(1 << 2) | (1 << 0)
	};
	reg.rq = nRQPSWData[n];

	if (snap_reg.plir0)
	{
		reg.rq |= (1 << 1);    // pli4r
	}

	if (snap_reg.uop)
	{
		reg.rq |= (1 << 3);
	}

	if (snap_reg.gpr[14] & (1 << 7)) //приоритет
	{
		reg.rq |= (1 << 4);
	}

	//
	// Not used matrix inputs
	//
	// if (false) reg.rq |= (1 << 5);
	// if (false) reg.rq |= (1 << 6);
	// if (false) reg.rq |= (1 << 7);
	//
	// Only master CPU processes vectored interrupts
	// Matrix accepts low level as active (asserted request)
	//
	if (!(wire.pin_irq[0] && (m_IOPins.pin_pa == 0)))
	{
		reg.rq |= (1 << 8);
	}

	if (snap_reg.qbto)
	{
		reg.rq |= (1 << 9);
	}

	if (snap_reg.reg_err & (1 << 0))
	{
		reg.rq |= (1 << 10);
	}

	if (wire.pin_aclo)
	{
		if (snap_reg.aclo)
		{
			reg.rq |= (1 << 11);
		}
	}
	else
	{
		if (snap_reg.acok)
		{
			reg.rq |= (1 << 13);
		}
	}

	if (snap_reg.reg_csr & (1 << 2))
	{
		reg.rq |= (1 << 12);
	}

	if (wire.pin_irq[1])
	{
		reg.rq |= (1 << 14);
	}

	if (snap_reg.gpr[14] & (1 << 4))    //Т-бит
	{
		reg.rq |= (1 << 15);
	}

	if (wire.pin_irq[2] && snap_reg.irq2)
	{
		reg.rq |= (1 << 16);
	}

	if (snap_reg.ivto)
	{
		reg.rq |= (1 << 17);
	}

	if (wire.pin_irq[3] && snap_reg.irq3)
	{
		reg.rq |= (1 << 18);
	}

	if (snap_reg.tve_intrq[0])
	{
		reg.rq |= (1 << 19);    // VE-timer interrupt request (vm1a_pli ignores)
	}

	if (snap_reg.pli_req)
	{
		reg.plir = ((wire.pli >> (10 - 2)) & (1 << 2))
		           | ((wire.pli >> (8 - 1)) & (1 << 1))
		           | ((wire.pli >> (6 - 0)) & (1 << 0));
	}

	//
	// Detector's reset
	//
	register bool uop_ack, aclo_ack, irq3_ack, irq2_ack;

	if (snap_reg.plm1x_hl && !(snap_reg.plr & (1 << 27)))
	{
		uop_ack  = (snap_reg.plir == 0);  // undefined instruction
		aclo_ack = (snap_reg.plir == 1);  // ACLO timer acknowlegement
		irq3_ack = (snap_reg.plir == 4);  // IRQ2 timer acknowlegement
		irq2_ack = (snap_reg.plir == 6);  // IRQ3 timer acknowlegement
	}
	else
	{
		uop_ack  = false;  // undefined instruction
		aclo_ack = false;  // ACLO timer acknowlegement
		irq3_ack = false;  // IRQ2 timer acknowlegement
		irq2_ack = false;  // IRQ3 timer acknowlegement
	}

	register bool exc_err7 = (snap_reg.plr & (1 << 30)) ? false : snap_reg.plm1x_hl;
	register bool iako_out = reg.iako_out_lh = snap_reg.din_out && snap_reg.iak_flag; //это из Qbus logic, просто оно тут нужнее

	//
	// ACLO edge detectors
	//
	if (aclo_ack)
	{
		reg.aclo = false;
		reg.acok = false;
	}
	else
	{
		if (snap_reg.reset)
		{
			reg.aclo = false;
		}

		if (wire.pin_dclo)
		{
			reg.acok = false;
		}

		if (wire.pin_aclo)
		{
			reg.acok = true;
		}
		else
		{
			reg.aclo = true;
		}
	}

	//
	// IRQ2 and IRQ3 falling edge detectors
	// Also resettable by internal INIT
	//
	if (wire.tve_reset)
	{
		reg.irq2 = false;
		reg.irq3 = false;
	}
	else
	{
		if (irq2_ack)
		{
			reg.irq2 = false;
		}
		else if (!wire.pin_irq[2])
		{
			reg.irq2 = true;
		}

		if (irq3_ack)
		{
			reg.irq3 = false;
		}
		else if (!wire.pin_irq[3])
		{
			reg.irq3 = true;
		}
	}

	//
	// Error exception latches
	//
	if (snap_reg.reset || uop_ack)
	{
		reg.uop  = false;
		reg.qbto = false;
		reg.ivto = false;
	}
	else
	{
		if (wire.exc_uop)
		{
			reg.uop = true;
		}

		if (snap_reg.qbus_tovf && iako_out)
		{
			reg.ivto = true;
		}

		if (snap_reg.qbus_tovf || wire.exc_oat)
		{
			reg.qbto = true;
		}
	}

	if (snap_reg.pli_req)
	{
		reg.vsel = (wire.pli & 0xf) ^ (1 << 2); // {wire.pli[3], !wire.pli[2], wire.pli[1], wire.pli[0]};
	}
	else if (snap_reg.plm1x)
	{
		//reg.vsel = { snap_reg.plr[18], !snap_reg.plr[20], !snap_reg.plr[21], !snap_reg.plr[22] };
		register int n = ((snap_reg.plr >> 19) & (1 << 3 | 1 << 2 | 1 << 1)) | (snap_reg.plr >> 18) & (1 << 0);
		static uint8_t pVSELData[16] =
		{
			7, 15, 3, 11, 5, 13, 1, 9,
			6, 14, 2, 10, 4, 12, 0, 8
		};
		reg.vsel = pVSELData[n];
	}

	reg.pli_req = snap_reg.plm23_ichk || snap_reg.abort;    // interrupt encoder request
	//______________________________________________________________________________
	//
	// Control and glue logic
	//
	reg.ir_seq     = wire.ir_seq_rc;
	reg.sop_out[2] = snap_reg.sop_out[1];

	if (wire.plm_stb_rc)
	{
		reg.sop_out[0] = false;
	}
	else if (wire.mjres_rc || snap_reg.plm_ena)
	{
		reg.sop_out[0] = true;
	}

	reg.plm_stb = wire.plm_stb_rc;
	reg.ustb1_h = snap_reg.ustb1;
	reg.tplm    = wire.tplm_rc;

	//
	// Reset Read Flag after read completion within
	// read-modify-write operations
	//
	if (wire.din_done)
	{
		reg.plrt &= ~(1 << 2);
	}

	if (wire.uplr_stb)
	{
		reg.plrt = snap_reg.plrtz;
		reg.qbus_adr = true;
	}

	if (snap_reg.mjres || wire.mjres_rc || wire.sync_fedge)
	{
		reg.qbus_adr = false;
	}

	//
	//      plr[6]  QBUS operation type: byte operation flag
	//      plr[7]  QBUS operation type: write flag
	//      plr[8]  QBUS operation type: read flag
	//                      00x - nothing
	//                      010 - write word
	//                      011 - write byte
	//                      100 - read word
	//                      101 - read byte
	//                      110 - read-modify-write word
	//                      111 - read-modify-write byte
	//
	static uint8_t pPLRTZdata[8] = { 0, 1, 0, 1, 4, 5, 6, 7 };
	reg.plrtz = pPLRTZdata[(snap_reg.plr >> 6) & 7];
	//______________________________________________________________________________
	//
	// Qbus logic
	//
	reg.rply_ack[1] = snap_reg.rply_ack[0];
	reg.rply_ack[3] = snap_reg.rply_ack[2];
	reg.qbus_win_h  = snap_reg.qbus_win;
	reg.sync_out_h  = snap_reg.sync_out;
	reg.qbus_free_h = wire.dma_in ? false : (m_IOPins.pin_pa == 0);
	reg.qbus_nosr_h = wire.qbus_nosr_rc;

	if (wire.qbus_done)
	{
		reg.qbus_own_rp = false;
	}
	else if (snap_reg.dmr_req_l && snap_reg.qbus_gnt_l)
	{
		reg.qbus_own_rp = true;
	}

	reg.qbus_flag = wire.qbus_flag_rc;
	reg.qbus_tovf = ((snap_reg.qbus_timer & 074) == 074);

	//
	// Start vector register at 177702
	// Due to there is no start vector write interrupt (disconncted from
	// interrupt controller matrix) the start vector register is not used
	//
	if (wire.sel_out && (snap_reg.sel_reg == 1))
	{
		reg.reg_vec = wire.pin_ad_in;
	}

	//
	// Error register at 177704
	// Bit 0 is Double Error
	// Bit 1 is Undefine Opcode
	// Bit 5 is not used (always read as one)
	// Bit 6 is Odd Address Trap (is not implmented)
	//
	if (wire.reset_rc || snap_reg.ir_set)
	{
		reg.reg_err = 040;
	}
	else
	{
		if (wire.sel_out && (snap_reg.sel_reg == 2))
		{
			reg.reg_err = (wire.pin_ad_in & 0377) | 040;
		}
		else
		{
			//
			// Bit 0 - double error
			//
			if ((snap_reg.exc_dbl[0] && wire.exc_uop)
			        || (snap_reg.exc_dbl[1] && snap_reg.qbus_tovf)
			        || (snap_reg.exc_dbl[2] && wire.exc_oat)
			        || (snap_reg.exc_dbl[3] && exc_err7))
			{
				reg.reg_err |= (1 << 0);
			}

			//
			// Bit 1 - undefined opcode
			//
			if (wire.exc_uop)
			{
				reg.reg_err |= (1 << 1);
			}

			//
			// Bit 2 && 3 - unknown error, exceptions not implemented
			//
			if (snap_reg.plm1x_hl)
			{
				if (!(snap_reg.plr & (1 << 26)))
				{
					reg.reg_err |= (1 << 2);
				}

				if (!(snap_reg.plr & (1 << 28)))
				{
					reg.reg_err |= (1 << 3);
				}
			}

			//
			// Bit 4 - qbus timeout
			//
			if (snap_reg.qbus_tovf)
			{
				reg.reg_err |= (1 << 4);
			}

			//
			// Bit 6 - odd address trap
			//
			if (wire.exc_oat)
			{
				reg.reg_err |= (1 << 6);
			}

			//
			// Bit 7 - unknown error, no exception
			//
			if (exc_err7)
			{
				reg.reg_err |= (1 << 7);
			}
		}
	}

	//
	// Double error detectors
	//
	if (!wire.exc_uop)
	{
		reg.exc_dbl[0] = GETBIT(snap_reg.reg_err, 1);
	}

	if (!snap_reg.qbus_tovf)
	{
		reg.exc_dbl[1] = GETBIT(snap_reg.reg_err, 4);
	}

	if (!wire.exc_oat)
	{
		reg.exc_dbl[2] = GETBIT(snap_reg.reg_err, 6);
	}

	if (!exc_err7)
	{
		reg.exc_dbl[3] = GETBIT(snap_reg.reg_err, 7);
	}

	if (!wire.pin_sync_in)
	{
		reg.sel_xx = ((wire.pin_ad_in & 0177760) == (0177700 | (m_IOPins.pin_pa << 4))); // peripheral block access

		if (reg.sel_xx) //оптимизация, здесь так и должно быть reg.sel_xx
		{
			reg.sel_reg = ((wire.pin_ad_in & 0xf) >> 1); //число 0..7
		}
		else
		{
			reg.sel_reg = -1; //не выбран, т.к. далее везде делается сравнение на равенство 0..7 => 00 .. 016
		}
	}

	//
	// Original circuit contains error
	// The start_irq request is reset by interrupt ack and EMT execution (last one is wrong)
	//
	if (snap_reg.reset || (wire.vc_vsel && (snap_reg.vsel & 7) == 6))
	{
		reg.start_irq = false;
	}
	else if (wire.sel_out && snap_reg.rply_s3 && (snap_reg.sel_reg == 1))
	{
		reg.start_irq = true;
	}

	//______________________________________________________________________________
	//
	// Reset circuits
	//
	reg.mjres_h = snap_reg.mjres;
	reg.abort_tm = wire.reset_rc ? false : snap_reg.abort;
	reg.abort = wire.abort_rc;

	if (!snap_reg.abort && reg.abort)
	{
		always_posedge_abort();
	}
	else
	{
		always_posedge_pin_clk_p_or_posedge_abort();
	}

	reg.reset = wire.reset_rc;

	if (!snap_reg.reset && reg.reset)
	{
		always_posedge_reset();
	}
	else
	{
		always_posedge_pin_clk_p_or_posedge_reset();
	}

	reg.mjres = wire.mjres_rc;

	if (!snap_reg.mjres && reg.mjres) //вот таким образом получается posedge, в snap_reg - реально предыдущие значения, а в reg - текущие
	{
		always_posedge_mjres();
	}
	else
	{
		always_posedge_pin_clk_p_or_posedge_mjres();
	}

	if (wire.reset_rc)
	{
		reg.init_out[0] = false;
	}
	else if (snap_reg.plm1x_hl)
	{
		if (!(snap_reg.plr & (1 << 23)))
		{
			reg.init_out[0] = false;
		}
		else if (!(snap_reg.plr & (1 << 10)))
		{
			reg.init_out[0] = true;
		}
	}

	reg.init_out[1] = snap_reg.init_out[0];
	reg.init_out[2] = snap_reg.init_out[1];
	//______________________________________________________________________________
	//
	// Microcode state machine
	//
	//
	// Instruction register
	//
	register bool ir_stb1 = !!(snap_reg.tplm & (1 << 1 | 1 << 3));

	if (ir_stb1)
	{
		reg.ira = wire.pin_ad_in;
	}

	if (snap_reg.ir_stb2)
	{
		reg.ir = ir_stb1 ? wire.pin_ad_in : snap_reg.ira;
	}

	//
	// Other bits have no reset facility
	//
	if (wire.plm_stb_rc)
	{
		//
		// Some of plm is not used here (microcode address directly uses plx instead)
		//
		reg.plm = wire.plx;
	}

	// Microcode register
	//
	if (snap_reg.ustb1_hl)
	{
		if (snap_reg.mj_stb1)
		{
			reg.mj &= ~(1 << 11 | 1 << 10 | 1 << 9 | 1 << 8);
			reg.mj |= (snap_reg.gpr[14] & (1 << 4)) << (11 - 4); //флаг Т
			reg.mj |= ((snap_reg.psw_mj ? snap_reg.gpr[14] : snap_reg.freg) & (1 << 3 | 1 << 2 | 1 << 1)) << (8 - 1); //флаги NZV
		}

		if (snap_reg.mj_stb2)
		{
			reg.mj &= ~(1 << 7);
			reg.mj |= ((snap_reg.psw_mj ? snap_reg.gpr[14] : snap_reg.freg) & (1 << 0)) << 7; //флаг С
		}
	}

	//
	// ALU qbus register
	//
	if (wire.au_qstbx)
	{
		reg.gpr[15] = wire.x;
	}
	else if (iako_out || (snap_reg.tplm & (1 << 2)))
	{
		reg.gpr[15] = wire.pin_ad_in;

		//если обрабатываем старший байт, то помещаем его в мл.байт регистра Q,
		//а его ст. байт значения не имеет
		if (snap_reg.au_hibyte)
		{
			reg.gpr[15] &= 0xff00;
			reg.gpr[15] |= (wire.pin_ad_in >> 8) & 0xff;
		}
	}

	//
	// ALU result flags and PSW
	//
	if (snap_reg.au_alsl)   //если операции в АЛУ завершились
	{
		reg.freg = wire.flag;   //то фиксируем флаги
	}

	//
	// Transaction address low bit latch
	//
	if (wire.sync_stb)
	{
		reg.au_hibyte = !!(snap_reg.areg & snap_reg.plrt & (1 << 0));
	}
}


void C1801VM1::always_posedge_pin_clk_p_or_posedge_mjres()
{
	//______________________________________________________________________________
	//
	// Control and glue logic
	//
	reg.ustb_h = snap_reg.ustb;

	if (snap_reg.plm2x)
	{
		reg.alu_busy_rp = true;
		reg.alu_nrdy = true;
	}
	else
	{
		if (snap_reg.ustb1)
		{
			reg.alu_busy_rp = false;
		}

		if (snap_reg.ustb1_h)
		{
			reg.alu_nrdy = false;
		}
	}

	if (wire.ir_clr)
	{
		reg.ir_stb2 = false;
		reg.ir_stop = true;
	}
	else
	{
		if (snap_reg.ir_set)
		{
			reg.ir_stb2 = true;
		}

		if (!(snap_reg.reg_csr & (1 << 0)))
		{
			reg.ir_stop = false;
		}
	}

	//______________________________________________________________________________
	//
	// Qbus logic
	//
	reg.dmr_req = wire.dmr_req_rc;
	reg.dout_req = wire.dout_req_rc;

	if (snap_reg.dout_done)
	{
		reg.dout_out = false;
	}
	else if (wire.dout_start)
	{
		reg.dout_out = true;
	}

	if (wire.din_done)
	{
		reg.din_out = false;
		reg.iak_flag = false;// Interrupt controller
	}
	else
	{
		if (snap_reg.oe_set || ((snap_reg.plrt & (1 << 2)) && wire.sync_fedge))
		{
			reg.din_out = true;
		}

		if (snap_reg.plm_ena && wire.vc_vsel && (snap_reg.vsel == 017))
		{
			reg.iak_flag = true;
		}
	}

	if (wire.qbus_done)
	{
		reg.sack_out = false;
		reg.qbus_req = false;
	}
	else
	{
		if (wire.pin_dmgi)
		{
			if ((wire.qbus_nosr_rc || (snap_reg.sync_out && !snap_reg.qbus_win)) && snap_reg.qbus_req)
			{
				reg.sack_out = true;
			}
		}
		else
		{
			if (wire.dmr_out)
			{
				reg.qbus_req = true;
			}
		}
	}

	//
	// Bits 14:12 poll the interrupt controller state
	//
	if (snap_reg.pli_req)
	{
		reg.mj &= ~(1 << 14 | 1 << 13 | 1 << 12);
		reg.mj |= ((wire.pli & (1 << 5)) << (14 - 5)
		           | (wire.pli & (1 << 7)) << (13 - 7)
		           | (wire.pli & (1 << 9)) << (12 - 9)) ^ (1 << 14 | 1 << 13);
		//reg.mj[14:12] = { ~wire.pli[5], ~wire.pli[7], wire.pli[9] };
	}
	else if (snap_reg.plm1x)
	{
		register uint32_t lplr = LODWORD(snap_reg.plr);
		reg.mj &= ~(1 << 14 | 1 << 13 | 1 << 12);
		reg.mj |= ((lplr & (1 << 14)) >> (14 - 14)
		           | (lplr & (1 << 16)) >> (16 - 13)
		           | (lplr & (1 << 17)) >> (17 - 12)) ^ (1 << 14 | 1 << 12);
		//reg.mj[14:12] = { ~snap_reg.plr[14], snap_reg.plr[16], ~snap_reg.plr[17] };
	}

	//______________________________________________________________________________
	//
	// Microcode register
	//
	//
	// Least bits are produced directly from main matrix
	// and have the async reset feature (next microcode address)
	//
	if (wire.plm_stb_rc)
	{
		register uint32_t lplx = LODWORD(wire.plx);
		reg.mj &= ~(1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1);
		reg.mj |= ((lplx & (1 << 24)) >> (24 - 1) |
		           (lplx & (1 << 19)) >> (19 - 2) |
		           (lplx & (1 << 15)) >> (15 - 3) |
		           (lplx & (1 <<  9)) >> (9 - 4) |
		           (lplx & (1 <<  5)) >> (5 - 5) |
		           (lplx & (1 <<  0)) <<       6) ^ (1 << 6 | 1 << 2 | 1 << 1);
		//reg.mj[1] = ~wire.plx[24];
		//reg.mj[2] = ~wire.plx[19];
		//reg.mj[3] =  wire.plx[15];
		//reg.mj[4] =  wire.plx[9];
		//reg.mj[5] =  wire.plx[5];
		//reg.mj[6] = ~wire.plx[0];
	}
}

void C1801VM1::always_posedge_pin_clk_p_or_posedge_abort()
{
	//______________________________________________________________________________
	//
	// Microcode register
	//
	//
	// The least bit is reset by abort
	// and set by common reset
	//
	if (snap_reg.reset)
	{
		reg.mj |= (1 << 0); //если ресет то формируем начальный адрес ячейки таблицы микрокода, это код ~(01)
	}
	else if (wire.plm_stb_rc)
	{
		if (wire.plx & (1 << 29)) //а иначе - младший бит адреса следующей ячейки микрокода
		{
			reg.mj &= ~(1 << 0);
		}
		else
		{
			reg.mj |= (1 << 0);
		}
	}
}

void C1801VM1::always_posedge_pin_clk_p_or_posedge_reset()
{
	//______________________________________________________________________________
	//
	// Qbus logic
	//
	//
	// Control register at 177700
	//
	if (wire.sel_out && (snap_reg.sel_reg == 0))
	{
		reg.reg_csr = wire.pin_ad_in & 7;
	}
	else
	{
		//
		// Bit 0 of control register
		//
		if (snap_reg.ir_set && (snap_reg.reg_csr & (1 << 1)))
		{
			//не работающий функционал
			reg.reg_csr |= 1 << 0;
		}

		if (snap_reg.plm1x_hl)
		{
			register uint32_t lplr = ~LODWORD(snap_reg.plr);

			//
			// Bit 0 of control register
			//
			if (lplr & (1 << 25))
			{
				reg.reg_csr |= 1 << 0;
			}

			//
			// Bit 1 of control register (controls set of bit 0)
			//
			// ничего нет.

			//
			// Bit 2 of control register (wait state)
			//
			if (lplr & (1 << 27))
			{
				reg.reg_csr &= ~(1 << 2);
			}
			else if (lplr & (1 << 7))
			{
				reg.reg_csr |= (1 << 2);
			}
		}
	}

	//______________________________________________________________________________
	//
	// Interrupt controller
	//
	if (snap_reg.pli_req)
	{
		reg.plir0 = GETBIT(wire.pli, 4);
	}
}

void C1801VM1::always_posedge_mjres()
{
	//______________________________________________________________________________
	//
	// Control and glue logic
	//
	reg.ustb_h      = false;
	reg.alu_busy_rp = false;
	reg.alu_nrdy    = false;
	reg.ir_stb2     = false;
	reg.ir_stop     = false;
	reg.ustb        = false;
	reg.alu_busy_fp = false;
	reg.tplmz       = 0;
	//______________________________________________________________________________
	//
	// Qbus logic
	//
	reg.dmr_req     = false;
	reg.dout_req    = false;
	reg.dout_out    = false;
	reg.din_out     = false;
	reg.sack_out    = false;
	reg.qbus_req    = false;
	reg.qbus_aseq[0] = false;
	reg.qbus_aseq[1] = false;
	//______________________________________________________________________________
	//
	// Interrupt controller
	//
	reg.iak_flag    = false;
	//______________________________________________________________________________
	//
	// Microcode register
	//
	//
	// Least bits are produced directly from main matrix
	// and have the async reset feature (next microcode address)
	//
	reg.mj |= (1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1); //начальный адрес ячейки микрокода
	//
	// Bits 14:12 poll the interrupt controller state
	//
	reg.mj &= ~(1 << 14 | 1 << 13 | 1 << 12); //начальные аргументы
}

void C1801VM1::always_posedge_abort()
{
	reg.mj &= ~(1 << 0);
}

void C1801VM1::always_posedge_reset()
{
	//______________________________________________________________________________
	//
	// Qbus logic
	//
	//
	// Control register at 177700
	//
	reg.reg_csr = 0;
	//______________________________________________________________________________
	//
	// Interrupt controller
	//
	reg.plir0   = false;
	reg.gpr[14] = m_IOPins.pin_pa << 8;  // должно быть число 0..3, иначе будет некорректно
}



//______________________________________________________________________________
//
// Vector address and constant generator
//
void C1801VM1::vc_always_p()
{
	static uint16_t vctbl[16] =
	{
		0160006,    //0 // double error
		0000020,    //1 // IOT instruction
		0000010,    //2 // reserved opcode
		0000014,    //3 // T-bit/BPT trap
		0000004,    //4 // invalid opcode
		0177716,    //5 // or qbus timeout
		0000030,    //6 // EMT instruction
		0160012,    //7 // int ack timeout
		0000270,    //8 // IRQ3 falling edge
		0000024,    //9 // ACLO falling edge
		0000100,    //10// IRQ2 falling edge
		0160002,    //11// IRQ1 low level/HALT
		0000034,    //12// TRAP instruction
		0,          //13//instruction register
		0,          //14 //start @177704
		0           //15 //unused vector (iako)
	};

	switch (snap_reg.vsel)
	{
		case 5:  reg.vmux = vctbl[snap_reg.vsel] | (m_IOPins.pin_pa << 4);   // qbus timeout
			break;

		case 13: reg.vmux = snap_reg.ir;        // instruction register
			break;

		case 14: reg.vmux = snap_reg.reg_vec;   //start @177704
			break;

		default: reg.vmux = vctbl[snap_reg.vsel];                    //
	}

	//
	// Constant generator and opcode fields shifter/truncator
	//
	// On schematics csel is plr[28:25]
	//
	//    csel0 = 4b'00xx
	//    csel1 = 4b'01xx
	//    csel2 = 4b'10xx
	//    csel3 = 4b'11xx
	//    csel4 = 4b'xx00
	//    csel5 = 4b'xx01
	//    csel6 = 4b'xx10
	//    csel7 = 4b'xx11
	//
	static uint16_t cctbl[16] =
	{
		0,          //0 // csel0 && csel4 (CLx/SEx)
		0000340,    //1 // csel0 && csel5 (start PSW constant)
		0000000,    //2 // csel0 && csel6 (vector output)
		0000002,    //3 // csel0 && csel7
		0,          //4 // csel1 && csel4 (MARK/SOB)
		0177716,    //5 // csel1 && csel5
		0177777,    //6 // csel1 && csel6
		0000001,    //7 // csel1 && csel7
		0,          //8 // csel2 && csel4
		0100000,    //9 // csel2 && csel5
		0177676,    //10// csel2 && csel6
		0000020,    //11// csel2 && csel7 (MUL)
		0,          //12// csel3 && csel4 (ADC/SBC)
		0177400,    //13// csel3 && csel5 (start address AND)
		0000010,    //14// csel3 && csel6
		0000000     //15// csel3 && csel7 (vector read/vsel)
	};

	switch (snap_reg.yadr)
	{
		case 0: reg.cmux = snap_reg.ir & 0xf;           // csel0 && csel4 (CLx/SEx)
			break;

		case 4: reg.cmux = (snap_reg.ir & 077) << 1;    // csel1 && csel4 (MARK/SOB)
			break;

		case 8:
			reg.cmux = ((short)(char)(snap_reg.ir & 0377)) << 1;
			break;

		case 12: reg.cmux = snap_reg.gpr[14] & (1 << 0);    // csel3 && csel4 (ADC/SBC)
			break;

		default: reg.cmux = cctbl[snap_reg.yadr];
	}
}

#if (DBG_OUT_PLI_LOG)

void C1801VM1::OutPLILog()
{
	static int nCLK_prev = -1;
	static int nPLI_prev = 0;

	if (nCLK_prev == m_nClk)
	{
		if (nPLI_prev == wire.pli)
		{
			return; //дублирующиеся значения пропускаем.
		}
		else
		{
			nPLI_prev = wire.pli;
		}
	}
	else
	{
		nCLK_prev = m_nClk;
	}

	static int nCounti = 0;
	m_PLILog = fopen(DBG_PLI_LOG_NAME, "a");

	if (!((nCounti++) % 20))
	{
		fprintf(m_PLILog, "        ");
		fprintf(m_PLILog, "     19     18     17     16     15     14     13     12     11     10     09     08     07     06     05     04     03     02     01     00       ");
		fprintf(m_PLILog, "     10     09     08     07     06     05     04     03     02     01     00\n");
		fprintf(m_PLILog, "        ");
		fprintf(m_PLILog, " VE-Trq IRQ3rq QBV-to IRQ2rq PSW4-T IRQ1rq ACLOup WAITmd ACLOdn DblErT QBOAto VIRQrq unused unused unused PSW7-P UnkOpc  PSW11 FBO-B4  PSW10       ");
		fprintf(m_PLILog, " RqDtRe MiCR12 RqDtRe MiCR13 RqDtRe MiCR14 FB-Pri VG-Sel VG-Sel VG-Sel VG-Sel\n");
	}

	fprintf(m_PLILog, "%06d  ", m_nClk);

	for (int i = 19; i >= 0; i--)
	{
		fprintf(m_PLILog, "      %d", (reg.rq >> i) & 1);
	}

	fprintf(m_PLILog, "       ");

	for (int i = 10; i >= 0; i--)
	{
		fprintf(m_PLILog, "      %d", (wire.pli & (1 << i)) ? 1 : 0);
	}

	fprintf(m_PLILog, "\n");
	fclose(m_PLILog);
}
#endif //DBG_OUT_PLI_LOG

#if (DBG_OUT_PLM_LOG)
static char *strOptypes[8] =
{
	"nothing",
	"nothing",
	"write word",
	"write byte",
	"read word",
	"read byte",
	"read - modify - write word",
	"read - modify - write byte"
};
static char *strIROptypes[8] =
{
	("no operation"),
	("RTT opcode, wait fetch completion"),
	("non-IR data retrieving"),
	("usual IR fetch"),
	("early IR prefetch"),
	("WAIT opcode, check irq only"),
	("no operation"),
	("~RTT opcode, wait fetch completion")
};
static char *strRegName[16] =
{
	("Q"),
	("R7"),
	("R11"),
	("R3"),
	("R13"),
	("R5"),
	("R9"),
	("R1"),
	("PSW"),
	("R6"),
	("R10"),
	("R2"),
	("R12"),
	("R4"),
	("R8"),
	("R0")
};
static char *strALUFlags[16] =
{
	("0000"),
	("0001"),
	("0010"),
	("0011"),
	("0100"),
	("0101"),
	("0110"),
	("0111"),
	("1000"),
	("1001"),
	("1010"),
	("1011"),
	("1100"),
	("1101"),
	("1110"),
	("1111")
};
void C1801VM1::OutPLMLog()
{
	static int nCLK_prev = -1;
	static uint64_t nPLX_prev = 0;

	if (nCLK_prev == m_nClk)
	{
		if (nPLX_prev == wire.plx)
		{
			return; //дублирующиеся значения пропускаем.
		}
		else
		{
			nPLX_prev = wire.plx;
		}
	}
	else
	{
		nCLK_prev = m_nClk;
	}

	static int nCountm = 0;
	m_PLMLog = fopen(DBG_PLM_LOG_NAME, "a");

	if (!((nCountm++) % 20))
	{
		fprintf(m_PLMLog, "        ");
		fprintf(m_PLMLog, "                             33   32   31   30   29   28   27   26   25   24   23   22   21   20   19   18   17   16   15   14   13   12   11   10   09   08   07   06   05   04   03   02   01   00\n");
		fprintf(m_PLMLog, "        ");
		fprintf(m_PLMLog, "opcode  mjf TNZVC MCAddr    [-- X selector ---] ~mj0 [-- Y selector ---] ~mj1 NFWC           WAFR ~mj2  WO  [ALU Opc]  mj3 [ALU Opr]  UO  YbTS NWDt  mj4 [QBUS Op Type]  mj5 PLOP [--IR Reg Op-] ~mj6\n");
	}

	fprintf(m_PLMLog, "%06d  ", m_nClk);
	fprintf(m_PLMLog, "%06o  ", LOWORD(reg.ir));
	fprintf(m_PLMLog, "%d", ((reg.mj & (1 << 14)) ? 1 : 0)); //возможно и тут надо инвертировать
	fprintf(m_PLMLog, "%d", ((reg.mj & (1 << 13)) ? 1 : 0));
	fprintf(m_PLMLog, "%d ", ((reg.mj & (1 << 12)) ? 1 : 0));
	fprintf(m_PLMLog, "%d", ((reg.mj & (1 << 11)) ? 1 : 0));
	fprintf(m_PLMLog, "%d", ((reg.mj & (1 << 10)) ? 1 : 0));
	fprintf(m_PLMLog, "%d", ((reg.mj & (1 <<  9)) ? 1 : 0));
	fprintf(m_PLMLog, "%d", ((reg.mj & (1 <<  8)) ? 1 : 0));
	fprintf(m_PLMLog, "%d", ((reg.mj & (1 <<  7)) ? 1 : 0));
	fprintf(m_PLMLog, " [0x%02x]  ", (~reg.mj & 0x7f));

	for (int i = 33; i >= 0; i--)
	{
		fprintf(m_PLMLog, "    %d", wire.plx & g_QwordBitMask[i] ? 1 : 0);
	}

	int nIROp = (wire.plx >> 1) & 7; //IR register operation
	int nQBUSOp = (wire.plx >> 6) & 7;//QBUS operation type
	int nPLOp = ((wire.plx >> 20) & 6) | ((wire.plx & (1 << 4)) ? 1 : 0);    //PSW and microcode control (plop)
	//    plx[0]   ~mj[6];
	//    plx[5]    mj[5]
	//    plx[9]    mj[4]
	//    plx[12]   opcode is not recognized
	//    plx[15]   mj[3]
	//    plx[19]  ~mj[2]
	//    plx[24]  ~mj[1]
	//    plx[29]  ~mj[0]
	int nNextAddr
	    = ((wire.plx & (1 <<  0)) ? 64 : 0)  //6-
	      | ((wire.plx & (1 <<  5)) ? 0 : 32)  //5
	      | ((wire.plx & (1 <<  9)) ? 0 : 16)  //4
	      | ((wire.plx & (1 << 15)) ? 0 : 8)   //3
	      | ((wire.plx & (1 << 19)) ? 4 : 0)   //2-
	      | ((wire.plx & (1 << 24)) ? 2 : 0)   //1-
	      | ((wire.plx & (1 << 29)) ? 1 : 0);  //0-
	fprintf(m_PLMLog, " toAddr/mjf:[0x%02x][", nNextAddr);
	fprintf(m_PLMLog, "%d", ((wire.plx & (1 << 14)) ? 0 : 1));
	fprintf(m_PLMLog, "%d", ((wire.plx & (1 << 16)) ? 1 : 0));
	fprintf(m_PLMLog, "%d", ((wire.plx & (1 << 17)) ? 0 : 1));
	fprintf(m_PLMLog, "] IRop:%d QBUSop:%d PLop:%d / %s / %s", nIROp, nQBUSOp, nPLOp, strIROptypes[nIROp], strOptypes[nQBUSOp]);
	fprintf(m_PLMLog, "\n");
	fclose(m_PLMLog);
}

#endif // DBG_OUT_PLM_LOG

#if (DBG_OUT_WIRESDIFF)
//вывод списка переменных, которые различаются в предыдущей итерации и текущей.
void C1801VM1::Out_Difference(int nClk, int n, const char *str)
{
	FILE *f = fopen(DBG_WIRESDIFF_LOG_NAME, "a");
	fprintf(f, "Clk: %06d Phase: %s Wires stage: %d -------------------------\n", m_nClk, str, n);
	compareBool(f, prev_wire.pin_dclo, wire.pin_dclo, "pin_dclo");
	compareBool(f, prev_wire.pin_aclo, wire.pin_aclo, "pin_aclo");
	compareBoolArray(f, prev_wire.pin_irq, wire.pin_irq, 4, "pin_irq[4]");
	compareWord(f, prev_wire.pin_ad_in, wire.pin_ad_in, "pin_ad_in");
	compareBool(f, prev_wire.pin_sync_in, wire.pin_sync_in, "pin_sync_in");
	compareBool(f, prev_wire.pin_dmgi, wire.pin_dmgi, "pin_dmgi");
	compareBool(f, prev_wire.dma_in, wire.dma_in, "dma_in");
	compareQWord(f, prev_wire.plx, wire.plx, "plx[34]");
	compareWord(f, prev_wire.pli, wire.pli, "pli[11]");
	compareBool(f, prev_wire.exc_uop, wire.exc_uop, "exc_uop");
	compareBool(f, prev_wire.exc_oat, wire.exc_oat, "exc_oat");
	compareBool(f, prev_wire.qbus_tena, wire.qbus_tena, "qbus_tena");
	compareBool(f, prev_wire.ir_clr, wire.ir_clr, "ir_clr");
	compareBool(f, prev_wire.ir_seq_rc, wire.ir_seq_rc, "ir_seq_rc");
	compareBool(f, prev_wire.plm_stb_rc, wire.plm_stb_rc, "plm_stb_rc");
	compareBool(f, prev_wire.plm_ena_fc, wire.plm_ena_fc, "plm_ena_fc");
	compareBool(f, prev_wire.uplr_stb, wire.uplr_stb, "uplr_stb");
	compareByte(f, prev_wire.tplm_rc, wire.tplm_rc, "tplm_rc");
	compareBool(f, prev_wire.mjres_rc, wire.mjres_rc, "mjres_rc");
	compareBool(f, prev_wire.reset_rc, wire.reset_rc, "reset_rc");
	compareBool(f, prev_wire.abort_rc, wire.abort_rc, "abort_rc");
	compareBool(f, prev_wire.sel_out, wire.sel_out, "sel_out");
	compareBool(f, prev_wire.dmr_out, wire.dmr_out, "dmr_out");
	compareBool(f, prev_wire.qbus_done, wire.qbus_done, "qbus_done");
	compareBool(f, prev_wire.rply_ack_fc, wire.rply_ack_fc, "rply_ack_fc");
	compareBool(f, prev_wire.din_done, wire.din_done, "din_done");
	compareBool(f, prev_wire.dmr_req_rc, wire.dmr_req_rc, "dmr_req_rc");
	compareBool(f, prev_wire.dout_req_rc, wire.dout_req_rc, "dout_req_rc");
	compareBool(f, prev_wire.dout_start, wire.dout_start, "dout_start");
	compareBool(f, prev_wire.qbus_flag_rc, wire.qbus_flag_rc, "qbus_flag_rc");
	compareBool(f, prev_wire.sync_stb, wire.sync_stb, "sync_stb");
	compareBool(f, prev_wire.sync_fedge, wire.sync_fedge, "sync_fedge");
	compareBool(f, prev_wire.qbus_nosr_rc, wire.qbus_nosr_rc, "qbus_nosr_rc");
	compareWord(f, prev_wire.x, wire.x, "x");
	compareWord(f, prev_wire.y, wire.y, "y");
	compareByte(f, prev_wire.flag, wire.flag, "flag");
	compareBool(f, prev_wire.au_pstbx, wire.au_pstbx, "au_pstbx");
	compareBool(f, prev_wire.au_astb, wire.au_astb, "au_astb");
	compareBool(f, prev_wire.au_qstbx, wire.au_qstbx, "au_qstbx");
	compareWord(f, prev_wire.rsw, wire.rsw, "rsw");
	compareBool(f, prev_wire.tve_reset, wire.tve_reset, "tve_reset");
	compareBool(f, prev_wire.tve_tclk128, wire.tve_tclk128, "tve_tclk128");
	compareBool(f, prev_wire.pin_spclk, wire.pin_spclk, "pin_spclk");
	compareBool(f, prev_wire.tve_zero, wire.tve_zero, "tve_zero");
	compareBool(f, prev_wire.tve_back, wire.tve_back, "tve_back");
	fprintf(f, "\n");
	fclose(f);
}
void C1801VM1::compareBool(FILE *f, bool bOrig, bool bTest, const char *str)
{
	if (bOrig != bTest)
	{
		fprintf(f, "%s\n  Prev: %d\n  Curr: %d\n", str, bOrig, bTest);
	}
}
void C1801VM1::compareByte(FILE *f, uint8_t bOrig, uint8_t bTest, const char *str)
{
	if (bOrig != bTest)
	{
		fprintf(f, "%s\n  Prev: %03o\n  Curr: %03o\n", str, bOrig, bTest);
	}
}
void C1801VM1::compareWord(FILE *f, uint16_t bOrig, uint16_t bTest, const char *str)
{
	if (bOrig != bTest)
	{
		fprintf(f, "%s\n  Prev: %06o\n  Curr: %06o\n", str, bOrig, bTest);
	}
}
void C1801VM1::compareDWord(FILE *f, uint32_t bOrig, uint32_t bTest, const char *str)
{
	if (bOrig != bTest)
	{
		fprintf(f, "%s\n  Prev: %08x\n  Curr: %08x\n", str, bOrig, bTest);
	}
}
void C1801VM1::compareQWord(FILE *f, uint64_t bOrig, uint64_t bTest, const char *str)
{
	if (bOrig != bTest)
	{
		fprintf(f, "%s\n  Prev: %016llx\n  Curr: %016llx\n", str, bOrig, bTest);
	}
}
void C1801VM1::compareBoolArray(FILE *f, bool *pOrig, bool *pTest, int nLen, const char *str)
{
	bool bComp = false;

	for (int i = 0; i < nLen; ++i)
	{
		if (pOrig[i] != pTest[i])
		{
			bComp = true;
			break;
		}
	}

	if (bComp)
	{
		fprintf(f, "%s\n  Prev: ", str);

		for (int i = nLen - 1; i >= 0; i--)
		{
			fprintf(f, "%d", (pOrig[i] ? 1 : 0));
		}

		fprintf(f, "\n  Curr: ");

		for (int i = nLen - 1; i >= 0; i--)
		{
			fprintf(f, "%d", (pTest[i] ? 1 : 0));
		}

		fprintf(f, "\n");
	}
}

#endif // DBG_OUT_WIRESDIFF

const uint16_t g_WordBitMask[16] =
{
	1 << 0,
	  1 << 1,
	  1 << 2,
	  1 << 3,
	  1 << 4,
	  1 << 5,
	  1 << 6,
	  1 << 7,
	  1 << 8,
	  1 << 9,
	  1 << 10,
	  1 << 11,
	  1 << 12,
	  1 << 13,
	  1 << 14,
	  1 << 15
};

const uint32_t g_DwordBitMask[32] =
{
	1 << 0,
	  1 << 1,
	  1 << 2,
	  1 << 3,
	  1 << 4,
	  1 << 5,
	  1 << 6,
	  1 << 7,
	  1 << 8,
	  1 << 9,
	  1 << 10,
	  1 << 11,
	  1 << 12,
	  1 << 13,
	  1 << 14,
	  1 << 15,
	  1 << 16,
	  1 << 17,
	  1 << 18,
	  1 << 19,
	  1 << 20,
	  1 << 21,
	  1 << 22,
	  1 << 23,
	  1 << 24,
	  1 << 25,
	  1 << 26,
	  1 << 27,
	  1 << 28,
	  1 << 29,
	  1 << 30,
	  1 << 31
};


const uint64_t g_QwordBitMask[64] =
{
	1i64 << 0,
	     1i64 << 1,
	     1i64 << 2,
	     1i64 << 3,
	     1i64 << 4,
	     1i64 << 5,
	     1i64 << 6,
	     1i64 << 7,
	     1i64 << 8,
	     1i64 << 9,
	     1i64 << 10,
	     1i64 << 11,
	     1i64 << 12,
	     1i64 << 13,
	     1i64 << 14,
	     1i64 << 15,
	     1i64 << 16,
	     1i64 << 17,
	     1i64 << 18,
	     1i64 << 19,
	     1i64 << 20,
	     1i64 << 21,
	     1i64 << 22,
	     1i64 << 23,
	     1i64 << 24,
	     1i64 << 25,
	     1i64 << 26,
	     1i64 << 27,
	     1i64 << 28,
	     1i64 << 29,
	     1i64 << 30,
	     1i64 << 31,
	     1i64 << 32,
	     1i64 << 33,
	     1i64 << 34,
	     1i64 << 35,
	     1i64 << 36,
	     1i64 << 37,
	     1i64 << 38,
	     1i64 << 39,
	     1i64 << 40,
	     1i64 << 41,
	     1i64 << 42,
	     1i64 << 43,
	     1i64 << 44,
	     1i64 << 45,
	     1i64 << 46,
	     1i64 << 47,
	     1i64 << 48,
	     1i64 << 49,
	     1i64 << 50,
	     1i64 << 51,
	     1i64 << 52,
	     1i64 << 53,
	     1i64 << 54,
	     1i64 << 55,
	     1i64 << 56,
	     1i64 << 57,
	     1i64 << 58,
	     1i64 << 59,
	     1i64 << 60,
	     1i64 << 61,
	     1i64 << 62,
	     1i64 << 63
};

