/****************************************************************************
 *  PAR - PARITY GENERATION AND TEST subsystem
 *
 *  AUTHOR:     John Pultorak
 *  DATE:       9/22/01
 *  FILE:       PAR.cpp
 *
 *  NOTES: see header file.
 *    
 *****************************************************************************
 */
#include "PAR.h"
#include "SEQ.h"
#include "BUS.h"
#include "MBF.h"

regP PAR::register_P;
regP2 PAR::register_P2;
regG15 PAR::register_G15; // memory buffer register bit 15
regPALM PAR::register_PALM; // PARITY ALARM FF

unsigned PAR::conv_WP[] =
{	
	BX, SG, B14, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2, B1 
};


	// NOTE: WP clears register_P before writing into it. Strictly speaking, WPx isn't
	// supposed to clear the register (should OR into the register), but in the counter
	// sequences where WPx is used, register_P is always cleared in the previous TP by
	// asserting WP with default zeroes on the write bus.


void PAR::execWP_WP()
{
			// set all bits except parity bit
		register_P.writeShift(BUS::glbl_WRITE_BUS, PAR::conv_WP);
			// now set parity bit; in the actual AGC, this is
			// a single operation.
		if(SEQ::isAsserted(RG))
			register_P.writeField(16, 16, register_G15.read());
		else
			register_P.writeField(16, 16, 0); // clear parity bit
}

void PAR::execWP_WPx()
{
			// set all bits except parity bit
		register_P.writeShift(BUS::glbl_WRITE_BUS, PAR::conv_WP);
			// now set parity bit; in the actual AGC, this is
			// a single operation.
		if(SEQ::isAsserted(RG))
			register_P.writeField(16, 16, register_G15.read());
		else
			register_P.writeField(16, 16, 0); // clear parity bit
}


void PAR::execWP_WP2()
{
	register_P2.write(gen1_15Parity(register_P.read()));
}

void PAR::execWP_RP2()
{
	register_G15.write(register_P2.read());
}

void PAR::execWP_GP()
{
	register_G15.write(gen1_15Parity(register_P.read()));
}

void PAR::execWP_SBWG()
{
	register_G15.write((MBF::readMemory() & 0100000) >> 15); // load bit 16 (parity) into G15
}

void PAR::execWP_WGx()
{
		// This is only used in PINC, MINC, and SHINC. Does not clear G
		// register; writes (ORs) into G from RWBus and writes into parity
		// from 1-15 generator. All done in one operation, although I show
		// it in two steps here. The sequence calls CLG in a previous TP.
	register_G15.write(PAR::gen1_15Parity(register_P.read()));
}

void PAR::execWP_CLG()
{
	register_G15.write(0);
}

void PAR::execWP_GENRST()
{
	register_PALM.write(0);
}

void PAR::execWP_TP()
{
	if(genP_15Parity(register_P.read())) // && S Register > 027 ****************************
        register_PALM.write(1);
}

void PAR::CLR_PALM()
{
	    // asynchronous clear for PARITY ALARM (from MON)
	register_PALM.write(0);
}


unsigned PAR::gen1_15Parity(unsigned r)
{
	//check the lower 15 bits of 'r' and return the odd parity;
	//bit 16 is ignored.
	unsigned evenParity =
		(1&(r>>0))  ^ (1&(r>>1))  ^ (1&(r>>2))  ^ (1&(r>>3))  ^
		(1&(r>>4))  ^ (1&(r>>5))  ^ (1&(r>>6))  ^ (1&(r>>7))  ^
		(1&(r>>8))  ^ (1&(r>>9))  ^ (1&(r>>10)) ^ (1&(r>>11)) ^
		(1&(r>>12)) ^ (1&(r>>13)) ^ (1&(r>>14));
	return ~evenParity & 1; // odd parity
}

unsigned PAR::genP_15Parity(unsigned r)
{
	//check all 16 bits of 'r' and return the odd parity
	unsigned evenParity =
		(1&(r>>0))  ^ (1&(r>>1))  ^ (1&(r>>2))  ^ (1&(r>>3))  ^
		(1&(r>>4))  ^ (1&(r>>5))  ^ (1&(r>>6))  ^ (1&(r>>7))  ^
		(1&(r>>8))  ^ (1&(r>>9))  ^ (1&(r>>10)) ^ (1&(r>>11)) ^
		(1&(r>>12)) ^ (1&(r>>13)) ^ (1&(r>>14)) ^ (1&(r>>15));
	return ~evenParity & 1; // odd parity
}

