/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit : synthetiseur logique                                        */
/*    Fichier : cout.c                                                      */
/*                                                                          */
/*    (c) copyright 1991 Laboratoire MASI equipe CAO & VLSI                 */
/*    Tous droits reserves                                                  */
/*    Support : e-mail cao-vlsi@masi.ibp.fr                                 */
/*                                                                          */
/*    Auteur(s) :     P. Allegre                        le : 21/08/91       */
/*                                                                          */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*                                                                          */
/****************************************************************************/

#include <stdio.h>
#include MUT_H
#include LOG_H
#include BEH_H
#include "types.h"
#include "../compil/lax_param.h"
#include "../synthe/sl_type.h"
#include "compile.h"
#include "oper.h"
#include "cout.h"

/*---------------------------------------------------------------------------
	delais	:	calcul de delai sur une expression mappee
-----------------------------------------------------------------------------
	return	:	son delai
---------------------------------------------------------------------------*/

long delais(expr)
chain_list *expr;
{
struct cellule *c;
struct sig *s;
struct virtuel *v;

   if (ATOM(expr))
      {
      if ((v = (struct virtuel *)testObj(VALUE_ATOM(expr),'v')) != NULL)
         return v->delais;
      if ((s = (struct sig *)testObj(VALUE_ATOM(expr),'s')) != NULL)
         return s->delais;
      if ((VALUE_ATOM(expr) == nameUn) ||
          (VALUE_ATOM(expr) == nameZero))
	 return 1;
      if (SL_TRACE)
         printf ("delais : object undefined = %s\n",VALUE_ATOM(expr));
      return 0;
      }
     else
     {
     cellList *cell = operToCell(expr);
     num_list *del;
     long max_del = 0;
       
        if (!cell)
        {
/*
           if (SL_TRACE) printf("delay : %s%d doesn't exist\n",
                  searchCharOper(OPER(expr)),ARITE(expr));
*/
           return -2;
        }
        del = cell->delais;
        while (expr = CDR(expr))
        {
        long delCour = delais(CAR(expr));

           if ((delCour + del->DATA) > max_del)
              max_del = delCour + del->DATA;
           del = del->NEXT;
        }
        return max_del;
     }
}

/*---------------------------------------------------------------------------
	delRC	:	calcul de delai sur une expression mappee
-----------------------------------------------------------------------------
	return	:	son delai
---------------------------------------------------------------------------*/
long delRC(virt,expr)
virtuelList *virt;
chain_list *expr;
{
struct cellule *c;
struct sig *signal;
struct virtuel *virtuel;

   if (virt->del_rc != -1) return virt->del_rc;
   if (ATOM(expr))
   {
	if (signal = (sig *)testObj(VALUE_ATOM(expr),'s'))
		return signal->delais + signal->capa;
	if (virtuel = (virtuelList *)testObj(VALUE_ATOM(expr),'v'))
	{
		if (virtuel->del_rc != -1) return virtuel->del_rc;
		return delRC(virtuel,CAR(virtuel->solutions));
	}
	return 0;
   }
   else
   {
	short oper = OPER(expr);
	tabNumList *delai = virt->op_log->delais_tech;
	num_list *del;
	ptype_list *resist = virt->op_log->resistance_tech;
	char *nameDef = virt->cellule;
	long maxDel = 0;
	chain_list *args;

	while ((char *)resist->DATA != nameDef) 
	{
    	   resist = CDR(resist);
	   delai = CDR(delai);
	}
	del = delai->ptNum;
	for(args = CDR(expr);args;args = CDR(args))
		{
		long d = delRC(virt,CAR(args)) + del->DATA;

		del = CDR(del);
		if (maxDel < d)
			maxDel = d;
		}
	virt->del_rc=maxDel + (resist->TYPE * virt->capa) / 1000;
	return virt->del_rc;
   }
}

long entrance(virtFan,name)
virtuelList *virtFan;
char *name;
{
chain_list *sol = CAR(virtFan->solutions);
chain_list *args;
tabNumList *capalist = virtFan->op_log->capa_tech;
num_list *capasNum;
	
   while (virtFan->cellule != capalist->name) 
	capalist = CDR(capalist);
   capasNum = capalist->ptNum;
   for(args = CDR(sol);args;args = CDR(args))
   {
      if (VALUE_ATOM(CAR(args)) == name) return capasNum->DATA;
      capasNum = capasNum->NEXT;
   }
   return (long)0;
}
/*---------------------------------------------------------------------------
	capa	:	calcul de capa
-----------------------------------------------------------------------------
	return	:	sa capa
---------------------------------------------------------------------------*/

void capa(name,virt)
char *name;
virtuelList *virt;
{
long totCapa = 0;
chain_list *f;
sig *signal;

    for(f = virt->fanout;f;f = CDR(f))
    {
    virtuelList *virtFan = (virtuelList *)testObj(f->DATA,'v');
    sig         *signal  = (sig         *)testObj(f->DATA,'s');

      if (name != (char *)f->DATA)
         if (virtFan && virtFan->op_log) /* cas atomique... */
	    totCapa += entrance(virtFan,name);

      if (signal && (signal->type == 5))
      {
      cellList *cell =((cellList *)testObj(nameNot1,'c'));
  
         if (cell)
         {
         tabNumList *capalist = cell->capa_tech;

   	      while(cell->nom != capalist->name) capalist = capalist->NEXT;
   	      totCapa += capalist->ptNum->DATA;
  	      signal->capa = capalist->ptNum->DATA;
         }
         else PRINTF("capa : any not\n");
      }
      if (signal && (signal->name == name)) signal->capa = totCapa;
    }
    if (!totCapa)
    {
    virtuelList *virtFan;
    chain_list *i;

      for(f = virt->fanout;f;f = CDR(f))
      {
      sig *s = (sig *)testObj((char *)(f->DATA),'s');

	if (s)
	{
	for (i = s->util;i;i = CDR(i))
	  if (testObj((char *)i->DATA,'v'))
           if (s->type == 3)
	     totCapa += entrance((virtuelList *)testObj((char *)i->DATA,'v'),
				 s->name);
	   else
	     totCapa += entrance((virtuelList *)testObj((char *)i->DATA,'v'),
				 name);
	s->capa = totCapa;
	}
      }
    }
    virt->capa = totCapa;
    if (!totCapa)	/* corrige le 21/12/92 on enleve meme les signaux */
    {
	if (virt->fanout)
	{
	   freechain(virt->fanout);
	   virt->fanout = NULL;
	}
        if (!testObj(name,'s')) suppVirtuel(name,NULL);

    }
}

/*---------------------------------------------------------------------------
	surface	:	calcul de surface sur une expression mappee
-----------------------------------------------------------------------------
	return	:	son delai
---------------------------------------------------------------------------*/

long surface(expr)
chain_list *expr;
{
struct cellule *c;
struct sig *s;
struct virtuel *v;

   if (ATOM(expr))
   {
      if ((v = (struct virtuel *)testObj(VALUE_ATOM(expr),'v')) != NULL)
	 if (v->cellule) 
	    return 0;
	 else
            return v->surface_cone;
      if ((s = (struct sig *)testObj(VALUE_ATOM(expr),'s')) != NULL)
         return 0;
      if ((VALUE_ATOM(expr) == nameUn) ||
          (VALUE_ATOM(expr) == nameZero))
      {
      cellList *cell;

         if (VALUE_ATOM(expr) == nameUn)
            cell = (cellList *)testObj(nameHigh,'c');
         else
            cell = (cellList *)testObj(nameLow,'c');
         if (cell) return cell->surface;
         return 0;
      }
      if (SL_TRACE)
         printf ("undefined object : %s\n",VALUE_ATOM(expr));
      return 0;
   }
   else
   {
   cellList *cell = operToCell(expr);
   long max_surf = 0;
       
      if (!cell)
      {
/*
         if (SL_TRACE) printf("area : %s%d doesn't exist\n",
                  searchCharOper(OPER(expr)),ARITE(expr));
*/
         return -2;
      }
	/* ajoute  le 18/09/92 */
      if (profExpr(expr) == 1 && testObj(exprToCharRed(expr),'a'))
         return 0;
      max_surf = cell->surface;
      while (expr = CDR(expr))
         max_surf += surface(CAR(expr));
      return max_surf;
   }
}

long surface_cone(cell)
virtuelList *cell;
{
   if (cell->cellule) return 0;
   return surface(CAR(cell->solutions));
}

long cout(expr)
chain_list *expr;
{
long val;
   
   switch (mappSys->coutSig)
   {
      case 0 : return surface(expr);
      case 1 : val = (mappSys->coef * 2) * surface(expr);
	       if (val >= 0) val += delais(expr);
	       break;
      case 2 : val = mappSys->coef * surface(expr);
	       if (val >=0) val += delais(expr);
	       break;
      case 3 : val = (mappSys->coef / 2) * surface(expr);
	       if (val >= 0) val += delais(expr);
	       break;
      case 4 : return delais(expr);
   }
   if (val < 0) return -2;
   return val;
}

void genDelta(signal)
sig *signal;
{
long del;
cellList *cell = (cellList *)testObj(nameNot1,'c');

if (cell) 
{
   del = cell->delais->DATA;
   mappSys->coef = cell->delais->DATA / cell->surface;
}
else 
{
   del = 400;
   mappSys->coef = 200;
}
   switch (signal->cout)
   {
      case 0 : mappSys->delta = del * 13;break;
      case 1 : mappSys->delta = del * 9;break;
      case 2 : mappSys->delta = del * 7;break;
      case 3 : mappSys->delta = del * 5;break;
      case 4 : mappSys->delta = del * 3;break;
/*
      case 0 : mappSys->delta = del * 13;break;
      case 1 : mappSys->delta = del * 9;break;
      case 2 : mappSys->delta = del * 8;break;
      case 3 : mappSys->delta = del * 7;break;
      case 4 : mappSys->delta = del * 5;break;
*/
   }
}
