/*
 * ext2spice.h --
 *	Definitions for ext2spice.c and ext2hier.c
 */

#ifndef _MAGIC__EXT2SPICE__EXT2SPICE_H
#define _MAGIC__EXT2SPICE__EXT2SPICE_H

/* cache list used to find parallel devs */
typedef struct _devMerge {
	float  l, w;
	EFNode *g, *s, *d, *b;
	Dev * dev;
	int	  esFMIndex;
	HierName *hierName;
	const struct _devMerge *next;
} devMerge;

#include "extflat/EFint.h" /* HierContext */

/* Forward declarations */
extern void CmdExtToSpice(MagWindow *w, TxCommand *cmd);
extern int spcParseArgs(int *pargc, char ***pargv);
extern int spccapVisit(HierName *hierName1, HierName *hierName2, double cap, ClientData cdata); /* @typedef cb_extflat_visitcaps_t (UNUSED) */
extern int spcdevVisit(Dev *dev, HierContext *hc, float scale, Transform *trans, ClientData cdata); /* @typedef cb_extflat_visitdevs_t (UNUSED) */
extern int spcnodeVisit(EFNode *node, int res, double cap, ClientData cdata); /* @typedef cb_extflat_visitnodes_t (UNUSED) */
extern int subcktVisit(Use *use, HierName *hierName, bool is_top); /* @typedef cb_extflat_visitsubcircuits_t */
extern int spcresistVisit(const HierName *hierName1, const HierName *hierName2, float res,  ClientData cdata); /* @typedef cb_extflat_visitresists_t (UNUSED) */
extern int devMergeVisit(Dev *dev, HierContext *hc, float scale, Transform *trans, ClientData cdata); /* @typedef cb_extflat_visitdevs_t (UNUSED) */
extern int devDistJunctVisit(Dev *dev, HierContext *hc, float scale, Transform *trans, ClientData cdata); /* @typedef cb_extflat_visitdevs_t (UNUSED) */
extern int spcsubVisit(EFNode *node, int res, double cap, ClientData cdata); /* @typedef cb_extflat_visitnodes_t (char** resstr) */
extern int subcktUndef(Use *use, HierName *hierName, bool is_top); /* @typedef cb_extflat_visitsubcircuits_t */
extern EFNode *spcdevSubstrate(HierName *prefix, HierName *suffix, int type, FILE *outf);
extern const char *nodeSpiceName(const HierName *hname, EFNode **rnode);
extern int nodeVisitDebug(EFNode *node, int res, double cap, ClientData cdata); /* @typedef cb_extflat_visitnodes_t (UNUSED) */
extern void topVisit(Def *def, bool doStub);
extern void swapDrainSource(Dev *dev);

extern const char *nodeSpiceHierName(HierContext *hc, const HierName *hname);
extern devMerge *mkDevMerge(float l, float w, EFNode *g, EFNode *s, EFNode *d, EFNode *b, HierName *hn, Dev *dev);
extern bool extHierSDAttr(DevTerm *term);

extern bool devIsKilled(int n);
extern float getCurDevMult(void);
extern void addDevMult(float f);
extern void setDevMult(int i, float f);

/* C99 compat */
extern int EFHNSprintf(char *str, HierName *hierName);
extern int printSubcktDict(void);
extern int spcdevOutNode(const HierName *prefix, const HierName *suffix, const char *name, FILE *outf);
extern int spcnAP(DevTerm *dterm, EFNode *node, int resClass, float scale, char *asterm, char *psterm, float m, FILE *outf, int w);
extern int parallelDevs(const devMerge *f1, const devMerge *f2);
extern int nodeHspiceName(char *s);
extern int devDistJunctHierVisit(HierContext *hc, Dev *dev, float scale, ClientData cdata); /* @typedef cb_extflat_hiervisitdevs_t (UNUSED) */
extern int spcnAPHier(DevTerm *dterm, HierName *hierName, int resClass, float scale, char *asterm, char *psterm, float m, FILE *outf);
extern void mergeAttr(char **a1, char **a2);
extern int update_w(short resClass, int w, EFNode *n);
extern void esSIvalue(FILE *file, float value);

/* Options specific to ext2spice */
extern bool esDoExtResis;
extern bool esDoPorts;
extern bool esDoHierarchy;
extern bool esDoBlackBox;
extern bool esDoResistorTee;
extern int  esDoSubckt;
extern bool esDevNodesOnly;
extern bool esNoAttrs;
extern bool esHierAP;
extern char spcesDefaultOut[FNSIZE];
extern const char *esSpiceCapNode;
extern const char esSpiceDefaultGnd[];
extern char *spcesOutName;
extern FILE *esSpiceF;
extern float esScale;	/* negative if hspice the EFScale/100 otherwise */

extern unsigned short esFormat;
extern TileTypeBitMask initMask;

extern int esCapNum;
extern int esDevNum;
extern int esResNum;
extern int esDiodeNum;
extern int esVoltNum;
extern int esNodeNum;  /* just in case we're extracting spice2 */
extern int esSbckNum; 	/* used in hspice node name shortening   */
extern int esNoModelType;  /* index for device type "None" (model-less device) */

extern bool esMergeDevsA; /* aggressive merging of devs L1=L2 merge them */
extern bool esMergeDevsC; /* conservative merging of devs L1=L2 and W1=W2 */
			   /* used with the hspice multiplier */
extern bool esDistrJunct;

extern float	*esFMult;       /* the array itself */
extern int	 esFMIndex;     /* current index to it */
extern int	 esFMSize; 	/* its current size (growable) */

extern int	 esSpiceDevsMerged;
extern const devMerge *devMergeList;

/*
 * The following hash table and associated functions are used only if
 * the format is hspice, to keep the translation between the hierarchical
 * prefix of a node and the x num that we use to output valid hspice
 * which also are meaningful.
 */
extern HashTable subcktNameTable ; /* the hash table itself */
extern DQueue    subcktNameQueue ; /* q used to print it sorted at the end*/


typedef struct {
   short resClassSource ;  /* the resistance class of the source of the dev */
   short resClassDrain ;  /* the resistance class of the drain of the dev */
   short resClassSub ; /* the resistance class of the substrate of the dev */
   char  *defSubs ;    /* the default substrate node */
} fetInfoList;

extern fetInfoList esFetInfo[TT_MAXTYPES];

#define MAX_STR_SIZE (1<<11) /* 2K should be enough for keeping temp
                                names even of the most complicated design */

/* Node clients for figuring out areas and perimeters of sources and drains */

typedef union {
	TileTypeBitMask	visitMask; /* mask for normal visits */
	float	*widths; /* width used for distributing area perim */
} maskOrWidth ;

typedef struct {
	char		*spiceNodeName;
	maskOrWidth	m_w;
} nodeClient;

typedef struct {
	HierName 	*lastPrefix;
	maskOrWidth	m_w;
} nodeClientHier;

#define	NO_RESCLASS	-1

#define markVisited(client, rclass) \
  { TTMaskSetType(&((client)->m_w.visitMask), rclass); }

#define clearVisited(client) \
   { TTMaskZero(&((client)->m_w.visitMask)); }

#define beenVisited(client, rclass)  \
   ( TTMaskHasType(&((client)->m_w.visitMask), rclass) )

#define initNodeClient(node) \
{ \
	(node)->efnode_client = (ClientData) mallocMagic((unsigned) (sizeof(nodeClient))); \
	(( nodeClient *)(node)->efnode_client)->spiceNodeName = NULL; \
	TTMaskZero (&((nodeClient *) (node)->efnode_client)->m_w.visitMask); \
	TTMaskSetMask(&(((nodeClient *)(node)->efnode_client)->m_w.visitMask), &initMask);\
}


#define initNodeClientHier(node) \
{ \
	(node)->efnode_client = (ClientData) mallocMagic((unsigned)(sizeof(nodeClientHier))); \
	TTMaskZero (&((nodeClientHier *) (node)->efnode_client)->m_w.visitMask); \
}

/* attributes controlling the Area/Perimeter extraction of dev terminals */
#define ATTR_FLATAP	"*[Ee][Xx][Tt]:[Aa][Pp][Ff]*"
#define ATTR_HIERAP	"*[Ee][Xx][Tt]:[Aa][Pp][Hh]*"
#define ATTR_SUBSAP	"*[Ee][Xx][Tt]:[Aa][Pp][Ss]*"

#define	SPICE2	0
#define	SPICE3	1
#define	HSPICE	2
#define	NGSPICE	3
#define	CDL	4

#define AUTO	2	/* TRUE | FALSE | AUTO for esDoSubckt */

#define NOT_PARALLEL    0
#define PARALLEL        1
#define ANTIPARALLEL    2

/*
 *---------------------------------------------------------
 * Variables used for merging parallel devs
 * The merging of devs is based on the fact that spcdevVisit
 * visits the devs in the same order all the time so the
 * value of esFMult[i] keeps the multiplier for the ith dev
 *---------------------------------------------------------
 */
#define	DEV_KILLED	((float) -1.0)
#define	FMULT_SIZE	(1<<10)
#define	DEV_KILLED	((float) -1.0)

#ifdef MAGIC_WRAPPER
#define 	atoCap(s)	((EFCapValue)atof(s))
#endif

extern int esFreeNodeClient(nodeClient *client);

#endif  /* _MAGIC__EXT2SPICE__EXT2SPICE_H */
