// ###########################################################################
// #
// # OSCAMathsAssist - Implementation of OSCA Maths Assist Unit
// # Copyright (C) 2009-2011 Tony Friery [DialTone]
// #
// # ALL RIGHTS RESERVED
// #
// ###########################################################################

#pragma hdrstop

#include "OSCAMathsAssist.h"
#include "FormDiag.h"

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

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION:	TOSCAMathsAssist::UpdateMathsResult
//
//  PURPOSE:	Internal function to force calculcation of the
//					multiplier output result
//
//  INPUTS:		void
//
//  OUTPUT:		void
//
///////////////////////////////////////////////////////////////////////
void __fastcall TOSCAMathsAssist::UpdateMathsResult(void)
{
	// Calculate the new result, masking/shifting as appropriate
	int result = (this->fMultValue) * this->fMathsEntries[this->fMultIndex];
	this->fMultResult = (short)((result & 0x3fffc000) >> 14);
}

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION:	TOSCAMathsAssist::WriteMathsTable
//
//  PURPOSE:	Update one (half) of the tabled values
//
//  INPUTS:		word					Address offset in the table to write
//					byte					Value to be written into the table
//
//  OUTPUT:		void
//
///////////////////////////////////////////////////////////////////////
void __fastcall TOSCAMathsAssist::WriteMathsTable(word Address, byte Value)
{
	// Store value differently depending whether it's an odd or
	// even register value
	if (Address & 0x1)
	{
		// Odd value - MSB
		this->fMathsEntries[(Address & 0x1fe) >> 1] &= 0xff;
		this->fMathsEntries[(Address & 0x1fe) >> 1] |= (Value << 8);
	}
	else
	{
		// Even value - LSB
		this->fMathsEntries[(Address & 0x1fe) >> 1] &= 0xff00;
		this->fMathsEntries[(Address & 0x1fe) >> 1] |= Value;
	}

	if ((DiagForm) && (DiagForm->IsActive(DIAG_MATHS)))
	{
		DiagForm->AddMessage(DIAG_MATHS, UnicodeString::Format(
			L"Table Entry %d set to 0x%04x",
			OPENARRAY(TVarRec, ((Address & 0x1fe) >> 1,
			this->fMathsEntries[(Address & 0x1fe) >> 1]))
		));
	}
}

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION:	TOSCAMathsAssist::WriteMathsIndex
//
//  PURPOSE:	Write the index selecting which of the tabled entries
//					are to be used in the maths calculation
//
//  INPUTS:		byte					Index number of the table entry to use
//
//  OUTPUT:		void
//
///////////////////////////////////////////////////////////////////////
void __fastcall TOSCAMathsAssist::WriteMathsIndex(byte Value)
{
	// Store new multiplier index
	this->fMultIndex = Value;

	if ((DiagForm) && (DiagForm->IsActive(DIAG_MATHS)))
	{
		DiagForm->AddMessage(DIAG_MATHS, UnicodeString::Format(
			L"Table Index 0x%02x selected",
			OPENARRAY(TVarRec, (Value))
		));
	}
}

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION:	TOSCAMathsAssist::WriteMathsValueMSB
//
//  PURPOSE:	Write the upper 8 bits of the value to be multiplied
//					with the tabled entry
//
//  INPUTS:		byte					Upper 8 bits of the multiplicand
//
//  OUTPUT:		void
//
///////////////////////////////////////////////////////////////////////
void __fastcall TOSCAMathsAssist::WriteMathsValueMSB(byte Value)
{
	this->fMultValue &= 0xff;				// Mask out MSB (preserve LSB)
	this->fMultValue |= (Value << 8);	// combine new MSB

	if ((DiagForm) && (DiagForm->IsActive(DIAG_MATHS)))
	{
		DiagForm->AddMessage(DIAG_MATHS, UnicodeString::Format(
			L"Multiplier Value set to: 0x%04x",
			OPENARRAY(TVarRec, (this->fMultValue))
		));
	}
}

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION:	TOSCAMathsAssist::WriteMathsValueLSB
//
//  PURPOSE:	Write the lower 8 bits of the value to be multiplied
//					with the tabled entry
//
//  INPUTS:		byte					Lower 8 bits of the multiplicand
//
//  OUTPUT:		void
//
///////////////////////////////////////////////////////////////////////
void __fastcall TOSCAMathsAssist::WriteMathsValueLSB(byte Value)
{
	this->fMultValue &= 0xff00;		// Mask out LSB (preserve MSB)
	this->fMultValue |= Value;			// combine new LSB

	if ((DiagForm) && (DiagForm->IsActive(DIAG_MATHS)))
	{
		DiagForm->AddMessage(DIAG_MATHS, UnicodeString::Format(
			L"Multiplier Value set to: 0x%04x",
			OPENARRAY(TVarRec, (this->fMultValue))
		));
	}
}

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION:	TOSCAMathsAssist::GetMathsResultLSB
//
//  PURPOSE:	Retrieve the lower 8 bits of the resulting
//					maths operation
//
//  INPUTS:		void
//
//  OUTPUT:		byte					Lower 8 bits of the maths result
//
///////////////////////////////////////////////////////////////////////
byte __fastcall TOSCAMathsAssist::GetMathsResultLSB(void)
{
	// Force an update of the result first
	this->UpdateMathsResult();

	if ((DiagForm) && (DiagForm->IsActive(DIAG_MATHS)))
	{
		DiagForm->AddMessage(DIAG_MATHS, UnicodeString::Format(
			L"Maths Result LSB: 0x%02x",
			OPENARRAY(TVarRec, (this->fMultResult & 0xff))
		));
	}

	// Return LSB of result
	return (this->fMultResult & 0xff);
}

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION:	TOSCAMathsAssist::GetMathsResultMSB
//
//  PURPOSE:	Retrieve the upper 8 bits of the resulting
//					maths operation
//
//  INPUTS:		void
//
//  OUTPUT:		byte					Upper 8 bits of the maths result
//
///////////////////////////////////////////////////////////////////////
byte __fastcall TOSCAMathsAssist::GetMathsResultMSB(void)
{
	// Force an update of the result first
	this->UpdateMathsResult();

	if ((DiagForm) && (DiagForm->IsActive(DIAG_MATHS)))
	{
		DiagForm->AddMessage(DIAG_MATHS, UnicodeString::Format(
			L"Maths Result MSB: 0x%02x",
			OPENARRAY(TVarRec, ((this->fMultResult & 0xff00) >> 8))
		));
	}

	// Return MSB of the result
	return (this->fMultResult & 0xff00) >> 8;
}

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION:	TOSCAMathsAssist::Reset
//
//  PURPOSE:	Perform Power-On-Reset of the Maths Assist Unit
//
//  INPUTS:		void
//
//  OUTPUT:		void
//
///////////////////////////////////////////////////////////////////////
void __fastcall TOSCAMathsAssist::Reset(void)
{
	// Clear all entries in the table
	for (int i = 0; i < 256; i++)
	{
		this->fMathsEntries[i] = 0;
	}

	// Reset table index, source value and result
	this->fMultIndex	= 0;
	this->fMultValue	= 0;
	this->fMultResult	= 0;
}

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION:	TOSCAMathsAssist::TOSCAMathsAssist [CONSTRUCTOR]
//
//  PURPOSE:	Constructor for the Maths Assist Unit Class
//
//  INPUTS:		none
//
//  OUTPUT:		none
//
///////////////////////////////////////////////////////////////////////
__fastcall TOSCAMathsAssist::TOSCAMathsAssist()
{
	// Perform initial Power-On Reset
	this->Reset();
}

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

#pragma package(smart_init)

