/*
 * Electric(tm) VLSI Design System
 *
 * File: tecschem.c
 * Schematic technology
 * Written by: Steven M. Rubin, Static Free Software
 * Inspired by Erwin S. K. Liu, University of Calgary
 *
 * Copyright (c) 2000 Static Free Software.
 *
 * Electric(tm) 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.
 *
 * Electric(tm) 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 Electric(tm); see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, Mass 02111-1307, USA.
 *
 * Static Free Software
 * 4119 Alpine Road
 * Portola Valley, California 94028
 * info@staticfreesoft.com
 */

/*
 * The primitives of this technology can be parameterized as follows:
 *
 * "FLIP-FLOP" has a string attribute "SCHEM_flipflop_type" which is:
 *    "TC"         for flipflop type T ("rs", "jk", "d", or "t")
 *                 with clocking C ("ms", "p", or "n")
 * "SOURCE" has a string attribute "SCHEM_source" which is:
 *    "a[/N]"      AC analysis [N is displayed]
 *    "b"          bulk connection
 *    "c[/N]"      current source [N is displayed]
 *    "cm[/N]"     metered current source [N is displayed]
 *    "n/N"        SPICE "NODESET" N
 *    "sE/N"       SPICE special line type E [N is displayed]
 *    "t[/N]"      transient analysis [N is displayed]
 *    "v[/N]"      voltage source [N is displayed]
 *    "vd[/N]"     DC analysis [N is displayed]
 *    "x/N"        SPICE extension card N
 * "TRANSISTOR" has a string attribute "SCHEM_transistor_type" which is:
 *    "nmos[W/L]"  N channel MOS transistor [width W and length L are displayed]
 *    "dmos[W/L]"  depletion MOS transistor [width W and length L are displayed]
 *    "pmos[W/L]"  P channel MOS transistor [width W and length L are displayed]
 *    "npn[A]"     NPN junction transistor [area A is displayed]
 *    "pnp[A]"     PNP junction transistor [area A is displayed]
 *    "njfet[A]"   N channel junction FET transistor [area A is displayed]
 *    "pjfet[A]"   P channel junction FET transistor [area A is displayed]
 *    "dmes[A]"    depletion MESFET transistor [area A is displayed]
 *    "emes[A]"    enhancement MESFET transistor [area A is displayed]
 *    "e2l[A]"     dual-emitter transistor [area A is displayed]
 * "DIODE" has a string attribute "SCHEM_diode" which is:
 *    "z[N]"       zener diode [area N is displayed]
 *    "[N]"        normal diode [area N is displayed]
 * "CAPACITOR" has a string attribute "SCHEM_capacitance" which is:
 *    "e[M]"       electrolytic capacitor [microfarads M are displayed]
 *    "[M]"        normal capacitor [microfarads M are displayed]
 * "TWOPORT" has a string attribute "SCHEM_twoport_type" which is:
 *    "g[G]"       transconductance (VCCS) [siemens G are displayed]
 *    "h[H]"       transresistance (CCVS) [ohms H are displayed]
 *    "u[E]"       voltage gain (VCVS) [value E are displayed]
 *    "f[F]"       current gain (CCCS) [value F are displayed]
 *    "l[Z[/P]]"   transmission line [impedance Z [and parameter P] are displayed]
 *
 * In addition, these names should be used to display attributes:
 * "BBOX"      uses "SCHEM_function"    to describe function
 * "POWER"     uses "SCHEM_source"      for characteristics
 * "RESISTOR"  uses "SCHEM_resistance"  for ohms
 * "INDUCTOR"  uses "SCHEM_inductance"  for Henrys
 * "METER"     uses "SCHEM_meter_type"  for SPICE range
 */

#include "global.h"
#include "egraphics.h"
#include "tech.h"
#include "tecschem.h"
#include "efunction.h"

/* #define SCALABLEGATES 1 */   /* uncomment for experimental scalable gate code */

/* twentieths of a unit fractions */
#define D1	(WHOLE/20)		/* 0.05 */
#define FO	(WHOLE/40)		/* 0.025 */
#define D2	(WHOLE/10)		/* 0.10 */
#define D3	(WHOLE/20 * 3)	/* 0.15 */
#define D4	(WHOLE/5)		/* 0.20 */
#define D5	(WHOLE/4)		/* 0.25 */
#define D6	(WHOLE/10 * 3)	/* 0.30 */
#define D7	(WHOLE/20 * 7)	/* 0.35 */
#define D8	(WHOLE/5 * 2)	/* 0.40 */
#define D9	(WHOLE/20 * 9)	/* 0.45 */
#define D12	(WHOLE/5 * 3)	/* 0.60 */
#define D13	(WHOLE/20 * 13)	/* 0.65 */
#define D14	(WHOLE/10 * 7)	/* 0.70 */
#define D16	(WHOLE/5 * 4)	/* 0.80 */

/* right of center by this amount */
#define	CENTERR0Q   0,Q0	/* 0.25 */
#define	CENTERR0T   0,T0	/* 0.75 */
#define	CENTERR1Q   0,Q1	/* 1.25 */
#define	CENTERR1T   0,T1	/* 1.75 */
#define	CENTERR2Q   0,Q2	/* 2.25 */
#define	CENTERR2T   0,T2	/* 2.75 */
#define	CENTERR3Q   0,Q3	/* 3.25 */
#define	CENTERR3T   0,T3	/* 3.75 */

/* left of center by this amount */
#define	CENTERL0Q   0,-Q0	/* 0.25 */
#define	CENTERL0T   0,-T0	/* 0.75 */
#define	CENTERL1Q   0,-Q1	/* 1.25 */
#define	CENTERL1T   0,-T1	/* 1.75 */
#define	CENTERL2Q   0,-Q2	/* 2.25 */
#define	CENTERL2T   0,-T2	/* 2.75 */
#define	CENTERL3Q   0,-Q3	/* 3.25 */
#define	CENTERL3T   0,-T3	/* 3.75 */
#define	CENTERL4Q   0,-Q4	/* 4.25 */
#define	CENTERL9    0,-K9	/* 9.00 */
#define	CENTERL10   0,-K10	/* 10.00 */

/* up from center by this amount */
#define	CENTERU0Q   0,Q0	/* 0.25 */
#define	CENTERU0T   0,T0	/* 0.75 */
#define	CENTERU1Q   0,Q1	/* 1.25 */
#define	CENTERU1T   0,T1	/* 1.75 */
#define	CENTERU2Q   0,Q2	/* 2.25 */
#define	CENTERU2T   0,T2	/* 2.75 */
#define	CENTERU3Q   0,Q3	/* 3.25 */
#define	CENTERU3T   0,T3	/* 3.75 */

/* down from center by this amount */
#define	CENTERD0Q   0,-Q0	/* 0.25 */
#define	CENTERD0T   0,-T0	/* 0.75 */
#define	CENTERD1Q   0,-Q1	/* 1.25 */
#define	CENTERD1T   0,-T1	/* 1.75 */
#define	CENTERD2Q   0,-Q2	/* 2.25 */
#define	CENTERD2T   0,-T2	/* 2.75 */
#define	CENTERD3Q   0,-Q3	/* 3.25 */
#define	CENTERD3T   0,-T3	/* 3.75 */

/* this much from the center to the left edge */
#define	LEFTBYP1   -D1,0		/* 0.1 */
#define LEFTBYP125 (-K1/15),0   /* 0.13333... */  /* wanted 0.125 but can't */
#define	LEFTBYP166 (-K1/12),0	/* 0.16666... */
#define	LEFTBYP2   -D2,0		/* 0.2 */
#define LEFTBYP25  (-D2-FO),0   /* 0.25 */
#define	LEFTBYP3   -D3,0		/* 0.3 */
#define	LEFTBYP33  (-K1/6),0	/* 0.3333... */
#define	LEFTBYP35  -(D3+FO),0	/* 0.35 (21/60) */
#define	LEFTBYP4   -D4,0		/* 0.4 */
#define LEFTBYP45  -(D4+FO),0   /* 0.45 (27/60) */
#define	LEFTBYP5   -D5,0		/* 0.5 */
#define	LEFTBYP6   -D6,0		/* 0.6 */
#define	LEFTBYP66  (-K1/3),0	/* 0.6666... */
#define	LEFTBYP7   -D7,0		/* 0.7 */
#define LEFTBYP75  (-D7-FO),0   /* 0.75 */
#define LEFTBYP8   -D8,0        /* 0.8 */
#define LEFTBYP875 -D9,0        /* 0.9 */ /* wanted 0.875 but can't */
#define	LEFTBYP9   -D9,0		/* 0.9 */
#define	LEFTBYP12  -D12,0		/* 1.2 */
#define	LEFTBYP14  -D14,0		/* 1.4 */
#define	LEFTBY1P6   -H0-D6,0	/* 1.6 */

/* this much from the center to the right edge */
#define	RIGHTBYP1   D1,0		/* 0.1       (6/60) */
#define RIGHTBYP125 (K1/15),0   /* 0.133...  (8/60) */ /* not precise */
#define	RIGHTBYP166 (K1/12),0	/* 0.166...  (10/60) */
#define	RIGHTBYP2   D2,0		/* 0.2       (12/60) */
#define RIGHTBYP25  (D2+FO),0   /* 0.25      (15/60) */
#define	RIGHTBYP3   D3,0		/* 0.3       (18/60) */
#define	RIGHTBYP33  (K1/6),0	/* 0.33...   (20/60) */
#define RIGHTBYP35  (D3+FO),0	/* 0.35      (21/60) */
#define RIGHTBYP3833  23,0		/* 0.3833... (23/60) */
#define	RIGHTBYP4   D4,0		/* 0.4       (24/60) */
#define RIGHTBYP433  26,0		/* 0.433...  (26/60) */
#define RIGHTBYP45  (D4+FO),0   /* 0.45      (27/60) */
#define	RIGHTBYP5   D5,0		/* 0.5       (30/60) */
#define RIGHTBYP5166   31,0		/* 0.5166... (31/60) */
#define RIGHTBYP55  (D5+FO),0	/* 0.55      (33/60) */
#define RIGHTBYP566   34,0		/* 0.566...  (34/60) */
#define	RIGHTBYP6   D6,0		/* 0.6       (36/60) */
#define RIGHTBYP6166   37,0		/* 0.6166... (37/60) */
#define	RIGHTBYP66  (K1/3),0	/* 0.66...   (40/60) */
#define	RIGHTBYP7   D7,0		/* 0.7       (42/60) */
#define RIGHTBYP75  (D7+FO),0   /* 0.75      (45/60) */
#define RIGHTBYP8   D8,0        /* 0.8       (48/60) */
#define RIGHTBYP875 D9,0        /* 0.9       (54/60) */ /* not precise */
#define	RIGHTBYP9   D9,0		/* 0.9       (54/60) */

/* this much from the center to the bottom edge */
#define	BOTBYP1    -D1,0		/* 0.1 */
#define	BOTBYP166   (-K1/12),0	/* 0.166... (10/60) */
#define	BOTBYP2    -D2,0		/* 0.2 */
#define	BOTBYP25   (-D2-FO),0	/* 0.25 */
#define	BOTBYP3    -D3,0		/* 0.3 */
#define	BOTBYP33   (-K1/6),0	/* 0.3333... */
#define BOTBYP375  -D4,0        /* 0.4 */
#define	BOTBYP4    -D4,0		/* 0.4 */
#define	BOTBYP5    -D5,0		/* 0.5 */
#define	BOTBYP6    -D6,0		/* 0.6 */
#define	BOTBYP66   (-K1/3),0	/* 0.6666... */
#define	BOTBYP7    -D7,0		/* 0.7 */
#define	BOTBYP75   (-D7-FO),0	/* 0.75 */
#define	BOTBYP8    -D8,0		/* 0.8 */
#define BOTBYP875  -D9,0        /* 0.9 */ /* wanted 0.875 but can't */
#define	BOTBYP9    -D9,0		/* 0.9 */

/* this much from the center to the top edge */
#define	TOPBYP1     D1,0		/* 0.1 */
#define	TOPBYP2     D2,0		/* 0.2 */
#define TOPBYP25    (D2+FO),0   /* 0.25 */
#define	TOPBYP3     D3,0		/* 0.3 */
#define	TOPBYP33    (K1/6),0	/* 0.3333... */
#define	TOPBYP4     D4,0		/* 0.4 */
#define	TOPBYP5     D5,0		/* 0.5 */
#define TOPBYP5833  35,0		/* 0.58333... (35/60) */
#define	TOPBYP6     D6,0		/* 0.6 */
#define	TOPBYP66    (K1/3),0	/* 0.6666... */
#define	TOPBYP7     D7,0		/* 0.7 */
#define TOPBYP75    45,0		/* 0.75       (45/60) */
#define	TOPBYP8     D8,0		/* 0.8 */
#define	TOPBYP866   (K1/12*5),0	/* 0.8666... */
#define TOPBYP875   D9,0        /* 0.9 */ /* wanted 0.875 but can't */
#define	TOPBYP9     D9,0		/* 0.9 */

/* the options table */
static COMCOMP schnegp = {NOKEYWORD, NOTOPLIST, NONEXTLIST, NOPARAMS, NOBACKUP,
	0, " \t", "size of negating bubble", "show current size"};
static KEYWORD schopt[] =
{
	{"negating-bubble-diameter",    1,{&schnegp,NOKEY,NOKEY,NOKEY,NOKEY}},
	{"disable-differential-ports",  0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
	{"enable-differential-ports",   0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
	TERMKEY
};
COMCOMP sch_parse = {schopt, NOTOPLIST, NONEXTLIST, NOPARAMS, NOBACKUP,
	0, " \t", "Schematic option", "show current options"};

TECHNOLOGY    *sch_tech;
INTBIG         sch_flipfloptypekey;		/* key for "SCHEM_flipflop_type" */
INTBIG         sch_transistortypekey;	/* key for "SCHEM_transistor_type" */
INTBIG         sch_sourcekey;			/* key for "SCHEM_source" */
INTBIG         sch_meterkey;			/* key for "SCHEM_meter_type" */
INTBIG         sch_diodekey;			/* key for "SCHEM_diode" */
INTBIG         sch_capacitancekey;		/* key for "SCHEM_capacitance" */
INTBIG         sch_resistancekey;		/* key for "SCHEM_resistance" */
INTBIG         sch_inductancekey;		/* key for "SCHEM_inductance" */
INTBIG         sch_twoportkey;			/* key for "SCHEM_twoport_type" */
INTBIG         sch_functionkey;			/* key for "SCHEM_function" */
NODEPROTO     *sch_wirepinprim, *sch_buspinprim, *sch_wireconprim, *sch_bufprim,
              *sch_andprim, *sch_orprim, *sch_xorprim, *sch_ffprim, *sch_muxprim,
              *sch_bboxprim, *sch_switchprim, *sch_offpageprim, *sch_pwrprim,
              *sch_gndprim, *sch_sourceprim, *sch_transistorprim, *sch_resistorprim,
              *sch_capacitorprim, *sch_diodeprim, *sch_inductorprim, *sch_meterprim,
			  *sch_wellprim, *sch_substrateprim, *sch_twoportprim;
ARCPROTO      *sch_wirearc, *sch_busarc;
static INTBIG  sch_bubblediameter = K1+D4;
static INTBIG  sch_bubblebox, sch_arrowbox;
PORTPROTO     *sch_anddiffports, *sch_ordiffports, *sch_xordiffports;

#ifdef SCALABLEGATES
void sch_fillpoly(POLYGON *poly, TECH_POLYGON *lay, NODEINST *ni, INTBIG lambda,
	INTSML sty);
INTBIG sch_getrange(INTBIG low, INTBIG high, INTBIG mul,INTBIG sum, INTBIG lambda, float scale);
#endif

/******************** LAYERS ********************/

#define	MAXLAYERS  4		/* total layers below      */

#define	LARC       0		/* wire                    */
#define	LBUS       1		/* bus                     */
#define	LNODE      2		/* schematic block and pin */
#define	LTEXT      3		/* documentation           */

static GRAPHICS sch_a_lay = {LAYERO, BLUE, SOLIDC, SOLIDC,
	{0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
static GRAPHICS sch_b_lay = {LAYERO, GREEN, SOLIDC, SOLIDC,
	{0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
static GRAPHICS sch_n_lay = {LAYERO, RED, SOLIDC, SOLIDC,
	{0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
static GRAPHICS sch_t_lay = {LAYERO, FACETTXT, SOLIDC, SOLIDC,
	{0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};

/* these tables must be updated together */
GRAPHICS *sch_layers[MAXLAYERS+1] = {&sch_a_lay, &sch_b_lay, &sch_n_lay,
	&sch_t_lay, NOGRAPHICS};
static char *sch_layer_names[MAXLAYERS] = {"Arc", "Bus", "Node", "Text"};
static INTBIG sch_layer_function[MAXLAYERS] = {LFMETAL1, LFBUS, LFART, LFART};
static char *sch_layer_letters[MAXLAYERS] = {"a", "b", "n", "t"};

/******************** ARCS ********************/

#define	ARCPROTOCOUNT   2

#define	AWIRE           0	/* wire               */
#define	ABUS            1	/* bus                */

/* wire arc */
static TECH_ARCLAY sch_al_w[] = { {LARC,0,FILLED}, {LARC,0,CIRCLE}, {LARC,0,VECTORS} };
static TECH_ARCS sch_a_w = {
	"wire",0,AWIRE,																	/* name */
	1,sch_al_w,																		/* layers */
	(APMETAL1<<AFUNCTIONSH)|WANTFIXANG|WANTCANTSLIDE|(45<<AANGLEINCSH)};			/* userbits */

/* bus arc */
static TECH_ARCLAY sch_al_b[] = { {LBUS,0,FILLED}, {LBUS,0,CIRCLE}, {LBUS,0,VECTORS} };
static TECH_ARCS sch_a_b = {
	"bus",K1,ABUS,																	/* name */
	1,sch_al_b,																		/* layers */
	(APBUS<<AFUNCTIONSH)|WANTFIXANG|WANTCANTSLIDE|WANTNOEXTEND|(45<<AANGLEINCSH)};	/* userbits */

TECH_ARCS *sch_arcprotos[ARCPROTOCOUNT+1] = {&sch_a_w, &sch_a_b, ((TECH_ARCS *)-1)};

/******************** PORTINST CONNECTIONS ********************/

/* these values are replaced with actual arcproto addresses */
INTBIG sch_pc_wire[]	= {-1, AWIRE, ALLGEN, -1};
INTBIG sch_pc_bus[]	= {-1, ABUS, ALLGEN, -1};
INTBIG sch_pc_either[]	= {-1, AWIRE, ABUS, ALLGEN, -1};

/******************** NODES ********************/

#define	NODEPROTOCOUNT	24

#define NWIREPIN	 1	/* wire pin */
#define NBUSPIN		 2	/* bus pin */
#define NWIRECON	 3	/* wire connector */
#define NBUF		 4	/* general BUFFER */
#define NAND		 5	/* general AND */
#define NOR			 6	/* general OR */
#define NXOR		 7	/* general XOR */
#define NFF			 8	/* general FLIP FLOP */
#define NMUX		 9	/* general MUX */
#define NBBOX		10	/* black box */
#define	NSWITCH		11	/* switch */
#define NOFFPAGE	12	/* off page connector */
#define NPWR		13	/* power */
#define NGND		14	/* ground */
#define NSOURCE		15	/* source (voltage, current) */
#define NTRANSISTOR	16	/* transistor */
#define NRESISTOR	17	/* resistor */
#define NCAPACITOR	18	/* capacitor */
#define NDIODE		19	/* diode */
#define NINDUCTOR	20	/* inductor */
#define NMETER		21	/* meter */
#define NWELL       22	/* well connection */
#define NSUBSTRATE  23	/* substrate connection */
#define NTWOPORT    24	/* generic two-port block */

/******************** POLYGONS ********************/

static char sch_NULLSTR[] = "";
static char sch_D[] = "D";
static char sch_E[] = "E";
static char sch_J[] = "J";
static char sch_K[] = "K";
static char sch_Q[] = "Q";
static char sch_R[] = "R";
static char sch_S[] = "S";
static char sch_T[] = "T";
static char sch_V[] = "V";
static char sch_ACANAL[] = "AC ANAL.";
static char sch_DCANAL[] = "DC ANAL.";
static char sch_PR[] = "PR";
static char sch_QB[] = "QB";
static char sch_CLR[] = "CLR";
static char sch_TRANANAL[] = "TRAN ANAL.";
static char sch_BULK[] = "BULK";
static char sch_METER[] = "METER";
static char sch_NODESET[] = "NODE SET";
static char sch_EXTENSION[] = "EXTENSION";
static char sch_SPECIAL[] = "SPECIAL";

static INTBIG sch_g_nullpin[]    = {CENTER,    CENTER,    CENTER,    CENTER};
static INTBIG sch_g_pindisc[]    = {CENTER,    CENTER,    RIGHTEDGE, CENTER};
static INTBIG sch_g_buspindisc[] = {CENTER,    CENTER,    RIGHTBYP5, CENTER};
static char  *sch_g_wireconj[]   = {0,  0,     0, 0,      sch_J};
static INTBIG sch_g_inv[]        = {RIGHTBYP66,CENTER,    LEFTEDGE,  TOPBYP875,
								    LEFTEDGE,  BOTBYP875};
static INTBIG sch_g_and[]        = {CENTERR0H, CENTER,    CENTERR0H, CENTERU3,
								    CENTERR0H, CENTERD3};
static INTBIG sch_g_andbox[]     = {CENTERR0H, CENTERU3,  CENTERL4,  CENTERU3,
								    CENTERL4,  TOPEDGE,   CENTERL4,  BOTEDGE,
								    CENTERL4,  CENTERD3,  CENTERR0H, CENTERD3};
static INTBIG sch_g_or[]         = {CENTERL4,  TOPEDGE,   CENTERL4,  CENTERU3,
								    CENTERL4,  CENTERU3,  CENTERL0T, CENTERU3,
								    CENTERL4,  BOTEDGE,   CENTERL4,  CENTERD3,
								    CENTERL4,  CENTERD3,  CENTERL0T, CENTERD3};
static INTBIG sch_g_ort[]        = {CENTERL0T, CENTERD3,  CENTERL0T, CENTERU3,
								    CENTERR4H, CENTER};
static INTBIG sch_g_orb[]        = {CENTERL0T, CENTERU3,  CENTERR4H, CENTER,
								    CENTERL0T, CENTERD3};
static INTBIG sch_g_orl[]        = {CENTERL9,  CENTER,    CENTERL4,  CENTERU3,
								    CENTERL4,  CENTERD3};
static INTBIG sch_g_xor[]        = {CENTERL10, CENTER,    CENTERL5,  CENTERU3,
								    CENTERL5,  CENTERD3};
static INTBIG sch_g_ffbox[]      = {LEFTEDGE,  BOTEDGE,   RIGHTEDGE, TOPEDGE};
static INTBIG sch_g_ffarrow[]    = {LEFTEDGE,  BOTBYP2,   LEFTBYP7,  CENTER,
								    LEFTEDGE,  TOPBYP2};
static char *sch_g_fftextd[]    = {(char *)-H0,  0,  (char *)D4,0,   (char *)-H0,  0,  (char *)D8,0,
								   (char *)-D4,0,  (char *)D8,0,   (char *)-D4,0,  (char *)D4,0,
								   sch_D};
static char *sch_g_fftexte[]    = {(char *)-H0,  0,  (char *)-D4,0,   (char *)-H0,  0,  (char *)-D8,0,
								   (char *)-D4,0,  (char *)-D8,0,   (char *)-D4,0,  (char *)-D4,0,
								   sch_E};
static char *sch_g_fftextq[]    = {(char *)H0,  0, (char *)D4,0,   (char *)H0,  0, (char *)D8,0,
								   (char *)D4,0, (char *)D8,0,   (char *)D4,0, (char *)D4,0,
								   sch_Q};
static char *sch_g_fftextqb[]   = {(char *)H0,  0, (char *)-D4,0,   (char *)H0,  0, (char *)-D8,0,
								   (char *)D4,0, (char *)-D8,0,   (char *)D4,0, (char *)-D4,0,
								   sch_QB};
static char *sch_g_fftextpr[]   = {(char *)-D6,0,  (char *)D6,0,   (char *)-D6,0,  (char *)H0,  0,
								   (char *)D6,0, (char *)H0,  0,   (char *)D6,0, (char *)D6,0,
								   sch_PR};
static char *sch_g_fftextclr[]  = {(char *)-D6,0,  (char *)-D6,0,   (char *)-D6,0,  (char *)-H0,  0,
								   (char *)D6,0, (char *)-H0,  0,   (char *)D6,0, (char *)-D6,0,
								   sch_CLR};
static char *sch_g_meterv[]     = {(char *)-H0,  0,  (char *)-H0,  0,   (char *)H0,  0, (char *)H0,  0,
								   sch_V};
static INTBIG sch_g_ffn[]        = {LEFTBYP6,  TOPBYP2,   LEFTBYP4,  TOPBYP2,
								    LEFTBYP4,  BOTBYP2,   LEFTBYP2,  BOTBYP2};
static INTBIG sch_g_ffp[]        = {LEFTBYP6,  BOTBYP2,   LEFTBYP4,  BOTBYP2,
								    LEFTBYP4,  TOPBYP2,   LEFTBYP2,  TOPBYP2};
static INTBIG sch_g_ffms[]       = {LEFTBYP6,  BOTBYP2,   LEFTBYP4,  BOTBYP2,
								    LEFTBYP4,  TOPBYP2,   LEFTBYP2,  TOPBYP2,
								    LEFTBYP2,  BOTBYP2,   CENTER,    BOTBYP2};
static INTBIG sch_g_mux[]        = {RIGHTBYP8, TOPBYP75,  RIGHTBYP8, BOTBYP75,
								    LEFTBYP8,  BOTEDGE,   LEFTBYP8,  TOPEDGE};
static INTBIG sch_g_bbox[]       = {LEFTEDGE,  BOTEDGE,   RIGHTEDGE, TOPEDGE};
static INTBIG sch_g_switchin[]   = {RIGHTIN1,  CENTER,    RIGHTIN1Q, CENTER};
static INTBIG sch_g_switchbar[]  = {RIGHTIN1,  CENTER,    LEFTIN1,   CENTER};
static INTBIG sch_g_switchout[]  = {LEFTIN1,   BOTIN0H,   LEFTIN0T,  BOTIN0H};
static INTBIG sch_g_offpage[]    = {LEFTEDGE,  BOTEDGE,   LEFTEDGE,  TOPEDGE,
								    RIGHTBYP5, TOPEDGE,   RIGHTEDGE, CENTER,
								    RIGHTBYP5, BOTEDGE};
static INTBIG sch_g_pwr1[]       = {CENTER,    CENTER,    CENTER,    TOPBYP66};
static INTBIG sch_g_pwr2[]       = {CENTER,    CENTER,    CENTER,    TOPBYP5};
static INTBIG sch_g_gnd[]        = {CENTER,    CENTER,    CENTER,    TOPEDGE,
								    LEFTBYP66, CENTER,    RIGHTBYP66,CENTER,
								    LEFTBYP5,  BOTBYP25,  RIGHTBYP5, BOTBYP25,
								    LEFTBYP33, BOTBYP5,   RIGHTBYP33,BOTBYP5,
								    LEFTBYP166,BOTBYP75,  RIGHTBYP166,BOTBYP75,
								    CENTER,    BOTEDGE,   CENTER,    BOTEDGE};

static char *sch_g_sourcet[]    = {0,  0,    (char *)-D4,0,   sch_TRANANAL};
static char *sch_g_sourced[]    = {0,  0,    (char *)-D4,0,   sch_DCANAL};
static char *sch_g_sourcea[]    = {0,  0,    (char *)-D4,0,   sch_ACANAL};
static char *sch_g_sourceb[]    = {0,  0,    (char *)-D4,0,   sch_BULK};
static char *sch_g_sourcem[]    = {0,  0,    (char *)-D4,0,   sch_METER};
static char *sch_g_sourcen[]    = {0,  0,    (char *)-D4,0,   sch_NODESET};
static char *sch_g_sourcex[]    = {0,  0,    (char *)-D4,0,   sch_EXTENSION};
static char *sch_g_sources[]    = {0,  0,    (char *)-D4,0,   sch_SPECIAL};
static INTBIG sch_g_source[]     = {CENTER,    CENTER,    RIGHTEDGE, CENTER};
static INTBIG sch_g_sourcec[]    = {CENTER,    TOPBYP9,   CENTER,    BOTBYP9,
								    CENTER,    BOTBYP9,   RIGHTBYP3, BOTBYP6,
								    CENTER,    BOTBYP9,   LEFTBYP3,  BOTBYP6};
static INTBIG sch_g_sourcepl[]   = {LEFTBYP3,  TOPBYP6,   RIGHTBYP3, TOPBYP6,
								    CENTER,    TOPBYP3,   CENTER,    TOPBYP9};
static INTBIG sch_g_sourcemi[]   = {LEFTBYP3,  BOTBYP7,   RIGHTBYP3, BOTBYP7};

static INTBIG sch_g_mos[]        = {LEFTEDGE,  BOTEDGE,   LEFTBYP75, BOTEDGE,
								    LEFTBYP75, BOTBYP5,   RIGHTBYP75,BOTBYP5,
								    RIGHTBYP75,BOTEDGE,   RIGHTEDGE, BOTEDGE};
static INTBIG sch_g_trantop[]    = {LEFTBYP75, BOTBYP25,  RIGHTBYP75,BOTBYP25};
static INTBIG sch_g_nmos[]       = {CENTER,    BOTBYP25,  CENTER,    TOPIN1};
static INTBIG sch_g_pmos[]       = {CENTER,    TOPBYP25,  CENTER,    TOPIN1};
static INTBIG sch_g_pmoscir[]    = {CENTER,    CENTER,    CENTER,    BOTBYP25};
static INTBIG sch_g_dmos[]       = {LEFTBYP75, BOTBYP75,  RIGHTBYP75,BOTBYP5};
static INTBIG sch_g_btran1[]     = {LEFTEDGE,  BOTEDGE,   LEFTBYP75, BOTEDGE,
								    LEFTBYP25, BOTBYP25,  RIGHTBYP25,BOTBYP25,
								    RIGHTBYP75,BOTEDGE,   RIGHTEDGE, BOTEDGE};
static INTBIG sch_g_btran2[]     = {LEFTBYP75, BOTBYP75,  LEFTBYP75, BOTEDGE,
								    LEFTBYP5,  BOTBYP875};
static INTBIG sch_g_btran3[]     = {LEFTBYP5,  BOTBYP375, LEFTBYP25, BOTBYP25,
								    LEFTBYP25, BOTBYP5};
static INTBIG sch_g_btran4[]     = {LEFTEDGE,  BOTEDGE,   LEFTBYP5,  BOTEDGE,
								    LEFTBYP5,  BOTBYP25,  RIGHTBYP5, BOTBYP25,
								    RIGHTBYP5, BOTEDGE,   RIGHTEDGE, BOTEDGE};
static INTBIG sch_g_btran5[]     = {LEFTBYP125,CENTER,    CENTER,    BOTBYP25,
								    RIGHTBYP125,CENTER};
static INTBIG sch_g_btran6[]     = {LEFTBYP125,CENTER,    CENTER,    TOPBYP25,
								    RIGHTBYP125,CENTER};
static INTBIG sch_g_btran7[]     = {LEFTEDGE,  BOTEDGE,   LEFTBYP75, BOTEDGE,
								    LEFTBYP75, BOTEDGE,   LEFTBYP75, BOTBYP25,
								    LEFTBYP875,BOTBYP25,  LEFTBYP5,  BOTBYP25,
								    LEFTBYP25, BOTBYP25,  RIGHTBYP25,BOTBYP25,
								    RIGHTBYP5, BOTBYP25,  RIGHTBYP875,BOTBYP25,
								    RIGHTBYP75,BOTBYP25,  RIGHTBYP75,BOTEDGE,
								    RIGHTBYP75,BOTEDGE,   RIGHTEDGE, BOTEDGE};
static INTBIG sch_g_resist[]     = {LEFTBYP66, CENTER,    LEFTBYP6,  CENTER,
								    LEFTBYP5,  TOPBYP5,   LEFTBYP3,  BOTBYP5,
								    LEFTBYP1,  TOPBYP5,   RIGHTBYP1, BOTBYP5,
								    RIGHTBYP3, TOPBYP5,   RIGHTBYP5, BOTBYP5,
								    RIGHTBYP6, CENTER,    RIGHTBYP66,CENTER};
static INTBIG sch_g_capac[]      = {LEFTIN0H,  TOPBYP2,   RIGHTIN0H, TOPBYP2,
								    LEFTIN0H,  BOTBYP2,   RIGHTIN0H, BOTBYP2,
								    CENTER,    TOPBYP2,   CENTER,    TOPEDGE,
								    CENTER,    BOTBYP2,   CENTER,    BOTEDGE};
static INTBIG sch_g_capace[]     = {RIGHTBYP2, BOTBYP6,   RIGHTBYP6, BOTBYP6,
								    RIGHTBYP4, BOTBYP4,   RIGHTBYP4, BOTBYP8};
static INTBIG sch_g_diode1[]     = {LEFTEDGE,  TOPBYP5,   RIGHTEDGE, TOPBYP5,
								    CENTER,    TOPBYP5,   CENTER,    TOPEDGE,
								    CENTER,    BOTBYP5,   CENTER,    BOTEDGE};
static INTBIG sch_g_diode2[]     = {LEFTEDGE,  BOTBYP5,   RIGHTEDGE, BOTBYP5,
								    CENTER,    TOPBYP5};
static INTBIG sch_g_diode3[]     = {LEFTEDGE,  TOPBYP75,  LEFTEDGE,  TOPBYP5,
								    LEFTEDGE,  TOPBYP5,   RIGHTEDGE, TOPBYP5,
								    RIGHTEDGE, TOPBYP5,   RIGHTEDGE, TOPBYP25,
								    CENTER,    TOPBYP5,   CENTER,    TOPEDGE,
								    CENTER,    BOTBYP5,   CENTER,    BOTEDGE};
static INTBIG sch_g_induct1[]    = {CENTER,    TOPEDGE,   CENTER,    BOTEDGE};
static INTBIG sch_g_induct2[]    = {LEFTBYP5,  TOPBYP33,  CENTER,    TOPBYP33};
static INTBIG sch_g_induct3[]    = {LEFTBYP5,  CENTER,    CENTER,    CENTER};
static INTBIG sch_g_induct4[]    = {LEFTBYP5,  BOTBYP33,  CENTER,    BOTBYP33};
static INTBIG sch_g_meter[]      = {CENTER,    CENTER,    RIGHTEDGE, CENTER};
static INTBIG sch_g_well[]       = {LEFTEDGE,  BOTEDGE,   RIGHTEDGE, BOTEDGE,
								    CENTER,    TOPEDGE,   CENTER,    BOTEDGE};
static INTBIG sch_g_substrate[]  = {CENTER,    CENTER,    CENTER,    TOPEDGE,
								    LEFTEDGE,  CENTER,    RIGHTEDGE, CENTER,
								    LEFTEDGE,  CENTER,    CENTER,    BOTEDGE,
								    RIGHTEDGE, CENTER,    CENTER,    BOTEDGE};

static INTBIG sch_g_twocsarr[]   = {RIGHTBYP3833,TOPBYP33,RIGHTBYP3833,BOTBYP33,
								    RIGHTBYP3833,BOTBYP33,RIGHTBYP33,BOTBYP166,
								    RIGHTBYP3833,BOTBYP33,RIGHTBYP433,BOTBYP166};
static INTBIG sch_g_twoulpl[]    = {LEFTBYP35, TOPBYP66,  LEFTBYP45, TOPBYP66,
								    LEFTBYP4,  TOPBYP5833,LEFTBYP4,  TOPBYP75};
static INTBIG sch_g_twourpl[]    = {RIGHTBYP35,TOPBYP66,  RIGHTBYP45,TOPBYP66,
								    RIGHTBYP4, TOPBYP5833,RIGHTBYP4, TOPBYP75};
static INTBIG sch_g_twourrpl[]   = {RIGHTBYP5166,TOPBYP66,RIGHTBYP6166,TOPBYP66,
								    RIGHTBYP566,TOPBYP5833,RIGHTBYP566,TOPBYP75};
static INTBIG sch_g_twobox[]     = {LEFTBYP8,  BOTEDGE,   RIGHTBYP8, TOPEDGE};
static INTBIG sch_g_twogwire[]   = {LEFTEDGE,  TOPBYP66,  LEFTBYP8,  TOPBYP66,
								    LEFTEDGE,  BOTBYP66,  LEFTBYP8,  BOTBYP66,
								    RIGHTEDGE, TOPBYP66,  RIGHTBYP8, TOPBYP66,
								    RIGHTEDGE, BOTBYP66,  RIGHTBYP8, BOTBYP66};
static INTBIG sch_g_twonormwire[]= {LEFTEDGE,  TOPBYP66,  LEFTBYP6,  TOPBYP66,
								    LEFTEDGE,  BOTBYP66,  LEFTBYP6,  BOTBYP66,
								    RIGHTEDGE, TOPBYP66,  RIGHTBYP6, TOPBYP66,
								    RIGHTBYP6, TOPBYP66,  RIGHTBYP6, TOPBYP3,
								    RIGHTEDGE, BOTBYP66,  RIGHTBYP6, BOTBYP66,
								    RIGHTBYP6, BOTBYP66,  RIGHTBYP6, BOTBYP3};
static INTBIG sch_g_twoccwire[]  = {LEFTBYP6,  TOPBYP66,  LEFTBYP6,  BOTBYP66};
static INTBIG sch_g_twocswire[]  = {RIGHTBYP6, TOPBYP3,   RIGHTBYP45,CENTER,
								    RIGHTBYP45,CENTER,    RIGHTBYP6, BOTBYP3,
								    RIGHTBYP6, BOTBYP3,   RIGHTBYP75,CENTER,
								    RIGHTBYP75,CENTER,    RIGHTBYP6, TOPBYP3};
static INTBIG sch_g_twovsc[]     = {RIGHTBYP6, CENTER,    RIGHTBYP6, TOPBYP3};
static INTBIG sch_g_twotr1[]     = {CENTER,    CENTER,    LEFTBYP8,  BOTEDGE,
								    LEFTBYP8,  TOPEDGE};
static INTBIG sch_g_twotr2[]     = {LEFTBY1P6, CENTER,    LEFTBYP8,  TOPEDGE,
								    LEFTBYP8,  BOTEDGE};
static INTBIG sch_g_twotr3[]     = {CENTER,    CENTER,    RIGHTBYP8, TOPEDGE,
								    RIGHTBYP8, BOTEDGE};
static INTBIG sch_g_twotrbox[]   = {LEFTBYP8,  TOPEDGE,   RIGHTBYP8, TOPEDGE,
								    LEFTBYP8,  BOTEDGE,   RIGHTBYP8, BOTEDGE};
static INTBIG sch_g_twotrwire[]  = {LEFTEDGE,  TOPBYP66,  LEFTBYP8,  TOPBYP66,
								    LEFTEDGE,  BOTBYP66,  LEFTBYP8,  BOTBYP66,
								    RIGHTEDGE, TOPBYP66,  RIGHTBYP9, TOPBYP66,
								    RIGHTEDGE, BOTBYP66,  RIGHTBYP9, BOTBYP66};

/******************** NODES ********************/

/* wire-pin */
static TECH_PORTS sch_wirepin_p[] = {				/* ports */
	{sch_pc_wire, "wire", NOPORTPROTO, (180<<PORTARANGESH),
		CENTER, CENTER, CENTER, CENTER}};
static TECH_POLYGON sch_wirepin_l[] = {				/* layers */
	{LARC, 0, 2, DISC, POINTS, sch_g_pindisc}};
static TECH_POLYGON sch_wirepinn_l[] = {			/* layers */
	{LARC, 0, 4, FILLEDRECT, BOX, sch_g_nullpin}};
TECH_NODES sch_wirepin = {
	"Wire_Pin",NWIREPIN,NONODEPROTO,				/* name */
	K1,K1,											/* size */
	1,sch_wirepin_p,								/* ports */
	1,sch_wirepin_l,								/* layers */
	(NPPIN<<NFUNCTIONSH)|NSQUARE|WIPEON1OR2,		/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* bus-pin */
static TECH_PORTS sch_buspin_p[] = {				/* ports */
	{sch_pc_either, "bus", NOPORTPROTO, (180<<PORTARANGESH),
		CENTER, CENTER, CENTER, CENTER}};
static TECH_POLYGON sch_buspin_l[] = {				/* layers */
	{LBUS, 0, 2, DISC, POINTS, sch_g_buspindisc}};
TECH_NODES sch_buspin = {
	"Bus_Pin",NBUSPIN,NONODEPROTO,					/* name */
	K2,K2,											/* size */
	1,sch_buspin_p,									/* ports */
	1,sch_buspin_l,									/* layers */
	(NPPIN<<NFUNCTIONSH)|NSQUARE|WIPEON1OR2,		/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* wire-con */
static TECH_PORTS sch_wirecon_p[] = {				/* ports */
	{sch_pc_either, "wire", NOPORTPROTO, (180<<PORTARANGESH)|PORTISOLATED,
		LEFTIN0H, TOPIN0H, RIGHTIN0H, BOTIN0H}};
static TECH_POLYGON sch_wirecon_l[] = {				/* layers */
	{LNODE, 0, 4, CLOSEDRECT, BOX, sch_g_bbox},
	{LTEXT, TXTMEDIUM, 1, TEXTCENT, POINTS, (INTBIG *)sch_g_wireconj}};
TECH_NODES sch_wirecon = {
	"Wire_Con",NWIRECON,NONODEPROTO,				/* name */
	K2,K2,											/* size */
	1,sch_wirecon_p,								/* ports */
	2,sch_wirecon_l,								/* layers */
	(NPCONNECT<<NFUNCTIONSH),						/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* general buffer */
static TECH_PORTS sch_buf_p[] = {					/* ports */
	{sch_pc_either, "a", NOPORTPROTO, (180<<PORTANGLESH)|(0<<PORTARANGESH)|
		(0<<PORTNETSH)|INPORT, LEFTEDGE, CENTER, LEFTEDGE, CENTER},
	{sch_pc_wire, "c", NOPORTPROTO, (270<<PORTANGLESH)|(0<<PORTARANGESH)|
		(1<<PORTNETSH)|INPORT, CENTER, BOTBYP33, CENTER, BOTBYP33},
	{sch_pc_either, "y", NOPORTPROTO, (0<<PORTANGLESH)|(0<<PORTARANGESH)|
		(2<<PORTNETSH)|OUTPORT, RIGHTBYP66, CENTER, RIGHTBYP66, CENTER}};
static TECH_POLYGON sch_buf_l[] = {					/* layers */
	{LNODE, 0, 3, CLOSED, POINTS, sch_g_inv}};
TECH_NODES sch_buf = {
	"Buffer", NBUF, NONODEPROTO,					/* name */
	K6,K6,											/* size */
	3,sch_buf_p,									/* ports */
	1,sch_buf_l,									/* layers */
	(NPBUFFER<<NFUNCTIONSH),						/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* general and */
static TECH_PORTS sch_and_p[] = {					/* ports */
	{sch_pc_either, "a", NOPORTPROTO, (180<<PORTANGLESH)|(0<<PORTARANGESH)|
		(0<<PORTNETSH)|INPORT|PORTISOLATED, CENTERL4,BOTEDGE,CENTERL4,TOPEDGE},
	{sch_pc_either, "y", NOPORTPROTO, (0<<PORTANGLESH)|(0<<PORTARANGESH)|
		(1<<PORTNETSH)|OUTPORT, CENTERR3H, CENTER, CENTERR3H, CENTER},
	{sch_pc_either, "yt", NOPORTPROTO, (0<<PORTANGLESH)|(0<<PORTARANGESH)|
		(2<<PORTNETSH)|OUTPORT, CENTERR2T, CENTERU2, CENTERR2T, CENTERU2},
	{sch_pc_either, "yc", NOPORTPROTO, (0<<PORTANGLESH)|(0<<PORTARANGESH)|
		(3<<PORTNETSH)|OUTPORT, CENTERR2T, CENTERD2, CENTERR2T, CENTERD2}};
static TECH_POLYGON sch_and_l[] = {					/* layers */
	{LNODE, 0, 3, CIRCLEARC,  POINTS, sch_g_and},
	{LNODE, 0, 6, OPENED,     POINTS, sch_g_andbox}};
TECH_NODES sch_and = {
	"And", NAND, NONODEPROTO,						/* name */
	K8,K6,											/* size */
	4,sch_and_p,									/* ports */
	2,sch_and_l,									/* layers */
	(NPGATEAND<<NFUNCTIONSH),						/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* general or */
static TECH_PORTS sch_or_p[] = {					/* ports */
	{sch_pc_either, "a", NOPORTPROTO, (180<<PORTANGLESH)|(0<<PORTARANGESH)|
		(0<<PORTNETSH)|INPORT|PORTISOLATED, CENTERL4,BOTEDGE, CENTERL3,TOPEDGE},
	{sch_pc_either, "y", NOPORTPROTO, (0<<PORTANGLESH)|(0<<PORTARANGESH)|
		(1<<PORTNETSH)|OUTPORT, CENTERR4H, CENTER, CENTERR4H, CENTER},
	{sch_pc_either, "yt", NOPORTPROTO, (0<<PORTANGLESH)|(0<<PORTARANGESH)|
		(2<<PORTNETSH)|OUTPORT, CENTERR2+D13, CENTERU2, CENTERR2+D13, CENTERU2},
	{sch_pc_either, "yc", NOPORTPROTO, (0<<PORTANGLESH)|(0<<PORTARANGESH)|
		(3<<PORTNETSH)|OUTPORT, CENTERR2+D13, CENTERD2, CENTERR2+D13, CENTERD2}};
static TECH_POLYGON sch_or_l[] = {					/* layers */
	{LNODE, 0, 3, CIRCLEARC, POINTS, sch_g_orl},
	{LNODE, 0, 3, CIRCLEARC, POINTS, sch_g_ort},
	{LNODE, 0, 3, CIRCLEARC, POINTS, sch_g_orb},
	{LNODE, 0, 8, VECTORS,   POINTS, sch_g_or}};
TECH_NODES sch_or = {
	"Or", NOR, NONODEPROTO,							/* name */
	K10,K6,											/* size */
	4,sch_or_p,										/* ports */
	4,sch_or_l,										/* layers */
	(NPGATEOR<<NFUNCTIONSH),						/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* general xor */
static TECH_PORTS sch_xor_p[] = {					/* ports */
	{sch_pc_either, "a", NOPORTPROTO, (180<<PORTANGLESH)|(0<<PORTARANGESH)|
		(0<<PORTNETSH)|INPORT|PORTISOLATED, CENTERL4,BOTEDGE, CENTERL3,TOPEDGE},
	{sch_pc_either, "y", NOPORTPROTO, (0<<PORTANGLESH)|(0<<PORTARANGESH)|
		(1<<PORTNETSH)|OUTPORT, CENTERR4H, CENTER, CENTERR4H, CENTER},
	{sch_pc_either, "yt", NOPORTPROTO, (0<<PORTANGLESH)|(0<<PORTARANGESH)|
		(2<<PORTNETSH)|OUTPORT, CENTERR2+D13, CENTERU2, CENTERR2+D13, CENTERU2},
	{sch_pc_either, "yc", NOPORTPROTO, (0<<PORTANGLESH)|(0<<PORTARANGESH)|
		(3<<PORTNETSH)|OUTPORT, CENTERR2+D13, CENTERD2, CENTERR2+D13, CENTERD2}};
static TECH_POLYGON sch_xor_l[] = {					/* layers */
	{LNODE, 0, 3, CIRCLEARC, POINTS, sch_g_orl},
	{LNODE, 0, 3, CIRCLEARC, POINTS, sch_g_ort},
	{LNODE, 0, 3, CIRCLEARC, POINTS, sch_g_orb},
	{LNODE, 0, 3, CIRCLEARC, POINTS, sch_g_xor},
	{LNODE, 0, 8, VECTORS,   POINTS, sch_g_or}};
TECH_NODES sch_xor = {
	"Xor", NXOR, NONODEPROTO,						/* name */
	K10,K6,											/* size */
	4,sch_xor_p,									/* ports */
	5,sch_xor_l,									/* layers */
	(NPGATEXOR<<NFUNCTIONSH),						/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* general flip flop */
static TECH_PORTS sch_ff_p[] = {					/* ports */
	{sch_pc_wire, "i1", NOPORTPROTO, (180<<PORTANGLESH)|(45<<PORTARANGESH)|
		(0<<PORTNETSH)|INPORT,  LEFTEDGE, TOPBYP6, LEFTEDGE, TOPBYP6},
	{sch_pc_wire, "i2", NOPORTPROTO, (180<<PORTANGLESH)|(45<<PORTARANGESH)|
		(1<<PORTNETSH)|INPORT,  LEFTEDGE, BOTBYP6, LEFTEDGE, BOTBYP6},
	{sch_pc_wire, "q", NOPORTPROTO, (0<<PORTANGLESH)|(45<<PORTARANGESH)|
		(2<<PORTNETSH)|OUTPORT, RIGHTEDGE, TOPBYP6, RIGHTEDGE, TOPBYP6},
	{sch_pc_wire, "qb", NOPORTPROTO, (0<<PORTANGLESH)|(45<<PORTARANGESH)|
		(3<<PORTNETSH)|OUTPORT, RIGHTEDGE, BOTBYP6, RIGHTEDGE, BOTBYP6},
	{sch_pc_wire, "ck", NOPORTPROTO, (180<<PORTANGLESH)|(45<<PORTARANGESH)|
		(4<<PORTNETSH)|INPORT,  LEFTEDGE, CENTER, LEFTEDGE, CENTER},
	{sch_pc_wire, "preset", NOPORTPROTO, (90<<PORTANGLESH)|(45<<PORTARANGESH)|
		(5<<PORTNETSH)|INPORT,  CENTER, TOPEDGE, CENTER, TOPEDGE},
	{sch_pc_wire, "clear", NOPORTPROTO,(270<<PORTANGLESH)|(45<<PORTARANGESH)|
		(6<<PORTNETSH)|INPORT,  CENTER, BOTEDGE, CENTER, BOTEDGE}};
static TECH_POLYGON sch_ffp_l[] = {					/* layers */
	{LNODE, 0,        4, CLOSEDRECT, BOX,    sch_g_ffbox},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftextd},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftexte},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftextq},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftextqb},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftextpr},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftextclr},
	{LNODE, 0,        3, OPENED,     POINTS, sch_g_ffarrow},
	{LNODE, 0,        4, OPENED,     POINTS, sch_g_ffp}};
static TECH_POLYGON sch_ffn_l[] = {					/* layers */
	{LNODE, 0,        4, CLOSEDRECT, BOX,    sch_g_ffbox},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftextd},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftexte},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftextq},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftextqb},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftextpr},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftextclr},
	{LNODE, 0,        3, OPENED,     POINTS, sch_g_ffarrow},
	{LNODE, 0,        4, OPENED,     POINTS, sch_g_ffn}};
static TECH_POLYGON sch_ffms_l[] = {				/* layers */
	{LNODE, 0,        4, CLOSEDRECT, BOX,    sch_g_ffbox},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftextd},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftexte},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftextq},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftextqb},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftextpr},
	{LTEXT, TXTSMALL, 4, TEXTBOX,    POINTS, (INTBIG *)sch_g_fftextclr},
	{LNODE, 0,        3, OPENED,     POINTS, sch_g_ffarrow},
	{LNODE, 0,        6, OPENED,     POINTS, sch_g_ffms}};
TECH_NODES sch_ff = {
	"Flip-Flop", NFF, NONODEPROTO,					/* name */
	K6,K10,											/* size */
	7,sch_ff_p,										/* ports */
	9,sch_ffp_l,									/* layers */
	(NPFLIPFLOP<<NFUNCTIONSH),						/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* general MUX */
static TECH_PORTS sch_mux_p[] = {					/* ports */
	{sch_pc_either, "a", NOPORTPROTO, (180<<PORTANGLESH)|(0<<PORTARANGESH)|
		(0<<PORTNETSH)|INPORT|PORTISOLATED, LEFTBYP8,BOTEDGE,LEFTBYP8,TOPEDGE},
	{sch_pc_bus, "s", NOPORTPROTO, (270<<PORTANGLESH)|(0<<PORTARANGESH)|
		(2<<PORTNETSH)|INPORT, CENTER, BOTBYP875, CENTER, BOTBYP875},
	{sch_pc_either, "y", NOPORTPROTO, (0<<PORTANGLESH)|(0<<PORTARANGESH)|
		(1<<PORTNETSH)|OUTPORT, RIGHTBYP8, CENTER, RIGHTBYP8, CENTER}};
	static TECH_POLYGON sch_mux_l[] = {					/* layers */
	{LNODE, 0, 4, CLOSED,     POINTS, sch_g_mux}};
TECH_NODES sch_mux = {
	"Mux", NMUX, NONODEPROTO,						/* name */
	K8,K10,											/* size */
	3,sch_mux_p,									/* ports */
	1,sch_mux_l,									/* layers */
	(NPMUX<<NFUNCTIONSH),							/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* black box */
static TECH_PORTS sch_bbox_p[] = {					/* ports */
	{sch_pc_either, "a", NOPORTPROTO, (0<<PORTANGLESH)|(45<<PORTARANGESH)|
		(0<<PORTNETSH)|PORTISOLATED, RIGHTEDGE, BOTEDGE, RIGHTEDGE, TOPEDGE},
	{sch_pc_either, "b", NOPORTPROTO, (90<<PORTANGLESH)|(45<<PORTARANGESH)|
		(1<<PORTNETSH)|PORTISOLATED, LEFTEDGE,  TOPEDGE, RIGHTEDGE, TOPEDGE},
	{sch_pc_either, "c", NOPORTPROTO, (180<<PORTANGLESH)|(45<<PORTARANGESH)|
		(2<<PORTNETSH)|PORTISOLATED, LEFTEDGE,  BOTEDGE, LEFTEDGE,  TOPEDGE},
	{sch_pc_either, "d", NOPORTPROTO, (270<<PORTANGLESH)|(45<<PORTARANGESH)|
		(3<<PORTNETSH)|PORTISOLATED, LEFTEDGE,  BOTEDGE, RIGHTEDGE, BOTEDGE}};
static TECH_POLYGON sch_bbox_l[] = {				/* layers */
	{LNODE, 0,         4, CLOSEDRECT, BOX,    sch_g_bbox}};
TECH_NODES sch_bbox = {
	"Bbox", NBBOX, NONODEPROTO,						/* name */
	K10,K10,										/* size */
	4,sch_bbox_p,									/* ports */
	1,sch_bbox_l,									/* layers */
	(NPUNKNOWN<<NFUNCTIONSH),						/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* switch */
static TECH_PORTS sch_switch_p[] = {				/* ports */
	{sch_pc_either, "a", NOPORTPROTO, (180<<PORTANGLESH)|(90<<PORTARANGESH)|
		(0<<PORTNETSH)|PORTISOLATED, LEFTIN1, BOTIN1, LEFTIN1, TOPIN1},
	{sch_pc_either, "y", NOPORTPROTO, (0<<PORTANGLESH)|(90<<PORTARANGESH)|
		(1<<PORTNETSH), RIGHTIN1, CENTER, RIGHTIN1, CENTER}};
static TECH_POLYGON sch_switch_l[] = {				/* layers */
	{LNODE, 0, 2, DISC,       POINTS, sch_g_switchin},
	{LNODE, 0, 2, OPENED,     POINTS, sch_g_switchbar},
	{LNODE, 0, 2, DISC,       POINTS, sch_g_switchout}};
TECH_NODES sch_switch = {
	"Switch",NSWITCH,NONODEPROTO,					/* name */
	K6,K2,											/* size */
	2,sch_switch_p,									/* ports */
	3,sch_switch_l,									/* layers */
	(NPUNKNOWN<<NFUNCTIONSH),						/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* off page connector */
static TECH_PORTS sch_offpage_p[] = {				/* ports */
	{sch_pc_either, "a", NOPORTPROTO, (180<<PORTANGLESH)|(45<<PORTARANGESH),
		LEFTEDGE,  CENTER, LEFTEDGE,  CENTER},
	{sch_pc_either, "y", NOPORTPROTO, (0<<PORTANGLESH)|(45<<PORTARANGESH),
		RIGHTEDGE, CENTER, RIGHTEDGE, CENTER}};
static TECH_POLYGON sch_offpage_l[] = {				/* layers */
	{LNODE, 0,         5, CLOSED,   POINTS, sch_g_offpage}};
TECH_NODES sch_offpage = {
	"Off-Page", NOFFPAGE, NONODEPROTO,				/* name */
	K4,K2,											/* size */
	2,sch_offpage_p,								/* ports */
	1,sch_offpage_l,								/* layers */
	(NPCONNECT<<NFUNCTIONSH),						/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* power */
static TECH_PORTS sch_pwr_p[] = {					/* ports */
	{sch_pc_wire, "pwr", NOPORTPROTO, (180<<PORTARANGESH)|PWRPORT,
		CENTER, CENTER, CENTER, CENTER}};
static TECH_POLYGON sch_pwr_l[] = {					/* layers */
	{LNODE, 0,        2, CIRCLE,   POINTS, sch_g_pwr1},
	{LNODE, 0,        2, CIRCLE,   POINTS, sch_g_pwr2}};
TECH_NODES sch_pwr = {
	"Power", NPWR, NONODEPROTO,						/* name */
	K4,K4,											/* size */
	1,sch_pwr_p,									/* ports */
	2,sch_pwr_l,									/* layers */
	(NPCONPOWER<<NFUNCTIONSH)|NSQUARE,				/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* ground */
static TECH_PORTS sch_gnd_p[] = {					/* ports */
	{sch_pc_wire, "gnd", NOPORTPROTO, (90<<PORTANGLESH)|(90<<PORTARANGESH)|
		GNDPORT, CENTER, TOPEDGE, CENTER, TOPEDGE}};
static TECH_POLYGON sch_gnd_l[] = {					/* layers */
	{LNODE, 0, 12, VECTORS, POINTS, sch_g_gnd}};
TECH_NODES sch_gnd = {
	"Ground", NGND, NONODEPROTO,					/* name */
	K4,K4,											/* size */
	1,sch_gnd_p,									/* ports */
	1,sch_gnd_l,									/* layers */
	(NPCONGROUND<<NFUNCTIONSH),						/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* source */
static TECH_PORTS sch_source_p[] = {				/* ports */
	{sch_pc_wire, "plus",   NOPORTPROTO, (90<<PORTANGLESH)|(0<<PORTARANGESH)|
		(0<<PORTNETSH), CENTER, TOPEDGE, CENTER, TOPEDGE},
	{sch_pc_wire, "minus",  NOPORTPROTO, (270<<PORTANGLESH)|(0<<PORTARANGESH)|
		(1<<PORTNETSH), CENTER, BOTEDGE, CENTER, BOTEDGE}};
static TECH_POLYGON sch_sourcev_l[] = {				/* layers */
	{LNODE, 0,         2, CIRCLE,   POINTS, sch_g_source},
	{LNODE, 0,         4, VECTORS,  POINTS, sch_g_sourcepl},
	{LNODE, 0,         2, VECTORS,  POINTS, sch_g_sourcemi},
	{LTEXT, TXTMEDIUM, 1, TEXTCENT, POINTS, (INTBIG *)sch_g_sourced}};
static TECH_POLYGON sch_sourcec_l[] = {				/* layers */
	{LNODE, 0,         2, CIRCLE,   POINTS, sch_g_source},
	{LNODE, 0,         6, VECTORS,  POINTS, sch_g_sourcec},
	{LTEXT, TXTMEDIUM, 1, TEXTCENT, POINTS, (INTBIG *)sch_g_sourced}};
static TECH_POLYGON sch_sourcet_l[] = {				/* layers */
	{LNODE, 0,         2, CIRCLE,   POINTS, sch_g_source},
	{LTEXT, TXTMEDIUM, 1, TEXTCENT, POINTS, (INTBIG *)sch_g_sourcet}};
static TECH_POLYGON sch_sourcen_l[] = {				/* layers */
	{LNODE, 0,         2, CIRCLE,   POINTS, sch_g_source},
	{LNODE, 0,         4, VECTORS,  POINTS, sch_g_sourcepl},
	{LTEXT, TXTMEDIUM, 1, TEXTCENT, POINTS, (INTBIG *)sch_g_sourcen}};
static TECH_POLYGON sch_sourcex_l[] = {				/* layers */
	{LNODE, 0,         2, CIRCLE,   POINTS, sch_g_source},
	{LNODE, 0,         4, VECTORS,  POINTS, sch_g_sourcepl},
	{LTEXT, TXTMEDIUM, 1, TEXTCENT, POINTS, (INTBIG *)sch_g_sourcex}};
static TECH_POLYGON sch_sources_l[] = {				/* layers */
	{LNODE, 0,         2, CIRCLE,   POINTS, sch_g_source},
	{LNODE, 0,         4, VECTORS,  POINTS, sch_g_sourcepl},
	{LTEXT, TXTMEDIUM, 1, TEXTCENT, POINTS, (INTBIG *)sch_g_sources}};
TECH_NODES sch_source = {
	"Source", NSOURCE, NONODEPROTO,					/* name */
	K6,K6,											/* size */
	2,sch_source_p,									/* ports */
	2,sch_sourcev_l,								/* layers */
	(NPSOURCE<<NFUNCTIONSH)|NSQUARE,				/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* transistor */
static TECH_PORTS sch_trans_p[] = {					/* ports */
	{sch_pc_wire, "g", NOPORTPROTO, (180<<PORTARANGESH)|
		(0<<PORTNETSH)|INPORT, CENTER, TOPIN1, CENTER, TOPIN1},
	{sch_pc_wire, "s", NOPORTPROTO, (180<<PORTANGLESH)|(90<<PORTARANGESH)|
		(1<<PORTNETSH)|BIDIRPORT, LEFTEDGE,  BOTEDGE,  LEFTEDGE,  BOTEDGE},
	{sch_pc_wire, "d", NOPORTPROTO, (0<<PORTANGLESH)|(90<<PORTARANGESH)|
		(2<<PORTNETSH)|BIDIRPORT, RIGHTEDGE, BOTEDGE,  RIGHTEDGE, BOTEDGE}};
static TECH_POLYGON sch_nmos_l[] = {				/* layers */
	{LNODE, 0,         6, OPENED,     POINTS, sch_g_mos},
	{LNODE, 0,         2, OPENED,     POINTS, sch_g_trantop},
	{LNODE, 0,         2, OPENED,     POINTS, sch_g_nmos}};
static TECH_POLYGON sch_pmos_l[] = {				/* layers */
	{LNODE, 0,         6, OPENED,     POINTS, sch_g_mos},
	{LNODE, 0,         2, OPENED,     POINTS, sch_g_trantop},
	{LNODE, 0,         2, OPENED,     POINTS, sch_g_pmos},
	{LNODE, 0,         2, CIRCLE,     POINTS, sch_g_pmoscir}};
static TECH_POLYGON sch_dmos_l[] = {				/* layers */
	{LNODE, 0,         6, OPENED,     POINTS, sch_g_mos},
	{LNODE, 0,         2, OPENED,     POINTS, sch_g_trantop},
	{LNODE, 0,         2, OPENED,     POINTS, sch_g_nmos},
	{LNODE, 0,         4, FILLEDRECT, BOX,    sch_g_dmos}};
static TECH_POLYGON sch_npn_l[] = {					/* layers */
	{LNODE, 0,         6, OPENED,     POINTS, sch_g_btran1},
	{LNODE, 0,         2, OPENED,     POINTS, sch_g_trantop},
	{LNODE, 0,         2, OPENED,     POINTS, sch_g_nmos},
	{LNODE, 0,         3, OPENED,     POINTS, sch_g_btran2}};
static TECH_POLYGON sch_pnp_l[] = {					/* layers */
	{LNODE, 0,         6, OPENED,     POINTS, sch_g_btran1},
	{LNODE, 0,         2, OPENED,     POINTS, sch_g_trantop},
	{LNODE, 0,         2, OPENED,     POINTS, sch_g_nmos},
	{LNODE, 0,         3, OPENED,     POINTS, sch_g_btran3}};
static TECH_POLYGON sch_njfet_l[] = {				/* layers */
	{LNODE, 0,         6, OPENED,     POINTS, sch_g_btran4},
	{LNODE, 0,         2, OPENED,     POINTS, sch_g_trantop},
	{LNODE, 0,         2, OPENED,     POINTS, sch_g_nmos},
	{LNODE, 0,         3, OPENED,     POINTS, sch_g_btran5}};
static TECH_POLYGON sch_pjfet_l[] = {				/* layers */
	{LNODE, 0,         6, OPENED,     POINTS, sch_g_btran4},
	{LNODE, 0,         2, OPENED,     POINTS, sch_g_trantop},
	{LNODE, 0,         2, OPENED,     POINTS, sch_g_nmos},
	{LNODE, 0,         3, OPENED,     POINTS, sch_g_btran6}};
static TECH_POLYGON sch_dmes_l[] = {				/* layers */
	{LNODE, 0,         6, OPENED,     POINTS, sch_g_btran4},
	{LNODE, 0,         2, OPENED,     POINTS, sch_g_trantop},
	{LNODE, 0,         2, OPENED,     POINTS, sch_g_nmos}};
static TECH_POLYGON sch_emes_l[] = {				/* layers */
	{LNODE, 0,        14, VECTORS,    POINTS, sch_g_btran7},
	{LNODE, 0,         2, OPENED,     POINTS, sch_g_nmos}};
TECH_NODES sch_trans = {
	"Transistor", NTRANSISTOR, NONODEPROTO,			/* name */
	K4,K4,											/* size */
	3,sch_trans_p,									/* ports */
	3,sch_nmos_l,									/* layers */
	(NPTRANS<<NFUNCTIONSH),							/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* resistor */
static TECH_PORTS sch_resist_p[] = {				/* ports */
	{sch_pc_wire, "a", NOPORTPROTO, (180<<PORTANGLESH)|(90<<PORTARANGESH)|
		(0<<PORTNETSH), LEFTBYP66,  CENTER, LEFTBYP66,  CENTER},
	{sch_pc_wire, "b", NOPORTPROTO, (0<<PORTANGLESH)|(90<<PORTARANGESH)|
		(1<<PORTNETSH), RIGHTBYP66, CENTER, RIGHTBYP66, CENTER}};
	static TECH_POLYGON sch_resist_l[] = {				/* layers */
	{LNODE, 0,        10, OPENED,   POINTS, sch_g_resist}};
TECH_NODES sch_resist = {
	"Resistor", NRESISTOR, NONODEPROTO,				/* name */
	K6,K2,											/* size */
	2,sch_resist_p,									/* ports */
	1,sch_resist_l,									/* layers */
	(NPRESIST<<NFUNCTIONSH),						/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* capacitor */
static TECH_PORTS sch_capac_p[] = {					/* ports */
	{sch_pc_wire, "a", NOPORTPROTO, (90<<PORTANGLESH)|(90<<PORTARANGESH)|
		(0<<PORTNETSH), CENTER, TOPEDGE, CENTER, TOPEDGE},
	{sch_pc_wire, "b", NOPORTPROTO, (270<<PORTANGLESH)|(90<<PORTARANGESH)|
		(1<<PORTNETSH), CENTER, BOTEDGE,  CENTER, BOTEDGE}};
static TECH_POLYGON sch_capac_l[] = {				/* layers */
	{LNODE, 0,         8, VECTORS,  POINTS, sch_g_capac},
	{LNODE, 0,         4, VECTORS,  POINTS, sch_g_capace}};
TECH_NODES sch_capac = {
	"Capacitor", NCAPACITOR, NONODEPROTO,			/* name */
	K4,K4,											/* size */
	2,sch_capac_p,									/* ports */
	1,sch_capac_l,									/* layers */
	(NPCAPAC<<NFUNCTIONSH),							/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* diode */
static TECH_PORTS sch_diode_p[] = {					/* ports */
	{sch_pc_wire, "a", NOPORTPROTO, (90<<PORTANGLESH)|(90<<PORTARANGESH)|
		(0<<PORTNETSH), CENTER, TOPEDGE, CENTER, TOPEDGE},
	{sch_pc_wire, "b", NOPORTPROTO, (270<<PORTANGLESH)|(90<<PORTARANGESH)|
		(1<<PORTNETSH), CENTER, BOTEDGE,  CENTER, BOTEDGE}};
static TECH_POLYGON sch_diode_l[] = {				/* layers */
	{LNODE, 0,         6, VECTORS,  POINTS, sch_g_diode1},
	{LNODE, 0,         3, FILLED,   POINTS, sch_g_diode2}};
TECH_NODES sch_diode = {
	"Diode", NDIODE, NONODEPROTO,					/* name */
	K2,K4,											/* size */
	2,sch_diode_p,									/* ports */
	2,sch_diode_l,									/* layers */
	(NPDIODE<<NFUNCTIONSH),							/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* inductor */
static TECH_PORTS sch_induct_p[] = {				/* ports */
	{sch_pc_wire, "a", NOPORTPROTO, (90<<PORTANGLESH)|(90<<PORTARANGESH)|
		(0<<PORTNETSH), CENTER, TOPEDGE, CENTER, TOPEDGE},
	{sch_pc_wire, "b", NOPORTPROTO, (270<<PORTANGLESH)|(90<<PORTARANGESH)|
		(1<<PORTNETSH), CENTER, BOTEDGE,  CENTER, BOTEDGE}};
static TECH_POLYGON sch_induct_l[] = {				/* layers */
	{LNODE, 0,         2, OPENED,   POINTS, sch_g_induct1},
	{LNODE, 0,         2, CIRCLE,   POINTS, sch_g_induct2},
	{LNODE, 0,         2, CIRCLE,   POINTS, sch_g_induct3},
	{LNODE, 0,         2, CIRCLE,   POINTS, sch_g_induct4}};
TECH_NODES sch_induct = {
	"Inductor", NINDUCTOR, NONODEPROTO,				/* name */
	K2,K4,											/* size */
	2,sch_induct_p,									/* ports */
	4,sch_induct_l,									/* layers */
	(NPINDUCT<<NFUNCTIONSH),						/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* meter */
static TECH_PORTS sch_meter_p[] = {					/* ports */
	{sch_pc_wire, "a",  NOPORTPROTO, (90<<PORTANGLESH)|(0<<PORTARANGESH)|
		(0<<PORTNETSH), CENTER, TOPEDGE, CENTER, TOPEDGE},
	{sch_pc_wire, "b",  NOPORTPROTO, (270<<PORTANGLESH)|(0<<PORTARANGESH)|
		(1<<PORTNETSH), CENTER, BOTEDGE, CENTER, BOTEDGE}};
static TECH_POLYGON sch_meterv_l[] = {				/* layers */
	{LNODE, 0,         2, CIRCLE,  POINTS, sch_g_meter},
	{LTEXT, TXTMEDIUM, 4, TEXTBOX, BOX,    (INTBIG *)sch_g_meterv}};
TECH_NODES sch_meter = {
	"Meter", NMETER, NONODEPROTO,					/* name */
	K6,K6,											/* size */
	2,sch_meter_p,									/* ports */
	2,sch_meterv_l,									/* layers */
	(NPMETER<<NFUNCTIONSH)|NSQUARE,					/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* well contact */
static TECH_PORTS sch_well_p[] = {				/* ports */
	{sch_pc_wire, "well", NOPORTPROTO, (90<<PORTANGLESH)|(90<<PORTARANGESH),
		CENTER, TOPEDGE, CENTER, TOPEDGE}};
static TECH_POLYGON sch_well_l[] = {				/* layers */
	{LNODE, 0, 4, VECTORS, POINTS, sch_g_well}};
TECH_NODES sch_well = {
	"Well", NWELL, NONODEPROTO,						/* name */
	K4,K2,											/* size */
	1,sch_well_p,									/* ports */
	1,sch_well_l,									/* layers */
	(NPWELL<<NFUNCTIONSH),							/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* substrate contact */
static TECH_PORTS sch_substrate_p[] = {				/* ports */
	{sch_pc_wire, "substrate", NOPORTPROTO, (90<<PORTANGLESH)|(90<<PORTARANGESH),
		CENTER, TOPEDGE, CENTER, TOPEDGE}};
static TECH_POLYGON sch_substrate_l[] = {			/* layers */
	{LNODE, 0, 8, VECTORS, POINTS, sch_g_substrate}};
TECH_NODES sch_substrate = {
	"Substrate", NSUBSTRATE, NONODEPROTO,			/* name */
	K3,K3,											/* size */
	1,sch_substrate_p,								/* ports */
	1,sch_substrate_l,								/* layers */
	(NPSUBSTRATE<<NFUNCTIONSH),						/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

/* two-port */
static TECH_PORTS sch_twoport_p[] = {				/* ports */
	{sch_pc_wire, "a", NOPORTPROTO, (180<<PORTANGLESH)|(90<<PORTARANGESH)|
		(0<<PORTNETSH), LEFTEDGE, TOPBYP66, LEFTEDGE, TOPBYP66},
	{sch_pc_wire, "b", NOPORTPROTO, (180<<PORTANGLESH)|(90<<PORTARANGESH)|
		(1<<PORTNETSH), LEFTEDGE, BOTBYP66, LEFTEDGE, BOTBYP66},
	{sch_pc_wire, "x", NOPORTPROTO, (0<<PORTANGLESH)|(90<<PORTARANGESH)|
		(2<<PORTNETSH), RIGHTEDGE, TOPBYP66, RIGHTEDGE, TOPBYP66},
	{sch_pc_wire, "y", NOPORTPROTO, (0<<PORTANGLESH)|(90<<PORTARANGESH)|
		(3<<PORTNETSH), RIGHTEDGE, BOTBYP66, RIGHTEDGE, BOTBYP66}};
static TECH_POLYGON sch_twoportg_l[] = {			/* layers */
	{LNODE, 0,         4, CLOSEDRECT, BOX,  sch_g_twobox},
	{LNODE, 0,         8, VECTORS,  POINTS, sch_g_twogwire},
	{LNODE, 0,         4, VECTORS,  POINTS, sch_g_twoulpl},
	{LNODE, 0,         4, VECTORS,  POINTS, sch_g_twourpl}};
static TECH_POLYGON sch_twoportvcvs_l[] = {			/* layers */
	{LNODE, 0,         4, CLOSEDRECT, BOX,  sch_g_twobox},
	{LNODE, 0,        12, VECTORS,  POINTS, sch_g_twonormwire},
	{LNODE, 0,         2, CIRCLE,   POINTS, sch_g_twovsc},
	{LNODE, 0,         4, VECTORS,  POINTS, sch_g_twourpl},
	{LNODE, 0,         4, VECTORS,  POINTS, sch_g_twoulpl}};
static TECH_POLYGON sch_twoportvccs_l[] = {			/* layers */
	{LNODE, 0,         4, CLOSEDRECT, BOX,  sch_g_twobox},
	{LNODE, 0,        12, VECTORS,  POINTS, sch_g_twonormwire},
	{LNODE, 0,         8, VECTORS,  POINTS, sch_g_twocswire},
	{LNODE, 0,         6, VECTORS,  POINTS, sch_g_twocsarr},
	{LNODE, 0,         4, VECTORS,  POINTS, sch_g_twoulpl}};
static TECH_POLYGON sch_twoportccvs_l[] = {			/* layers */
	{LNODE, 0,         4, CLOSEDRECT, BOX,  sch_g_twobox},
	{LNODE, 0,         2, /*VECTORS*/OPENEDT1,  POINTS, sch_g_twoccwire},
	{LNODE, 0,        12, VECTORS,  POINTS, sch_g_twonormwire},
	{LNODE, 0,         2, CIRCLE,   POINTS, sch_g_twovsc},
	{LNODE, 0,         4, VECTORS,  POINTS, sch_g_twourpl},
	{LNODE, 0,         4, VECTORS,  POINTS, sch_g_twoulpl}};
static TECH_POLYGON sch_twoportcccs_l[] = {			/* layers */
	{LNODE, 0,         4, CLOSEDRECT, BOX,  sch_g_twobox},
	{LNODE, 0,         2, /*VECTORS*/OPENEDT1,  POINTS, sch_g_twoccwire},
	{LNODE, 0,        12, VECTORS,  POINTS, sch_g_twonormwire},
	{LNODE, 0,         8, VECTORS,  POINTS, sch_g_twocswire},
	{LNODE, 0,         6, VECTORS,  POINTS, sch_g_twocsarr},
	{LNODE, 0,         4, VECTORS,  POINTS, sch_g_twoulpl}};
static TECH_POLYGON sch_twoporttran_l[] = {			/* layers */
	{LNODE, 0,         4, VECTORS,  POINTS, sch_g_twotrbox},
	{LNODE, 0,         3, CIRCLEARC,POINTS, sch_g_twotr1},
	{LNODE, 0,         3, CIRCLEARC,POINTS, sch_g_twotr2},
	{LNODE, 0,         3, CIRCLEARC,POINTS, sch_g_twotr3},
	{LNODE, 0,         8, VECTORS,  POINTS, sch_g_twotrwire},
	{LNODE, 0,         4, VECTORS,  POINTS, sch_g_twoulpl},
	{LNODE, 0,         4, VECTORS,  POINTS, sch_g_twourrpl}};
TECH_NODES sch_twoport = {
	"Two-Port", NTWOPORT, NONODEPROTO,				/* name */
	K10,K6,											/* size */
	4,sch_twoport_p,								/* ports */
	4,sch_twoportg_l,								/* layers */
	(NPTLINE<<NFUNCTIONSH),							/* userbits */
	0,0,0,0,0,0,0,0,0};								/* characteristics */

TECH_NODES *sch_nodeprotos[NODEPROTOCOUNT+1] = {
	&sch_wirepin,  &sch_buspin,   &sch_wirecon,					/* pins */
	&sch_buf,      &sch_and,      &sch_or,       &sch_xor,		/* gates */
	&sch_ff,       &sch_mux,									/* flipflop, mux */
	&sch_bbox,     &sch_switch,									/* box/switch */
	&sch_offpage,												/* offpage */
	&sch_pwr,      &sch_gnd,      &sch_source,					/* pwr/gnd/source */
	&sch_trans,    &sch_resist,   &sch_capac,					/* trans/resist/capac */
	&sch_diode,    &sch_induct,									/* diode/inductor */
	&sch_meter,													/* meter */
	&sch_well,     &sch_substrate,								/* well/substrate */
	&sch_twoport,												/* twoport */
	((TECH_NODES *)-1)
};

static INTBIG sch_node_widoff[NODEPROTOCOUNT*4] = {
	  0, 0, 0, 0,    0, 0, 0, 0,    0, 0, 0, 0,					/* pins */
/*	 H0,H0,H0,H0,    0, 0, 0, 0,   H0,H0,H0,H0, */				/* pins */
	  0,K1, 0, 0,    0,H0, 0, 0,   K1,H0, 0, 0,    0,H0, 0, 0,	/* gates */
	  0, 0, 0, 0,    0, 0, 0, 0,								/* flipflop, mux */
	  0, 0, 0, 0,    0, 0, 0, 0,								/* box/switch */
	  0, 0, 0, 0,												/* offpage */
	  0, 0, 0, 0,    0, 0, 0, 0,    0, 0, 0, 0,					/* pwr/gnd/source */
	  0, 0, 0,K1,    0, 0, 0, 0,    0, 0, 0, 0,					/* trans/resist/capac */
	  0, 0, 0, 0,    0, 0, 0, 0,								/* diode/inductor */
	  0, 0, 0, 0,												/* meter */
	  0, 0, 0, 0,    0, 0, 0, 0,								/* well/substrate */
	  0, 0, 0, 0												/* twoport */
};

static char *sch_node_vhdlstring[NODEPROTOCOUNT] = {
	"", "", "",													/* pins */
	"buffer/inverter", "and%d/nand%d", "or%d/nor%d", "xor%d/xnor%d",	/* gates */
	"ff", "mux%d",												/* flipflop, mux */
	"", "",														/* box/switch */
	"",															/* offpage */
	"", "", "",													/* pwr/gnd/source */
	"", "", "",													/* trans/resist/capac */
	"", "",														/* diode/inductor */
	"",															/* meter */
	"", "",														/* well/substrate */
	""															/* twoport */
};

/******************** VARIABLE AGGREGATION ********************/

TECH_VARIABLES sch_variables[] =
{
	/* set general information about the technology */
	{"TECH_layer_names", (char *)sch_layer_names, 0.0,
		VSTRING|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},
	{"TECH_layer_function", (char *)sch_layer_function, 0.0,
		VINTEGER|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},
	{"TECH_node_width_offset", (char *)sch_node_widoff, 0.0,
		VFRACT|VDONTSAVE|VISARRAY|((NODEPROTOCOUNT*4)<<VLENGTHSH)},
	{"TECH_vhdl_names", (char *)sch_node_vhdlstring, 0.0,
		VSTRING|VDONTSAVE|VISARRAY|(NODEPROTOCOUNT<<VLENGTHSH)},

	/* set information for the USER analysis aid */
	{"USER_layer_letters", (char *)sch_layer_letters, 0.0,
		VSTRING|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},
	{NULL, NULL, 0.0, 0}
};

/******************** ROUTINES ********************/

INTSML sch_initprocess(TECHNOLOGY *tech, INTSML pass)
{
	/* initialize the technology variable */
	if (pass == 0) sch_tech = tech; else
		if (pass == 1)
	{
		sch_wirepinprim = getnodeproto("schematic:Wire_Pin");
		sch_buspinprim = getnodeproto("schematic:Bus_Pin");
		sch_wireconprim = getnodeproto("schematic:Wire_Con");
		sch_bufprim = getnodeproto("schematic:Buffer");
		sch_andprim = getnodeproto("schematic:And");
		sch_orprim = getnodeproto("schematic:Or");
		sch_xorprim = getnodeproto("schematic:Xor");
		sch_ffprim = getnodeproto("schematic:Flip-Flop");
		sch_muxprim = getnodeproto("schematic:Mux");
		sch_bboxprim = getnodeproto("schematic:Bbox");
		sch_switchprim = getnodeproto("schematic:Switch");
		sch_offpageprim = getnodeproto("schematic:Off-Page");
		sch_pwrprim = getnodeproto("schematic:Power");
		sch_gndprim = getnodeproto("schematic:Ground");
		sch_sourceprim = getnodeproto("schematic:Source");
		sch_transistorprim = getnodeproto("schematic:Transistor");
		sch_resistorprim = getnodeproto("schematic:Resistor");
		sch_capacitorprim = getnodeproto("schematic:Capacitor");
		sch_diodeprim = getnodeproto("schematic:Diode");
		sch_inductorprim = getnodeproto("schematic:Inductor");
		sch_meterprim = getnodeproto("schematic:Meter");
		sch_wellprim = getnodeproto("schematic:Well");
		sch_substrateprim = getnodeproto("schematic:Substrate");
		sch_twoportprim = getnodeproto("schematic:Two-Port");

		sch_wirearc = getarcproto("schematic:wire");
		sch_busarc = getarcproto("schematic:bus");

		sch_flipfloptypekey = makekey("SCHEM_flipflop_type");
		sch_transistortypekey = makekey("SCHEM_transistor_type");
		sch_sourcekey = makekey("SCHEM_source");
		sch_meterkey = makekey("SCHEM_meter_type");
		sch_diodekey = makekey("SCHEM_diode");
		sch_capacitancekey = makekey("SCHEM_capacitance");
		sch_resistancekey = makekey("SCHEM_resistance");
		sch_inductancekey = makekey("SCHEM_inductance");
		sch_twoportkey = makekey("SCHEM_twoport_type");
		sch_functionkey = makekey("SCHEM_function");

		/* differential ports are enabled */
		sch_anddiffports = sch_ordiffports = sch_xordiffports = NOPORTPROTO;
	}
	return(0);
}

void sch_termprocess(void)
{
	/* put all ports into play so that deallocation will be complete */
	if (sch_anddiffports == NOPORTPROTO) return;
	sch_andprim->firstportproto->nextportproto->nextportproto = sch_anddiffports;
	sch_orprim->firstportproto->nextportproto->nextportproto = sch_ordiffports;
	sch_xorprim->firstportproto->nextportproto->nextportproto = sch_xordiffports;
	sch_anddiffports = sch_ordiffports = sch_xordiffports = NOPORTPROTO;
}

void sch_setmode(INTSML count, char *par[])
{
	REGISTER char *pp;
	REGISTER INTSML l;

	if (count == 0)
	{
		/* report size of negating bubbles */
		ttyputmsg("Diameter of negating bubbles is %s", frtoa(sch_bubblediameter));
		return;
	}

	l = strlen(pp = par[0]);
	if (namesamen(pp, "negating-bubble-diameter", l) == 0)
	{
		/* get new negating bubble diameter */
		if (count <= 1)
		{
			ttyputmsg("Diameter of negating bubbles is %s", frtoa(sch_bubblediameter));
			return;
		}
		l = (INTSML)atofr(par[1]);
		if (l > 0) sch_bubblediameter = l; else
			ttyputerr("Bubble diameter must be positive and nonzero");
		return;
	}
	if (namesamen(pp, "disable-differential-ports", l) == 0)
	{
		if (sch_anddiffports != NOPORTPROTO)
		{
			ttyputerr("Differential ports are already disabled");
			return;
		}
		sch_anddiffports = sch_andprim->firstportproto->nextportproto->nextportproto;
		sch_andprim->firstportproto->nextportproto->nextportproto = NOPORTPROTO;

		sch_ordiffports = sch_orprim->firstportproto->nextportproto->nextportproto;
		sch_orprim->firstportproto->nextportproto->nextportproto = NOPORTPROTO;

		sch_xordiffports = sch_xorprim->firstportproto->nextportproto->nextportproto;
		sch_xorprim->firstportproto->nextportproto->nextportproto = NOPORTPROTO;
		return;
	}
	if (namesamen(pp, "enable-differential-ports", l) == 0)
	{
		if (sch_anddiffports == NOPORTPROTO)
		{
			ttyputerr("Differential ports are already enabled");
			return;
		}
		sch_andprim->firstportproto->nextportproto->nextportproto = sch_anddiffports;
		sch_orprim->firstportproto->nextportproto->nextportproto = sch_ordiffports;
		sch_xorprim->firstportproto->nextportproto->nextportproto = sch_xordiffports;
		sch_anddiffports = sch_ordiffports = sch_xordiffports = NOPORTPROTO;
		return;
	}
	ttyputerr("Unknown SCHEMATIC option: %s", pp);
}

INTBIG sch_request(char *command, va_list ap)
{
	if (namesame(command, "get-bubble-size") == 0)
	{
		return(sch_bubblediameter);
	}
	if (namesame(command, "set-bubble-size") == 0)
	{
		sch_bubblediameter = va_arg(ap, INTBIG);
		return(0);
	}
	return(0);
}

static TECH_POLYGON *sch_layerlist;
static INTBIG sch_specialkey;		/* variable key for current node info */
static INTSML sch_advancestring;		/* amount to adjust string in variable */

INTSML sch_nodepolys(NODEINST *ni)
{
	REGISTER VARIABLE *var;
	char *extra;
	REGISTER char *str;
	REGISTER INTSML total, pindex, i;
	REGISTER INTBIG hei;
	REGISTER PORTARCINST *pi;

	/* get the default number of polygons and list of layers */
	pindex = ni->proto->primindex;
	total = sch_nodeprotos[pindex-1]->layercount;
	sch_layerlist = sch_nodeprotos[pindex-1]->layerlist;
	sch_specialkey = -1;

	/* special cases for special primitives */
	switch (pindex)
	{
		case NWIREPIN:	/* wire pins disappear with one or two wires */
			if (tech_pinusecount(ni, NOARCPROTO) != 0) sch_layerlist = sch_wirepinn_l;
			break;

		case NBUSPIN:	/* bus pins get bigger in "T" configurations, disappear when alone and exported */
			for (i=0, pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
				if (pi->conarcinst->proto == sch_busarc) i++;
			if (i > 2)
			{
				/* larger pin because it is connected to 3 or more arcs */
				sch_g_buspindisc[4] = H0;
			} else
			{
				/* smaller pin because it has 0, 1, or 2 connections */
				sch_g_buspindisc[4] = Q0;
				if (i == 0 && ni->firstportexpinst != NOPORTEXPINST) total = 0;
			}
			break;

		case NFF:	/* add on more if this is a special flip-flop */
			var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_flipfloptypekey);
			sch_g_fftextd[16] = sch_D;
			sch_g_fftexte[16] = sch_E;
			if (var != NOVARIABLE)
			{
				for (str = (char *)var->addr; *str != 0; str++)
				{
					if (namesamen(str, "rs", 2) == 0)
					{
						sch_g_fftextd[16] = sch_R;
						sch_g_fftexte[16] = sch_S;
						str++;   continue;
					}
					if (namesamen(str, "jk", 2) == 0)
					{
						sch_g_fftextd[16] = sch_J;
						sch_g_fftexte[16] = sch_K;
						str++;   continue;
					}
					if (namesamen(str, "t", 1) == 0)
					{
						sch_g_fftextd[16] = sch_T;
						sch_g_fftexte[16] = sch_NULLSTR;
						continue;
					}
					if (namesamen(str, "d", 1) == 0) continue;
					if (namesamen(str, "ms", 2) == 0)
					{
						sch_layerlist = sch_ffms_l;
						str++;   continue;
					}
					if (namesamen(str, "p", 1) == 0) continue;
					if (namesamen(str, "n", 1) == 0)
					{
						sch_layerlist = sch_ffn_l;
						continue;
					}
				}
			}
			break;

		case NSWITCH:	/* add in multiple connection sites for switch */
			hei = (ni->highy - ni->lowy) / sch_tech->deflambda;
			if (hei >= 4) total += (hei/2)-1;
			if (((hei/2)&1) == 0) sch_g_switchbar[7] = 0; else
				sch_g_switchbar[7] = K1;
			break;

		case NSOURCE:	/* sources require voltage/current distinction */
			switch (nodefunction(ni, &extra))
			{
				case NPSOURCEV:
					total = 3;
					break;
				case NPSOURCEC:
					sch_layerlist = sch_sourcec_l;
					break;
				case NPSOURCECM:
					sch_layerlist = sch_sourcec_l;
					sch_layerlist[2].points = (INTBIG *)sch_g_sourcem;
					total = 3;
					break;
				case NPSOURCET:
					sch_layerlist = sch_sourcet_l;
					total = 2;
					break;
				case NPSOURCEDC:
					sch_layerlist[3].points = (INTBIG *)sch_g_sourced;
					total = 4;
					break;
				case NPSOURCEAC:
					sch_layerlist[3].points = (INTBIG *)sch_g_sourcea;
					total = 4;
					break;
				case NPSOURCEN:
					sch_layerlist = sch_sourcen_l;
					total = 3;
					break;
				case NPSOURCEX:
					sch_layerlist = sch_sourcex_l;
					total = 3;
					break;
				case NPSOURCEB:
					sch_layerlist[3].points = (INTBIG *)sch_g_sourceb;
					total = 4;
					break;
				case NPSOURCES:
					sch_layerlist = sch_sources_l;
					total = 3;
					break;
			}
			var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_sourcekey);
			if (var != NOVARIABLE)
			{
				sch_specialkey = sch_sourcekey;
				if (extra != 0) sch_advancestring = extra - (char *)var->addr; else
					sch_advancestring = strlen((char *)var->addr);
			}
			break;

		case NTRANSISTOR:	/* determine table to use for transistors */
			switch (nodefunction(ni, &extra))
			{
				case NPTRANMOS:  sch_layerlist = sch_nmos_l;   total = 3;   break;
				case NPTRAPMOS:  sch_layerlist = sch_pmos_l;   total = 4;   break;
				case NPTRADMOS:  sch_layerlist = sch_dmos_l;   total = 4;   break;
				case NPTRANPN:   sch_layerlist = sch_npn_l;    total = 4;   break;
				case NPTRAPNP:   sch_layerlist = sch_pnp_l;    total = 4;   break;
				case NPTRANJFET: sch_layerlist = sch_njfet_l;  total = 4;   break;
				case NPTRAPJFET: sch_layerlist = sch_pjfet_l;  total = 4;   break;
				case NPTRADMES:  sch_layerlist = sch_dmes_l;   total = 3;   break;
				case NPTRAEMES:  sch_layerlist = sch_emes_l;   total = 2;   break;
			}
			var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_transistortypekey);
			if (var != NOVARIABLE)
			{
				sch_specialkey = sch_transistortypekey;
				if (extra != 0) sch_advancestring = extra - (char *)var->addr; else
					sch_advancestring = strlen((char *)var->addr);
			}
			break;

		case NDIODE:		/* add in type and area for diodes */
			if (nodefunction(ni, &extra) == NPDIODEZ)
			{
				sch_diode_l[0].points = sch_g_diode3;
				sch_diode_l[0].count = 10;
			} else
			{
				sch_diode_l[0].points = sch_g_diode1;
				sch_diode_l[0].count = 6;
			}
			var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_diodekey);
			if (var != NOVARIABLE)
			{
				sch_specialkey = sch_diodekey;
				if (extra != 0) sch_advancestring = extra - (char *)var->addr; else
					sch_advancestring = strlen((char *)var->addr);
			}
			break;

		case NCAPACITOR:		/* add in type etc. for capacitors */
			if (nodefunction(ni, &extra) == NPECAPAC) total++;
			var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_capacitancekey);
			if (var != NOVARIABLE)
			{
				sch_specialkey = sch_capacitancekey;
				if (extra != 0) sch_advancestring = extra - (char *)var->addr; else
					sch_advancestring = strlen((char *)var->addr);
			}
			break;

		case NMETER:	/* meters require voltage/amperage distinction */
			break;

		case NTWOPORT:		/* add in two-port type */
			var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_twoportkey);
			if (var != NOVARIABLE)
			{
				str = (char *)var->addr;
				while (*str == ' ') str++;
				switch (*str)
				{
					case 'u':  case 'U':
						sch_layerlist = sch_twoportvcvs_l;
						total = 5;
						str++;
						break;
					case 'g':  case 'G':
						sch_layerlist = sch_twoportvccs_l;
						total = 5;
						str++;
						break;
					case 'h':  case 'H':
						sch_layerlist = sch_twoportccvs_l;
						total = 6;
						str++;
						break;
					case 'f':  case 'F':
						sch_layerlist = sch_twoportcccs_l;
						total = 6;
						str++;
						break;
					case 'l':  case 'L':
						sch_layerlist = sch_twoporttran_l;
						total = 7;
						str++;
						break;
				}

				/* if the variable is displayable, don't show it here */
				sch_specialkey = sch_twoportkey;
				sch_advancestring = str - (char *)var->addr;
			}
			break;
	}

	/* add in displayable variables */
	tech_realpolys = total;
	total += tech_displayablenvars(ni);
	return(total);
}

INTSML sch_nodeEpolys(NODEINST *ni)
{
	return(0);
}

void sch_shapeEnodepoly(NODEINST *ni, INTSML box, POLYGON *poly) {}

void sch_shapenodepoly(NODEINST *ni, INTSML box, POLYGON *poly)
{
	REGISTER VARIABLE *var;

	/* handle displayable variables */
	if (box >= tech_realpolys)
	{
		var = tech_filldisplayablenvar(ni, poly);
		if (var != NOVARIABLE && var->key == sch_specialkey)
		{
			/* store character offset in the variable */
			var->type |= (sch_advancestring << VLENGTHSH);
			poly->string += sch_advancestring;
		}
		return;
	}

	/* handle extra blobs on tall switches */
	if (ni->proto->primindex == NSWITCH && box >= 2)
	{
		sch_g_switchout[3] = sch_g_switchout[7] = WHOLE*2*(box-1) - WHOLE;
		box = 2;
	}

#ifdef SCALABLEGATES
	if (ni->proto->primindex == NAND || ni->proto->primindex == NOR ||
		ni->proto->primindex == NXOR)
	{
		sch_fillpoly(poly, &sch_layerlist[box], ni, sch_tech->deflambda, FILLED);
	} else
#endif
	{
		tech_fillpoly(poly, &sch_layerlist[box], ni, sch_tech->deflambda, FILLED);
	}

	poly->font = sch_layerlist[box].portnum;
	poly->tech = sch_tech;
	poly->desc = sch_layers[poly->layer];
}

#ifdef SCALABLEGATES
/* scalable version of polygon filling for AND, OR, and XOR gates */
void sch_fillpoly(POLYGON *poly, TECH_POLYGON *lay, NODEINST *ni, INTBIG lambda,
	INTSML sty)
{
	REGISTER INTSML i, lastpoint;
	REGISTER INTBIG *pt, xm, xs, ym, ys;
	INTBIG minlx, minhx, minly, minhy;
	float scale;

	/* one thing is constant */
	poly->layer = lay->layernum;

	/* normal description from the technology tables */
	switch (lay->representation)
	{
		case BOX:
		lastpoint = 8;
		if (lay->style == FILLEDRECT || lay->style == CLOSEDRECT)
		{
			if (poly->limit < 2) (void)extendpolygon(poly, 2);
			subrange(ni->lowx, ni->highx, lay->points[0], lay->points[1],
				lay->points[4], lay->points[5], &poly->xv[0], &poly->xv[1], lambda);
			subrange(ni->lowy, ni->highy, lay->points[2], lay->points[3],
				lay->points[6], lay->points[7], &poly->yv[0], &poly->yv[1], lambda);
			if (lay->representation == MINBOX)
			{
				/* make sure the box is large enough */
				lastpoint = 16;
				subrange(ni->lowx, ni->highx, lay->points[8], lay->points[9],
					lay->points[12], lay->points[13], &minlx, &minhx, lambda);
				subrange(ni->lowy, ni->highy, lay->points[10], lay->points[11],
					lay->points[14], lay->points[15], &minly, &minhy, lambda);
				if (poly->xv[0] > minlx) poly->xv[0] = minlx;
				if (poly->xv[1] < minhx) poly->xv[1] = minhx;
				if (poly->yv[0] > minly) poly->yv[0] = minly;
				if (poly->yv[1] < minhy) poly->yv[1] = minhy;
			}
		} else
		{
			if (poly->limit < 4) (void)extendpolygon(poly, 4);
			subrange(ni->lowx, ni->highx, lay->points[0], lay->points[1],
				lay->points[4], lay->points[5], &poly->xv[0], &poly->xv[2], lambda);
			subrange(ni->lowy, ni->highy, lay->points[2], lay->points[3],
				lay->points[6], lay->points[7], &poly->yv[0], &poly->yv[1], lambda);
			if (lay->representation == MINBOX)
			{
				/* make sure the box is large enough */
				lastpoint = 16;
				subrange(ni->lowx, ni->highx, lay->points[8], lay->points[9],
					lay->points[10], lay->points[13], &minlx, &minhx, lambda);
				subrange(ni->lowy, ni->highy, lay->points[10], lay->points[11],
					lay->points[14], lay->points[15], &minly, &minhy, lambda);
				if (poly->xv[0] > minlx) poly->xv[0] = minlx;
				if (poly->xv[2] < minhx) poly->xv[2] = minhx;
				if (poly->yv[0] > minly) poly->yv[0] = minly;
				if (poly->yv[1] < minhy) poly->yv[1] = minhy;
			}
			poly->xv[1] = poly->xv[0];   poly->xv[3] = poly->xv[2];
			poly->yv[3] = poly->yv[0];   poly->yv[2] = poly->yv[1];
		}
		break;

		case POINTS:
		pt = &lay->points[0];
		scale = (float)(ni->highx - ni->lowx);
		scale /= (ni->proto->highx - ni->proto->lowx);
		if (poly->limit < lay->count) (void)extendpolygon(poly, lay->count);
		for(i=0; i<lay->count; i++)
		{
			xm = *pt++;   xs = *pt++;   ym = *pt++;   ys = *pt++;
			poly->xv[i] = sch_getrange(ni->lowx,ni->highx, xm,xs, lambda, scale);
			poly->yv[i] = sch_getrange(ni->lowy,ni->highy, ym,ys, lambda, 1.0);
		}
		lastpoint = lay->count*4;
		break;
	}
	poly->count = lay->count;
	poly->style = lay->style;
	if (lay->style >= TEXTCENT && lay->style <= TEXTBOX)
		poly->string = (char *)lay->points[lastpoint];
}

/*
 * routine to perform a range calculation (similar to "subrange") but on
 * only one value rather than two.  The extent of the range is from "low"
 * to "high" and the value of lambda is "lambda".  The routine returns
 * the value (low+high)/2 + (high-low)*mul/WHOLE + sum*lambda/WHOLE.
 */
INTBIG sch_getrange(INTBIG low, INTBIG high, INTBIG mul,INTBIG sum, INTBIG lambda, float scale)
{
	REGISTER float center, range, offset;

	center = (float)(low + high);   center /= 2.0;
	range = (float)(high - low); 
	offset = range*mul/WHOLE;
	offset += sum*lambda/WHOLE;
	offset *= scale;
	return((INTBIG)(center + offset));
}
#endif

void sch_shapeportpoly(NODEINST *ni, PORTPROTO *pp, POLYGON *poly, XARRAY trans,
	INTSML purpose)
{
	REGISTER INTSML pindex, i, e, total, besti;
	REGISTER INTBIG xposition, yposition, x, y, lambda, wantx, wanty, bestdist,
		bestx, besty, dist;
	REGISTER PORTARCINST *pi;
	REGISTER ARCINST *ai;
	extern AIDENTRY *us_aid;
	REGISTER WINDOWPART *w;

	pindex = ni->proto->primindex;

	/* special case for extendible primitives */
	if (purpose != 0 && sch_nodeprotos[pindex-1]->portlist[0].addr == pp)
	{
		/* initialize */
		wantx = poly->xv[0];   wanty = poly->yv[0];
		poly->count = 1;
		poly->style = FILLED;
		lambda = ni->proto->tech->deflambda;
		bestdist = HUGEINT;

		/* schematic gates must keep connections discrete and separate */
		if (pindex == NAND || pindex == NOR || pindex == NXOR || pindex == NMUX)
		{
			/* determine total number of arcs already on this port */
			for(total=0, pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
				if (pi->proto == pp) total++;

			/* cycle through the arc positions */
			total = (INTSML)maxi(total+2, 3);
			for(i=0; i<total; i++)
			{
				/* compute the position along the left edge */
				yposition = (i+1)/2 * WHOLE * 2;
				if ((i&1) != 0) yposition = -yposition;

				/* compute indentation (for OR and XOR) */
				if (pindex != NMUX) xposition = -K4; else
					xposition = -(ni->highx - ni->lowx) * 4 / 10 * WHOLE / sch_tech->deflambda;
				if (pindex == NOR || pindex == NXOR) switch (i)
				{
					case 0: xposition += T0;   break;
					case 1:
					case 2: xposition += H0;   break;
				}

				/* fill the polygon with that point */
				x = getrange(ni->lowx, ni->highx, 0, xposition, lambda);
				y = getrange(ni->lowy, ni->highy, 0, yposition, lambda);
				xform(x, y, &poly->xv[0], &poly->yv[0], trans);
				x = poly->xv[0];   y = poly->yv[0];

				/* check for duplication */
				for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
				{
					ai = pi->conarcinst;
					if (ai->end[0].portarcinst == pi) e = 0; else e = 1;
					if (ai->end[e].xpos == x && ai->end[e].ypos == y) break;
				}

				/* if there is no duplication, this is a possible position */
				if (pi == NOPORTARCINST)
				{
					dist = abs(wantx - x) + abs(wanty - y);
					if (dist < bestdist)
					{
						bestdist = dist;   bestx = x;   besty = y;   besti = i;
					}
				}
			}
			if (bestdist == HUGEINT) ttyputerr("Warning: cannot find gate port");

			/* set the closest port */
			poly->xv[0] = bestx;   poly->yv[0] = besty;

			/* make sure the node is large enough */
			if (besti*lambda*2 >= ni->highy - ni->lowy)
			{
				startobjectchange((INTBIG)ni, VNODEINST);
				modifynodeinst(ni, 0, -lambda*2, 0, lambda*2, 0, 0);
				endobjectchange((INTBIG)ni, VNODEINST);

				/* make this gate change visible if it is in a window */
				for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
					if (w->curnodeproto == ni->parent) break;
				if (w != NOWINDOWPART) (void)askaid(us_aid, "flush-changes");
			}
			return;
		}

		/* switches must discretize the location of connections */
		if (pindex == NSWITCH)
		{
			/* cycle through the possible positions */
			total = (ni->highy - ni->lowy) / lambda / 2;
			for(i=0; i<total; i++)
			{
				yposition = i * 2 * WHOLE + K1;
				xposition = -K2;
				x = getrange(ni->lowx, ni->highx, 0, xposition, lambda);
				y = getrange(ni->lowy, ni->highy, -H0, yposition, lambda);
				xform(x, y, &poly->xv[0], &poly->yv[0], trans);
				x = poly->xv[0];   y = poly->yv[0];
				dist = abs(wantx - x) + abs(wanty - y);
				if (dist < bestdist)
				{
					bestdist = dist;   bestx = x;   besty = y;   besti = i;
				}
			}
			if (bestdist == HUGEINT) ttyputerr("Warning: cannot find switch port");

			/* set the closest port */
			poly->xv[0] = bestx;   poly->yv[0] = besty;
			return;
		}
	}
	tech_fillportpoly(ni, pp, poly, trans, sch_nodeprotos[pindex-1], CLOSED);
}

INTSML sch_arcpolys(ARCINST *ai)
{
	REGISTER INTSML i;

	i = sch_arcprotos[ai->proto->arcindex]->laycount;
	sch_bubblebox = sch_arrowbox = -1;
	if ((ai->userbits&(ISNEGATED|NOTEND0)) == ISNEGATED) sch_bubblebox = i++;
	if ((ai->userbits&ISDIRECTIONAL) != 0) sch_arrowbox = i++;

	/* add in displayable variables */
	tech_realpolys = i;
	i += tech_displayableavars(ai);
	return(i);
}

void sch_shapearcpoly(ARCINST *ai, INTSML box, POLYGON *poly)
{
	REGISTER INTSML aindex, angle, bubbleend;
	REGISTER INTBIG x1,y1, cosdist, sindist, x2,y2, lambda, i,
		saveendx, saveendy, bubblesize;
	REGISTER TECH_ARCLAY *thista;

	/* handle displayable variables */
	if (box >= tech_realpolys)
	{
		(void)tech_filldisplayableavar(ai, poly);
		return;
	}

	/* initialize for the arc */
	aindex = ai->proto->arcindex;
	thista = &sch_arcprotos[aindex]->list[box];
	poly->layer = thista->lay;
	poly->desc = sch_layers[poly->layer];
	lambda = sch_tech->deflambda;
	if (sch_bubblebox < 0 && sch_arrowbox < 0)
	{
		/* simple arc */
		makearcpoly(ai->length, ai->width-thista->off*lambda/WHOLE,
			ai, poly, thista->style);
		return;
	}

	/* prepare special information for negated and/or directional arcs */
	bubbleend = 0;
	x1 = ai->end[0].xpos;   y1 = ai->end[0].ypos;
	x2 = ai->end[1].xpos;   y2 = ai->end[1].ypos;
	angle = (INTSML)(((ai->userbits&AANGLE) >> AANGLESH) * 10);
	if ((ai->userbits&REVERSEEND) != 0)
	{
		i = x1;   x1 = x2;   x2 = i;
		i = y1;   y1 = y2;   y2 = i;
		bubbleend = 1;
		angle = (angle+1800) % 3600;
	}
	bubblesize = sch_bubblediameter * lambda;
	cosdist = mult(cosine(angle), bubblesize) / WHOLE;
	sindist = mult(sine(angle), bubblesize) / WHOLE;

	/* handle the main body of the arc */
	if (box == 0)
	{
		if (sch_bubblebox >= 0)
		{
			/* draw the arc, shortened at the end for the negating bubble */
			saveendx = ai->end[bubbleend].xpos;
			saveendy = ai->end[bubbleend].ypos;
			ai->end[bubbleend].xpos = x1 + cosdist;
			ai->end[bubbleend].ypos = y1 + sindist;
			makearcpoly(ai->length-sch_bubblediameter,
				ai->width-thista->off*lambda/WHOLE, ai, poly, thista->style);
			ai->end[bubbleend].xpos = saveendx;
			ai->end[bubbleend].ypos = saveendy;
		} else
		{
			makearcpoly(ai->length, ai->width-thista->off*lambda/WHOLE,
				ai, poly, thista->style);
		}
		return;
	}

	/* draw the negating bubble */
	if (box == sch_bubblebox)
	{
		poly->count = 2;
		if (poly->limit < 2) (void)extendpolygon(poly, 2);
		poly->xv[0] = x1 + cosdist / 2;
		poly->yv[0] = y1 + sindist / 2;
		poly->xv[1] = x1;   poly->yv[1] = y1;
		poly->style = CIRCLE;
		return;
	}

	/* draw the directional arrow */
	if (box == sch_arrowbox)
	{
		if ((ai->userbits&(ISNEGATED|NOTEND0)) == ISNEGATED)
		{
			x1 += cosdist;
			y1 += sindist;
		}
		poly->style = VECTORS;
		poly->layer = -1;
		if (aindex == ABUS)
		{
			poly->desc = &sch_t_lay;
			x2 -= cosdist / 2;
			y2 -= sindist / 2;
		}
		if (poly->limit < 2) (void)extendpolygon(poly, 2);
		poly->count = 2;
		poly->xv[0] = x1;   poly->yv[0] = y1;
		poly->xv[1] = x2;   poly->yv[1] = y2;
		if ((ai->userbits&NOTEND1) == 0) tech_addheadarrow(poly, angle, x2, y2);
	}
}
