/*
   sf.c  --  Flatten hierarchical LOGSPC (version 1.0) output.

Written by Harold Levy (har@caltech.edu)

Version		Date	Description
^^^^^^^		^^^^	^^^^^^^^^^^
0.1 beta       11/06/93 First version handles MOSFET's only.
0.2 beta       02/22/94 Fixed internal-node prefixes and added
                        version-number print-out.

*/
#define VERSION "0.2"

#include <stdio.h>

#include "hash.h"
#include "spice.h"

void		Flatten ();
void		ShowInstance ();


main (argc, argv)
  int	argc;
  char	*argv[];
{
  FILE		*inputfile;
  char		STR1[256], STR2[256], STR3[256], STR4[256], STR5[256];
  char		*line, *word, *label;
  struct Bucket *CellTable[HASH_TABLE_SIZE];
  struct Bucket *NodeTable[HASH_TABLE_SIZE];
  struct Bucket *RemainderTable[HASH_TABLE_SIZE];
  struct Bucket *CounterTable[HASH_TABLE_SIZE];
  struct Symbol	*cell, *node, *instance, *remainder, *port, *subordinate;
  struct Symbol *counter;
  int		i, nPorts;

/* initialize hash tables for cells & nodes
*/
  InitHashTable (CellTable);
  InitHashTable (NodeTable);
  InitHashTable (RemainderTable);
  InitHashTable (CounterTable);

  cell = GetSymbol (CellTable, "M");		/* MOSFET */
  cell->namePtr = &cell->name;
  cell->label = NULL;
  cell->ports = NULL;
  cell->remainder = NULL;
  cell->instances = NULL;
  for (i = 1; i <= 4; i ++) AddBucket (&cell->ports);

/* open input file
*/
  if (argc == 2)
  {
    strcpy (STR1, argv[1]);
    inputfile = fopen (STR1, "r");
    if (!inputfile)
    {
      fprintf (stderr, "Cannot find \"%s\"\n", STR1);
      exit (2);
    }
  }
  else
  {
    fprintf (stderr, "usage (v%s):  sf <hierarchical spc file>\n", VERSION);
    exit (1);
  }

/* read subcircuits
*/
  while (fgets (STR1, 256, inputfile))
  {
    strcpy (STR2, STR1);
    line = STR1;
    word = STR2;

    GetSpiceWord (line, word, inputfile);
    if (strcmp (word, ".SUBCKT")) continue;

    GetSpiceWord (line, word, inputfile);	/* subckt name */
    strcpy (STR3, "_");
    strcat (STR3, word);
    cell = GetSymbol (CellTable, STR3);
    cell->namePtr = &cell->name;
    cell->label = NULL;
    cell->ports = NULL;
    cell->instances = NULL;

    do
    {
      GetSpiceWord (line, word, inputfile);	/* subckt ports */
      if (*word)
      {
        node = GetSymbol (NodeTable, word);
        AddBucket (&cell->ports);
        cell->ports->symbol->name = node->name;
        cell->ports->symbol->namePtr = &cell->ports->symbol->name;
      }
    } while (*word);

    while (strncmp (fgets (STR1, 256, inputfile), ".ENDS", 5))
    {
      strcpy (STR2, STR1);
      line = STR1;
      word = STR2;

      GetSpiceWord (line, word, inputfile);	/* device name */

      if (word[1])
        label = &word[1];
      else
        label = NULL;
      counter = GetSymbol (CounterTable, label);

      switch (*word)
      {
        case 'M':
          instance = GetSymbol (CellTable, "M");
          AddBucket (&cell->instances);
          cell->instances->symbol->name = instance->name;
          cell->instances->symbol->namePtr = &cell->instances->symbol->name;
          cell->instances->symbol->label = counter->name;
	  for (i = 1; i <= 4; i ++)
	  {
	    GetSpiceWord (line, word, inputfile);	/* MOSFET pins */
	    if (*word)
            {
              AddBucket (&cell->instances->symbol->ports);
              if (port = InBucket (&cell->ports, word))
                cell->instances->symbol->ports->symbol->namePtr = &port->name;
              else
              {
                node = GetSymbol (NodeTable, word);
                cell->instances->symbol->ports->symbol->name = node->name;
                cell->instances->symbol->ports->symbol->namePtr =
                  &cell->instances->symbol->ports->symbol->name;
              }
            }
	  }
          if (*line)
          {
            remainder = GetSymbol (RemainderTable, line);
            cell->instances->symbol->remainder = remainder->name;
          }
          break;
	case 'X':
	  nPorts = GetLastSpiceWord (line, STR3, inputfile) - 1;
          strcpy (STR4, "_");
          strcat (STR4, STR3);
          instance = GetSymbol (CellTable, STR4);
          AddBucket (&cell->instances);
          cell->instances->symbol->name = instance->name;
          cell->instances->symbol->namePtr = &cell->instances->symbol->name;
          cell->instances->symbol->label = counter->name;
	  for (i = 1; i <= nPorts; i ++)
	  {
	    GetSpiceWord (line, word, inputfile);	/* SUBCKT pins */
            if (*word)
            {
              AddBucket (&cell->instances->symbol->ports);
              if (port = InBucket (&cell->ports, word))
                cell->instances->symbol->ports->symbol->namePtr = &port->name;
              else
              {
                node = GetSymbol (NodeTable, word);
                cell->instances->symbol->ports->symbol->name = node->name;
                cell->instances->symbol->ports->symbol->namePtr =
                  &cell->instances->symbol->ports->symbol->name;
              }
            }
	  }
	  break;
      }
    }
  }

/* read root cell
*/
  rewind (inputfile);
  while (fgets (STR1, 256, inputfile))
  {
    strcpy (STR2, STR1);
    line = STR1;
    word = STR2;

    GetSpiceWord (line, word, inputfile);

    if (*word == '*') continue;		/* comment */
    if (*word == 0) continue;		/* blank line */
    if (!strncmp (word, ".SUBCKT", 7))	/* skip subcircuit definitions now */
    {
      while (strncmp (fgets (STR1, 256, inputfile), ".ENDS", 5)) ;
      continue;
    }

    if (word[1])
      label = &word[1];
    else
      label = NULL;
    counter = GetSymbol (CounterTable, label);

    switch (*word)
    {
      case 'M':
        instance = GetSymbol (CellTable, "M");
        FirstBucket (&instance->ports);
        for (i = 1; i <= 4; i ++)
        {
          GetSpiceWord (line, word, inputfile);
          if (*word)
          {
            node = GetSymbol (NodeTable, word);
            instance->ports->symbol->name = node->name;
            if (instance->ports->next)
              instance->ports = instance->ports->next;
          }
        }
        remainder = GetSymbol (RemainderTable, line);
        instance->remainder = remainder->name;
        Flatten (CellTable, instance, counter->name);
        break;

      case 'X':
        nPorts = GetLastSpiceWord (line, STR3, inputfile) - 1;
        strcpy (STR4, "_");
        strcat (STR4, STR3);
        instance = GetSymbol (CellTable, STR4);
        FirstBucket (&instance->ports);
        for (i = 1; i <= nPorts; i ++)
        {
          GetSpiceWord (line, word, inputfile);
          if (*word)
          {
            node = GetSymbol (NodeTable, word);
            instance->ports->symbol->name = node->name;
            if (instance->ports->next)
              instance->ports = instance->ports->next;
          }
        }
        FirstBucket (&instance->instances);
        sprintf (STR5, "%s#%s", STR4, counter->name);
        Flatten (CellTable, NodeTable, instance->instances->symbol, STR5);
        while (instance->instances->next)
        {
          instance->instances = instance->instances->next;
          sprintf (STR5, "%s#%s", STR4, counter->name);
          Flatten (CellTable, NodeTable, instance->instances->symbol, STR5);
        }
        break;
    }
  }

/* close input file
*/
  fclose (inputfile);

}


void Flatten (celltable, nodetable, instance, prefix)
  struct Bucket *celltable[HASH_TABLE_SIZE];
  struct Bucket *nodetable[HASH_TABLE_SIZE];
  struct Symbol *instance;
  char          *prefix;
{
  static int	m_counter = 0;
  int		i;
  struct Symbol *subordinate, *node;
  struct Bucket *ipBP, *spBP;
  char		STR1[256], STR2[256];

  switch (*(instance->name))
  {
    case 'M':
      m_counter ++;
      printf ("M%s/%s", prefix, instance->label);
      FirstBucket (&instance->ports);
      for (i = 1; i <= 4; i ++)
      {
        if (*instance->ports->symbol->namePtr == instance->ports->symbol->name)
          printf (" %s/%s", prefix, *instance->ports->symbol->namePtr);
        else
          printf (" %s", *instance->ports->symbol->namePtr);
        if (instance->ports->next)
          instance->ports = instance->ports->next;
      }
      printf (" %s", instance->remainder);
      break;
    case '_':
      subordinate = GetSymbol (celltable, instance->name);
      sprintf (STR1, "%s/%s#%s", prefix, subordinate->name, instance->label);
      FirstBucket (&instance->ports);
      ipBP = instance->ports;
      FirstBucket (&subordinate->ports);
      spBP = subordinate->ports;
      if (*ipBP->symbol->namePtr == ipBP->symbol->name)
      {
        sprintf (STR2, "%s/%s", prefix, *ipBP->symbol->namePtr);
        node = GetSymbol (nodetable, STR2);
        spBP->symbol->name = node->name;
      }
      else
        spBP->symbol->name = *ipBP->symbol->namePtr;
      while (ipBP->next)
      {
        ipBP = ipBP->next;
        spBP = spBP->next;
        if (*ipBP->symbol->namePtr == ipBP->symbol->name)
        {
          sprintf (STR2, "%s/%s", prefix, *ipBP->symbol->namePtr);
          node = GetSymbol (nodetable, STR2);
          spBP->symbol->name = node->name;
        }
        else
          spBP->symbol->name = *ipBP->symbol->namePtr;
      }
      FirstBucket (&subordinate->instances);
      Flatten (celltable, nodetable, subordinate->instances->symbol, STR1);
      while (subordinate->instances->next)
      {
        subordinate->instances = subordinate->instances->next;
        Flatten (celltable, nodetable, subordinate->instances->symbol, STR1);
      }
      break;
  }
}


void ShowInstance (instance)
  struct Symbol *instance;
{
  printf ("name = %s:\n\n", instance->name);
  FirstBucket (&instance->instances);
  printf ("%s\n", instance->instances->symbol->name);
  FirstBucket (&instance->instances->symbol->ports);
  printf ("%s\n", *instance->instances->symbol->ports->symbol->namePtr);
  while (instance->instances->symbol->ports->next)
  {
    instance->instances->symbol->ports =
      instance->instances->symbol->ports->next;
    printf ("%s\n", *instance->instances->symbol->ports->symbol->namePtr);
  }
  printf ("%s\n", instance->instances->symbol->remainder);
  while (instance->instances->next)
  {
    instance->instances = instance->instances->next;
    printf ("%s\n", instance->instances->symbol->name);
    FirstBucket (&instance->instances->symbol->ports);
    printf ("%s\n", *instance->instances->symbol->ports->symbol->namePtr);
    while (instance->instances->symbol->ports->next)
    {
      instance->instances->symbol->ports =
      instance->instances->symbol->ports->next;
      printf ("%s\n", *instance->instances->symbol->ports->symbol->namePtr);
    }
    printf ("%s\n", instance->instances->symbol->remainder);
  }
}


