#include <stdio.h>
#include <string.h>
#include "util.h"
#include "vpack.h"
#include "globals.h"
#include "ff_pack.h"

/*------------------------------------------------------------
 *  Copyright 2002 By Kara K.W. Poon and Steve Wilton
 *
 * Permission to use, copy, and modify this software and its documentation is
 * hereby granted only under the following terms and conditions.  Both the
 * above copyright notice and this permission notice must appear in all copies
 * of the software, derivative works or modified versions, and any portions
 * thereof, and both notices must appear in supporting documentation.
 * Permission is granted ONLY for non-commercial use.  For
 * commercial use, please contact the authors.
 *
 * This software may be distributed (but not offered for sale or transferred
 * for compensation) to third parties, provided such third parties agree to
 * abide by the terms and conditions of this notice.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS, AS
 * WELL AS THE UNIVERSITY OF BRITISH COLUMBIA AND THE
 * UNIVERSITY OF TORONTO DISCLAIM ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL THE
 * AUTHORS OR THE UNIVERSITY OF BRITISH COLUMBIA OR THE
 * UNIVERSITY OF TORONTO BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *------------------------------------------------------------*/

/*
  T-Vpack was written by Vaughn Betz at the University of Toronto.
  
  May 2001   Modified by Dr. Steve Wilton at the University 
             of British Columbia to propagate signal 
             activities
  July 2001  Further modified by Kara Poon at the University 
             of British Columbia to propagate both
             static probability and transition density

 */
/*
  November 2006		Modified by Yu Chi Wai at the Imperial
					College of London to support adding 
					virtual embedded block (VEB) to the circuit
 */
int get_block_name_index(char *name);

int move_net_pin(int from_blk, int pin_num, int to_blk);

static int get_block_carryout_to_name_index(char *name)
{
  int iblk;

  for(iblk=0;iblk<num_blocks;iblk++) {
     if (block[iblk].carryout_to != -1) {
	     if (block[iblk].carryout_to_name == NULL) {
	       printf("Block: %d %s has carryout_to: %d but no carryout_to_name.\n", iblk, block[iblk].name, block[iblk].carryout_to);
	     }
	     if (strcmp(block[iblk].carryout_to_name, name) == 0) {
                /*printf("Block: %d %s has carryout_to: %d %s.\n", iblk, block[iblk].name, block[iblk].carryout_to, block[iblk].carryout_to_name);*/
	        return(iblk);
	     }
     }
  }
  return(-1);
}

void pack_luts_and_ffs (int lut_size, int pass) {

/* This routine uses a simple pattern matching algorithm to pack flip-  *
 * flops into the same clb as a LUT, where possible.  Currently the     *
 * pattern to be matched is hard-coded into the program.  It is a FF    *
 * following a LUT whose output does not fan-out.  If a FF does not     *
 * fit this pattern, it is left as in its own clb (the LUT in this      *
 * clb is unused).  This pattern corresponds to a clb with n LUT inputs * 
 * and a clock input.  It has only one output -- a multiplexer selects  *
 * whether this output comes from the LUT or the FF.  As well, all      *
 * unconnected pins in a clb are set to OPEN by this routine.           */

 int bnum, in_blk, ipin, out_net, clock_net, in_net, carry_src_blk;
 int cin, cout;
 int muxcy_s;
 int temp_blk;
 int temp_ipin;
 int inv_in_net, inv_out_net;
 char *tmp_name, *tmp_carry_name;
 float block_probability;
 float block_density;
 int array_size;
 boolean match_LUT;
 int muxf_in0, muxf_in1, muxf_s;

 int match_MULTAND_I0;
 int match_MULTAND_I1;
 int inet;

 int ilut;

 for (bnum=0;bnum<num_blocks;bnum++) {
	 block[bnum].probability = 0.0;
	 block[bnum].density = 0.0;
 }

/* Pin ordering for the clb blocks (1 LUT + 1 FF in each block) is      *
 * output, n LUT inputs, clock input.                                   */

//pass 1, compact LUT to more than 4-input
if (pass ==1)
{

}

//pass 2, pack the muxcy
if (pass ==2)
{
		printf("pass 2 pack the muxcy  to LUT\n");
		for (bnum = 0; bnum<num_blocks; bnum ++)
		{
			if ((block[bnum].type == MUXCY)  || (block[bnum].type == MUXCY_L)	)
			{				
				//find the LUT output enter to its LI (lut_in[0])
				in_net = block[bnum].nets[MUXCY_DI];	//DI
				cin = block[bnum].nets[MUXCY_CI];//CI
				muxcy_s = block[bnum].nets[MUXCY_S]; // S
				
				//printf("block name : %s, in_net %d, cin %d, muxcy_s %d\n", block[bnum].name, in_net, cin, muxcy_s);	

				block_probability = net[in_net].probability;
				block_density = net[in_net].density;
				
				//handle  L first				
				in_blk = net[muxcy_s].pins[0];	//driver to this input

				if ((block[in_blk].type == LUT) && (block[in_blk].use_muxcy == 0))
				{    /* We match! */
					
				
					/* Fold the MUXCY into previous LUT block.  
					Update block and net data. */             
					//this net is still here
					//net[in_net].pins[0] = OPEN; /* This net disappears; mark. */

//					printf("in_blk %d (%s), B_COUT %d, B_CIN %d \n", in_blk, block[in_blk].name,block[in_blk].nets[B_COUT], block[in_blk].nets[B_CIN]);
								
					//Set B_YB to LUT_MC15 first 
					block[in_blk].nets[B_YB] = block[in_blk].nets[LUT_MC15];

					//check the COUT connect to others CIN or normal input only 
					for (inet = 1; inet < net[block[bnum].nets[MUXCY_O]].num_pins; inet ++)
					{
						temp_blk = net[block[bnum].nets[MUXCY_O]].pins[inet];
						if (block[bnum].nets[MUXCY_O] == block[temp_blk].nets[MUXCY_CI] 
							|| block[bnum].nets[MUXCY_O] == block[temp_blk].nets[B_CIN] 
							|| block[temp_blk].type == XORCY 
							|| block[temp_blk].type == MUXCY_L 
							|| block[temp_blk].type == MUXCY  )
						{
							//COUT is connecting to CIN 
							if (block[bnum].nets[MUXCY_O] != block[temp_blk].nets[MUXCY_DI])
							{
								block[in_blk].nets[B_COUT] = block[bnum].nets[MUXCY_O];  //set cout to muxcy_out
							}
						}
						if (block[bnum].nets[MUXCY_O] != block[temp_blk].nets[MUXCY_CI] 
						&& block[bnum].nets[MUXCY_O] != block[temp_blk].nets[B_CIN] 
						&& block[temp_blk].type != XORCY 
						&& block[temp_blk].type != MUXCY_L 
						&& block[temp_blk].type != MUXCY  )						
						{
							//connect to a LUT / FF input 
							block[in_blk].nets[B_YB] = block[bnum].nets[MUXCY_O]; //set to YB output to the LUT/ FF
							//set COUT to open
							block[in_blk].nets[B_COUT] = OPEN;  					
							/*
							if (in_blk == 17941)
							{
								printf("bnum %d, in_blk %d (%s), B_COUT %d, B_CIN %d, inet %d \n", bnum,in_blk, block[in_blk].name,block[in_blk].nets[B_COUT], block[in_blk].nets[B_CIN], inet);
							}
							*/
						}
					}
					//block[in_blk].nets[B_COUT] = block[bnum].nets[MUXCY_O];  //cout
					/*
					if (in_blk == 17941)
					{
							printf("bnum %d, in_blk %d (%s), B_COUT %d, B_CIN %d, inet %d \n", bnum,in_blk, block[in_blk].name,block[in_blk].nets[B_COUT], block[in_blk].nets[B_CIN], inet);
					}
					*/

					temp_ipin = block[bnum].nets[MUXCY_CI];
					if (block[net[temp_ipin].pins[0]].type != INPAD &&  
						block[net[temp_ipin].pins[0]].type != GND &&  
						block[net[temp_ipin].pins[0]].type != VCC )
  
					{
						block[in_blk].nets[B_CIN] = block[bnum].nets[MUXCY_CI];  //cin 
					}
					else
						block[in_blk].nets[B_CIN] = OPEN;		
				//	printf("bnum %d, in_blk %d (%s), B_COUT %d, B_CIN %d \n", bnum,in_blk, block[in_blk].name,block[in_blk].nets[B_COUT], block[in_blk].nets[B_CIN]);


					

					block[in_blk].use_muxcy = 1;					
	
					temp_blk = net[in_net].pins[0];	//check the input DI is MULTAND or not
//					printf("inet %d(%s), temp_blk %d(%s) \n", in_net, net[in_net].name, temp_blk, block[temp_blk].name);
					if (block[temp_blk].type == MULT_AND)
					{
						match_MULTAND_I0 = -1;
						match_MULTAND_I1 = -1;

						//find the input of MULTAND is connect to same net as LUT


						//case 1 both I0, I1 are open => error
						if ( (block[temp_blk].nets[MULTAND_I0] == OPEN)  && (block[temp_blk].nets[MULTAND_I1] == OPEN))
						{
							printf("MUXCY block name : %s \n", block[bnum].name);
							printf("LUT block name : %s \n", block[in_blk].name);
							printf("MULTAND block name : %s \n", block[temp_blk].name);
							printf("MULTAND net name : %s, LUT net name : %s \n", net[block[temp_blk].nets[MULTAND_I0]].name, net[block[in_blk].nets[B_LUT_IN]].name);
								
							printf("Error: both input of MULTAND is OPEN \n");
							exit(1);
						}

						//check for I0
						if (block[temp_blk].nets[MULTAND_I0] != OPEN)
						{
							//check which net from LUT is the same as I0
							for (ilut = 0 ; ilut <lut_size; ilut ++)
							{
								if (block[temp_blk].nets[MULTAND_I0] == block[in_blk].nets[B_LUT_IN + ilut] )
								{
									match_MULTAND_I0 = ilut;
									break;
								}
							}

							if (match_MULTAND_I0 == -1)
							{
								//can't find the net in LUT which is the same as I0
								
								//we accept VCC or GND even can't find the net 
								if (block[net[block[temp_blk].nets[MULTAND_I0]].pins[0]].type == VCC)
								{
										block[in_blk].nets[B_VCC] = block[temp_blk].nets[MULTAND_I0];
										//move the net from MULTAND to this LUT
										move_net_pin(temp_blk, MULTAND_I0, in_blk);
								}

								if (block[net[block[temp_blk].nets[MULTAND_I0]].pins[0]].type == GND)
								{
										block[in_blk].nets[B_GND] = block[temp_blk].nets[MULTAND_I0];
										//move the net from MULTAND to this LUT
										move_net_pin(temp_blk, MULTAND_I0, in_blk);
								}

								//if I0 not VCC or GND, need to find an empty LUT input 
								if ( block[net[block[temp_blk].nets[MULTAND_I0]].pins[0]].type != VCC &&
										block[net[block[temp_blk].nets[MULTAND_I0]].pins[0]].type != GND 		
								)
								{
									//then find an empty net for the I0 connect to LUT
									for (ilut = 0 ; ilut <lut_size; ilut ++)
									{
										if ( block[in_blk].nets[B_LUT_IN + ilut] == OPEN)
										{
											match_MULTAND_I0 = ilut;
											break;
										}
									}

									if (match_MULTAND_I0 == -1)
									{
										//still can't find the space for I0																											
										printf("MUXCY block name : %s \n", block[bnum].name);
										printf("LUT block name : %s \n", block[in_blk].name);
										printf("MULTAND block name : %s \n", block[temp_blk].name);
										printf("MULTAND net name : %s, LUT net name : %s \n", net[block[temp_blk].nets[MULTAND_I0]].name, net[block[in_blk].nets[B_LUT_IN]].name);												
										printf("Error: the input of MULTAND is not consistent to LUT input \n");
										exit(1);									
									}
									else
									{
										//found the space for I0
										block[in_blk].nets[B_LUT_IN + match_MULTAND_I0] = block[temp_blk].nets[MULTAND_I0];
										move_net_pin(temp_blk, MULTAND_I0, in_blk);
									}
								}
							}
							else
							{
								//find the net in LUT which is the same as I0
								block[in_blk].nets[B_LUT_IN + match_MULTAND_I0] = block[temp_blk].nets[MULTAND_I0];
							}

						}
																			
						
						//check for I1
						if (block[temp_blk].nets[MULTAND_I1] != OPEN)
						{
							for (ilut = 0 ; ilut <lut_size; ilut ++)
							{
								if (block[temp_blk].nets[MULTAND_I1] == block[in_blk].nets[B_LUT_IN + ilut] )
								{
									match_MULTAND_I1 = ilut;
									break;
								}
							}

							if (match_MULTAND_I1 == -1)
							{
								//can't find the net in LUT which is the same as I1
								
								//we accept VCC or GND even can't find the net 
								if (block[net[block[temp_blk].nets[MULTAND_I1]].pins[0]].type == VCC)
								{
										block[in_blk].nets[B_VCC] = block[temp_blk].nets[MULTAND_I1];
										//move the net from MULTAND to this LUT
										move_net_pin(temp_blk, MULTAND_I1, in_blk);
								}

								if (block[net[block[temp_blk].nets[MULTAND_I1]].pins[0]].type == GND)
								{
										block[in_blk].nets[B_GND] = block[temp_blk].nets[MULTAND_I1];
										//move the net from MULTAND to this LUT
										move_net_pin(temp_blk, MULTAND_I1, in_blk);
								}

								//if I1 not VCC or GND, need to find an empty LUT input 
								if ( block[net[block[temp_blk].nets[MULTAND_I1]].pins[0]].type != VCC &&
										block[net[block[temp_blk].nets[MULTAND_I1]].pins[0]].type != GND 		
								)
								{
									//then find an empty net for the I1 connect to LUT
									for (ilut = 0 ; ilut <lut_size; ilut ++)
									{
										if ( block[in_blk].nets[B_LUT_IN + ilut] == OPEN)
										{
											match_MULTAND_I1 = ilut;
											break;
										}
									}

									if (match_MULTAND_I1 == -1)
									{
										//still can't find the space for I1																											
										printf("MUXCY block name : %s \n", block[bnum].name);
										printf("LUT block name : %s \n", block[in_blk].name);
										printf("MULTAND block name : %s \n", block[temp_blk].name);
										printf("MULTAND net name : %s, LUT net name : %s \n", net[block[temp_blk].nets[MULTAND_I1]].name, net[block[in_blk].nets[B_LUT_IN]].name);												
										printf("Error: the input of MULTAND is not consistent to LUT input \n");
										exit(1);									
									}
									else
									{
										//found the space for I1
										block[in_blk].nets[B_LUT_IN + match_MULTAND_I1] = block[temp_blk].nets[MULTAND_I1];
										move_net_pin(temp_blk, MULTAND_I1, in_blk);
									}
								}
							}
							else
							{
								//find the net in LUT which is the same as I1
								block[in_blk].nets[B_LUT_IN + match_MULTAND_I1] = block[temp_blk].nets[MULTAND_I1];
							}						
						}
	
						//---------------------------------------------------------------------------------------------------------------------------						
						
						//remove MULTAND
						if (net[in_net].num_pins > 2) 
						{
						/*
							printf("MUXCY block name : %s \n", block[bnum].name);
							printf("LUT block name : %s \n", block[in_blk].name);
							printf("MULTAND block name : %s \n", block[temp_blk].name);
							printf("net name : %s, num_pin %d \n", net[in_net].name, net[in_net].num_pins);
						*/
							printf("Error: MULTAND output pin drive more than 1 net\n");
							exit(1);
						}
						net[in_net].pins[0] = OPEN;	// the DI pin of MUXCY disappear
						block[temp_blk].type = EMPTY;	//empty MULTAND
						block[in_blk].use_mult_and = 1;
					}
					else
					{
						//the MUXCY 's DI is connect to either G1 , G2, GND, VCC, BY
						if (block[temp_blk].type == GND)
						{
							block[in_blk].nets[B_GND] = block[bnum].nets[MUXCY_DI];

							//move the receiver (DIN) connection from MUXCY to LUT
							move_net_pin(bnum, MUXCY_DI, in_blk);

						}
						else if (block[temp_blk].type == VCC)
						{
							block[in_blk].nets[B_VCC] = block[bnum].nets[MUXCY_DI];
							move_net_pin(bnum, MUXCY_DI, in_blk);

						}
						else
						{
							if (block[in_blk].nets[B_LUT_IN] !=  block[bnum].nets[MUXCY_DI])
							{
							
									if (block[in_blk].nets[B_LUT_IN +1] !=  block[bnum].nets[MUXCY_DI])
									{
										//connect to BY
										block[in_blk].nets[B_BY] = block[bnum].nets[MUXCY_DI];

										//move the receiver (CIN) connection from MUXCY to LUT
										move_net_pin(bnum, MUXCY_DI, in_blk);

									}//connect to G2
							}//connect to G1
						}
					}
										
					block[bnum].type = EMPTY;   /* remove the muxcy */					

					block[in_blk].probability = block_probability;
					block[in_blk].density = block_density;										

					//move the driver (COUT) connection from MUXCY to LUT
					move_net_pin(bnum, MUXCY_O, in_blk);

			

					//move the receiver (CIN) connection from MUXCY to LUT
					move_net_pin(bnum, MUXCY_CI, in_blk);

					//delete the muxcy_s net
					
					//remove the original net
					for (ipin = 0; ipin<net[muxcy_s].num_pins; ipin ++)
					{					
						if (net[muxcy_s].pins[ipin] == bnum)
						{
							temp_ipin = ipin;
						}					
					}				
					//net[muxcy_s].pins[temp_ipin] = OPEN;
					
					for (ipin = temp_ipin ; ipin < net[muxcy_s].num_pins -1;ipin++)
					{
						net[muxcy_s].pins[ipin] = net[muxcy_s].pins[ipin + 1];
					}
					net[muxcy_s].num_pins = net[muxcy_s].num_pins - 1;
					
					net[muxcy_s].pins = realloc(net[muxcy_s].pins, net[muxcy_s].num_pins* sizeof(int));

					//save the main In/out
					block[in_blk].nets[B_Y] = block[in_blk].nets[LUT_D];	//temperately regard the block output Y is from LUT_D (it may be from xorcy, or orcy					
					
					block[in_blk].nets[B_SHIFTOUT] = block[in_blk].nets[LUT_MC15];

				}
				else
				{
					//MUXCY selection is connected to VCC, handle it later
					//block[in_blk].nets[B_VCC] = block[bnum].nets[MUXCY_S];
				}
			}		
		}


}

//pass 3, pack the xorcy
if (pass ==3)
{
	printf("pass 3, pack xorcy to LUT\n");
	for (bnum = 0; bnum<num_blocks; bnum ++)
	{
		if (block[bnum].type == XORCY)	//carry chain xor gate
		{
			in_net = block[bnum].nets[XORCY_LI];	//LI
			cin = block[bnum].nets[XORCY_CI];//CI
			out_net = block[bnum].nets[XORCY_O];

			in_blk = net[in_net].pins[0];	//driver to this input

			if  ((block[in_blk].type == LUT)  && (block[in_blk].use_xorcy == 0))
			{    /* We match! */
				/* Fold the XORCY into previous LUT block.  
				Update block and net data. */             
				//this net is still here
				//net[in_net].pins[0] = OPEN; /* This net disappears; mark. */
				block[in_blk].nets[B_Y] = block[bnum].nets[XORCY_O];  //xorcy out to Y, overwrite the output from LUT
				if (block[in_blk].nets[B_CIN] != OPEN)
				{   
					if (block[in_blk].nets[B_CIN] != block[bnum].nets[XORCY_CI])
					{
						printf("Error: XORCY CIN is not matched to Block CIN \n");
						exit(1);
					}
				}
				else
				{
					block[in_blk].nets[B_CIN] = block[bnum].nets[XORCY_CI];
					//printf("XORCY combine with LUT, LUT %d(%s), nets %d(%s) \n", in_blk, block[in_blk].name, block[bnum].nets[XORCY_CI], net[block[bnum].nets[XORCY_CI]].name);
					//printf("LUT COUT %d \n", block[in_blk].nets[B_COUT]);
				}

				//if connect to GND/VDD set CIN to open
				temp_ipin = block[in_blk].nets[B_CIN];
				if (block[net[temp_ipin].pins[0]].type != INPAD &&  
					block[net[temp_ipin].pins[0]].type != GND &&  
					block[net[temp_ipin].pins[0]].type != VCC )
  
				{
					//block[in_blk].nets[B_CIN] = block[bnum].nets[MUXCY_CI];  //cin 
				}
				else
					block[in_blk].nets[B_CIN] = OPEN;		


				//LUT_D disappear

				//remove xorcy
				/*
				if (net[in_net].num_pins > 2) 
				{
					printf("XORCY block name : %s \n", block[bnum].name);
					printf("LUT block name : %s \n", block[in_blk].name);
					printf("in_net : %s , num_pins %d \n", net[in_net].name, net[in_net].num_pins);
					printf("Error: LUT_D  to XORCY  drive more than 1 net\n");
					exit(1);
				}
				*/
				net[in_net].pins[0] = OPEN;	// the LI pin of xorcy disappear
				block[bnum].type = EMPTY;	//empty xorcy
				
				block[in_blk].use_xorcy = 1;					
				block[in_blk].nets[B_Y] = out_net;	//connect output of xorcy to Y

				block[in_blk].probability = block_probability;
				block[in_blk].density = block_density;										

				//move the driver  connection from xorcy to LUT
				move_net_pin(bnum, XORCY_O, in_blk);
				move_net_pin(bnum, XORCY_CI, in_blk);
//				printf("Block %d(%s), B_Y %d(%s) \n", in_blk, block[in_blk].name, out_net, net[out_net].name);

//					printf("LUT COUT %d \n", block[in_blk].nets[B_COUT]);
//				if (block[in_blk].nets[B_COUT] != OPEN)
//					printf("Net name %s\n", net[block[in_blk].nets[B_COUT]].name);

			}
			else
			{
				printf("XORCY block : %s , can't find match LUT\n", block[bnum].name);
			}
		}
	}
}

//pass 4, pack the FF to LUT
if (pass ==4)
{
		printf("\npass 4 , Packing FF to LUT, num_blocks = %d\n", num_blocks);		

		for (bnum = 0; bnum<num_blocks; bnum ++)
		{			
			if (block[bnum].type == LATCH)
			{
				
				//find a matching 
				clock_net = block[bnum].nets[FF_CLK];
				in_net = block[bnum].nets[FF_D];
				out_net = block[bnum].nets[FF_Q];
				
				
//				printf("block name: %s, in_net name: %s, out_net  name %s \n", block[bnum].name, net[in_net].name, net[out_net].name);
				

				block_probability = net[in_net].probability;
				block_density = net[in_net].density;
				
				in_blk = net[in_net].pins[0];	
				
//				printf("in_blk name : %s\n", block[in_blk].name);
				//if the input of CLK, CE, SR, BY is INV, then remove the INV net, since there is internal INV for these pins
			
				if (block[in_blk].type == VEB || block[in_blk].type == INPAD)
					continue;

				if (block[bnum].nets[FF_CLK] != OPEN)
				{
					temp_blk = net[block[bnum].nets[FF_CLK]].pins[0];	//clk input			
					
					if (block[temp_blk].type == INV)
					{											
						//printf("Remove INV net for clk input, FF block = %d\n", bnum);					
						inv_out_net = block[temp_blk].nets[INV_O];
						inv_in_net = block[temp_blk].nets[INV_IN];
						//remove the original net
						for (ipin = 0; ipin<net[inv_out_net].num_pins; ipin ++)
						{
							//printf("net[%d].pins[%d] = %d \n", inv_out_net, ipin, bnum);
							if (net[inv_out_net].pins[ipin] == bnum)
							{
								temp_ipin = ipin;
								//net[inv_out_net].pins[ipin] = OPEN;
								break;
							}					
						}	
						//delete the net
						//the net must here 
	//					printf("net[%d].num_pins = %d \n", inv_out_net, net[inv_out_net].num_pins);
						for (ipin = temp_ipin ; ipin < net[inv_out_net].num_pins -1;ipin++)
						{
							net[inv_out_net].pins[ipin] = net[inv_out_net].pins[ipin + 1];
						}
						net[inv_out_net].num_pins = net[inv_out_net].num_pins - 1;
						net[inv_out_net].pins = realloc(net[inv_out_net].pins, net[inv_out_net].num_pins * sizeof(int));
						//add net to the net connects to the input of INV
						net[inv_in_net].pins = realloc(net[inv_in_net].pins, (net[inv_in_net].num_pins + 1) *sizeof(int) );
						net[inv_in_net].num_pins ++;
						net[inv_in_net].pins[net[inv_in_net].num_pins -1] = bnum;
						block[bnum].nets[FF_CLK] = inv_in_net; 
						block[bnum].use_inv_clk = 1; 
						//block[temp_blk].num_nets --;
					}
				}

				if (block[bnum].nets[FF_SR] != OPEN)
				{
					temp_blk = net[block[bnum].nets[FF_SR]].pins[0];	//SR input					
					
					if (block[temp_blk].type == INV)
					{
						//printf("Remove INV net for SR input, FF block = %d\n", bnum);
						inv_out_net = block[temp_blk].nets[INV_O];
						inv_in_net = block[temp_blk].nets[INV_IN];
						//remove the original net
						//the net must here
						for (ipin = 0; ipin<net[inv_out_net].num_pins; ipin ++)
						{
							if (net[inv_out_net].pins[ipin] == bnum)
							{
								temp_ipin = ipin;
								//net[inv_out_net].pins[ipin] = OPEN;
							}					
						}			
						//delete the net
						for (ipin = temp_ipin ; ipin < net[inv_out_net].num_pins -1;ipin++)
						{
							net[inv_out_net].pins[ipin] = net[inv_out_net].pins[ipin + 1];
						}
						net[inv_out_net].num_pins = net[inv_out_net].num_pins - 1;

						net[inv_out_net].pins = realloc(net[inv_out_net].pins, net[inv_out_net].num_pins * sizeof(int));
						//add net to the net connects to the input of INV
						net[inv_in_net].pins = realloc(net[inv_in_net].pins, (net[inv_in_net].num_pins + 1) * sizeof(int));
						net[inv_in_net].num_pins ++;
						net[inv_in_net].pins[net[inv_in_net].num_pins -1] = bnum;
						block[bnum].nets[FF_SR] = inv_in_net; 
						block[bnum].use_inv_sr = 1; 
						//block[bnum].nets[FF_SR] = add_net (net[inv_in_net].name,RECEIVER,bnum, 1); 
						//block[temp_blk].num_nets --;
					}
				}

				if (block[bnum].nets[FF_CE] != OPEN)
				{
					temp_blk = net[block[bnum].nets[FF_CE]].pins[0];	//CE input

					
					if (block[temp_blk].type == INV)
					{
						inv_out_net = block[temp_blk].nets[INV_O];
						inv_in_net = block[temp_blk].nets[INV_IN];
						//printf("Remove INV net: %s for CE input, FF block = %d\n", net[inv_out_net].name,bnum);
						//remove the original net
						for (ipin = 0; ipin<net[inv_out_net].num_pins; ipin ++)
						{
							//printf("net[%d].pins[%d] = %d \n", inv_out_net, ipin, net[inv_out_net].pins[ipin]);
							if (net[inv_out_net].pins[ipin] == bnum)
							{
								temp_ipin = ipin;
							//	net[inv_out_net].pins[ipin] = OPEN;
							}					
						}	
						//delete the net
						//printf("net[%d].num_pins = %d \n", inv_out_net, net[inv_out_net].num_pins);
						for (ipin = temp_ipin ; ipin < net[inv_out_net].num_pins -1;ipin++)
						{
							net[inv_out_net].pins[ipin] = net[inv_out_net].pins[ipin + 1];
						}
						net[inv_out_net].num_pins = net[inv_out_net].num_pins - 1;
						
						net[inv_out_net].pins = realloc(net[inv_out_net].pins, net[inv_out_net].num_pins * sizeof(int));
						//printf("net: %s, net[%d].num_pins = %d \n",net[inv_in_net].name, inv_in_net, net[inv_in_net].num_pins);
						//add net to the net connects to the input of INV		
						net[inv_in_net].num_pins ++;										
						net[inv_in_net].pins = realloc(net[inv_in_net].pins, net[inv_in_net].num_pins * sizeof(int));
						
						//printf("net[%d].num_pins = %d \n", inv_in_net, net[inv_in_net].num_pins);
						net[inv_in_net].pins[net[inv_in_net].num_pins -1] = bnum;
						block[bnum].nets[FF_CE] = inv_in_net; 
						block[bnum].use_inv_ce = 1; 
						//block[temp_blk].num_nets --;
						//block[bnum].nets[FF_CE] = add_net (net[inv_in_net].name,RECEIVER,bnum, 1); 
					}
				}


				
				//finding LUT which match FF
				if ( (block[in_blk].type == LUT) && (block[in_blk].use_ff == 0) )
				{
				
//					printf("found match LUT to FF\n");
					match_LUT = TRUE;
					//check the LUT have CIN/COUT or not
					//if there is carry in or out , check for the previous and next LUT to check for common 
					if (block[in_blk].nets[B_CIN] != OPEN)
					{
						//check the carry chain input 
						temp_blk = net[block[in_blk].nets[B_CIN]].pins[0];			
						if (block[temp_blk].use_ff == 1)
						{
							//the FF is used in the previous LUT, check the share pin CE, CLK, SR
							
							if (block[temp_blk].nets[B_CE] != OPEN && block[in_blk].nets[B_CE] != OPEN)
							{
								if (block[temp_blk].nets[B_CE]  != block[in_blk].nets[B_CE])
								{
									match_LUT =FALSE;
								}
								else
								{
									//one input use inv but the other not using inv
									if (block[temp_blk].use_inv_ce != block[in_blk].use_inv_ce)
									{
										match_LUT =FALSE;
									}
								}
							}

							if (block[temp_blk].nets[B_CLK] != OPEN && block[in_blk].nets[B_CLK] != OPEN)
							{
								if (block[temp_blk].nets[B_CLK]  != block[in_blk].nets[B_CLK])
								{
									match_LUT =FALSE;
								}
								else
								{
									//one input use inv but the other not using inv
									if (block[temp_blk].use_inv_clk != block[in_blk].use_inv_clk)
									{
										match_LUT =FALSE;
									}
								}
							}

							if (block[temp_blk].nets[B_SR] != OPEN && block[in_blk].nets[B_SR] != OPEN)
							{
								if (block[temp_blk].nets[B_SR]  != block[in_blk].nets[B_SR])
								{
									match_LUT =FALSE;
								}
								else
								{
									//one input use inv but the other not using inv
									if (block[temp_blk].use_inv_sr != block[in_blk].use_inv_sr)
									{
										match_LUT =FALSE;
									}
								}
							}							
						}
					}
					if (block[in_blk].nets[B_COUT] != OPEN)
					{
						//check the carry chain output 
						for (ipin = 1; ipin < net[block[in_blk].nets[B_COUT]].num_pins;  ipin++)
						{
							temp_blk = net[block[in_blk].nets[B_COUT]].pins[ipin];			
							if (block[temp_blk].use_ff == 1)
							{
								//the FF is used in the next LUT, check the share pin CE, CLK, SR

								if (block[temp_blk].nets[B_CE] != OPEN)
								{
									if (block[temp_blk].nets[B_CE]  != block[in_blk].nets[B_CE])
									{
										match_LUT =FALSE;
									}
									else
									{
										//one input use inv but the other not using inv
										if (block[temp_blk].use_inv_ce != block[in_blk].use_inv_ce)
										{
											match_LUT =FALSE;
										}
									}

								}

								if (block[temp_blk].nets[B_CLK] != OPEN)
								{
									if (block[temp_blk].nets[B_CLK]  != block[in_blk].nets[B_CLK])
									{
										match_LUT =FALSE;
									}
									else
									{
										//one input use inv but the other not using inv
										if (block[temp_blk].use_inv_clk != block[in_blk].use_inv_clk)
										{
											match_LUT =FALSE;
										}
									}
								}

								if (block[temp_blk].nets[B_SR] != OPEN)
								{
									if (block[temp_blk].nets[B_SR]  != block[in_blk].nets[B_SR])
									{
										match_LUT =FALSE;
									}
									else
									{
										//one input use inv but the other not using inv
										if (block[temp_blk].use_inv_clk != block[in_blk].use_inv_clk)
										{
											match_LUT =FALSE;
										}
										else
										{
											//one input use inv but the other not using inv
											if (block[temp_blk].use_inv_sr != block[in_blk].use_inv_sr)
											{
												match_LUT =FALSE;
											}
										}
									}
								}							
							}
						}															
					}

					
					//can't connect COUT to the same block
					if (block[in_blk].use_muxcy == 1)
					{
						if (block[in_blk].nets[B_COUT] == in_net || block[in_blk].nets[B_YB] == in_net)
						{
							match_LUT = FALSE;
							if (block[in_blk].nets[B_YB] == OPEN )
							{								
								block[in_blk].nets[B_YB] = block[in_blk].nets[B_COUT];
							}
							else
							{
								//B_YB already connect to COUT
								/*
								if (block[in_blk].nets[B_YB] != in_net)
								{
									printf("Error: 0. FF(%s) can't find the input net in LUT (%s) \n", block[bnum].name, block[in_blk].name );
									//printf("B_YB = %d (%s), in_blk = %d, in_net = %d" , block[in_blk].nets[B_YB], net[block[in_blk].nets[B_YB]].name, in_blk, in_net);
									exit(1);
								}
								*/
							}
						}
					}

					//printf("found match LUT for FF, LUT block = %d (%s), FF block = %d(%s)\n", in_blk, block[in_blk].name, bnum, block[bnum].name);
					
					if (match_LUT)
					{
						//output_block(in_blk, lut_size);
						//match 
						if (block[in_blk].nets[B_Y] == OPEN)
						{
							if (block[in_blk].nets[LUT_D] != block[bnum].nets[FF_D])
							{			
								printf("Error: 1. FF(%s) can't find the input net in LUT (%s) \n", block[bnum].name, block[in_blk].name );
								exit(1);
							}
							//LUT_D connect to FF_D
							//output_block(in_blk, lut_size);
							//printf ( "LUT_D %d num_pins  = %d \n", block[in_blk].nets[LUT_D], net[block[in_blk].nets[LUT_D]].num_pins);
							if (net[block[in_blk].nets[LUT_D]].num_pins > 2)
							{
								//the LUT output connect to outside block
								block[in_blk].nets[B_Y] = block[in_blk].nets[LUT_D];

								//block[in_blk].nets[B_DY] = block[in_blk].nets[LUT_D];						
								block[in_blk].nets[B_DY] = OPEN;			
								block[in_blk].use_ff_int_conn = 1;
							}
							else
							{

								//remove the net from LUT_D, internal connection
								//block[in_blk].nets[B_Y] = block[in_blk].nets[LUT_D];
								block[in_blk].nets[B_Y] = OPEN;

								//block[in_blk].nets[B_DY] = block[in_blk].nets[LUT_D];
								block[in_blk].nets[B_DY] = OPEN;
								net[block[in_blk].nets[LUT_D]].pins[0]= OPEN;
								block[in_blk].use_ff_int_conn = 1;

							}																							
						}else
						{
							//B_Y not  open
							if (block[in_blk].nets[B_Y] == block[bnum].nets[FF_D])
							{
								if (net[block[in_blk].nets[B_Y]].num_pins > 2)
								{
									//connect to outside block
									//block[in_blk].nets[B_DY] = block[in_blk].nets[LUT_D];
									block[in_blk].nets[B_DY] = OPEN;
									block[in_blk].use_ff_int_conn = 1;
								}else
								{
								
									block[in_blk].nets[B_DY] = OPEN;
									block[in_blk].use_ff_int_conn = 1;
								}																			
							}
							else
							{																
								printf("Error: 2. FF(%s) can't find the input net in LUT (%s) \n", block[bnum].name, block[in_blk].name );
								printf(" in_net = %d , MUXCY_O = %d \n", in_net , block[in_blk].nets[MUXCY_O]);
								exit(1);
							}						
						}
						//no need to handle INV of BY here, since FF_D is connect to LUT_D
						//save the net from FF to LUT block
						block[in_blk].nets[B_CLK] = block[bnum].nets[FF_CLK];
						block[in_blk].nets[B_SR] = block[bnum].nets[FF_SR];
						block[in_blk].nets[B_CE] = block[bnum].nets[FF_CE];
						block[in_blk].nets[B_Q] = block[bnum].nets[FF_Q];
						block[in_blk].use_ff = 1;	//add ff in the LUT
						block[in_blk].use_inv_ce = block[bnum].use_inv_ce;
						block[in_blk].use_inv_sr = block[bnum].use_inv_sr;
						block[in_blk].use_inv_clk = block[bnum].use_inv_clk;

						block[bnum].type = EMPTY;
						block[in_blk].type = LUT_AND_LATCH;					

						//connect the net original to FF to LUT block
						//printf("move net %d from block %d to block %d \n", block[in_blk].nets[B_Q], bnum, in_blk);
						move_net_pin(bnum, FF_D, in_blk);
				
						//connect the net original to FF to LUT block
						move_net_pin(bnum, FF_Q, in_blk);

						//output_block(in_blk, lut_size);
						move_net_pin(bnum, FF_SR, in_blk);
						move_net_pin(bnum, FF_CLK, in_blk);

						move_net_pin(bnum, FF_CE, in_blk);
					}
					
				}
				else
				{

//					printf("no match LUT for FF\n");
					//handle BY INV
					if  (block[in_blk].type == INV)  
					{
						//printf("no match LUT for FF with INV input (%s) \n", block[bnum].name);
						inv_out_net = block[in_blk].nets[INV_O];
						inv_in_net = block[in_blk].nets[INV_IN];
						//remove the original net
						for (ipin = 0; ipin<net[inv_out_net].num_pins; ipin ++)
						{
							if (net[inv_out_net].pins[ipin] == bnum)
							{
								temp_ipin = ipin;
								//net[inv_out_net].pins[ipin] = OPEN;
							}					
						}	
						//delete the net
						//the net must here
						for (ipin = temp_ipin ; ipin < net[inv_out_net].num_pins -1;ipin++)
						{
							net[inv_out_net].pins[ipin] = net[inv_out_net].pins[ipin + 1];
						}
						net[inv_out_net].num_pins = net[inv_out_net].num_pins - 1;
					//	net[inv_out_net].pins = realloc(net[inv_out_net].pins, net[inv_out_net].num_pins* sizeof(int));
						//add net to the net connects to the input of INV
						net[inv_in_net].pins = realloc(net[inv_in_net].pins, (net[inv_in_net].num_pins + 1) * sizeof (int) );
						net[inv_in_net].num_pins ++;
						net[inv_in_net].pins[net[inv_in_net].num_pins -1] = bnum;
						block[bnum].nets[FF_D] = inv_in_net; 
						//block[bnum].nets[FF_D] = add_net (net[inv_in_net].name,RECEIVER,bnum, 1); 

					}

				}
			}
		}
}

//pass 5, convert INV to LUT,
if (pass  ==5 )
{
	printf("pass 5, convert INV to LUT\n");
	//regard the INV as single LUT to generate inverting function

	for (bnum = 0; bnum<num_blocks; bnum ++)
	{
		if (block[bnum].type == INV)
		{
			//output_block(bnum, lut_size);
//			printf("Number of pins connect to INV_O = %d \n", net[block[bnum].nets[INV_O]].num_pins);
			if (net[block[bnum].nets[INV_O]].num_pins ==1)	//only driver pin left
			{
				//printf("Remove the block INV : %s\n", block[bnum].name);
				//delete the INV
				block[bnum].type = EMPTY;			
				//remove out net
				net[block[bnum].nets[INV_O]].pins[0] = OPEN;
				//delete the in net
				inv_in_net = block[bnum].nets[INV_IN];

				//remove the original net
				for (ipin = 0; ipin<net[inv_in_net].num_pins; ipin ++)
				{					
					if (net[inv_in_net].pins[ipin] == bnum)
					{
						temp_ipin = ipin;
					}					
				}				
				//delete the net
				//printf("net[%d].num_pins = %d \n", inv_out_net, net[inv_out_net].num_pins);
				for (ipin = temp_ipin ; ipin < net[inv_in_net].num_pins -1;ipin++)
				{
					net[inv_in_net].pins[ipin] = net[inv_in_net].pins[ipin + 1];
				}
				net[inv_in_net].num_pins = net[inv_in_net].num_pins - 1;

				net[inv_in_net].pins = realloc(net[inv_in_net].pins, net[inv_in_net].num_pins* sizeof(int));
				
			}
			else
			{
				block[bnum].type = LUT;			
				block[bnum].nets[LUT_D] = block[bnum].nets[INV_O];
				block[bnum].nets[B_Y] = block[bnum].nets[INV_O];
				block[bnum].nets[B_LUT_IN] = block[bnum].nets[INV_IN];
			}
			
		}		
	}
}

//pass 6, pack the remaining blocks
if (pass  ==6 )
{
	printf("pass 6 pack the remaining blocks\n");
	for (bnum = 0; bnum<num_blocks; bnum ++)
	{
		//error if xorcy is remaining
		if (block[bnum].type == XORCY)
		{
			printf("Error: XORCY shouldn't remain in pass 6 of packing\n");
			exit(1);
		}

		
		if (block[bnum].type == MUXF)
		{
			//MUXF select must connect to LUT
			muxf_in0 = block[bnum].nets[MUXF_I0];
			muxf_in1 = block[bnum].nets[MUXF_I1];
			muxf_s = block[bnum].nets[MUXF_S]; 		

			match_LUT = FALSE;

			for (in_blk = 0; in_blk < num_blocks; in_blk ++ )
			{
				if ( (block[in_blk].type == LUT || block[in_blk].type == LUT_AND_LATCH) && block[in_blk].use_muxf ==0 && block[in_blk].nets[B_BY] == OPEN)
				{
//					printf("MUXF (%s), net : muxf_s (%s) \n", block[bnum].name, net[muxf_s].name);

					match_LUT = TRUE;

					block[in_blk].use_muxf = 1;	

					block[in_blk].nets[B_FXINA] = muxf_in0;
					block[in_blk].nets[B_FXINB] = muxf_in1;
					block[in_blk].nets[B_FX] =  block[bnum].nets[MUXF_O];

					block[in_blk].nets[B_BY] = block[bnum].nets[MUXF_S];
				
					block[bnum].type = EMPTY;   // remove the muxf 

					//move the driver (MUXF_O) connection from MUXF to LUT
					move_net_pin(bnum, MUXF_O, in_blk);
					//move the input net to LUT
					move_net_pin(bnum, MUXF_I0, in_blk);
					move_net_pin(bnum, MUXF_I1, in_blk);
					move_net_pin(bnum,MUXF_S, in_blk);


					break;
				}
			}
		
			if (match_LUT == FALSE)
			{
				printf("Error:  MUXF_S is not connection to a LUT or connect to a used LUT or connect to LUT_AND_LATCH\n");
				printf(" LUT (%s) , MUXF_S (%s) , [in_blk].use_muxf = %d\n", block[in_blk].name, block[bnum].name, block[in_blk].use_muxf);
				exit(1);
			}
		
		}

		if ((block[bnum].type == MUXCY)  || (block[bnum].type == MUXCY_L)			)
		{
			//this MUXCY should have muxcy_s connect to VCC
			in_net = block[bnum].nets[MUXCY_DI];
			cin = block[bnum].nets[MUXCY_CI];
			muxcy_s = block[bnum].nets[MUXCY_L]; 

			block[bnum].type = LUT;
			
			//search the LUT with XORCY inside and connect CIN to MUXCY
			
			in_blk = OPEN;
			for ( ipin = 1; ipin <  net[muxcy_s].num_pins; ipin ++)
			{
				if (block[net[muxcy_s].pins[ipin]].nets[B_CIN] == cin)
				{
					if (block[net[muxcy_s].pins[ipin]].use_muxcy == 0)
					{
						in_blk = net[muxcy_s].pins[ipin];	//get the block muxcy should connect to 
						break;
					}					
				}								
			}
			
			if (in_blk != OPEN)
			{
				if ( (block[in_blk].type == LUT) || (block[in_blk].type == LUT_AND_LATCH) )
				{
					//merge muxcy to that block					
					//check the COUT connect to others CIN or normal input only 
					for (inet = 1; inet < net[block[bnum].nets[MUXCY_O]].num_pins; inet ++)
					{
						temp_blk = net[block[bnum].nets[MUXCY_O]].pins[inet];
						if (block[bnum].nets[MUXCY_O] == block[temp_blk].nets[MUXCY_CI] 
							|| block[bnum].nets[MUXCY_O] == block[temp_blk].nets[B_CIN] 
							|| block[temp_blk].type == XORCY 
							|| block[temp_blk].type == MUXCY_L 
							|| block[temp_blk].type == MUXCY  )
						{
							//COUT is connecting to CIN 
							block[in_blk].nets[B_COUT] = block[bnum].nets[MUXCY_O];  //set cout to muxcy_out
						}
						if (block[bnum].nets[MUXCY_O] != block[temp_blk].nets[MUXCY_CI] 
						&& block[bnum].nets[MUXCY_O] != block[temp_blk].nets[B_CIN] 
						&& block[temp_blk].type != XORCY 
						&& block[temp_blk].type != MUXCY_L 
						&& block[temp_blk].type != MUXCY  )
						{
							//connect to a LUT / FF input 
							block[in_blk].nets[B_YB] = block[bnum].nets[MUXCY_O]; //set to YB output to the LUT/ FF
							//set COUT to OPEN if not connect to next CIN
							block[in_blk].nets[B_COUT] = OPEN;  
						}
					}
					//block[in_blk].nets[B_COUT] = block[bnum].nets[MUXCY_O];  //cout

					//set cin to open if connect to VCC/GND
					temp_ipin = block[bnum].nets[MUXCY_CI];
					if (block[net[temp_ipin].pins[0]].type != INPAD &&  
						block[net[temp_ipin].pins[0]].type != GND &&  
						block[net[temp_ipin].pins[0]].type != VCC )
  
					{
						block[in_blk].nets[B_CIN] = block[bnum].nets[MUXCY_CI];  //cin 
					}
					else
						block[in_blk].nets[B_CIN] = OPEN;		

 
					//block[in_blk].nets[B_CIN] = block[bnum].nets[MUXCY_CI];  //cin 
					block[in_blk].use_muxcy = 1;	

					temp_blk = net[in_net].pins[0];	//check the input DI is MULTAND or not
					if (block[temp_blk].type == MULT_AND)
					{
						//Input of MULTAND should belong to G1, G2 of the block
						if (block[in_blk].nets[B_LUT_IN ] != OPEN)
						{
							if (block[temp_blk].nets[MULTAND_I0] != block[in_blk].nets[B_LUT_IN ])
							{
								if (block[temp_blk].nets[MULTAND_I0] != block[in_blk].nets[B_LUT_IN + 1])
								{
									printf("Error: the input of MULTAND is not consistent to LUT input \n");
									exit(1);
								}
							}
						}
						else
						{
							//G2 is not open now
							block[in_blk].nets[B_LUT_IN ] = block[temp_blk].nets[MULTAND_I0];
						}

						if (block[in_blk].nets[B_LUT_IN + 1] != OPEN)
						{
							if (block[temp_blk].nets[MULTAND_I1] != block[in_blk].nets[B_LUT_IN +1])
							{
								if (block[temp_blk].nets[MULTAND_I1] != block[in_blk].nets[B_LUT_IN])
								{
									printf("Error: the input of MULTAND is not consistent to LUT input \n");
									exit(1);
								}
							}
						}
						else
						{
							//G1 is not open now
							block[in_blk].nets[B_LUT_IN + 1] = block[temp_blk].nets[MULTAND_I1];
						}

						//remove MULTAND
						if (net[in_net].num_pins > 1) 
						{
							printf("Error: MULTAND output pin drive more than 1 net\n");
							exit(1);
						}
						net[in_net].pins[0] = OPEN;	// the DI pin of MUXCY disappear
						block[temp_blk].type = EMPTY;	//empty MULTAND
						block[in_blk].use_mult_and = 1;
					}
					else
					{
						//the MUXCY 's DI is connect to either G1 , G2, GND, VCC, BY
						if (block[temp_blk].type == GND)
						{
							block[in_blk].nets[B_GND] = block[bnum].nets[MUXCY_DI];
						}
						else if (block[temp_blk].type == VCC)
						{
							block[in_blk].nets[B_VCC] = block[bnum].nets[MUXCY_DI];
						}
						else
						{
							if (block[in_blk].nets[B_LUT_IN] !=  block[bnum].nets[MUXCY_DI])
							{

								if (block[in_blk].nets[B_LUT_IN +1] !=  block[bnum].nets[MUXCY_DI])
								{
									//connect to BY
									block[in_blk].nets[B_BY] = block[bnum].nets[MUXCY_DI];

									//move the receiver (DI) connection from outside to LUT
									if (block[bnum].nets[MUXCY_DI] != OPEN)
									{					 
										for (ipin = 0; ipin<net[block[bnum].nets[MUXCY_DI]].num_pins; ipin ++)
										{
											if (block[bnum].nets[MUXCY_DI] != OPEN)
											{ 
												if  (net[block[bnum].nets[MUXCY_DI]].pins[ipin] == bnum)
												{
													net[block[bnum].nets[MUXCY_DI]].pins[ipin] = in_blk;
												}
											}

										}					
									}
	
								}//connect to G2
							}//connect to G1
						}
					}

					block[bnum].type = EMPTY;   /* remove the muxcy */

					//move the driver (COUT) connection from MUXCY to LUT
					move_net_pin(bnum, MUXCY_O, in_blk);
					move_net_pin(bnum, MUXCY_CI, in_blk);
				}
			}
			else
			{
				//can't find the block with CIN connect to this muxcy
				temp_blk = net[in_net].pins[0];	//check the input DI is MULTAND or not
				if (block[temp_blk].type == MULT_AND)
				{
					//Input of MULTAND should belong to G1, G2 of the block

					//G2 is not open now
					block[in_blk].nets[B_LUT_IN] = block[temp_blk].nets[MULTAND_I0];
	
					//G1 is not open now
					block[in_blk].nets[B_LUT_IN +1 ] = block[temp_blk].nets[MULTAND_I1];
	

					//remove MULTAND
					if (net[in_net].num_pins > 1) 
					{
						printf("Error: MULTAND output pin drive more than 1 net\n");
						exit(1);
					}
					net[in_net].pins[0] = OPEN;	// the DI pin of MUXCY disappear
					block[temp_blk].type = EMPTY;	//empty MULTAND
					block[bnum].use_mult_and = 1;
					block[bnum].use_muxcy = 1;
				}
				else
				{
					//the MUXCY 's DI is connect to either G1 , G2, GND, VCC, BY
					if (block[temp_blk].type == GND)
					{
						block[bnum].nets[B_GND] = block[bnum].nets[MUXCY_DI];
					}
					else if (block[temp_blk].type == VCC)
					{
						block[bnum].nets[B_VCC] = block[bnum].nets[MUXCY_DI];
					}
					else
					{
						
							//connect to BY
							block[in_blk].nets[B_BY] = block[bnum].nets[MUXCY_DI];						
						}//connect to G1
					}
				}
			}									
	}
}



//pack the remaining LATCH
if (pass  ==7)
{
	printf("pass 7, pack the remaining FF\n");
	for (bnum = 0; bnum<num_blocks; bnum ++)
	{
		if (block[bnum].type == LATCH)
		{
			//printf("bnum %d (%s)\n" , bnum, block[bnum].name);
			//set the input / output of this FF
			block[bnum].nets[B_BY] = block[bnum].nets[FF_D];
			block[bnum].nets[B_CE] = block[bnum].nets[FF_CE];
			block[bnum].nets[B_SR] = block[bnum].nets[FF_SR];
			block[bnum].nets[B_CLK] = block[bnum].nets[FF_CLK];
			block[bnum].nets[B_Q] = block[bnum].nets[FF_Q];

		}
	}
}

if (pass  ==-1)
{
	printf("pass 7\n");
	for (bnum = 0; bnum<num_blocks; bnum ++)
	{
		if (block[bnum].type == LATCH)
		{
			//search any block have free space for this FF
			for (in_blk=0;in_blk<num_blocks;in_blk++) 
			{
				match_LUT = FALSE;
				if  (block[in_blk].type == LUT && block[in_blk].use_ff == 0) 
				{
					match_LUT = TRUE;

					//check the LUT have CIN/COUT or not
					//if there is carry in or out , check for the previous and next LUT to check for common 
					if (block[in_blk].nets[B_CIN] != OPEN)
					{
						//check the carry chain input 
						temp_blk = net[block[in_blk].nets[B_CIN]].pins[0];			

						if (block[temp_blk].use_ff == 1)
						{
							//the FF is used in the previous LUT, check the share pin CE, CLK, SR

							if (block[temp_blk].nets[B_CE] != OPEN && block[in_blk].nets[B_CE] != OPEN)
							{
								if (block[temp_blk].nets[B_CE]  != block[in_blk].nets[B_CE])
								{
									match_LUT =FALSE;
								}
								else
								{
									//one input use inv but the other not using inv
									if (block[temp_blk].use_inv_ce != block[in_blk].use_inv_ce)
									{
										match_LUT =FALSE;
									}
								}
							}

							if (block[temp_blk].nets[B_CLK] != OPEN && block[in_blk].nets[B_CLK] != OPEN)
							{
								if (block[temp_blk].nets[B_CLK]  != block[in_blk].nets[B_CLK])
								{
									match_LUT =FALSE;
								}
								else
								{
									//one input use inv but the other not using inv
									if (block[temp_blk].use_inv_clk != block[in_blk].use_inv_clk)
									{
										match_LUT =FALSE;
									}
								}
							}

							if (block[temp_blk].nets[B_SR] != OPEN && block[in_blk].nets[B_SR] != OPEN)
							{
								if (block[temp_blk].nets[B_SR]  != block[in_blk].nets[B_SR])
								{
									match_LUT =FALSE;
								}
								else
								{
									//one input use inv but the other not using inv
									if (block[temp_blk].use_inv_sr != block[in_blk].use_inv_sr)
									{
										match_LUT =FALSE;
									}
								}
							}							
						}
					}

					if (block[in_blk].nets[B_COUT] != OPEN)
					{
						//check the carry chain output 
						for (ipin = 1; ipin < net[block[in_blk].nets[B_COUT]].num_pins;  ipin++)
						{
							temp_blk = net[block[in_blk].nets[B_COUT]].pins[ipin];			
							if (block[temp_blk].use_ff == 1)
							{
								//the FF is used in the next LUT, check the share pin CE, CLK, SR

								if (block[temp_blk].nets[B_CE] != OPEN && block[in_blk].nets[B_CE] != OPEN)
								{
									if (block[temp_blk].nets[B_CE]  != block[in_blk].nets[B_CE])
									{
										match_LUT =FALSE;
									}
									else
									{
										//one input use inv but the other not using inv
										if (block[temp_blk].use_inv_ce != block[in_blk].use_inv_ce)
										{
											match_LUT =FALSE;
										}
									}
								}

								if (block[temp_blk].nets[B_CLK] != OPEN && block[in_blk].nets[B_CLK] != OPEN)
								{
									if (block[temp_blk].nets[B_CLK]  != block[in_blk].nets[B_CLK])
									{
										match_LUT =FALSE;
									}
									else
									{
										//one input use inv but the other not using inv
										if (block[temp_blk].use_inv_clk != block[in_blk].use_inv_clk)
										{
											match_LUT =FALSE;
										}
									}
								}

								if (block[temp_blk].nets[B_SR] != OPEN && block[in_blk].nets[B_SR] != OPEN)
								{
									if (block[temp_blk].nets[B_SR]  != block[in_blk].nets[B_SR])
									{
										match_LUT =FALSE;
									}
									else
									{
										//one input use inv but the other not using inv
										if (block[temp_blk].use_inv_sr != block[in_blk].use_inv_sr)
										{
											match_LUT =FALSE;
										}
									}
								}							
							}
						}							
					}

					
					if (match_LUT)
					{					
						if (block[in_blk].nets[B_BY] == OPEN)
						{
							//the BY is not used, can merge to this LUT
							block[in_blk].nets[B_BY] = block[bnum].nets[FF_D];
							block[in_blk].nets[B_CE] = block[bnum].nets[FF_CE];
							block[in_blk].nets[B_SR] = block[bnum].nets[FF_SR];
							block[in_blk].nets[B_CLK] = block[bnum].nets[FF_CLK];
							block[in_blk].nets[B_Q] = block[bnum].nets[FF_Q];
							block[in_blk].use_ff = 1;
							block[in_blk].use_inv_ce = block[bnum].use_inv_ce;
							block[in_blk].use_inv_clk = block[bnum].use_inv_clk;
							block[in_blk].use_inv_sr = block[bnum].use_inv_sr;

							if (block[in_blk].nets[B_Y] == OPEN) 
								block[in_blk].nets[B_Y] = block[in_blk].nets[LUT_D];

							block[in_blk].type = LUT_AND_LATCH;
							block[bnum].type = EMPTY;

							block[in_blk].probability = block_probability;
							block[in_blk].density = block_density;										

							//move the driver  connection from FF to LUT
							move_net_pin(bnum, FF_Q, in_blk);
							move_net_pin(bnum, FF_D, in_blk);
							move_net_pin(bnum, FF_CE, in_blk);
							move_net_pin(bnum, FF_SR, in_blk);
							move_net_pin(bnum, FF_CLK, in_blk);

							break;
						}			
						else
						{
							match_LUT = FALSE;
						}
					}
				}			
			}	

			if (match_LUT == FALSE)
			{				
				//set the input / output of this FF
				block[bnum].nets[B_BY] = block[bnum].nets[FF_D];
				block[bnum].nets[B_CE] = block[bnum].nets[FF_CE];
				block[bnum].nets[B_SR] = block[bnum].nets[FF_SR];
				block[bnum].nets[B_CLK] = block[bnum].nets[FF_CLK];
				block[bnum].nets[B_Q] = block[bnum].nets[FF_Q];
			}
			
		}		
	}
}

//Set the output pin "Y" to LUT_D
if (pass  ==8)
{
	printf("pass 8, set output Y to LUT_D\n");
	for (bnum = 0; bnum<num_blocks; bnum ++)
	{
		if (block[bnum].type == LUT)
		{
			if (block[bnum].use_xorcy == 0)
			{
				block[bnum].nets[B_Y] = block[bnum].nets[LUT_D];
			}
		}
	}
}

}


void compress_netlist (int lut_size) {

/* This routine removes all the EMPTY blocks and OPEN nets that *
 * may have been created by the ff_pack routine.  After this    *
 * routine, all the LUT+FF blocks that exist in the netlist     *
 * are in a contiguous list with no unused spots.  The same     *
 * goes for the list of nets.  This means that blocks and nets  *
 * have to be renumbered somewhat.                              */

 int inet, iblk, index, ipin, new_num_nets, new_num_blocks, max_pin;
 int *net_remap, *block_remap;
 int new_ipin;

 new_num_nets = 0;
 new_num_blocks = 0;
//printf("num_nets %d, num_blocks %d \n", num_nets, num_blocks);

 net_remap = my_malloc (num_nets * sizeof(int));
 block_remap = my_malloc (num_blocks * sizeof(int));

/*
for (iblk=0;iblk<num_blocks;iblk++) {
    if (block[iblk].type == VEB) {
		for(inet=0;inet<block[iblk].num_nets;inet++)
		{
			//printf("inet %d (%s) Net num %d\n",inet, net[block[iblk].nets[inet]].name,  block[iblk].nets[inet]);
//			printf("inet %d (%s),  Net num %d, net num pin %d\n",inet,  net[block[iblk].nets[inet]].name,block[iblk].nets[inet], net[block[iblk].nets[inet]].num_pins);
		}
    }
    else {
    }
 }
*/

printf("compress net \n");
//exit(1);
 for (inet=0;inet<num_nets;inet++) 
 {
	 //printf("inets %d (%s), pins[0] %d\n", inet, net[inet].name, net[inet].pins[0]);
	 //printf("inets %d (%s), pins[0] \n", inet, net[inet].name);
    if (net[inet].pins[0] != OPEN) 
	{
//		printf("num_pins %d\n", net[inet].num_pins);
		if (net[inet].num_pins > 1)
		{
       			net_remap[inet] = new_num_nets;
       			new_num_nets++;
		}
		else
		{
			net[inet].pins[0] = OPEN;
			net_remap[inet] = OPEN;
		}
    }
    else 
	{
       net_remap[inet] = OPEN;
    }
	
 }

printf("compress block \n");
 for (iblk=0;iblk<num_blocks;iblk++) {
    if (block[iblk].type != EMPTY) {
       block_remap[iblk] = new_num_blocks;
       new_num_blocks++;
    }
    else {
       block_remap[iblk] = -1;
    }
 }
//	printf("new_num_net %d, num_nets %d, new_num_blocks %d, num_blocks %d \n", new_num_nets, num_nets, new_num_blocks, num_blocks);
 if (new_num_nets != num_nets || new_num_blocks != num_blocks) {

    for (inet=0;inet<num_nets;inet++) 
	{
       if (net[inet].pins[0] != OPEN) 
	   {
          index = net_remap[inet];
          net[index] = net[inet];
		  new_ipin = 0;
          for (ipin=0;ipin<net[index].num_pins;ipin++)
		  { 
			 if (block_remap[net[index].pins[ipin]] != OPEN)
			 {
             	//net[index].pins[ipin] = block_remap[net[index].pins[ipin]];
				net[index].pins[new_ipin] = block_remap[net[index].pins[ipin]];
				new_ipin ++;
			 }
		  }
		  net[index].num_pins = new_ipin;
       }
       else {
          free (net[inet].name);
          free (net[inet].pins);
       }
    }
 
    num_nets = new_num_nets;
    net = (struct s_net *) my_realloc (net, num_nets * sizeof (struct s_net));
	
    for (iblk=0;iblk<num_blocks;iblk++)
	{
		
       if (block[iblk].type != EMPTY) {
          index = block_remap[iblk];
          block[index] = block[iblk];

          if (block[index].type == INPAD || block[index].type == OUTPAD || block[index].type == VCC || block[index].type == GND) 
             max_pin = 1;
          else if ((block[index].type == DSP) || (block[index].type == DSPS) || (block[index].type == MEMORY) || (block[index].type == VEB)) 
	  {
             	max_pin = block[index].num_nets;
//	 	printf("DSP or MEM or VEB. num nets %d.\n", block[index].num_nets); 
//		 printf("VEB %s num input %d, num output %d, num net %d .\n", block[index].name, block[index].num_input, block[index].num_output, block[index].num_nets); 
		//fflush(NULL);
	  }
          else 
             max_pin = lut_size+ B_LUT_IN ;
	
          for (ipin=0;ipin<max_pin;ipin++) 
	  {
          	if (block[index].nets[ipin] != OPEN) 
		{
					//printf("index %d, ipin %d, block.nets %d\n", index, ipin, block[index].nets[ipin]);
                 	block[index].nets[ipin] = net_remap[block[index].nets[ipin]];
	      	}
          	else 
                	block[index].nets[ipin] = OPEN;
          }
       }

       else 
       {
          free (block[iblk].name);
			 // The nets element is statically allocated, so I can't deallocate it.
	}
    }

    num_blocks = new_num_blocks;
    block = (struct s_block *) my_realloc (block, 
              num_blocks * sizeof (struct s_block));
			  
 }

/* Now I have to recompute the number of primary inputs and outputs, since *
 * some inputs may have been unused and been removed.  No real need to     *
 * recount primary outputs -- it's just done as defensive coding.          */

 num_p_inputs = 0;
 num_p_outputs = 0;
 
 for (iblk=0;iblk<num_blocks;iblk++) {
    if (block[iblk].type == INPAD || block[iblk].type == GND || block[iblk].type == VCC) 
       num_p_inputs++;
    else if (block[iblk].type == OUTPAD) 
       num_p_outputs++;
 }
 
 
 free (net_remap);
 free (block_remap);
}


int get_block_name_index(char *name)
{
  int iblk;

  for(iblk=0;iblk<num_blocks;iblk++) {
     if (strcmp(block[iblk].name, name) == 0) {
        return(iblk);
     }
  }
  return(-1);
}

void update_carryout_to()
{
   int iblk;
   int dest;
   for(iblk = 0;iblk<num_blocks;iblk++) {
      if ((block[iblk].type == LUT) ||
          (block[iblk].type == LUT_AND_LATCH)) {
         if (block[iblk].carryout_to != -1) {
            dest = get_block_name_index(block[iblk].carryout_to_name);
            if (dest == -1) {
                printf("Error constructing carry chain on compressed netlist: block %s does not exist\n",
                     block[iblk].carryout_to_name);
                exit(0);
	    }
            if ((block[dest].type != LUT) &&
                (block[dest].type != LUT_AND_LATCH)) {
                  printf("Error constructing carry chain on compressed netlist.\n");
                  printf("Block %s has carryout %s, but %s is not a LUT or LUT_AND_LATCH.\n",
                       block[iblk].name,
                       block[dest].name,
                       block[dest].name);
                  exit(0);
	    }
/*            printf("Block %s has carryout %s, changing %d to %d.\n",
                       block[iblk].name,
                       block[dest].name,
                       block[iblk].carryout_to, dest);
  */        
            block[iblk].carryout_to = dest;
	 }
      }
   }
}

boolean *alloc_and_load_is_clock (boolean global_clocks, int lut_size) {

/* Looks through all the block to find and mark all the clocks, by setting *
 * the corresponding entry in is_clock to true.  global_clocks is used     *
 * only for an error check.                                                */

 int num_clocks, bnum, clock_net;
 boolean *is_clock;

 num_clocks = 0;

 is_clock = (boolean *) my_calloc (num_nets, sizeof(boolean)); 
 //printf("size of boolean %d %d\n", sizeof(boolean), sizeof(int));
 //is_clock = (boolean *) malloc (num_nets * sizeof(boolean));

/* Want to identify all the clock nets.  */

 for (bnum=0;bnum<num_blocks;bnum++) 
 {
    if (block[bnum].type == LATCH || block[bnum].type == LUT_AND_LATCH  || block[bnum].type == MUXCY || block[bnum].type == MUXCY_L) {
       clock_net = block[bnum].nets[B_CLK];
	   if (clock_net != OPEN)
	   {
		if (is_clock[clock_net] == FALSE) {
			is_clock[clock_net] = TRUE;
			num_clocks++;
			//printf("Net %d (%s) is clock \n", clock_net, net[clock_net].name);
			//printf("Net %d is clock \n", clock_net);
		}
	   }
    } 
	/*
	else if (block[bnum].type == DSP ||  block[bnum].type == DSPS) 
	{
       if (block[bnum].num_of_each_type[2] > 0) {
          clock_net = block[bnum].nets[block[bnum].num_of_each_type[0]+
                                       block[bnum].num_of_each_type[1]];
          if (is_clock[clock_net] == FALSE) {
             is_clock[clock_net] = TRUE;
             num_clocks++;
          }
       }
    } else if (block[bnum].type == MEMORY) 
	{
       if (block[bnum].num_of_each_type[3] > 0) 
	   {

          clock_net = block[bnum].nets[block[bnum].num_of_each_type[0]+
                                       block[bnum].num_of_each_type[1]+
                                       block[bnum].num_of_each_type[2]];
          if (is_clock[clock_net] == FALSE) {
             is_clock[clock_net] = TRUE;
             num_clocks++;
          }
       }
	} else if (block[bnum].type == VEB) {
		if (block[bnum].num_of_each_type[2] > 0) 
		{
          clock_net = block[bnum].nets[block[bnum].num_of_each_type[0]+
                                       block[bnum].num_of_each_type[1]];
          if (is_clock[clock_net] == FALSE) {
             is_clock[clock_net] = TRUE;
             num_clocks++;
          }
       }
		
	}

	*/
 }

/* If we have multiple clocks and we're supposed to declare them global, *
 * print a warning message, since it looks like this circuit may have    *
 * locally generated clocks.                                             */

 if (num_clocks > 1 && global_clocks) {
    printf("Warning:  circuit contains %d clocks.\n", num_clocks);
    printf("          All will be marked global.\n");
 }

 return (is_clock);
}

int move_net_pin(int from_blk, int pin_num, int to_blk)
{
	int ipin;
	//move the connection from from_blk to  to_blk
	if (block[from_blk].nets[pin_num] != OPEN)
	{					
		for (ipin = 0; ipin<net[block[from_blk].nets[pin_num]].num_pins; ipin ++)
		{
			if (net[block[from_blk].nets[pin_num]].pins[ipin] == from_blk)
			{
				net[block[from_blk].nets[pin_num]].pins[ipin] = to_blk;
			}					
		}				
	}
	return 0;
}

