Example #1
0
   FPge_expr::FPge_expr(Target* _target, int wE, int wF) :
         Operator(_target) {

      ostringstream name;

      name<<"FPge_expr_" <<wE<<"_"<<wF;
      setName(name.str());

      setCopyrightString("Fabrizio Ferrandi (2011-2017)");

      /* Set up the IO signals */

      addFPInput ("X", wE,wF);
      addFPInput ("Y", wE,wF);
      addOutput ("R", 1);

      /*	VHDL code description	*/
      manageCriticalPath(_target->localWireDelay() + _target->lutDelay());
      vhdl << tab << declare("nY",wE+wF+3) << "  <= Y"<< range(wE+wF+2,wE+wF+1) << " & not(Y"<< of(wE+wF) << ") & Y" << range(wE+wF-1,0) << ";" << endl;
      FPAdderSinglePath * value_difference = new FPAdderSinglePath(_target, wE, wF, wE, wF, wE, wF);
      value_difference->changeName(getName()+"value_difference");
      oplist.push_back(value_difference);
      inPortMap  (value_difference, "X", "X");
      inPortMap  (value_difference, "Y", "nY");
      outPortMap (value_difference, "R","valueDiff");
      vhdl << instance(value_difference, "value_difference");
      syncCycleFromSignal("valueDiff");
      setCriticalPath(value_difference->getOutputDelay("R"));

      manageCriticalPath(_target->localWireDelay() + _target->lutDelay());
      vhdl << tab << "R(0) <=   '1' when (valueDiff" << of(wE+wF) << "='0' or (valueDiff" << range(wE+wF+2,wE+wF+1) << " = \"00\")) else '0';" << endl;
   }
Example #2
0
	FPSumOf3Squares::FPSumOf3Squares(Target* target, int wE, int wF, int optimize)
		: Operator(target), wE(wE), wF(wF)
	{
		setCopyrightString("F. de Dinechin, Bogdan Pasca (2011)");
		srcFileName="FPSumOf3Squares";
		ostringstream o;
		o << "FPSumOf3Squares_" << wE << "_" << wF;
		if(!optimize)
			o << "_FP";
		setName(o.str());

		addFPInput("X", wE, wF);
		addFPInput("Y", wE, wF);
		addFPInput("Z", wE, wF);
		addFPOutput("R", wE, wF, 2); // This 2 means: we will allow two possible inputs (faithful rounding)

		if(!optimize) {
			//////////////////////////////////////////////////////////////////:
			//            A version that assembles FP operators             //
			//////////////////////////////////////////////////////////////////:

			FPMult* mult = new FPMult(target, wE, wF, wE, wF, wE, wF, 1);
			oplist.push_back(mult);
			FPAddSinglePath* add =  new FPAddSinglePath(target, wE, wF, wE, wF, wE, wF);
			oplist.push_back(add);
		
			inPortMap (mult, "X", "X");
			inPortMap (mult, "Y", "X");
			outPortMap(mult, "R", "X2");
			vhdl << instance(mult, "multx");
		
			inPortMap (mult, "X", "Y");
			inPortMap (mult, "Y", "Y");
			outPortMap(mult, "R", "Y2");
			vhdl << instance(mult, "multy");
		
			inPortMap (mult, "X", "Z");
			inPortMap (mult, "Y", "Z");
			outPortMap(mult, "R", "Z2");
			vhdl << instance(mult, "multz");
		
			syncCycleFromSignal("Z2", false);
			nextCycle(); 
		
			inPortMap (add, "X", "X2");
			inPortMap (add, "Y", "Y2");
			outPortMap(add, "R", "X2PY2");
			vhdl << instance(add, "add1");
		
			syncCycleFromSignal("X2PY2", false);
			nextCycle(); 
		
			inPortMap (add, "X", "X2PY2");
			inPortMap (add, "Y", "Z2");
			outPortMap(add, "R", "X2PY2PZ2");
			vhdl << instance(add, "add2");
		
			syncCycleFromSignal("X2PY2PZ2", false);
			setCriticalPath(add->getOutputDelay("R"));
			vhdl << tab << "R <= X2PY2PZ2;"<<endl;
			outDelayMap["R"]=getCriticalPath();
		}
		else { ////////////////// here comes the FloPoCo version	//////////////////////////:
			// Error analysis
			// 3 ulps(wF+g) in the multiplier truncation
			// Again 2 ulps(wF+g) in the shifter output truncation
			// Normalisation truncation: either 0 (total 5), or 1 ulp(wF+g) but dividing the previous by 2 (total 3.5)
			// Total max 5 ulps, we're safe with 3 guard bits

			// guard bits for a faithful result
			int g=3; 

			// The exponent datapath

			// setCriticalPath( getMaxInputDelays(inputDelays) + target->localWireDelay());
			setCriticalPath(0);

			manageCriticalPath(  target->adderDelay(wE+1) // subtractions 
													 + target->localWireDelay(wE) // fanout of XltY etc
													 + target->lutDelay()         // & and mux
													 );

			//---------------------------------------------------------------------
			// extract the three biased exponents. 
			vhdl << tab << declare("EX", wE) << " <=  X" << range(wE+wF-1, wF) << ";" << endl;
			vhdl << tab << declare("EY", wE) << " <=  Y" << range(wE+wF-1, wF) << ";" << endl;
			vhdl << tab << declare("EZ", wE) << " <=  Z" << range(wE+wF-1, wF) << ";" << endl;
		
			// determine the max of the exponents
			vhdl << tab << declare("DEXY", wE+1) << " <=   ('0' & EX) - ('0' & EY);" << endl;
			vhdl << tab << declare("DEYZ", wE+1) << " <=   ('0' & EY) - ('0' & EZ);" << endl;
			vhdl << tab << declare("DEXZ", wE+1) << " <=   ('0' & EX) - ('0' & EZ);" << endl;
			vhdl << tab << declare("XltY") << " <=   DEXY("<< wE<<");" << endl;
			vhdl << tab << declare("YltZ") << " <=   DEYZ("<< wE<<");" << endl;
			vhdl << tab << declare("XltZ") << " <=   DEXZ("<< wE<<");" << endl;
		
			// rename the exponents  to A,B,C with A>=(B,C)
			vhdl << tab << declare("EA", wE)  << " <= " << endl
				  << tab << tab << "EZ when (XltZ='1') and (YltZ='1')  else " << endl
				  << tab << tab << "EY when (XltY='1') and (YltZ='0')  else " << endl
				  << tab << tab << "EX; " << endl;
			vhdl << tab << declare("EB", wE)  << " <= " << endl
				  << tab << tab << "EX when (XltZ='1') and (YltZ='1')  else " << endl
				  << tab << tab << "EZ when (XltY='1') and (YltZ='0')  else " << endl
				  << tab << tab << "EY; " << endl;
			vhdl << tab << declare("EC", wE)  << " <= " << endl
				  << tab << tab << "EY when (XltZ='1') and (YltZ='1')  else " << endl
				  << tab << tab << "EX when (XltY='1') and (YltZ='0')  else " << endl
				  << tab << tab << "EZ; " << endl;
		
			//---------------------------------------------------------------------
			// Now recompute our two shift values -- they were already computed at cycle 0 but it is cheaper this way, otherwise we have to register, negate and mux them.
			manageCriticalPath(  target->adderDelay(wE-1) );

			vhdl << tab << declare("fullShiftValB", wE) << " <=  (EA" << range(wE-2,0) << " - EB" << range(wE-2,0) << ") & '0' ; -- positive result, no overflow " << endl;
			vhdl << tab << declare("fullShiftValC", wE) << " <=  (EA" << range(wE-2,0) << " - EC" << range(wE-2,0) << ") & '0' ; -- positive result, no overflow " << endl;
	
			double cpfullShiftValC = getCriticalPath();
			//---------------------------------------------------------------------
			Shifter* rightShifterDummy = new Shifter(target,wF+g+2, wF+g+2, Shifter::Right);
			int sizeRightShift = rightShifterDummy->getShiftInWidth(); 

			//-- Manage the shift value of the mantissa of B --------
			manageCriticalPath( target->localWireDelay() + target->lutDelay());
			vhdl<<tab<<declare("shiftedOutB") << " <= "; 
			if (wE>sizeRightShift){
				for (int i=wE-1;i>=sizeRightShift;i--) {
					vhdl<< "fullShiftValB("<<i<<")";
					if (i>sizeRightShift)
						vhdl<< " or ";
				}
				vhdl<<";"<<endl;
			}
			else
				vhdl<<tab<<"'0';"<<endl; 
			
			if (wE>sizeRightShift) {
				manageCriticalPath( target->localWireDelay() + target->lutDelay());
				vhdl<<tab<<declare("shiftValB",sizeRightShift) << " <=  fullShiftValB("<< sizeRightShift-1<<" downto 0)"
					  << " when shiftedOutB='0'"<<endl
					  <<tab << tab << "    else CONV_STD_LOGIC_VECTOR("<<wF+g+1<<","<<sizeRightShift<<") ;" << endl; 
			}else if (wE==sizeRightShift) {
				vhdl<<tab<<declare("shiftValB",sizeRightShift) << " <= fullShiftValB;" << endl ;
			}else { //  wE< sizeRightShift
				vhdl<<tab<<declare("shiftValB",sizeRightShift) << " <= CONV_STD_LOGIC_VECTOR(0,"<<sizeRightShift-wE <<") & fullShiftValB;" <<	endl;
			}
			double cpshiftValB = getCriticalPath();
			
			//-- Manage the shift value of the mantissa of C --------
			manageCriticalPath( target->localWireDelay() + target->lutDelay()); 
			//FIXME possible fixme needed when or does not fit on lut
			vhdl<<tab<<declare("shiftedOutC") << " <= "; 
			if (wE>sizeRightShift){
				for (int i=wE-1;i>=sizeRightShift;i--) {
					vhdl<< "fullShiftValC("<<i<<")";
					if (i>sizeRightShift)
						vhdl<< " or ";
				}
				vhdl<<";"<<endl;
			}
			else
				vhdl<<tab<<"'0';"<<endl; 
		
			setCycleFromSignal("fullShiftValC",cpfullShiftValC);
			if (wE>sizeRightShift) {
				manageCriticalPath( target->localWireDelay() + target->lutDelay());//the mux delay
				vhdl<<tab<<declare("shiftValC",sizeRightShift) << " <= fullShiftValC("<< sizeRightShift-1<<" downto 0)"
					  << " when shiftedOutC='0'"<<endl
					  <<tab << tab << "    else CONV_STD_LOGIC_VECTOR("<<wF+g+1<<","<<sizeRightShift<<") ;" << endl; 
			} else if (wE==sizeRightShift) {
				vhdl<<tab<<declare("shiftValC",sizeRightShift) << " <= fullShiftValC;" << endl ;
			} else 	{ //  wE< sizeRightShift
				vhdl<<tab<<declare("shiftValC",sizeRightShift) << " <= CONV_STD_LOGIC_VECTOR(0,"<<sizeRightShift-wE <<") & fullShiftValC;" <<	endl;
			}

			// Back to cycle 0 for the significand datapath
			setCycle(0);
			//FIXME add inDelayMap for use within hierarchies of components 
			// Square the significands 
#define USE_SQUARER 1
#if  USE_SQUARER
			IntSquarer* mult = new IntSquarer(target,  1+ wF);
#else
			IntMultiplier* mult = new IntMultiplier(target, 1+ wF, 1+ wF);
#endif
			oplist.push_back(mult);
		
			vhdl << tab << declare("mX", wF+1)  << " <= '1' & X" << range(wF-1, 0) << "; " << endl;
		
			inPortMap (mult, "X", "mX");
#if  !USE_SQUARER
			inPortMap (mult, "Y", "mX");
#endif
			outPortMap(mult, "R", "mX2");
			vhdl << instance(mult, "multx");
	
			vhdl << tab << declare("mY", wF+1)  << " <= '1' & Y" << range(wF-1, 0) << "; " << endl;

			inPortMap (mult, "X", "mY");
#if  !USE_SQUARER	
			inPortMap (mult, "Y", "mY");
#endif
			outPortMap(mult, "R", "mY2");
			vhdl << instance(mult, "multy");
		
			vhdl << tab << declare("mZ", wF+1)  << " <= '1' & Z" << range(wF-1, 0) << "; " << endl;
		
			inPortMap (mult, "X", "mZ");
#if  !USE_SQUARER	
			inPortMap (mult, "Y", "mZ");
#endif
			outPortMap(mult, "R", "mZ2");
			vhdl << instance(mult, "multz");

			syncCycleFromSignal("mZ2", false);
			setCriticalPath(mult->getOutputDelay("R"));
			// truncate the three results to wF+g+2
			int prodsize = 2+2*wF;
			vhdl << tab << declare("X2t", wF+g+2)  << " <= mX2" << range(prodsize-1, prodsize - wF-g-2) << "; " << endl;
			vhdl << tab << declare("Y2t", wF+g+2)  << " <= mY2" << range(prodsize-1, prodsize - wF-g-2) << "; " << endl;
			vhdl << tab << declare("Z2t", wF+g+2)  << " <= mZ2" << range(prodsize-1, prodsize - wF-g-2) << "; " << endl;
	
			// Now we have our three FP squares, we rename them to A,B,C with A>=(B,C) 
			// only 3 3-muxes
			manageCriticalPath(target->localWireDelay(wF) + target->lutDelay());  
			vhdl << tab << declare("MA", wF+g+2)  << " <= " << endl
				  << tab << tab << "Z2t when (XltZ='1') and (YltZ='1')  else " << endl
				  << tab << tab << "Y2t when (XltY='1') and (YltZ='0')  else " << endl
				  << tab << tab << "X2t; " << endl;
			vhdl << tab << declare("MB", wF+g+2)  << " <= " << endl
				  << tab << tab << "X2t when (XltZ='1') and (YltZ='1')  else " << endl
				  << tab << tab << "Z2t when (XltY='1') and (YltZ='0')  else " << endl
				  << tab << tab << "Y2t; " << endl;
			vhdl << tab << declare("MC", wF+g+2)  << " <= " << endl
				  << tab << tab << "Y2t when (XltZ='1') and (YltZ='1')  else " << endl
				  << tab << tab << "X2t when (XltY='1') and (YltZ='0')  else " << endl
				  << tab << tab << "Z2t; " << endl;
			
			//Synchronize exponent and significand datapath
			syncCycleFromSignal("shiftValB", cpshiftValB, false);

			// B and C right shifters are the same
			Shifter* rightShifter = new Shifter(target,wF+g+2, wF+g+2, Shifter::Right, inDelayMap("X",target->localWireDelay()+getCriticalPath())); 
			oplist.push_back(rightShifter);

			inPortMap  (rightShifter, "X", "MB");
			inPortMap  (rightShifter, "S", "shiftValB");
			outPortMap (rightShifter, "R","shiftedB");
			vhdl << instance(rightShifter, "ShifterForB");

			inPortMap  (rightShifter, "X", "MC");
			inPortMap  (rightShifter, "S", "shiftValC");
			outPortMap (rightShifter, "R","shiftedC");
			vhdl << instance(rightShifter, "ShifterForC");
		
			// superbly ignore the bits that are shifted out
			syncCycleFromSignal("shiftedB", false);
			setCriticalPath( rightShifter->getOutputDelay("R"));
			
			int shiftedB_size = getSignalByName("shiftedB")->width();
			vhdl << tab << declare("alignedB", wF+g+2)  << " <= shiftedB" << range(shiftedB_size-1, shiftedB_size -(wF+g+2)) << "; " << endl;
			vhdl << tab << declare("alignedC", wF+g+2)  << " <= shiftedC" << range(shiftedB_size-1, shiftedB_size -(wF+g+2)) << "; " << endl;
		
			vhdl << tab << declare("paddedA", wF+g+4)  << " <= \"00\" & MA; " << endl;
			vhdl << tab << declare("paddedB", wF+g+4)  << " <= \"00\" & alignedB; " << endl;
			vhdl << tab << declare("paddedC", wF+g+4)  << " <= \"00\" & alignedC; " << endl;
		
			IntMultiAdder* adder = new IntMultiAdder(target,wF+g+4, 3, inDelayMap("X0", target->localWireDelay() + getCriticalPath() ));
			oplist.push_back(adder);

			inPortMap   (adder, "X0", "paddedA");
			inPortMap   (adder, "X1", "paddedB");
			inPortMap   (adder, "X2", "paddedC");
			inPortMapCst(adder, "Cin", "'0'"); // a 1 would compensate the two truncations in the worst case -- to explore
			outPortMap  (adder, "R","sum");
			vhdl << instance(adder, "adder1");

			syncCycleFromSignal("sum", false);
			setCriticalPath(adder->getOutputDelay("R"));

			manageCriticalPath(target->localWireDelay() + target->lutDelay());
			// Possible 3-bit normalisation, with a truncation
			vhdl << tab << declare("finalFraction", wF+g)  << " <= " << endl
				  << tab << tab << "sum" << range(wF+g+2,3) << "   when sum(" << wF+g+3 << ")='1'    else " << endl
				  << tab << tab << "sum" << range(wF+g+1, 2) <<  "   when (sum" << range(wF+g+3, wF+g+2) << "=\"01\")     else " << endl
				  << tab << tab << "sum" << range(wF+g, 1) <<  "   when (sum" << range(wF+g+3, wF+g+1) << "=\"001\")     else " << endl
				  << tab << tab << "sum" << range(wF+g-1, 0) << "; " << endl;

			// Exponent datapath. We have to compute 2*EA - bias + an update corresponding to the normalisatiobn
			// since (1.m)*(1.m) = xx.xxxxxx sum is xxxx.xxxxxx
			// All the following ignores overflows, infinities, zeroes, etc for the sake of simplicity.
			manageCriticalPath(target->localWireDelay() + target->lutDelay());
			int bias = (1<<(wE-1))-1;
			vhdl << tab << declare("exponentUpdate", wE+1)  << " <= " << endl
				  << tab << tab << "CONV_STD_LOGIC_VECTOR(" << bias-3 << ", "<< wE+1 <<")  when sum(" << wF+g+3 << ")='1'    else " << endl
				  << tab << tab << "CONV_STD_LOGIC_VECTOR(" << bias-2 << ", "<< wE+1 <<")  when (sum" << range(wF+g+3, wF+g+2) << "=\"01\")     else " << endl
				  << tab << tab << "CONV_STD_LOGIC_VECTOR(" << bias-1 << ", "<< wE+1 <<")  when (sum" << range(wF+g+3, wF+g+1) << "=\"001\")     else " << endl
				  << tab << tab << "CONV_STD_LOGIC_VECTOR(" << bias   << ", "<< wE+1 <<")  ; " << endl;
		
			manageCriticalPath( target->localWireDelay() + target->adderDelay(wE+1));
			vhdl << tab << declare("finalExp", wE+1)  << " <= (EA & '0') - exponentUpdate ; " << endl;
			
			IntAdder *roundingAdder = new IntAdder(target, wE +1 + wF);
			oplist.push_back(roundingAdder);
			
			vhdl << tab << declare("roundingOp",wE+1 + wF) << "<= finalExp & finalFraction"<<range(wF+g-1,g)<<";"<<endl;
			
			inPortMap     ( roundingAdder, "X", "roundingOp");
			inPortMapCst  ( roundingAdder, "Y", zg(wE+1+wF));
			inPortMapCst   ( roundingAdder, "Cin", "'1'");
			outPortMap    ( roundingAdder, "R", "expFrac");
			vhdl << tab << instance( roundingAdder, "RoundingAdder"); 
			syncCycleFromSignal("expFrac");
			setCriticalPath( roundingAdder->getOutputDelay("R"));
				
			//TODO 		
			vhdl << tab << declare("rExc",2) << " <= \"01\" when  expFrac"<<of(wE+wF)<<"='0' else \"10\";"<<endl;
			vhdl << tab << "R <= rExc & '0' & expFrac"<<range(wE+1 + wF-2,0)<<";"<<endl;
		}
	
	}