/****************************************************************************
    Copyright (C) 1987-2005 by Jeffery P. Hansen

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "vparser.h"
#include "gsim.h"

extern char *topModule;

SHash 	module_table;

static struct {
  SModule	*mod;
  SGate		*gate;
} cur;

int yyerror(char *err,...)
{
  char buf[STRMAX];
  va_list ap;
  extern int errCount;

  va_start(ap, err);

  sprintf(buf,"<%s,%d> ",ycFileName,ycLineNumber);
  vsprintf(buf+strlen(buf),err,ap);
  va_end(ap);

  errorFile("%s",buf);
  errCount++;

  return 0;
}

void VerNewModule(const char *name,int isTop)
{
  SModule *M = new_SModule(name);

  SHash_insert(&module_table,name,M);

  cur.mod = M;
}

void VerModParm(const char *name)
{
  SNet *N = SModule_findAddNet(cur.mod,name);

  SModule_addPort(cur.mod,N);
}

void VerEndModule()
{
  if (cur.mod->m_ports.num == 0 && !topModule)
    topModule = cur.mod->m_name;

  cur.mod = 0;
  cur.gate = 0;
}

void VerSetRootMod()
{
  topModule = cur.mod->m_name;
}

void VerNewNet(const char *name,int nbits)
{
  SNet *N = SModule_findAddNet(cur.mod,name);
  SNet_setNBits(N,nbits);
}

void VerGate(const char *gtype,const char *gname)
{
  static int gcount = 0;
  char buf[STRMAX];
  SGate *g;
  SGateInfo *gi;

  gi = SGateInfo_find(gtype);

  if (gi && gi->gi_code == GT_IGNORE) {
    cur.gate = 0; 
    return;
  }

  if (!gname) {
    sprintf(buf,"$%d",gcount++);
    gname = buf;
  }

  g = new_SGate(gtype,gname);
  SModule_addGate(cur.mod,g);

  g->g_type = gi;

  cur.gate = g; 
}

void VerEndGate()
{
  SGate *g = cur.gate;
  if (g && g->g_type) {
    unsigned mask = SGateInfo_compMask(g->g_type,g->g_typeName);

    SGate_sortPins(g);

    if (mask) {
      int i;
      for (i = 0;i < g->g_ports.num;i++)
	if ((mask & (1<<i)))
	  g->g_ports.port[i]->p_comp = !g->g_ports.port[i]->p_comp;
    }
  }
  cur.gate = 0;
}

void VerAttach(const char *pin,const char *net,int isComp)
{
  if (cur.gate) {
    SNet *N = SModule_findAddNet(cur.mod,net);
    SGate_addPort(cur.gate,pin,N,isComp);
   }
}

void VerTranRange(int msb,int lsb)
{
  (*cur.gate->g_type->gi_setProp)(cur.gate,"/msb",&msb);
  (*cur.gate->g_type->gi_setProp)(cur.gate,"/lsb",&lsb);
}


void VerSetProperty(const char *prop,int n)
{
  if (!cur.gate || !cur.gate->g_type) return;

  if (strcmp(prop,"/cpc") == 0) {
    if (n)
      cur.gate->g_flags |= GF_CPCUT;
    else
      cur.gate->g_flags &= ~GF_CPCUT;
  }

  if (cur.gate->g_type->gi_setProp)
    (*cur.gate->g_type->gi_setProp)(cur.gate,prop,&n);
}

void VerSetStrProperty(const char *prop,const char *s)
{
  if (!cur.gate || !cur.gate->g_type) return;

  if (strcmp(prop,"/tech") == 0) {
    cur.gate->g_tech = strdup(s);
  }

  if (strcmp(prop,"/delay") == 0) {
    char buf[STRMAX],*p;
    int i,n;
    SGateInfo *gi = cur.gate->g_type;

    if (gi) {
      n = 0;
      for (i = 0;gi->gi_delayNames[i].ds_name;i++)
	n++;
      if (n == 0) n = 1;
      cur.gate->g_delayParms = (int*) malloc(sizeof(int)*n);

      strcpy(buf,s);
      for (i = 0, p = strtok(buf," ");p;i++, p = strtok(0," ")) {
	int d;
	sscanf(p,"%d",&d);
	cur.gate->g_delayParms[i] = d;
#if 0
	logMsg("custom delay on %s is %d",cur.gate->g_name,d);
#endif
      }
    }
  }

  if (cur.gate->g_type->gi_setProp)
    (*cur.gate->g_type->gi_setProp)(cur.gate,prop,s);
}

void VerilogDump()
{
  HashElem *E;

  for (E = Hash_first(&module_table);E;E = Hash_next(&module_table,E)) {
    SModule *M = (SModule*) HashElem_obj(E);
    SModule_print(M,stdout);
  }
}

/*******************************************************************/
/*
   These functions are place holders for parser functions used only
   by tkgate.
*/

void VerMakeNode(int x,int y)		{}
void VerMakeWire(int p)			{}
void VerEndDecls()			{}
void VerSetPos(int x,int y)		{}
void VerSetSize(int w,int h)		{}
void VerSetRot(int r)			{}
void VerSetShowName(int sn)		{}
void VerSetWireDecorationPos(int dp)	{}
void VerSetState(int s)			{}
void VerPlaceWire(int p)		{}
void VerJointNet(const char *net)	{}
void VerBeginBD()			{}
void VerEndBD()				{}
void VerCheckVersion(const char *v)	{}
void VerAddScript(const char *name)	{}
void VerTranDup()			{}
void VerCircuitProp(const char *name,const void *value,int ptype)				{}
void VerBlockPort(const char *pname,int pdir,int widx)				{}
void VerBDPort(const char *pname,int pdir,const char *name ,int nbits,int onum,int oden) 	{}
