/***
*	ERIC CHABOD
*	ANTOINE MARTIN
*	D.E.A. M.E.M.I. 1992
*
*   Laurent WINCKEL
*
*	PROJET BSG : Barrel Shifter Generator
*
*	NOM:	 bsg_layo.c
*   VERSION: 2.00
*	DATE:	 (29/09/1993)
*	OBJET:	 generation du layout.
*/

static char *layo_ident="@(#)(BSG) layout view generation, version 2.00 (29/09/1993)";

/***
*	parties du shifter
*/

#define	P_HAT	"h"
#define P_DEC	"d"
#define P_SEL	"s"
#define P_LMX	"l"
#define P_MAT	"m"
#define P_RMX	"r"
#define P_OUT	"o"
#define P_ALI	"a"



/***
*	hauteurs du shifter 
*/

#define H_NON	""
#define H_TOP	"t"
#define H_MED	"m"
#define H_BOT	"b"
#define H_ODD	"i"



/***
*	bit slices
*/

#define B_HIGH	1
#define B_LOW	2



/***
*	declaration des variables 
*/

static char	*c_buff;	/* noms de cellules */

static char	*i_buff;	/* noms d'instances */
static char	*idx_buff;	/* noms d'instances indexees */

static char	*r_buff;	/* noms de references */



/* retour a la cellule du bas */

#define BACK_DOWN	DEF_PHINS( inst_idx(0) )



/* define pour les contacts et vias des and */

#define CONT_LEVEL( i )  ( ( ( ad_size == 5 && ( i == 2 || i == 3 || i == 4 ) ) || ( ad_size == 4 && ( i == 2 || i == 3 ) ) || ( ad_size == 3 && i == 2 ) || ( ( ad_size == 1 ) && ( i == 1 ) ) )? CONT_POLY : CONT_VIA )


/* piste autorisee */

#define T_ENA( i )  ( (i != 4) && (i != 6) && (i!= 7) && ( i!= 9 ) )

#define T_HENA0( i )  ( (i != 0) && (i != 1) && (i!= 2) && ( i!= 7 ) && ( i!= 8 ) && ( i!= 9 ) )
#define T_HENA1( i )  ( (i != 0) && (i != 1) && (i!= 2) && ( i!= 9 ) )

/* define pour savoir si le nombre de bits est impair */

#define ODD ( ( size % 2 == 0 )? 1 : 0 )
#define ODDA ( ( (size % 2 == 0) && (ad_size == bs_size) )? 1 : 0 )
#define H_ODDS ( ( size % 2 == 0 )? "i" : "" )


/***
*	fonction de formation du nom des
*	cellules.
*	elle recoit comme parametres la
*	partie de la cellule, le nom, eventuellement 
*	la hauteur, et la taille.
*/

static char *cell_name( partie, nom, hauteur, taille )
long	partie, hauteur, taille;
char	*nom;
{
	c_buff = NAME( "bs%s%s%s%d_c", partie, nom, hauteur, taille );
	return ( c_buff );
}



/***
*       fonction de formation du nom des instances.
*       elle recoit comme parametres la partie de 
*	la cellule, le nom et eventuellement
*       la hauteur.
*	elle place l'index a 0. On peut obtenir un 
*	autre index de la meme cellule en appelent 
*	inst_idx. 
*/
 
static char *instname( partie, nom )
long    partie;
char    *nom;
{
	idx_buff = NAME( "bs%s%s", partie, nom );
	i_buff = NAME( "%s[0]", idx_buff );
 
        return ( i_buff );
}



/***
*	fonction qui renvoie l'index corespondant pour l'instance en cours
*/

static char *inst_idx( index )
long index;
{

	i_buff = NAME( "%s[%d]", idx_buff, index );
	return ( i_buff );
}



/***
*	routine qui renvoie un nom de reference pour le decodage
*/

static char *dec_ref( adresse, bit, slice )
long adresse, bit, slice;
{
	if ( ( adresse & ( 1 << bit ) ) == 0 ) 
		r_buff = NAME( "ref_na%d_%d", bit, slice );
	else 
		r_buff = NAME( "ref_a%d_%d", bit, slice );

	return ( r_buff );
}



/***
*	routine qui renvoie un nom de reference pour les buffers
*/

static char *buf_ref( adresse, bit, slice )
long adresse, bit, slice;
{
	if ( bit == 0 ) 
		r_buff = NAME( "ref_cna%d_%d", adresse, slice );
	else 
		r_buff = NAME( "ref_ca%d_%d", adresse, slice );

	return ( r_buff );
}



/***
*	routine qui renvoie un nom de reference 
*	pour les commandes de la matrice
*/

static char *mat_ref( adresse, slice )
long adresse, slice;
{
	if ( adresse % 2 == 0 ) 
		r_buff = NAME( "ref_cl_%d", slice );
	else 
		r_buff = NAME( "ref_cr_%d", slice );

	return ( r_buff );
}




/***
* routine de placement des connecteurs flottants
*/
static void con_flot()
{
	long i, j;

	/* a gauche en bas */
	instname( P_DEC, "buf" );

	for( i = 0; i <= ad_size - ODDA; i++ )
	{
		inst_idx( i );

		/* donnee du bas */
		for( j = 0; j <= 9; j++ )
		{
			COPY_UP_REF( NAME( "in_d_2_%d", j ), i_buff, NAME( "in_d[%d]_%d", size - ( i * 2 ), j ) );
			PLACE_SEG_REF( i_buff, NAME( "in_d_2_%d", j ), TALU2, 2, WEST );
		}


		/* donnee du haut */
		for( j = 5; j <= 9; j++ )
		{
			COPY_UP_REF( NAME( "in_d_1_%d", j ), i_buff, NAME( "in_d[%d]_%d", size - ( i * 2 + 1 ), j ) );
			PLACE_SEG_REF( i_buff, NAME( "in_d_1_%d", j ), TALU2, 2, WEST );
		}

		/* commande */
		for( j = 0; j <= 4; j++ )
		{
			COPY_UP_REF( NAME( "in_s_%d", j ), i_buff, NAME( "in_s[%d]_%d", ad_size - i, j ) );
			PLACE_SEG_REF( i_buff, NAME( "in_s_%d", j ), TALU2, 2, WEST );
		}
	}

	if ( ODDA )
	{
		inst_idx( bs_size );

		/* donnee du bas */
		for( j = 0; j <= 9; j++ )
		{
			COPY_UP_REF( NAME( "in_d_2_%d", j ), i_buff, NAME( "in_d[%d]_%d", size - ( i * 2 ), j ) );
			PLACE_SEG_REF( i_buff, NAME( "in_d_2_%d", j ), TALU2, 2, WEST );
		}


		/* commande */
		for( j = 0; j <= 4; j++ )
		{
			COPY_UP_REF( NAME( "in_s_%d", j ), i_buff, NAME( "in_s[%d]_%d", 0, j ) );
			PLACE_SEG_REF( i_buff, NAME( "in_s_%d", j ), TALU2, 2, WEST );
		}
	}
		
	
	/* a gauche en haut */
	instname( P_DEC, "ept" );

	for( i = ad_size + 1; i <= bs_size - ODD; i++ )
	{
		inst_idx( i );

		for( j = 0; j <= 9; j++ )
		{
			COPY_UP_REF( NAME( "in_d_2_%d", j ), i_buff, NAME( "in_d[%d]_%d", size - ( 2 * i ), j ) );
			PLACE_SEG_REF( i_buff, NAME( "in_d_2_%d", j ), TALU2, 2, WEST );
			COPY_UP_REF( NAME( "in_d_1_%d", j ), i_buff, NAME( "in_d[%d]_%d", size - ( 2 * i + 1 ), j ) );
			PLACE_SEG_REF( i_buff, NAME( "in_d_1_%d", j ), TALU2, 2, WEST );
		}
	}


	if ( ODD && !( ad_size == bs_size ) )
	{
		inst_idx( bs_size );

		for( j = 0; j <= 9; j++ )
		{
			COPY_UP_REF( NAME( "in_d_2_%d", j ), i_buff, NAME( "in_d[%d]_%d", 0, j ) );
			PLACE_SEG_REF( i_buff, NAME( "in_d_2_%d", j ), TALU2, 2, WEST );
		}
	}




	/* a droite */
	instname( P_OUT, "out" );

	for( i = 0; i <= bs_size - ODD; i++ )
	{
		inst_idx( i );

		/* donnees en entree */
		for( j = 7; j <= 9; j++ )
		{
			COPY_UP_REF( NAME( "in_d_2_%d", j ), i_buff, NAME( "in_d[%d]_%d", size - ( i * 2 ), j ) );
			PLACE_SEG_REF( i_buff, NAME( "in_d_2_%d", j ), TALU2, 2, EAST );

			COPY_UP_REF( NAME( "in_d_1_%d", j ), i_buff, NAME( "in_d[%d]_%d", size - ( i * 2 + 1 ), j ) );
			PLACE_SEG_REF( i_buff, NAME( "in_d_1_%d", j ), TALU2, 2, EAST );
		}

		/* donnees en sortie */
		for( j = 4; j <= 6; j++ )
		{
			COPY_UP_REF( NAME( "out_d_2_%d", j ), i_buff, NAME( "out_d[%d]_%d", size - ( i * 2 ), j ) );
			PLACE_SEG_REF( i_buff, NAME( "out_d_2_%d", j ), TALU2, 2, EAST );

			COPY_UP_REF( NAME( "out_d_1_%d", j ), i_buff, NAME( "out_d[%d]_%d", size - ( i * 2 + 1 ), j ) );
			PLACE_SEG_REF( i_buff, NAME( "out_d_1_%d", j ), TALU2, 2, EAST );
		}
	}

	if ( ODD )
	{
                inst_idx( bs_size );
 
                /* donnees en entree */
                for( j = 7; j <= 9; j++ )
                {
                        COPY_UP_REF( NAME( "in_d_2_%d", j ), i_buff, NAME( "in_d[%d]_%d", 0, j ) );
                        PLACE_SEG_REF( i_buff, NAME( "in_d_2_%d", j ), TALU2, 2, EAST );
                }
 
                /* donnees en sortie */
                for( j = 4; j <= 6; j++ )
                {
                        COPY_UP_REF( NAME( "out_d_2_%d", j ), i_buff, NAME( "out_d[%d]_%d", 0, j ) );
                        PLACE_SEG_REF( i_buff, NAME( "out_d_2_%d", j ), TALU2, 2, EAST );
                }
        }
}



/***
* routine de placement des connecteurs en dur
*/
static void con_dur()
{
	long i;

	/* a gauche en bas */
	instname( P_DEC, "buf" );

	for( i = 0; i <= ad_size - ODDA; i++ )
	{
		inst_idx( i );

		/* donnee du bas */
		PLACE_VIA_REF( i_buff, "in_d_2_7", CONT_VIA );
		PLACE_CON_REF( inst_idx( i ), "in_d_2_7", NAME( "in_d[%d]", size - ( i * 2 ) ), ALU2, 2, WEST );

		/* donnee du haut */
		PLACE_VIA_REF( i_buff, "in_d_1_7", CONT_VIA );
		PLACE_CON_REF( i_buff, "in_d_1_7", NAME( "in_d[%d]", size - ( i * 2 + 1 ) ), ALU2, 2, WEST );

		/* commande */
		PLACE_VIA_REF( i_buff, "in_s_4", CONT_VIA );
		PLACE_CON_REF( i_buff, "in_s_4", NAME( "in_s[%d]", ad_size - i ), ALU2, 2, WEST );
	}

	if ( ODDA )
	{
                inst_idx( bs_size );

                /* donnee du bas */
                PLACE_VIA_REF( i_buff, "in_d_2_7", CONT_VIA );
                PLACE_CON_REF( inst_idx( i ), "in_d_2_7", NAME( "in_d[%d]", 0 ), ALU2, 2, WEST );

                /* commande */
                PLACE_VIA_REF( i_buff, "in_s_4", CONT_VIA );
                PLACE_CON_REF( i_buff, "in_s_4", NAME( "in_s[%d]", 0 ), ALU2, 2, WEST );
        }	
	
	/* a gauche en haut */
	instname( P_DEC, "ept" );

	for( i = ad_size + 1; i <= bs_size - ODD; i++ )
	{
		inst_idx( i );

		PLACE_VIA_REF( i_buff, "in_d_2_7", CONT_VIA );
		PLACE_CON_REF( i_buff, "in_d_2_7", NAME( "in_d[%d]", size - (i*2) ), ALU2, 2, WEST );

		PLACE_VIA_REF( i_buff, "in_d_1_7", CONT_VIA );
		PLACE_CON_REF( i_buff, "in_d_1_7", NAME( "in_d[%d]", size - (i*2+1) ), ALU2, 2, WEST );
	}

	if ( ODD && !( bs_size == ad_size ) )
        {
                inst_idx( bs_size );

                PLACE_VIA_REF( i_buff, "in_d_2_7", CONT_VIA );
                PLACE_CON_REF( i_buff, "in_d_2_7", NAME( "in_d[%d]", 0 ), ALU2, 2, WEST );
        }

	/* a droite */
	instname( P_OUT, "out" );

	for( i = 0; i <= bs_size - ODD; i++ )
	{
		inst_idx( i );

		PLACE_VIA_REF( i_buff, "in_d_1_7", CONT_VIA );
		PLACE_VIA_REF( i_buff, "in_d_2_7", CONT_VIA );
		PLACE_VIA_REF( i_buff, "out_d_1_6", CONT_VIA );
		PLACE_VIA_REF( i_buff, "out_d_2_6", CONT_VIA );

		PLACE_CON_REF( i_buff, "in_d_2_7", NAME( "in_d[%d]", size - (i*2) ), ALU2, 2, EAST );
		PLACE_CON_REF( i_buff, "in_d_1_7", NAME( "in_d[%d]", size - (i*2+1) ), ALU2, 2, EAST );

		PLACE_CON_REF( i_buff, "out_d_2_6", NAME( "out_d[%d]", size - (i*2) ), ALU2, 2, EAST );
		PLACE_CON_REF( i_buff, "out_d_1_6", NAME( "out_d[%d]", size - (i*2+1) ), ALU2, 2, EAST );
	}


	if ( ODD )
        {
                inst_idx( bs_size );
 
                PLACE_VIA_REF( i_buff, "in_d_2_7", CONT_VIA );
                PLACE_VIA_REF( i_buff, "out_d_2_6", CONT_VIA );
 
                PLACE_CON_REF( i_buff, "in_d_2_7", NAME( "in_d[%d]", 0 ), ALU2, 2, EAST );
 
                PLACE_CON_REF( i_buff, "out_d_2_6", NAME( "out_d[%d]", 0 ), ALU2, 2, EAST );
        }
}



/***
*	routine de placement des cellules.
*	elle accepte comme argument un boleen qui 
*	indique si les connecteurs doivent etre places
*	en dur.
*/

static void gen_layout( virtual, msb0, physical_box )
long virtual, msb0, physical_box;
{
	long i, j;

	DEF_PHFIG( name );


	/* placement des buffers */
	PLACE( cell_name( P_DEC, "buf", H_NON, 32 ), instname( P_DEC, "buf" ), NOSYM, 0, 0 );

	for( i = 1; i <= ad_size - ODDA; i++ ) 
		PLACE_TOP( c_buff, inst_idx( i ), NOSYM );
	
	if ( ODDA ) 
		PLACE_TOP( cell_name( P_DEC, "buf", H_ODD, 32 ), inst_idx( ad_size ), NOSYM );


	/* placement des cellules vides */
	cell_name( P_DEC, "ept", H_NON, 32 );
	instname( P_DEC, "ept" );

	for( i = ad_size + 1; i <= bs_size - ODD; i++ )
		PLACE_TOP( c_buff, inst_idx( i ), NOSYM );

	if ( ODD && ( ad_size != bs_size ) )
		PLACE_TOP( cell_name( P_DEC, "ept", H_ODD, 32 ), inst_idx( bs_size ), NOSYM );


	/* placement des and de decodage */
	DEF_PHINS( instname( P_DEC, "buf" ) );
	PLACE_RIGHT( cell_name( P_DEC, "and", H_NON, r_size ), instname( P_DEC, "and" ), NOSYM );

	for ( i = 1; i <= ad_size-ODDA; i++ ) 
		PLACE_TOP( c_buff, inst_idx( i ), NOSYM );

	for(i=ad_size+1-ODDA;i<=bs_size-ODD;i++)
		PLACE_TOP(NAME("bsdandh%d_c",r_size),inst_idx(i),NOSYM);

	if ( ODD )
		if( size > 4 ) /* Eh ben oui il y a eu un size-- */
			PLACE_TOP( NAME("bs%s%s%s%d_c", P_DEC, "andh", H_ODD, r_size),
                           inst_idx( bs_size ), NOSYM );
   		else
			PLACE_TOP( NAME("bs%s%s%s%d_c", P_DEC, "and", H_ODD, r_size),
                           inst_idx( bs_size ), NOSYM );

	/* placement des selecteurs */
	BACK_DOWN;

	PLACE_RIGHT( cell_name( P_SEL, "sel", H_MED, 32 ), instname( P_SEL, "sel" ), NOSYM );

	for ( i = 1; i <= bs_size - 1; i++ ) 
		PLACE_TOP( c_buff, inst_idx( i ), NOSYM );

	if ( ODD )
		PLACE_TOP( cell_name( P_SEL, "sel", H_ODD, 32 ), inst_idx( bs_size ), NOSYM );
	else
		PLACE_TOP( cell_name( P_SEL, "sel", H_TOP, 32 ), inst_idx( bs_size ), NOSYM );



	/* placement des bleeders */
	BACK_DOWN;
	PLACE_RIGHT( cell_name( P_SEL, "nbl", H_MED, 32 ), instname( P_SEL, "nbl" ), NOSYM );

	for ( i = 1; i <= bs_size - 1; i++ ) 
		PLACE_TOP( c_buff, inst_idx( i ), NOSYM );

	if ( ODD )
		PLACE_TOP( cell_name( P_SEL, "nbl", H_ODD, 32 ), inst_idx( bs_size ), NOSYM );
	else
		PLACE_TOP( cell_name( P_SEL, "nbl", H_TOP, 32 ), inst_idx( bs_size ),NOSYM );



	/* placement des multiplexeurs */
	BACK_DOWN;
	PLACE_RIGHT( cell_name( P_LMX, "mux", H_MED, 32 ), instname( P_LMX, "mux" ), NOSYM );

	for ( i = 1; i <= bs_size - 1; i++ ) 
		PLACE_TOP( c_buff, inst_idx( i ), NOSYM );

	if ( ODD )
		PLACE_TOP( cell_name( P_LMX, "mux", H_ODD, 32 ), inst_idx( bs_size ), NOSYM );
	else
		PLACE_TOP( cell_name( P_LMX, "mux", H_TOP, 32 ), inst_idx( bs_size ), NOSYM );


	/* placement des cellules de gauche de la matrice */
	BACK_DOWN;
	PLACE_RIGHT( cell_name( P_MAT, "lef", H_NON, 32 ), instname( P_MAT, "[0]" ), NOSYM );

	for ( i = 1; i <= bs_size - ODD; i++ ) 
		PLACE_TOP( c_buff, inst_idx( i ), NOSYM );

	if ( ODD )
		PLACE_TOP( cell_name( P_MAT, "lef", H_ODD, 32 ), inst_idx( bs_size ), NOSYM );


	/* placement des cellules de la matrice */
	BACK_DOWN;

	for( j = 1; j <= bs_size; j++ )
	{
		PLACE_RIGHT( cell_name( P_MAT, "mat", H_NON, 32 ), instname( P_MAT, NAME( "[%d]", j ) ), NOSYM );

		for( i = 1; i <= bs_size - ODD; i++ ) 
			PLACE_TOP( c_buff, inst_idx( i ), NOSYM );

		if ( ODD )
			PLACE_TOP( cell_name( P_MAT, "mat", H_ODD, 32 ), inst_idx( bs_size ), NOSYM );

		BACK_DOWN;
	}



	/* placement des cellules de droite de la matrice */
	if ( !ODD )
	{
		PLACE_RIGHT( cell_name( P_MAT, "rig", H_NON, 32 ), instname( P_MAT, NAME( "[%d]", bs_size + 1 ) ), NOSYM );

		for ( i = 1; i <= bs_size; i++ ) 
			PLACE_TOP( c_buff, inst_idx( i ), NOSYM );
		BACK_DOWN;
	}


	/* placement des multiplexeurs */
	PLACE_RIGHT( cell_name( P_RMX, "mux", H_NON, 32 ), instname( P_RMX, "mux" ), NOSYM );

	for( i = 1; i <= bs_size - ODD; i++ ) 
		PLACE_TOP( c_buff, inst_idx( i ), NOSYM );

	if ( ODD )
		PLACE_TOP( cell_name( P_RMX, "mux", H_ODD, 32 ), inst_idx( bs_size ), NOSYM );


	/* placement des inverseurs de sortie */
	BACK_DOWN;
	PLACE_RIGHT( cell_name( P_OUT, "out", H_NON, 32 ), instname( P_OUT, "out" ), NOSYM );

	for( i = 1; i <= bs_size - ODD; i++ ) 
		PLACE_TOP( c_buff, inst_idx( i ), NOSYM );

	if ( ODD )
		PLACE_TOP( cell_name( P_OUT, "out", H_ODD, 32 ), inst_idx( bs_size ), NOSYM );


	/* placement des rappels d'alimentations */
	BACK_DOWN;
	PLACE_RIGHT( "bsalim_c", instname( P_ALI, "lim" ), NOSYM );

	for( i = 1; i <= bs_size; i++ ) 
		PLACE_TOP( "bsalim_c", inst_idx( i ), NOSYM );

	PLACE_TOP( "bshalim_c", instname( P_HAT, "alim" ), NOSYM );


	/* chapeau */
	if ( bs_size != ad_size )
		instname( P_DEC, "ept" );
	else
		instname( P_DEC, "buf" );

	DEF_PHINS( inst_idx( bs_size ) );

	PLACE_TOP( cell_name( P_HAT, "ept", H_NON, 32 ), instname( P_HAT, "ept" ), NOSYM );
	PLACE_RIGHT( cell_name( P_HAT, "and", H_NON, r_size ), instname( P_HAT, "and" ), NOSYM );


	PLACE_RIGHT( cell_name( P_HAT, "sel", H_ODDS, 32 ), instname( P_HAT, "sel" ), NOSYM );
	PLACE_RIGHT( cell_name( P_HAT, "lmx", H_ODDS, 32 ), instname( P_HAT, "lmx" ), NOSYM );
	PLACE_RIGHT( cell_name( P_HAT, "cmd", H_ODDS, 32 ), instname( P_HAT, "cmd" ), NOSYM );

	cell_name( P_HAT, "mat", H_ODDS, 32 );
	instname( P_HAT, "mat" );

	for ( i = 0; i <= bs_size - 1; i++ )
		PLACE_RIGHT( c_buff, inst_idx( i ), NOSYM );

	if ( !ODD )
		PLACE_RIGHT( cell_name( P_HAT, "matr", H_NON, 32 ), instname( P_HAT, "matr" ), NOSYM );

	PLACE_RIGHT( cell_name( P_HAT, "rmx", H_NON, 32 ), instname( P_HAT, "rmx" ), NOSYM );
	PLACE_RIGHT( cell_name( P_HAT, "out", H_NON, 32 ), instname( P_HAT, "out" ), NOSYM );



	/* placement des vias pour les nand */

	instname( P_DEC, "and" );

	for( i = 0; i <= bs_size - 1; i++ )
		for( j = 0; j <= ad_size; j++ )
		{
			PLACE_VIA_REF( inst_idx( i ), dec_ref( i + 1, j, B_LOW ), CONT_LEVEL( j ) );
			PLACE_VIA_REF( inst_idx( i ), dec_ref( size - i, j, B_HIGH ), CONT_LEVEL( j ) );
		}


	for( j = 0; j <= ad_size; j++ )
	{
		if ( !ODD )
			PLACE_VIA_REF( inst_idx( bs_size ), dec_ref( bs_size + 1, j, B_LOW ), CONT_LEVEL( j ) );
		PLACE_VIA_REF( inst_idx( bs_size ), dec_ref( 0, j, B_HIGH ), CONT_LEVEL( j ) );
	}


	/* placement des vias pour les buffers */
	for( i = 0; i <= ad_size; i++ )
	{
		PLACE_VIA_REF( inst_idx( i ), buf_ref( i, 1, B_LOW ), CONT_VIA );
		PLACE_VIA_REF( inst_idx( i ), buf_ref( i, 0, B_HIGH ), CONT_VIA );
	}



	/* placement des commandes de la matrice */
	for ( i = 0; i <= bs_size - 1; i++ )
	{
		instname( P_MAT, NAME( "[%d]", (i + 1)/ 2 ) );
		PLACE_VIA_REF( inst_idx( i ), mat_ref( i + 1, B_LOW ), CONT_VIA );

		instname( P_MAT, NAME( "[%d]", (size - i) / 2 ) );
		PLACE_VIA_REF( inst_idx( i ), mat_ref( size - i, B_HIGH ), CONT_VIA );
	}

	if ( ODD )
	{
		instname( P_MAT, NAME( "[%d]", bs_size ) );
		PLACE_VIA_REF( inst_idx( bs_size ), mat_ref( size + 1, B_HIGH ), CONT_VIA );
	}
	else
	{
		instname( P_MAT, NAME( "[%d]", (bs_size + 1) / 2 ) );
		PLACE_VIA_REF( inst_idx( bs_size ), mat_ref( bs_size + 1, B_LOW ), CONT_VIA );

		instname( P_MAT, "[0]" );
		PLACE_VIA_REF( inst_idx( bs_size ), mat_ref( 0, B_HIGH ), CONT_VIA );
	}

	if ( virtual )
	    DEF_AB( 0, 0, 0, 0 );
    else
	    DEF_AB( 0, -(4+3), 0, (4+3) );

	/* placement des alims */
	for( i = 0; i <= bs_size + 2; i++ )
		THRU_CON_H( ALU2, 8, "VSS",  i * 120  );

	for( i = 0; i <= bs_size + 1; i++ )
		THRU_CON_H( ALU2, 6, "VDD", 60 + ( i * 120 ) );

	COPY_UP_CON_FACE( SOUTH, "VSS", instname( P_ALI, "lim" ), "VSS" );
	COPY_UP_CON_FACE( SOUTH, "VDD", instname( P_ALI, "lim" ), "VDD" );

	COPY_UP_CON_FACE( NORTH, "VSS", instname( P_HAT, "alim" ), "VSS" );
	COPY_UP_CON_FACE( NORTH, "VDD", instname( P_HAT, "alim" ), "VDD" );

	/* placement des transparences */
	for( i = 0; i<= bs_size; i++ )
	{
		for( j = 9; j >= 0; j-- )
			if T_ENA( j )
				THRU_H( TALU2, 2, (120 * i) + 8 + (5 * (9 - j)) );

		for( j = 0; j <= 9; j++ )
			if T_ENA( j )
				THRU_H( TALU2, 2, (120 * i) + 67 + (5 * j) );
	}

	for( j = 9; j >= 0; j-- )
		if T_HENA0( j )
			THRU_H( TALU2, 2, (120 * i) + 8 + (5 * (9 - j)) );

	for( j = 0; j <= 9; j++ )
		if T_HENA1( j )
			THRU_H( TALU2, 2, (120 * i) + 67 + (5 * j) );
	

	/* placement d'une transparence pour la donnee du haut dans le cas impair */
	if ( ODD )
		THRU_H( TALU2, 2, (120 * bs_size) + 102 );

	/* remontee des references de NWELL */
	instname( P_ALI, "lim" );

	for( i = 0; i <= bs_size; i++ )
	{
		COPY_UP_REF( "nwell_1", inst_idx( i ), NAME( "nwellr%d_28", size - (i*2+1) ) );
		COPY_UP_REF( "nwell_2", i_buff, NAME( "nwellr%d_28", size - i * 2 ) );
	}

	COPY_UP_REF( "nwell", instname( P_HAT, "alim" ), "nwellhr_68" );

	instname( P_DEC, "buf" );

	for( i = 0; i <= ad_size; i++ )
	{
		COPY_UP_REF( "nwell_1", inst_idx( i ), NAME( "nwelll%d_28", size - (i*2+1) ) );
		COPY_UP_REF( "nwell_2", i_buff, NAME( "nwelll%d_28", size - i * 2 ) );
	}

	instname( P_DEC, "ept" );

	for( i = ad_size + 1; i <= bs_size; i++ )
	{
		COPY_UP_REF( "nwell_1", inst_idx( i ), NAME( "nwelll%d_28", size - (i*2+1) ) );
		COPY_UP_REF( "nwell_2", i_buff, NAME( "nwelll%d_28", size - i * 2 ) );
	}

	COPY_UP_REF( "nwell", instname( P_HAT, "ept" ), "nwellhl_68" ); 

	if ( virtual )
		con_flot();	
	else 
		con_dur();		

	/* connecteurs sur le chapeau */
	COPY_UP_CON_FACE( NORTH, "left", instname( P_HAT, "sel" ), "left" );
	COPY_UP_CON_FACE( NORTH, "ext", instname( P_HAT, "cmd" ), "ext" );
	COPY_UP_CON_FACE( NORTH, "rot", instname( P_HAT, "cmd" ), "rot" );

    if ( !msb0 )
	{
        REVERSE_PHCON("in_s");
        REVERSE_PHCON("in_d");
        REVERSE_PHCON("out_d");
	}

	if ( !physical_box ) 
    	SAVE_PHFIG();

/*
	PRINTF( "Layout generated...\n" );
*/
}
