/*******************************************************************************
* mbk : logical vti v7r5 driver (hns, fne, hdn, fdn formats)                   *
*                                                                              *
* version : 4.04                                                               *
* date    : 08/07/92                                                           *
*                                                                              *
* Modified, rewritten and maintained by Frederic Petrot since september 1990   *
*                                                                              *
*******************************************************************************/

#ident "@(#)vti logical views driver version 4.04"

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "drive_vti_l.h"
#include MUT_H
#include MLO_H
#include MLU_H

/*******************************************************************************
* needed to allow edition with vi on big interfaces instances                  *
*******************************************************************************/
#define LINEBREAK if (linelength > 70) { \
							(void)fputs("-\n", ptfile); \
							linelength = 0; \
						}

/*******************************************************************************
* function getdate()                                                           *
*******************************************************************************/
static void vtigetdate(date)
char *date;
{
time_t timer;
char day[4], month[4];
int year, nday, hour, minute, second;

	(void)time(&timer);
	(void)strcpy(date, ctime(&timer));
	(void)sscanf(date, "%s %s %d %d:%d:%d 19%d",
						day, month, &nday, &hour, &minute, &second, &year);
	(void)sprintf(date, "%02d-%s-%02d %02d:%02d",
						nday, month, year, hour, minute);
}

/*******************************************************************************
* function busname                                                             *
*******************************************************************************/
static char *busname(name)
char *name;
{
char buffer[255], *s, *t;
char one = 1;

	if (!name)
		return NULL;

	s = name;
	t = buffer;
	while (*s) {
		if (*s == ' ')
			if (one) {
				*t++ = '[';
				s++;
				one = 0;
			} else {
				*t++ = ']';
				*t++ = '[';
				s++;
			}
		if (*s == SEPAR && !one) {
			*t++ = ']';
			one = 1;
		}
		*t++ = *s++;
	}
	if (!one)
		*t++ = ']';
	*t = '\0';
	return buffer;
}

/*******************************************************************************
* function env()                                                               *
*******************************************************************************/
static void env(tn, tp)
char *tn, *tp;
{
char *s, *getenv(); /* what include is needed? stdlib.h but no on pc */

	s = getenv("MBK_VTI_TN");
	*tn = s ? *s : 'e';
	if (islower(*tn))
		*tn = toupper(*tn);
	s = getenv("MBK_VTI_TP");
	*tp = s ? *s : 'p';
	if (islower(*tp))
		*tp = toupper(*tp);
}

/*******************************************************************************
* function savelofig()                                                         *
*******************************************************************************/
void vtisavelofig(ptfig)
lofig_list *ptfig;
{
loins_list *ptins;
lotrs_list *pttrs;
locon_list *ptcon;
losig_list *ptsig;
chain_list *ptscan, *ptlist;
FILE *ptfile;
long nbio;
long con_id;
float f1, f2;
char date[30];
long sig_vdd = -1, sig_vss = -1;
int linelength;
ht *h; /* to check a signal name unicity */
char *s;
int *old_index; /* table indexed by the file indexes giving mbk's one */
static char tn, tp;

	if (!tn) /* either one, don't matter */
		env(&tn, &tp);

	if ((ptfile = mbkfopen(ptfig->NAME, OUT_LO, WRITE_TEXT)) == NULL) {
		(void)fflush(stdout);
		(void)fprintf(stderr, "*** mbk error ***\n");
		(void)fprintf(stderr, "vtisavelofig can't open file %s.%s\n",
							ptfig->NAME, OUT_LO);
		EXIT(1);
	}  else if (TRACE_MODE == YES)
		(void)printf("--- mbk --- writing the file : %s.%s\n",
							ptfig->NAME, OUT_LO);

	/* reverse instances, connectors and parameters order */
	ptfig->LOCON = (locon_list *)reverse((chain_list *)ptfig->LOCON);
	ptfig->LOINS = (loins_list *)reverse((chain_list *)ptfig->LOINS);
	ptfig->LOTRS = (lotrs_list *)reverse((chain_list *)ptfig->LOTRS);
	for (ptins = ptfig->LOINS; ptins; ptins = ptins->NEXT)
		ptins->LOCON = (locon_list *)reverse((chain_list *)ptins->LOCON);

	/* space for old indexes to be restored at the end */
	con_id = 1;
	for (ptsig = ptfig->LOSIG; ptsig; ptsig = ptsig->NEXT)
		con_id++;
	old_index = (int *)mbkalloc((unsigned int)(con_id * sizeof(int)));

	/* changing signals indexes : externals signals must be first for vti */
	con_id = 0;
	for (ptcon = ptfig->LOCON; ptcon; ptcon = ptcon->NEXT) {
		old_index[++con_id] = ptcon->SIG->INDEX;
		ptcon->SIG->INDEX = con_id;
		ptcon->SIG->TYPE = EXTERNAL;
		if (isvdd(ptcon->NAME))
			sig_vdd = con_id;
		else if (isvss(ptcon->NAME))
			sig_vss = con_id;
	}
	nbio = con_id;
	for (ptsig = ptfig->LOSIG; ptsig; ptsig = ptsig->NEXT) {
		if (ptsig->TYPE != EXTERNAL) {
			old_index[++con_id] = ptsig->INDEX;
			ptsig->INDEX = con_id;
			s = getsigname(ptsig);
			if (isvdd(s))
				sig_vdd = con_id;
			else if (isvss(s))
				sig_vss = con_id;
		}
	}

	if (sig_vdd == -1) {
		sig_vdd = ++con_id;
		(void)fprintf(stderr, "*** mbk warning ***\n vti %s driver detected",
							OUT_LO);
		(void)fprintf(stderr, " no '*vdd*' signal in figure %s (assigned to %d)\n",
									ptfig->NAME, sig_vdd);
	}
	if (sig_vss == -1) {
		sig_vss = ++con_id;
		(void)fprintf(stderr, "*** mbk warning ***\n vti %s driver detected",
							OUT_LO);
		(void)fprintf(stderr, " no '*vss*' signal in figure %s (assigned to %d)\n",
									ptfig->NAME, sig_vss);
	}

	/* needed to check signals name unicity fast */
	h = addht(con_id << 1); /* bigger means faster! */

	/* header */
	vtigetdate(date);
	if (strcmp(OUT_LO, "hns") == 0) {
		(void)fprintf(ptfile, "#cell1 %s %s hnSchematic 0 v7r5.6\n",
							 ptfig->NAME, TECHNO);
		(void)fprintf(ptfile, "# %s %s mbkvti400 * .\n", date, date);
		(void)fprintf(ptfile, "H 1 ;\n");
	} else {
		(void)fprintf(ptfile, "#cell1 %s %s fnExtracted 4096 v7r5.6\n",
							ptfig->NAME, TECHNO);
		(void)fprintf(ptfile, "# %s %s mbkvti400 * .\n", date, date);
		(void)fprintf(ptfile, "H 3 ;\n");
	}
	(void)fprintf(ptfile, "B 0 %ld ;\n", nbio);

	/* connectors */
	for (ptcon = ptfig->LOCON; ptcon; ptcon = ptcon->NEXT) {
		addhtitem(h, ptcon->NAME, 0);
		(void)fprintf(ptfile, "X "); /* unable to represent direction in hns */
		(void)fprintf(ptfile, "%ld ", ptcon->SIG->INDEX);
		(void)fprintf(ptfile, "%ld ", ptcon->SIG->INDEX);
		(void)fprintf(ptfile, "%s ", busname(ptcon->NAME));
		(void)fprintf(ptfile, ";\n");
	}

	/* signals */
	for (ptsig = ptfig->LOSIG; ptsig; ptsig = ptsig->NEXT) {
		if (ptsig->TYPE == INTERNAL && ptsig->NAMECHAIN != NULL) {
			s = getsigname(ptsig);
			if (!sethtitem(h, s, 0)) {
				(void)fprintf(ptfile, "N ");
				(void)fprintf(ptfile, "%ld ", ptsig->INDEX);
				(void)fprintf(ptfile, "%s ", busname(s));
				(void)fprintf(ptfile, ";\n");
			}
		}
		if (ptsig->CAPA && strcmp(OUT_LO, "hns")) {
			(void)fprintf(ptfile, "C 0 * * ");           /* type */
			(void)fprintf(ptfile, "%.3e ", ptsig->CAPA); /* val  */
			(void)fprintf(ptfile, "%ld ", ptsig->INDEX); /* equi */
			(void)fprintf(ptfile, "%ld ", sig_vss);      /* bulk */
			(void)fprintf(ptfile, ";\n");
		}
	}
	delht(h);

	/* local models derived from the first instances */
	ptlist = NULL;
	for (ptins = ptfig->LOINS; ptins; ptins = ptins->NEXT) {
		for (ptscan = ptlist; ptscan; ptscan = ptscan->NEXT)
			if (ptins->FIGNAME == (char *)ptscan->DATA)  
				break;
		if (ptscan == NULL) {
			ptlist = addchain(ptlist, (void *)ptins->FIGNAME);
			linelength = fprintf(ptfile, "M HNS ");
			linelength += fprintf(ptfile, "%s ", ptins->FIGNAME);
			linelength += fprintf(ptfile, "| ");
			linelength += fprintf(ptfile, "| ");
			for (ptcon = ptins->LOCON; ptcon; ptcon = ptcon->NEXT) {
				linelength += fprintf(ptfile, "%s ", busname(ptcon->NAME));
				LINEBREAK;
			}
			linelength += fprintf(ptfile, "| ");
			LINEBREAK;
			con_id = 0;
			for (ptcon = ptins->LOCON; ptcon != NULL; ptcon = ptcon->NEXT) {
				linelength += fprintf(ptfile, "%d ", ++con_id);
				LINEBREAK;
			}
			(void)fprintf(ptfile, ";\n");
		}
	}
	freechain(ptlist);

	/* instances */
	for (ptins = ptfig->LOINS; ptins != NULL; ptins = ptins->NEXT) {
		linelength = fprintf(ptfile, "I HNS ");
		linelength += fprintf(ptfile, "%s ", ptins->FIGNAME);
		linelength += fprintf(ptfile, "%s ", ptins->INSNAME);
		linelength += fprintf(ptfile, "| ");
		linelength += fprintf(ptfile, "| ");
		for (ptcon = ptins->LOCON; ptcon; ptcon = ptcon->NEXT) {
			linelength += fprintf(ptfile, "%ld ", ptcon->SIG->INDEX);
			LINEBREAK;
		}
		(void)fprintf(ptfile, ";\n");
	}

	/* transistors */
	for (pttrs = ptfig->LOTRS; pttrs; pttrs = pttrs->NEXT) {
		(void)fprintf(ptfile, "T ");
		(void)fprintf(ptfile, "%c ", pttrs->TYPE == TRANSN ? tn : tp);
		(void)fprintf(ptfile, "* ");
		f1 = (float)pttrs->X / SCALE_X;
		f2 = (float)pttrs->Y / SCALE_X;
		(void)fprintf(ptfile, "[%.2f,%.2f] ", f1, f2);
		f1 = (float)pttrs->WIDTH / SCALE_X;
		f2 = (float)pttrs->LENGTH / SCALE_X;
		(void)fprintf(ptfile, "%.2f %.2f ", f1, f2);
		(void)fprintf(ptfile, "0 ");
		(void)fprintf(ptfile, "%ld ", pttrs->GRID->SIG->INDEX);
		(void)fprintf(ptfile, "%ld ", pttrs->SOURCE->SIG->INDEX);
		(void)fprintf(ptfile, "%ld ", pttrs->DRAIN->SIG->INDEX);
		(void)fprintf(ptfile, "%ld ", pttrs->TYPE == TRANSN ? sig_vss : sig_vdd);
		(void)fprintf(ptfile, ";\n");
	}

	(void)fprintf(ptfile, "E ;\n");

	/* put back indexes in their place */
	for (ptsig = ptfig->LOSIG; ptsig; ptsig = ptsig->NEXT)
		ptsig->INDEX = old_index[ptsig->INDEX];
	mbkfree(old_index);

	/* reverse instances, connectors and transistor order */
	ptfig->LOCON = (locon_list *)reverse((chain_list *)ptfig->LOCON);
	ptfig->LOTRS = (lotrs_list *)reverse((chain_list *)ptfig->LOTRS);
	ptfig->LOINS = (loins_list *)reverse((chain_list *)ptfig->LOINS);
	for (ptins = ptfig->LOINS; ptins; ptins = ptins->NEXT)
		ptins->LOCON = (locon_list *)reverse((chain_list *)ptins->LOCON);

	if (fclose(ptfile)) {
		(void)fflush(stdout);
		(void)fprintf(stderr, "*** mbk error ***\n");
		(void)fprintf(stderr, "vtisavelofig can't close file %s.%s\n",
							ptfig->NAME, OUT_LO);
		EXIT(1);
	}
}
