#include <signal.h>
#include "ObjProDSP/portable.h"
#include "ObjProComGui/usercom.h"
#include "ObjProArith/hrdarth.h"
#include "ObjProArithGen/arthfnc.h"
#include "ObjProArith/hrdcmp.h"
#include "ObjProComGui/cgidbg.h"
#include "ObjProArithGen/artherr.h"
#include "ObjProDSPint/netlnk.h"
#include "ObjProNet/dfnode.h"

#include "ObjProUsr/trunc.h"
#include "ObjProGen/outtok.h"
#include "ObjProGui/intfc.h"
#include "ObjProGui/remmen.h"
#include "ObjProGui/user.h"
#include "ObjProGui/dynmnu.h"
#include "ObjProArith/typout.h"
#include "ObjProGui/array.h"
#include "ObjProGui/interinit.h"
#include "ObjProGen/stattyp.h"
static EntityList * TruncateNodeList = 0 ;
static InteractiveEntity * IntEntTruncate ;
void TruncateNodesInit();
Truncate::Truncate (const char * Name, int16 Range, int16 Accuracy, int16 OverflowMode, 
		int16 Round):
	ProcessNodeStr(Name, 1, 1, 
	 new StreamStr(SizeVariable , SizeVariable , ArithType::ArithCapabilityAny), new StreamStr(StreamNotSet), 0, 1, 1, 0, 0, TimingTypeLinear)
,
	Range_1(Range),
	Accuracy_2(Accuracy),
	OverflowMode_3(OverflowMode),
	Round_4(Round)
{
	if (!TruncateNodeList) TruncateNodesInit() ;
	TruncateNodeList->Append(MakeDeclaredEntity(this, IntEntTruncate)) ;
	InitArithType(TheArithType);
	NewMenuItem("Truncate",GetName());
#line 100 "../trunc.usr"
 
	parameter_changed();
#line 43 "../trunc.cxx"
} // end constructor

ErrCode Truncate::EmitStaticCtorParameters(OutTokens& Out)
{
	ostream& Outs = *(Out.GetStream());
	Outs << ",\n\tTruncateStaticInitbinary_read_flag_" << GetName() << "";
	return OK;
}

ErrCode Truncate::EmitStaticInit(OutTokens& Out)
{
	ostream& Outs = *(Out.GetStream());
	Outs << "static int TruncateStaticInitbinary_read_flag_" << GetName() << " = ";	
	OutStringStaticValue(Outs,"int", &(binary_read_flag)) ;

	Outs << ";\n";
	return OK;
}

Truncate::~Truncate()
{
	TheMenuServer->DeleteMenuItem("Truncate",GetName());
	TruncateNodeList->Delete(GetName()) ;
} // end destructor

int Truncate::CheckSafeDelete()
{
	int Safe_Check_Return = UserEntity::CheckSafeDelete();
	if (!Safe_Check_Return) return 0;
	return 1;
} // end check safe delete

Truncate * TruncateDef;

ErrCode Truncate::DoNode(int32 k)
{
#line 124 "../trunc.usr"
 
	for (int32 i = 0 ; i < k ; i++ ) 
		for (int32 b = 0; b< GetBlockSize(); b++)
			for (int32 l = 0 ; l < GetEltSize(); l++) {
				MachWord temp ;
				if (binary_read_flag) temp =
					(IntegerMachWord) ReadInteger();
				else temp = ReadWord();
				int over_flow = 0 ;
				int sign = (MachWordCast) temp >= 0  ;
				MachWord abs_temp = (sign ? temp : -temp) + round_offset ;
				if ((MachWordCast) abs_temp > over_max) over_flow = 1 ;
				if (!over_flow ||
				  (GetOverflowMode() && (MachWordCast) abs_temp <= int_over_max)) {
					int32 val = (int32) (MachWordCast) abs_temp ;
					val = val & mask ;
					if (sign) WriteWord(val);
					else WriteWord(-val);
					continue ;
				}
				if (sign) WriteWord(over_max);
				else WriteWord(over_min);
				
			}
	return OK ;
#line 106 "../trunc.cxx"
} // end kernel code

static UserEntity * MakeTruncate(OutTokens& Out, EntityReq Request,
	InteractiveEntity& IntNode,
	ArithType::ArithCapabilities arith = (ArithType::ArithCapabilities) TheArithType) ;
int Truncate::CppList(OutTokens& Out, CppListCmds Cmd)
{
	return IntEntTruncate->CppList(Out,Cmd,this);
}

void Truncate::Describe(OutTokens& Out, ListEntity Option)
{
	switch(Option) {
case ListSingleEntity:
		Out.NewLine();
		MakeTruncate(Out,EntityReqDescribeFull,*IntEntTruncate, (ArithType::ArithCapabilities) TheArithType);
		Out.NewLine();
		Out.NextQuoteOut("Range");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetRange()));
		Out.NextFillOut(")");
		Out.NextFillOut("is the number of bits in the dynamic range of the output");
		Out.NextFillOut("(not counting the sign bit).");
		Out.NextQuoteOut("Accuracy");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetAccuracy()));
		Out.NextFillOut(")");
		Out.NextFillOut("is the number of significant bits retained in the output");
		Out.NextFillOut("(not counting the sign bit).");
		Out.NextQuoteOut("Accuracy");
		Out.NextFillOut("will always be <=");
		Out.NextQuoteOut("Range");
		Out.NextFillOutConcat(".");
		Out.NextFillOut("If you specify more accuracy then range accuracy will equal range.");
		Out.NextQuoteOut("OverflowMode");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetOverflowMode()));
		Out.NextFillOut(")");
		Out.NextFillOut("selects saturation (0) or truncation (1) mode.");
		Out.NextFillOut("In saturation mode an overflow is replaced by the largest positive");
		Out.NextFillOut("or negative number representable depending on the sign of the input");
		Out.NextFillOut("value. In Truncation mode the high order bits are truncated as if");
		Out.NextFillOut("the number was in sign magnitude form.");
		Out.NextQuoteOut("Round");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetRound()));
		Out.NextFillOut(")");
		Out.NextFillOut("if set rounds the result. Otherwise it is");
		Out.NextFillOut("truncated. Truncation is always towards 0 and not two's compliment");
		Out.NextFillOut("truncation.");
		Out.NewLine();
		break;
case ListEntityMembers:
		Out.NextOut(GetName());
		break;
case ListGlobalClasses:
case ListEntityClasses:
		break ;
case ListSetParameterValues:
		IntEntTruncate->GetOneParameter("Range")->
			IntP->CurrentValue = Range_1;
		IntEntTruncate->GetOneParameter("Accuracy")->
			IntP->CurrentValue = Accuracy_2;
		IntEntTruncate->GetOneParameter("OverflowMode")->
			IntP->CurrentValue = OverflowMode_3;
		IntEntTruncate->GetOneParameter("Round")->
			IntP->CurrentValue = Round_4;
		break;
	}
} // end  list entity switch

static ValueType * SetRange(OutTokens&,EntityReq Request,
		UserParameters * Param,UserEntity *This) 
{
	switch (Request) {
case EntityReqDescribe:
	break ;
case EntityReqDescribeFull:
	break ;
case EntityReqCall:
		{		// Call procedure
				int16 Range =
			Param->GetIntParameterValue("Range");
		((Truncate *) This)->SetRange(Range);
		return 0 ;
	}
	}
	return 0;
}

static ValueType * SetAccuracy(OutTokens&,EntityReq Request,
		UserParameters * Param,UserEntity *This) 
{
	switch (Request) {
case EntityReqDescribe:
	break ;
case EntityReqDescribeFull:
	break ;
case EntityReqCall:
		{		// Call procedure
				int16 Accuracy =
			Param->GetIntParameterValue("Accuracy");
		((Truncate *) This)->SetAccuracy(Accuracy);
		return 0 ;
	}
	}
	return 0;
}

static ValueType * SetOverflowMode(OutTokens&,EntityReq Request,
		UserParameters * Param,UserEntity *This) 
{
	switch (Request) {
case EntityReqDescribe:
	break ;
case EntityReqDescribeFull:
	break ;
case EntityReqCall:
		{		// Call procedure
				int16 OverflowMode =
			Param->GetIntParameterValue("OverflowMode");
		((Truncate *) This)->SetOverflowMode(OverflowMode);
		return 0 ;
	}
	}
	return 0;
}

static ValueType * SetRound(OutTokens&,EntityReq Request,
		UserParameters * Param,UserEntity *This) 
{
	switch (Request) {
case EntityReqDescribe:
	break ;
case EntityReqDescribeFull:
	break ;
case EntityReqCall:
		{		// Call procedure
				int16 Round =
			Param->GetIntParameterValue("Round");
		((Truncate *) This)->SetRound(Round);
		return 0 ;
	}
	}
	return 0;
}

void TruncateNodesInit()
{
	if (TruncateNodeList)  return ;

	static StringParam TruncateNameParam =
		{"Truncate", MakeNewEntityName, 0, LegalEntityName};
	static IntParam TruncateRangeParam = {
		 31, 0,  0,  1,  0,  31};
	static IntParam TruncateAccuracyParam = {
		 31, 0,  0,  1,  0,  31};
	static IntParam TruncateOverflowModeParam = {
		 0, 0,  0,  0,  0,  1};
	static IntParam TruncateRoundParam = {
		 0, 0,  0,  0,  0,  1};

	static OneParameter TruncateParArray[] = {
		{"Name", 0, "node name", 0, 0, &TruncateNameParam},
		{"Range", 0, 
			"Bits for dynamic range",
			&TruncateRangeParam},
		{"Accuracy", 0, 
			"Significant bits retained in output",
			&TruncateAccuracyParam},
		{"OverflowMode", 0, 
			"For overflows: 0 - saturate, 1 - truncate",
			&TruncateOverflowModeParam},
		{"Round", 0, 
			"Flag indicates rounding (1) or truncation (0)",
			&TruncateRoundParam},
		{0}
	};

	static OneParameter SetRangeTruncateList[] = {
		{"Range", 0, "Bits for dynamic range",
			 &TruncateRangeParam},
			{0}
	};
	UserParameters * SetRangeMemberParam = new UserParameters
		(SetRangeTruncateList);

	Procedure * SetMemberProcRange = new Procedure("SetRange", SetRange,
		 SetRangeMemberParam, "void");
	static OneParameter SetAccuracyTruncateList[] = {
		{"Accuracy", 0, "Significant bits retained in output",
			 &TruncateAccuracyParam},
			{0}
	};
	UserParameters * SetAccuracyMemberParam = new UserParameters
		(SetAccuracyTruncateList);

	Procedure * SetMemberProcAccuracy = new Procedure("SetAccuracy", SetAccuracy,
		 SetAccuracyMemberParam, "void");
	static OneParameter SetOverflowModeTruncateList[] = {
		{"OverflowMode", 0, "For overflows: 0 - saturate, 1 - truncate",
			 &TruncateOverflowModeParam},
			{0}
	};
	UserParameters * SetOverflowModeMemberParam = new UserParameters
		(SetOverflowModeTruncateList);

	Procedure * SetMemberProcOverflowMode = new Procedure("SetOverflowMode", SetOverflowMode,
		 SetOverflowModeMemberParam, "void");
	static OneParameter SetRoundTruncateList[] = {
		{"Round", 0, "Flag indicates rounding (1) or truncation (0)",
			 &TruncateRoundParam},
			{0}
	};
	UserParameters * SetRoundMemberParam = new UserParameters
		(SetRoundTruncateList);

	Procedure * SetMemberProcRound = new Procedure("SetRound", SetRound,
		 SetRoundMemberParam, "void");
static ValueType * TruncateMembers[5] ;
	int ii = 0 ;
	TruncateMembers[ii++] = new ValueType(DecProcedure, SetMemberProcRange) ;
	TruncateMembers[ii++] = new ValueType(DecProcedure, SetMemberProcAccuracy) ;
	TruncateMembers[ii++] = new ValueType(DecProcedure, SetMemberProcOverflowMode) ;
	TruncateMembers[ii++] = new ValueType(DecProcedure, SetMemberProcRound) ;
	TruncateMembers[ii++] = 0 ;
	TruncateNodeList = new EntityList;
	IntEntTruncate = new InteractiveEntity("Truncate", TruncateNodeList,
		MakeTruncate, InteractiveNode, "trunc.h",
		TruncateMembers, "ProcessNodeStr");
	IntEntTruncate->SetParameters(new UserParameters(TruncateParArray));
	TheNodes->Append(IntEntTruncate);
} // end initalization

static UserEntity * MakeTruncate(OutTokens& Out, EntityReq Request,
	InteractiveEntity& IntNode,
	ArithType::ArithCapabilities arith)
{
	switch(Request) {
case EntityReqDescribe:

case EntityReqDescribeFull:
		Out.NextQuoteOut("Truncate");
		Out.NextFillOut("converts the MachWord input data to a 32 bit integer");
		Out.NextFillOut("(after checking for overflow). On the floating point simulator");
		Out.NextFillOut("the input can also be 32 bit integers.");
		Out.NextFillOut("The dynamic range is then");
		Out.NextFillOut("restricted to");
		Out.NextQuoteOut("Range");
		Out.NextFillOutConcat(". The number of significant bits");
		Out.NextFillOut("is restricted to");
		Out.NextQuoteOut("Accuracy");
		Out.NextFillOutConcat(". Neither");
		Out.NextQuoteOut("Range");
		Out.NextFillOut("nor");
		Out.NextQuoteOut("Accuracy");
		Out.NextFillOut("include");
		Out.NextFillOut("the sign bit. Although integers are represented is twos compliment format");
		Out.NextFillOut("truncation can be thought of as working on signed magnitude data.");
		Out.NextFillOut("Overflow will saturate if");
		Out.NextQuoteOut("OverflowMode");
		Out.NextFillOut("is 0 and cause the high order bits to be ignored if");
		Out.NextQuoteOut("OverflowMode");
		Out.NextFillOut("is 1.");
		Out.NextFillOut("The output is converted back to MachWord format.");
		Out.NewLine();
		break;

case EntityReqCreate:
	{
		const char * Name = IntNode.GetStringParameterValue("Name");
		int16 Range =
			IntNode.GetIntParameterValue("Range");
		int16 Accuracy =
			IntNode.GetIntParameterValue("Accuracy");
		int16 OverflowMode =
			IntNode.GetIntParameterValue("OverflowMode");
		int16 Round =
			IntNode.GetIntParameterValue("Round");
		return new Truncate(Name, Range, Accuracy, OverflowMode, Round);

	}
	}
	return 0;
}

static InitObj LocalInit(TruncateNodesInit, "Truncate", "ProcessNodeStr");

