/******************************************************************
 *  (C) Copyright 1994; dit/upm
 *  Distributed under the conditions stated in the
 *  TOPO General Public License (see file LICENSE)
 ******************************************************************
 *  $Log$
 ******************************************************************/

#ifndef lint
static char rcsid[]= "$Id$";
#endif

/******************************************************************
 *
 *  Santiago Pavon Gomez
 *  David Larrabeiti Lopez
 *
 *  15 Jan 1990
 *
 *  Management of gates : gates, gate sets & gate lists.
 *
 *  COMPILATION FLAGS:
 *
 *  LOG:
 *
 ******************************************************************/

/* LINTLIBRARY */

/* KJT 12/02/12: Added */
#include <stdlib.h>
#include "listdh.h"
#include "limisc.h"
#include "baattr.h"
#include "batables.h"


/******************************************************************
 *                                                                *
 *            GL   -> Gate List (GateListTyp)                     *
 *                                                                *
 ******************************************************************/


/* FreeGL
 * Free the memory used by the gate list gl.
 */
void FreeGL( gl )
     GateListTyp  gl;
{
  Disp_list(gl);
}

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

/* CopyGL
 * Copy the gate list gl.
 */
GateListTyp CopyGL( gl )
     GateListTyp gl;
{
  return Copy_list(gl,(DataListTyp(*)())EchoInt);
}

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

static void (*stpstr)();

     /* DrawGate
      * Draw a gate g.
      */
     static void DrawGate( g )
     DescriptorTyp g;
{
  stpstr(" ");
  stpstr(GetG_name(g));
  stpstr(" ");
}

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

/* DrawGL
 * Draw the gate list gl
 * pstr is the function used to print strings.
 */
void DrawGL( gl, pstr )
     ListTyp    gl;
     void (*pstr)();
{
  stpstr = pstr;
  Apply_Proc_list(gl,DrawGate);
}

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

/* PrintGL
 * Print the gate list gl.
 * pstr is the function used to print strings.
 */
void PrintGL( gl, pstr )
     GateListTyp gl;
     void (*pstr)();
{
  char * str;

  str = SPrintGL( gl );
  pstr(str);
  (void)free(str);
}

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

static char * CopyG_name( d )
     DescriptorTyp d;
{
  return CopyString( GetG_name( d ) );
}

/* SPrintGL
 * Make a string with the name of a list of gates
 */
char * SPrintGL( gl )
     GateListTyp gl;
{
  return SPrint_list( gl, CopyG_name );
}

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

/* AddGL
 * Add a gate to a gate list
 */
GateListTyp AddGL(g,gl)
     DescriptorTyp g;
     GateListTyp gl;
{
  return (GateListTyp)Add_list((DataListTyp)g,gl);
}

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

/* InsertGL
 * Insert a gate in a gate list
 */
GateListTyp InsertGL(g,gl)
     DescriptorTyp g;
     GateListTyp gl;
{
  return (GateListTyp)Insert_list((DataListTyp)g,gl);
}

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

/* InGL
 * return TRUE if g is in gl
 */
boolean InGL(gl,g)
     GateListTyp  gl;
     DescriptorTyp  g;
{
  return In_list((DataListTyp)g,gl,EqInt) ;
}

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

/* JoinGL
 * return the concatenation gl1,gl2
 */
GateListTyp JoinGL (gl1,gl2)
     GateListTyp gl1,gl2;
{
  return Join_list(gl1,gl2);
}

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

/* JunctionGL
 * return the union of two gates lists as sets ( removing equal elements )
 */
GateListTyp JunctionGL(gl1,gl2)
     GateListTyp gl1,gl2;
{
  ToMake("JunctionGL");
  gl2=gl2;
  return gl1;
}

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

/* GateList_to_GateSet
 * Transform a gate list into a gate set
 */
GateSetTyp GateList_to_GateSet( gl )
     GateListTyp gl;
{
  GateSetTyp gs;

  for ( gs = NewGS(); gl!=NULL; gl=Next_list(gl) )
    gs = AddGS( gs, (DescriptorTyp)LookInfo_list(gl) );

  return gs;
}

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

GateListTyp GateSet_to_GateList(gs)
     GateSetTyp gs;
{
  GateListTyp   gl;
  DescriptorTyp n;
  int           word, bits;

  /* KJT 05/01/23: introduced "one" as a 4/8 byte value for 32/64 bits */
  unsigned long one = 1ul;
  gl = Create_list();
  for ( n=1, word=0; word < GATESET_WORDS; word++ ) {
    for ( bits=0; bits < WORDLENGTH; bits++, n++ ) {
      if ( (one << bits) & gs[word] ) {
	gl = AddGL( n, gl );
      }
    }
  }
  return gl;
}

/******************************************************************
 *                                                                *
 *            GSA   -> Gate Set (GateSetTyp)                      *
 *                                                                *
 ******************************************************************/

static GateSetTyp delGS  = NULL;
/* KJT 22/01/23: added "int" type */
static int new_gs_count      = 0;
static int eleased_gs_count = 0;
static int max_gs_count      = 0;

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

/* NewGS
 * Create an empty gate set
 */
GateSetTyp NewGS()
{
  GateSetTyp gs;

  gs = (GateSetTyp)NewCellM(GATESET_WORDS*sizeof(unsigned));
#ifdef SDEBUG
  new_gs_count++;
  max_gs_count=MAX( max_gs_count, new_gs_count-released_gs_count );
#endif
  gs = ClearGS(gs);
  return gs;
}

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

/* FreeGS
 * Free a gate set
 */
void FreeGS( gs )
     GateSetTyp gs;
{
  /*
     cfree ((char*)gs);
     */
  FreeCellM(gs,GATESET_WORDS*sizeof(unsigned));
#ifdef SDEBUG
  released_gs_count++;
#endif
}

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

/* CopyGS
 * Copy a gate set
 */
GateSetTyp CopyGS( gs )
     GateSetTyp gs;
{
  unsigned n;
  GateSetTyp gs1,g;

  LASSERT(gs!=NULL);
  gs1 = NewGS();
  g   = gs1;
  for( n=0; n<GATESET_WORDS; n++ )
    *gs1++ = *gs++;

  return g;
}

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

/* IsEmptyGS
 * return TRUE if gs is an empty gate set, else FALSE
 */
boolean IsEmptyGS( gs )
     GateSetTyp gs;
{
  unsigned n;
  LASSERT(gs!=NULL);
  for ( n=0; n<GATESET_WORDS; n++)
    if (*gs++!=0)
      return FALSE;
  return TRUE;
}

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

/* IsFullGS
 * Say whether the Gate Set is full ( contains all gates up to max).
 * max is the last element of any set.
 */
boolean IsFullGS( gs, max )
     GateSetTyp gs;
     int        max;
{
  unsigned words,bits,n;

  LASSERT((max <= MAX_GATE_TABLE) && (gs!=NULL));

  words = max / WORDLENGTH;
  bits  = max % WORDLENGTH;
  if ( bits == 0 ){
    bits  = WORDLENGTH;
    words = words-1;
  }
  for ( n=0; n<words; n++ )
    if ( *(gs+n) != ~0 )
      return FALSE;

  /* unsigned compulsory to prevent 1s from entering */
  return *(gs+words) == ((unsigned)(~0) >> (WORDLENGTH-bits));

}

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

/* DrawGS
 * Draw the Gate Set gs.
 * pstr is the function used to print strings.
 */
void DrawGS( gs, pstr )
     GateSetTyp gs;
     void       (*pstr)();
{
  unsigned g,words,bits;

  if (!IsEmptyGS(gs))
    for ( g=1; g<=MAX_GATE_TABLE; g++ ){
      words = g / WORDLENGTH;
      bits  = g % WORDLENGTH;
      if ( bits == 0 ){
	bits  = WORDLENGTH;
	words = words-1;
      }
      if ( (*(gs+words) & (1<<(bits-1))) != 0 ) {
	PrintInt(pstr,(int)g);
	pstr(" ");
      }
    }
}

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

/* PrintGS
 * Print the gate set gs.
 * pstr is the function used to print strings.
 */
void PrintGS( gs, pstr )
     GateSetTyp gs;
     void       (*pstr)();
{
  char * str;

  str = SPrintGS(gs);
  pstr(str);
  (void)free(str);
}

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

/* SPrintGS
 * Make a string with the names of gates given for a mask
 */
char * SPrintGS( gs )
     GateSetTyp gs;
{
  GateListTyp gl;
  char *      str;

  gl  = GateSet_to_GateList(gs);
  str = SPrintGL( gl );
  FreeGL(gl);

  return str;
}

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

/* GateInGS
 * Say if a gate belongs to a gate set
 */
boolean GateInGS( g,gs )
     DescriptorTyp g;
     GateSetTyp gs;
{
  unsigned words,bits;

  LASSERT(gs!=NULL);
  words = g / WORDLENGTH;
  bits  = g % WORDLENGTH;
  if ( bits == 0 ) {
    bits  = WORDLENGTH;
    words = words-1;
  }
  return ( *(gs+words) & ( 1 << (bits-1)) ) != 0;
}

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

/* JunctionGS
 * Union of two gate sets.
 */
GateSetTyp JunctionGS( gs1,gs2 )
     GateSetTyp gs1,gs2;
{
  unsigned n;
  GateSetTyp w,g;

  LASSERT((gs1!=NULL) && (gs2!=NULL));
  w = NewGS();
  g = w;
  for( n=0; n<GATESET_WORDS; n++ )
    *(w++) = (*gs1++ | *gs2++ );

  return g;
}

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

/* IntersGS
 * Intersection of two gate sets
 */
GateSetTyp IntersGS(gs1,gs2)
     GateSetTyp gs1,gs2;
{
  unsigned n;
  GateSetTyp w,g;

  LASSERT((gs1!=NULL) && (gs2!=NULL));

  w = NewGS();
  g = w;
  for ( n=0; n<GATESET_WORDS; n++ )
    *(w++) = ( *gs1++ & *gs2++ );

  return g;
}

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

/* DiffGS
 * Difference of gate sets
 */
GateSetTyp  DiffGS(gs1,gs2)
     GateSetTyp gs1,gs2;
{
  unsigned n;
  GateSetTyp w,g;

  LASSERT((gs1!=NULL) && (gs2!=NULL));

  w = NewGS();
  g = w;
  for ( n=0; n<GATESET_WORDS; n++, gs1++ )
    *(w++) = *gs1 & (*gs1 ^ *gs2++);

  return g;
}

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

/* EqualGS
 * return TRUE if the gate sets are equal
 */
boolean EqualGS(gs1,gs2)
     GateSetTyp gs1,gs2;
{
  boolean eq;
  int word;

  if ( gs1==gs2 )
    return TRUE;

  for ( eq=TRUE,word=0; eq && word< GATESET_WORDS; word++ )
    eq= gs1[word]==gs2[word];

  return eq;

}

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

/* SubSetGS
 * return TRUE if a gate set is included in another
 */
boolean SubSetGS ( gs1, gs2 )
     GateSetTyp gs1,gs2;
{
  GateSetTyp m;
  LASSERT((gs1!=NULL) && (gs2!=NULL));

  m = DiffGS( gs1, gs2 );
  if ( IsEmptyGS(m) ) {
    FreeGS(m);
    return TRUE;
  }
  FreeGS(m);
  return FALSE;
}

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

/* ClearGS
 * Clear up a gate set
 */
GateSetTyp  ClearGS (gs)
     GateSetTyp gs;
{
  unsigned n;
  GateSetTyp g;

  LASSERT(gs!=NULL);
  g=gs;
  for( n=0; n<GATESET_WORDS; n++ )
    *gs++=0;
  return g;
}

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

/* FullGS
 * return a gate set filled up to a given descriptor g.
 * example: gs = FullGS( LastTableG() );
 *          would return a gate set containing all the gates in the table.
 */
GateSetTyp  FullGS (g)
     DescriptorTyp g;
{
  unsigned words,bits,n;
  GateSetTyp gs;

  LASSERT( ( g<=MAX_GATE_TABLE ) && ( g>0 ) );

  words = g / WORDLENGTH;
  bits  = g % WORDLENGTH;
  if ( bits == 0 ){
    bits  = WORDLENGTH;
    words = words-1;
  }
  gs = NewGS();
  for ( n=0; n<words; n++ )
    *(gs+n) = ~0 ;

  /* unsigned compulsory to prevent 1s from entering */
  *(gs+words) = ((unsigned)(~0) >> (WORDLENGTH-bits));
  return gs;

}

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

/* AddGS
 * Add a gate to a gate set
 */
GateSetTyp AddGS( gs, g )
     GateSetTyp    gs;
     DescriptorTyp g;
{
  unsigned words,bits;

  LASSERT((g <= MAX_GATE_TABLE) && (gs!=NULL));

  words = g / WORDLENGTH;
  bits  = g % WORDLENGTH;
  if ( bits == 0 ){
    bits  = WORDLENGTH;
    words = words-1;
  }
  *(gs+words) |= (1 << (bits-1));

  return gs;
}

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

/* RemoveGS
 * Remove a gate from a gate set
 */
GateSetTyp RemoveGS(gs,g)
     GateSetTyp gs;
     DescriptorTyp g;
{
  unsigned words,bits;

  LASSERT((g <= MAX_GATE_TABLE) && (gs!=NULL));

  words = g / WORDLENGTH;
  bits  = g % WORDLENGTH;
  if ( bits == 0 ){
    bits  = WORDLENGTH;
    words = words-1;
  }
  *(gs+words) &= ~(1 << (bits-1));
  return gs;
}


/******************************************************************
 *                                                                *
 *              Gate Mask and descriptor                          *
 *                                                                *
 ******************************************************************/

/* Descr_to_Mask
 * Return the gate mask for the descriptor d.
 */
GateMaskTyp Descr_to_Mask( d )
     DescriptorTyp  d;
{
  GateSetTyp gs;

  gs = NewGS();
  gs = AddGS( gs, d );

  return ((GateMaskTyp)gs);
}

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

/* Mask_to_Descr
 * Return the gate descriptor for the gate mask m.
 */
DescriptorTyp Mask_to_Descr( m )
     GateMaskTyp  m;
{
  DescriptorTyp words,bits;

  for( words=0; words<GATESET_WORDS; words++ )
    if( *(m+words) != 0 )
      for ( bits=1; bits<=WORDLENGTH; bits++ )
	if ( (*(m+words)) & (1<<(bits-1)) != 0 )
	  return (bits+words*WORDLENGTH);

  Error("Mask_to_Descr: void mask");
  return bits; /*lint*/
}

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

/* EqualGL
 * Say if two GLs are equal ( in the same order )
 */
boolean EqualGL( gl1, gl2 )
     GateListTyp gl1,gl2;
{
  while (gl1!=NULL&&gl2!=NULL) {
    if (LookInfo_list(gl1)!=LookInfo_list(gl2))
      return FALSE;
    gl1=Next_list(gl1);
    gl2=Next_list(gl2);
  }
  return (gl1==gl2);
}

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

/* StatGS
 * new      : number of cell queries the system has granted this module with.
 * released : number of cell releases.
 * max      : max number of cells hold on by this module till now.
 */
void StatGS( new, released, max )
     int *new, *released, *max;
{
  *new      = new_gs_count;
/* KJT 22/01/23: added conditional assignment */
#ifdef SDEBUG
  *released = released_gs_count;
#else
  *released = 0;
#endif
  *max      = max_gs_count;
}

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

/* InitGS
 * Init the GS module
 */
void InitGS()
{
#ifdef SDEBUG
  new_gs_count      = 0;
  released_gs_count = 0;
  max_gs_count      = 0;
#endif
}

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

