
/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit : ring router                                                 */
/*    Fichier : distance.c                                                     */
/*                                                                          */
/*    (c) copyright 1992 Laboratoire MASI equipe CAO & VLSI                 */
/*    Tous droits reserves                                                  */
/*    Support : e-mail cao-vlsi@masi.ibp.fr                                 */
/*                                                                          */
/*    Ecrit   par : Olivier Van Hautte                  le : 01/08/92       */
/*    Modifie par : Franck Wajsburt                     le :   /  /         */
/*                                                                          */
/****************************************************************************/

/*-----------------------------------------------------------------------------------*/

/* RING 19 aout 92                   DISTANCE.C                               */

#include <stdio.h>
#include <string.h>
#include "includes.h"
#include "struct.h"

/*-----------------------------------------------------------------------------------*/

/* Calcul de la distance entre deux connecteurs */
/* Si un des connecteurs n'est pas de largeur standard, on calcul la distance reelle.
   A ce moment on prend en compte l'encombrement d'un via
   S'ils sont de largeur standard alors la distance est la diff des coordonnees      */

long	distance_con_con(x1, y1, w1, l1, x2, y2, w2, l2, face)
long	x1, y1, w1;
char	l1;
long	x2, y2, w2;
char	l2;
int	face;
{
	long	dist, xa, ya, wa;
	long	largeurmin, dminmetalmetal;
	char	la;

	switch (face) {
	case NORD:
	case SUD :
		/* on garde dans x1 ,y1 les plus petites coordonnees */
		if (x2 < x1) { 
			xa = x1;
			ya = y1;
			wa = w1;
			la = l1; 
			x1 = x2; 
			y1 = y2; 
			w1 = w2; 
			l1 = l2;
			x2 = xa; 
			y2 = ya; 
			w2 = wa; 
			l2 = la;
		}

		dminmetalmetal = ymetal_dmin;

		if ((l1 != ymetal) || (l2 != ymetal)) {
			if (ymetal_width < xmetal_width) 
				largeurmin = ymetal_width;
			else 
				largeurmin = xmetal_width;
		} else
		 {
			largeurmin = ymetal_width;
		}

		if ((w1 > largeurmin) || (w2 > largeurmin)) {
			dist = x2 - x1 - w2 / 2 - w1 / 2;
			if ((w1 < taille_via) && (w2 < taille_via)) 
				dist -= (taille_via - w1 / 2 - w2 / 2);
			else if ((w1 < taille_via) && !(w2 < taille_via)) 
				dist -= (taille_via / 2 - w1 / 2);
			else if (!(w1 < taille_via) && (w2 < taille_via)) 
				dist -= (taille_via / 2 - w2 / 2);
		} else 
			dist = x2 - x1;

		return(dist);
		break;

	case EST  :
	case OUEST:
		/* on garde dans x1 ,y1 les plus petites coordonnees */
		if (y2 < y1) { 
			xa = x1;
			ya = y1;
			wa = w1;
			la = l1; 
			x1 = x2; 
			y1 = y2; 
			w1 = w2; 
			l1 = l2;
			x2 = xa; 
			y2 = ya; 
			w2 = wa; 
			l2 = la;
		}

		dminmetalmetal = xmetal_dmin;

		if ((l1 != xmetal) || (l2 != xmetal)) {
			if (ymetal_width < xmetal_width) 
				largeurmin = ymetal_width;
			else 
				largeurmin = xmetal_width;
		} else
		 {
			largeurmin = xmetal_width;
		}

		if ((w1 > largeurmin) || (w2 > largeurmin)) {
			dist = y2 - y1 - w2 / 2 - w1 / 2;
			if ((w1 < taille_via) && (w2 < taille_via)) 
				dist -= (taille_via - w1 / 2 - w2 / 2);
			else if ((w1 < taille_via) && !(w2 < taille_via)) 
				dist -= (taille_via / 2 - w1 / 2);
			else if (!(w1 < taille_via) && (w2 < taille_via)) 
				dist -= (taille_via / 2 - w2 / 2);
		} else 
			dist = y2 - y1;

		return(dist);
		break;
	}

}

/*-----------------------------------------------------------------------------------------*/
/* Cette fonction utilisee pour la fabrication de nouveaux pas de grille
   parcoure toutes les coordonnees precedentes correspondant a des pseudo-connecteurs
   pour donner la distance minimum qu'il existe entre le connecteur
   et les connecteurs precedents d'alim. Ceci pour corriger un bug
   qui vient du fait que des alim peuvent etre en vis a vis et que
   si on calcule seulement la distance avec le connecteur precedent
   on ne prend peut etre pas en compte un connecteur d'alim voisin
   plus gros qui recouvre largement le connecteur precedent.          
   on retourne une coordonnee qui est soit la precedente soit
   une autre qui rcouvre la coordonne precedente */

PT_COORDONNEES existe_con_precalim(x2, y2, w2, l2, face, liste_coor, distance)
long	x2, y2, w2;
char	l2;
int	face;
PT_COORDONNEES liste_coor;
long	distance;
{
	long	mindist = distance;
	long	dist;
	LST_PSEUDO_CON con;
	PT_COORDONNEES coordalim = NULL;

	if (mode_debug) 
		printf("Existeprecalim x %ld y %ld face %d ptcoor %d\n\n", x2, y2, face, (int)liste_coor);

	switch (face) {
	case NORD:
	case SUD:
		while (NULL != liste_coor) {
			if ((NULL != liste_coor->proprio) && ((eq_vdd == ((LST_PSEUDO_CON)liste_coor->proprio)->nom_con)  ||
			    (eq_vss == ((LST_PSEUDO_CON)liste_coor->proprio)->nom_con)) && (liste_coor->xabs < x2)) {
				con = ((LST_PSEUDO_CON)liste_coor->proprio);
				dist = distance_con_con(liste_coor->xabs, liste_coor->yabs, con->largeur, con->layer, x2,
				     y2, w2, l2, face);

				if (dist < mindist) {
					mindist = dist; 
					coordalim = liste_coor;
				}
			}

			if (liste_coor->xabs >= x2) 
				break;
			else 
				liste_coor = liste_coor->suiv;
		}

		return(coordalim);

		break;

	case EST:
	case OUEST:
		while (NULL != liste_coor) {
			if ((NULL != liste_coor->proprio) && ((eq_vdd == ((LST_PSEUDO_CON)liste_coor->proprio)->nom_con)  ||
			    (eq_vss == ((LST_PSEUDO_CON)liste_coor->proprio)->nom_con)) && (liste_coor->yabs < y2)) {
				con = ((LST_PSEUDO_CON)liste_coor->proprio);
				dist = distance_con_con(liste_coor->xabs, liste_coor->yabs, con->largeur, con->layer, x2,
				     y2, w2, l2, face);

				if (dist < mindist) {
					mindist = dist; 
					coordalim = liste_coor;
				}
			}

			if (liste_coor->yabs >= y2) 
				break;
			else 
				liste_coor = liste_coor->suiv;
		}

		return(coordalim);

		break;
	}

}

/*-----------------------------------------------------------------------------------------*/
/* Cette fonction utilisee pour la fabrication de nouveaux pas de grille
   parcoure toutes les coordonnees suivantes correspondant a des pseudo-connecteurs
   pour donner la distance minimum qu'il existe entre le connecteur
   et les connecteurs suivants d'alim. Ceci pour corriger un bug
   qui vient du fait que des alim peuvent etre en vis a vis et que
   si on calcule seulement la distance avec le connecteur suivant
   on ne prend peut etre pas en compte un connecteur d'alim voisin
   plus gros qui recouvre largement le connecteur precedent.    
   on retourne une coordonnee soit la precedente soit une autre qui
   recouvre la precedente.      */

PT_COORDONNEES existe_con_suiv(x1, y1, w1, l1, face, liste_coor)
long	x1, y1, w1;
char	l1;
int	face;
PT_COORDONNEES liste_coor;
{
	long	mindist = 0;
	int	first = 1;
	long	dist;
	LST_PSEUDO_CON con;
	PT_COORDONNEES coordalim = NULL;

	if (mode_debug) 
		printf("Existesuivalim x %ld y %ld face %d ptcoor %d\n\n", x1, y1, face, (int)liste_coor);

	switch (face) {
	case NORD:
	case SUD:
		while (NULL != liste_coor) {
			if (mode_debug) 
				printf("ptcoor %d proprio %d x %ld\n", (int) liste_coor, (int)liste_coor->proprio, liste_coor->xabs);

			if (NULL != liste_coor->proprio) {
				con = ((LST_PSEUDO_CON)liste_coor->proprio);
				dist = distance_con_con(x1, y1, w1, l1, liste_coor->xabs, liste_coor->yabs, con->largeur,
				     con->layer, face);

				if (first) { 
					mindist = dist; 
					first = 0; 
					coordalim = liste_coor;
				} else if (dist < mindist) {
					mindist = dist; 
					coordalim = liste_coor;
				}
				if (mode_debug) 
					printf("ptcoordalim %d\n", (int) coordalim);
			}

			liste_coor = liste_coor->suiv;
		}

		return(coordalim);

		break;

	case EST:
	case OUEST:
		while (NULL != liste_coor) {
			if (mode_debug) 
				printf("ptcoor %d proprio %d x %ld\n", (int) liste_coor, (int)liste_coor->proprio, liste_coor->yabs);

			if (NULL != liste_coor->proprio) {
				con = ((LST_PSEUDO_CON)liste_coor->proprio);
				dist = distance_con_con(x1, y1, w1, l1, liste_coor->xabs, liste_coor->yabs, con->largeur,
				     con->layer, face);

				if (first) { 
					mindist = dist; 
					first = 0;
					coordalim = liste_coor;
				} else if (dist < mindist) {
					mindist = dist; 
					coordalim = liste_coor;
				}
				if (mode_debug) 
					printf("ptcoordalim %d\n", (int) coordalim);
			}

			liste_coor = liste_coor->suiv;
		}

		return(coordalim);

		break;
	}

}

