/*
 * Electric(tm) VLSI Design System
 *
 * File: planfacets.c
 * Programmable Logic Array Generator: Defining the facets that make up a PLA
 * Written by: Steven M. Rubin, Static Free Software
 * Written by: Sundaravarathan R. Iyengar, Schlumberger Palo Alto Research
 *
 * 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
 */

#include "config.h"
#if PLAAID

#include "global.h"
#include "planmos.h"

/* prototypes for local routines */
NODEPROTO *pla_nmos_InPullup(void);
NODEPROTO *pla_nmos_OutPullup(void);

PORTPROTO *pla_FindPort(NODEINST *node, INTBIG x, INTBIG y)
{
	REGISTER PORTPROTO *pp;
	static POLYGON *poly = NOPOLYGON;

	/* get polygon */
	if (poly == NOPOLYGON) poly = allocstaticpolygon(4, pla_aid->cluster);
	if (node != NONODEINST)
	{
		for(pp = node->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
		{
			shapeportpoly(node, pp, poly, 0);
			if (isinside(x, y, poly) != 0)  return(pp);
		}
	} else ttyputerr("pla_FindPort: an empty NODEINST pointer was passed In");
	return(NOPORTPROTO);
}

NODEPROTO *pla_nmos_Connect(void)
{
	NODEPROTO *facet;
	NODEINST *mp_contact, *md_contact, *poly_pin;
	ARCINST *pa;

	facet = newnodeproto(nmosConnect, el_curlib);
	if (facet == NONODEPROTO) ttyputerr("nmos_Connect: cannot obtain a proto");

	mp_contact = newnodeinst(pla_mp_proto, 0, 4*pla_lam, 3*pla_lam, 7*pla_lam, NOTRANS, NOROT,
		facet);
	poly_pin = newnodeinst(pla_pp_proto, 6*pla_lam+pla_GndWidth, 8*pla_lam+pla_GndWidth,
		5*pla_lam, 7*pla_lam, NOTRANS, NOROT, facet);
	if (mp_contact == NONODEINST || poly_pin == NONODEINST)
		ttyputerr("nmos_Connect: cannot instance basic elements");

	pa = newarcinst(pla_pa_proto, 2*pla_lam, FIXANG, poly_pin, pla_pp_proto->firstportproto,
		7*pla_lam+pla_GndWidth, 6*pla_lam, mp_contact, pla_mp_proto->firstportproto, 2*pla_lam,
			6*pla_lam, facet);
	if (pa == NOARCINST) ttyputerr("nmos_Connect: cannot instance p arc");

	/* Extend the AndEnd of the metal-poly pin by one lambda */
	if (newarcinst(pla_ma_proto, 4*pla_lam, FIXANG, mp_contact, pla_mp_proto->firstportproto,
		pla_lam, 5*pla_lam, mp_contact, pla_mp_proto->firstportproto, 2*pla_lam, 5*pla_lam,
			facet) == NOARCINST)
				ttyputerr("nmos_Connect: cannot extend AndEnd");

	/* Instance a metal-diff contact for ground connection and export it */
	md_contact = newnodeinst(pla_md_proto, 7*pla_lam, 7*pla_lam+pla_GndWidth,
		0, 4*pla_lam, NOTRANS, NOROT, facet);
	if (md_contact == NONODEINST)
		ttyputerr("nmos_Connect: cannot instance ground connection");

	if ((newportproto(facet, md_contact, pla_md_proto->firstportproto, "DiffGnd") == NOPORTPROTO) ||
		(newportproto(facet, mp_contact, pla_mp_proto->firstportproto, "AndEnd") == NOPORTPROTO) ||
		(newportproto(facet, poly_pin, pla_pp_proto->firstportproto, "OrEnd") == NOPORTPROTO))
			ttyputerr("nmos_Connect: cannot export ports");

	/* ensure that the facet is the proper size */
	(*el_curconstraint->solve)(facet);
	return(facet);
}

NODEPROTO *pla_nmos_InPullup(void)
{
	NODEPROTO *pu;
	NODEINST *dtran, *bc, *dpin, *ppin1, *ppin2;
	ARCINST *pa, *da;
	PORTPROTO *dtran_dport, *dtran_pport, *bc_dport, *bc_pport;

	pu = newnodeproto("nmos_InPullup",el_curlib);
	if (pu == NONODEPROTO) ttyputerr("Cannot create nmos_InPullup");

	dtran = newnodeinst(pla_dtran_proto, pla_lam, 7*pla_lam, 5*pla_lam, 11*pla_lam, NOTRANS, NOROT,
		pu);
	if (dtran == NONODEINST)
		ttyputerr("Cannot instance %s in facet %s",
			describenodeproto(pla_dtran_proto), describenodeproto(pu));

	dtran_dport = pla_FindPort(dtran, 4*pla_lam, 6*pla_lam);
	dtran_pport = pla_FindPort(dtran, 2*pla_lam, 8*pla_lam);
	if (dtran_pport == NOPORTPROTO || dtran_dport == NOPORTPROTO)
		ttyputerr("nmos_InPullup: implant transistor ports inaccessible");

	if (pla_buttingcontact == OFF)
		ttyputerr("nmos_InPullup: Buried contacts are not yet supported");
	bc = newnodeinst(pla_bc_proto, pla_lam, 7*pla_lam, 0, 4*pla_lam, NOTRANS, 1800, pu);
	if (bc == NONODEINST)
		ttyputerr("nmos_InPullup: cannot instance butting contact");

	bc_dport = pla_FindPort(bc, 6*pla_lam, 2*pla_lam);
	bc_pport = pla_FindPort(bc, 3*pla_lam, pla_lam);
	if (bc_pport == NOPORTPROTO || bc_dport == NOPORTPROTO)
		ttyputerr("nmos_InPullup: butting contact ports inaccessible");

	/* export the bc_dport, bc_pport for external connections */
	if (newportproto(pu, bc, bc_dport, "PullDNpt") == NOPORTPROTO ||
		newportproto(pu, bc, bc_pport, "Outpt") == NOPORTPROTO)
			ttyputerr("nmos_InPullup: cannot export bc_dport");

	/* have to create pins to bend the arcs */
	dpin = newnodeinst(pla_dp_proto, 3*pla_lam, 7*pla_lam, 2*pla_lam, 6*pla_lam, NOTRANS, NOROT, pu);
	ppin1 = newnodeinst(pla_pp_proto, 0, 2*pla_lam, 7*pla_lam, 9*pla_lam, NOTRANS, NOROT, pu);
	if (dpin == NONODEINST || ppin1 == NONODEINST)
		ttyputerr("nmos_InPullup: cannot create d,p pins");

	/* connect the pins to the dtran */
	pa = newarcinst(pla_pa_proto, 2*pla_lam, FIXANG, dtran, dtran_pport, 2*pla_lam, 8*pla_lam,
		ppin1, pla_pp_proto->firstportproto, pla_lam, 8*pla_lam, pu);
	da = newarcinst(pla_da_proto, 2*pla_lam, FIXANG, dtran, dtran_dport, 4*pla_lam,6*pla_lam,
		dpin, pla_dp_proto->firstportproto, 4*pla_lam, 4*pla_lam, pu);
	if (pa == NOARCINST || da == NOARCINST)
		ttyputerr("nmos_InPullup: cannot create p,d arcs from tran to pin 1");

	/* now connect these pins to the butting contact */
	ppin2 = newnodeinst(pla_pp_proto, 0, 2*pla_lam, 0, 2*pla_lam, NOTRANS, NOROT, pu);
	if (ppin2 == NONODEINST)
		ttyputerr("nmos_InPullup: cannot create ppin close bc");

	if (newarcinst(pla_pa_proto, 2*pla_lam, FIXANG, ppin1, pla_pp_proto->firstportproto,
		pla_lam, 8*pla_lam, ppin2, pla_pp_proto->firstportproto, pla_lam, pla_lam, pu) == NOARCINST)
			ttyputerr("nmos_InPullup: cannot connect the two ppins");

	pa = newarcinst(pla_pa_proto, 2*pla_lam, FIXANG, ppin2, pla_pp_proto->firstportproto,
		pla_lam, pla_lam, bc, bc_pport, 3*pla_lam, pla_lam, pu);
	da = newarcinst(pla_da_proto, 2*pla_lam, FIXANG, dpin, pla_dp_proto->firstportproto,
		6*pla_lam, 3*pla_lam, bc, bc_dport, 6*pla_lam, 2*pla_lam, pu);
	if (pa == NOARCINST || da == NOARCINST)
		ttyputerr("nmos_InPullup: cannot create p,d arcs from contact to tran");

	/*
	 * export the diffusion top of the dtran for Vdd connection
	 * and the right poly end
	 */
	dtran_dport = pla_FindPort(dtran, 4*pla_lam, 10*pla_lam);
	if (newportproto(pu, dtran, dtran_dport, "Vddpt") == NOPORTPROTO)
		ttyputerr("nmos_InPullup: cannot export vdd connection from dtran");

	dtran_pport = pla_FindPort(dtran, 6*pla_lam, 8*pla_lam);
	if (newportproto(pu, dtran, dtran_pport, "Invpt") == NOPORTPROTO)
		ttyputerr("nmos_InPullup: cannot export Inverter point from dtran");

	/* ensure that the facet is the proper size */
	(*el_curconstraint->solve)(pu);
	return(pu);
}

NODEPROTO *pla_nmos_Input(void)
{
	NODEPROTO *facet, *pu;
	NODEINST *pu1,  *pu2, *ppin, *etran1, *etran2,
		*ppin1, *ppin2, *dpin1, *dpin2, *md_contact, *md_contact1;
	ARCINST *ai;

	/* make sure Input Pullup is defined */
	pu = pla_nmos_InPullup();

	/*
	 * Now create a diffusion to metal contact wide enough to accommodate
	 * the Vdd line.  Assume that the global variables pla_VddWidth and
	 * pla_GndWidth contain the widths of  Vdd and Gnd lines.  The
	 * Y size of the Input facet is these two widths plus the heights
	 * two inverters.  These inverters are identical.  The difference
	 * in heights (see code below) comes from the savings resulting
	 * from the fact that these two are interconnected.
	 */
	facet = newnodeproto("nmos_Input", el_curlib);
	if (facet == NONODEPROTO)
		ttyputerr("nmos_Input: cannot create facet");

	md_contact = newnodeinst(pla_md_proto, 2*pla_lam, 8*pla_lam,
		17*pla_lam, 17*pla_lam+pla_VddWidth, NOTRANS, NOROT, facet);
	if (md_contact == NONODEINST)
		ttyputerr("nmos_Input: cannot create Vdd Line contact");

	/* export this for vdd connection */
	if (newportproto(facet, md_contact, pla_md_proto->firstportproto, "Vdd") ==
		NOPORTPROTO) ttyputerr("nmos_Input: cannot export Vdd contact");

	/* Instance the pullups on either side (top and bottom) of this contact */
	pu1 = newnodeinst(pu, 0, 7*pla_lam, 7*pla_lam, 18*pla_lam, NOTRANS, NOROT, facet);
	pu2 = newnodeinst(pu, 0, 7*pla_lam, 16*pla_lam+pla_VddWidth,
		27*pla_lam+pla_VddWidth, TRANS, 2700, facet);
	if (pu1 == NONODEINST || pu2 == NONODEINST)
		ttyputerr("nmosInput: cannot instance pullups");

	/* connect these pullups to the Vdd line */
	ai = newarcinst(pla_da_proto, 2*pla_lam, FIXANG, pu1, pla_FindPort(pu1,4*pla_lam,17*pla_lam),
		4*pla_lam, 17*pla_lam, md_contact, pla_md_proto->firstportproto, 4*pla_lam, 18*pla_lam,
			facet);
	if (ai == NOARCINST) ttyputerr("nmos_Input: cannot connect pu1 to Vdd");

	ai = newarcinst(pla_da_proto, 2*pla_lam, FIXANG, pu2,
		pla_FindPort(pu2,4*pla_lam,17*pla_lam+pla_VddWidth), 4*pla_lam, 17*pla_lam+pla_VddWidth,
			md_contact, pla_md_proto->firstportproto, 4*pla_lam, (17-1)*pla_lam+pla_VddWidth, facet);
	if (ai == NOARCINST) ttyputerr("nmos_Input: cannot connect pu2 to Vdd");

	/*
	 * Create two pulldown transistors to be combined with the pullups
	 * to make two inverters. They appear on the right of the pullups.
	 * etran1 is centered at (10,6). etran2 is centered at
	 * (10,17+11-2+pla_VddWidth/pla_lam)
	 */
	etran1 = newnodeinst(pla_etran_proto, 4*pla_lam, 16*pla_lam,
		3*pla_lam, 9*pla_lam, NOTRANS, 900, facet);
	etran2 = newnodeinst(pla_etran_proto, 4*pla_lam, 16*pla_lam,
		(17+11-3-3)*pla_lam+pla_VddWidth, (17+11-3+3)*pla_lam+pla_VddWidth, NOTRANS, 900, facet);
	if (etran1 == NONODEINST || etran2 == NONODEINST)
		ttyputerr("nmos_Input: cannot create the pulldowns");

	/* connect the pullups to the pulldowns */
	ai = newarcinst(pla_da_proto, 2*pla_lam, FIXANG, pu1, pla_FindPort(pu1,5*pla_lam,9*pla_lam),
		5*pla_lam, 9*pla_lam, etran1, pla_FindPort(etran1,8*pla_lam,9*pla_lam), 8*pla_lam,
			9*pla_lam, facet);
	if (ai == NOARCINST) ttyputerr("nmos_Input: cannot connect pu1 to etran1");

	ai = newarcinst(pla_da_proto, 2*pla_lam, FIXANG, pu2,
		pla_FindPort(pu2,5*pla_lam,25*pla_lam+pla_VddWidth), 5*pla_lam, 25*pla_lam+pla_VddWidth,
			etran2, pla_FindPort(etran2,8*pla_lam,25*pla_lam+pla_VddWidth), 8*pla_lam,
				25*pla_lam+pla_VddWidth, facet);
	if (ai == NOARCINST) ttyputerr("nmos_Input: cannot connect pu2 to etran2");
	/*
	 * Instance diff pins on the pulldowns so that they can be connected
	 * together to ground. The postion of dpin2 is again adjusted with
	 * respect to pla_VddWidth.
	 */
	dpin1 = newnodeinst(pla_dp_proto, 12*pla_lam, 15*pla_lam,
		6*pla_lam, 9*pla_lam, NOTRANS, NOROT, facet);
	dpin2 = newnodeinst(pla_dp_proto, 12*pla_lam, 15*pla_lam,
		(17+5)*pla_lam+pla_VddWidth, (17+5+3)*pla_lam+pla_VddWidth, NOTRANS, NOROT, facet);
	if (dpin1 == NONODEINST || dpin2 == NONODEINST)
		ttyputerr("nmos_Input: cannot create d pins for ground connection");

	/* Connect the diff pins to the respective pulldowns */
	if (newarcinst(pla_da_proto, 3*pla_lam, FIXANG, etran1,
		pla_FindPort(etran1,12*pla_lam,(INTBIG)(7.5*pla_lam)), 12*pla_lam, (INTBIG)(7.5*pla_lam),
			dpin1, pla_dp_proto->firstportproto, (INTBIG)(13.5*pla_lam),(INTBIG)(7.5*pla_lam),
				facet) == NOARCINST)
					ttyputerr("nmos_Input: cannot create d arc to etran1");
	if (newarcinst(pla_da_proto, 3*pla_lam, FIXANG, etran2, pla_FindPort(etran2,12*pla_lam,
		(INTBIG)((17+11-4.5)*pla_lam)+pla_VddWidth), 12*pla_lam,
			(INTBIG)((17+11-4.5)*pla_lam)+pla_VddWidth, dpin2, pla_dp_proto->firstportproto,
				(INTBIG)(13.5*pla_lam), (INTBIG)((17+11-4.5)*pla_lam)+pla_VddWidth, facet) == NOARCINST)
					ttyputerr("nmos_Input: cannot create d arc to etran2");

	/* Now connect these d pins together */
	if (newarcinst(pla_da_proto, 3*pla_lam, FIXANG, dpin1, pla_dp_proto->firstportproto,
		(INTBIG)(13.5*pla_lam), (INTBIG)(7.5*pla_lam), dpin2, pla_dp_proto->firstportproto,
			(INTBIG)(13.5*pla_lam), (INTBIG)((17+11-4.5)*pla_lam)+pla_VddWidth, facet) == NOARCINST)
				ttyputerr("nmos_Input: cannot connect the d pins together");

	/*
	 * Connect the inverters together on the poly layer to output
	 * a noninverted signal
	 *
	 * First instance a poly pin to bend the poly line from the bottom
	 * pullup to the top pulldown.  Then draw arcs to pullup and pulldown
	 */
	if ((ppin = newnodeinst(pla_pp_proto, 9*pla_lam, 11*pla_lam,
		14*pla_lam, 16*pla_lam, NOTRANS, NOROT, facet)) == NONODEINST)
			ttyputerr("nmos_Input: cannot connect Invs together.  No ppin");

	if (newarcinst(pla_pa_proto, 2*pla_lam, FIXANG, pu1, pla_FindPort(pu1, 6*pla_lam, 15*pla_lam),
		6*pla_lam, 15*pla_lam, ppin, pla_pp_proto->firstportproto, 10*pla_lam, 15*pla_lam,
			facet) == NOARCINST)
				ttyputerr("nmos_Input: cannot connect pu1 to ppin");

	if (newarcinst(pla_pa_proto, 2*pla_lam, FIXANG, ppin, pla_pp_proto->firstportproto,
		10*pla_lam, 15*pla_lam, etran2, pla_FindPort(etran2,10*pla_lam, (17+3)*pla_lam+pla_VddWidth),
			10*pla_lam, (17+3)*pla_lam+pla_VddWidth, facet) == NOARCINST)
				ttyputerr("nmos_Input: cannot connect ppin to etran2");

	/*
	 * Now pull this connection to the top to form the inverted output
	 * from the Input facet.
	 */
	if ((ppin1 = newnodeinst(pla_pp_proto, 9*pla_lam, 11*pla_lam,
		(17+11+4-2)*pla_lam+pla_VddWidth+pla_GndWidth,
			(17+11+4)  *pla_lam+pla_VddWidth+pla_GndWidth, NOTRANS, NOROT, facet)) == NONODEINST)
				ttyputerr("nmos_Input: cannot extend etran2.  No ppin");
	if (newarcinst(pla_pa_proto, 2*pla_lam, FIXANG, ppin1, pla_pp_proto->firstportproto,
		10*pla_lam, (17+11+4-1)*pla_lam+pla_VddWidth+pla_GndWidth, etran2,
			pla_FindPort(etran2,10*pla_lam, (17+11+2)*pla_lam+pla_VddWidth),
				10*pla_lam, (17+11+2)*pla_lam+pla_VddWidth, facet) == NOARCINST)
					ttyputerr("nmos_Input: cannot connect etran2 to ppin");

	/*
	 * Pull a poly connection from the butting/buried contact of
	 * pu2 to form the noninverted (doubly inverted) output.
	 */
	if ((ppin2 = newnodeinst(pla_pp_proto, pla_lam, 3*pla_lam,
		(17+11+4-2)*pla_lam+pla_VddWidth+pla_GndWidth,
			(17+11+4)*pla_lam+pla_VddWidth+pla_GndWidth, NOTRANS, NOROT, facet)) == NONODEINST)
				ttyputerr("nmos_Input: cannot connect ppin to pu2.  No ppin");

	if (newarcinst(pla_pa_proto, 2*pla_lam, FIXANG, ppin2, pla_pp_proto->firstportproto,
		2*pla_lam, (17+11+4-1)*pla_lam+pla_VddWidth+pla_GndWidth, pu2, pla_FindPort(pu2,2*pla_lam,
			(17+11-3)*pla_lam+pla_VddWidth), 2*pla_lam, (17+11-3)*pla_lam+pla_VddWidth,
				facet) == NOARCINST)
					ttyputerr("nmos_Input: cannot connect pu2 to ppin");

	/* Pull a diff arc from the pulldowns to a ground pin at the top */
	if ((md_contact = newnodeinst(pla_md_proto, 12*pla_lam, 16*pla_lam,
		(17+11+4)*pla_lam+pla_VddWidth, (17+11+4)*pla_lam+pla_VddWidth+pla_GndWidth,
			NOTRANS, NOROT, facet)) == NONODEINST)
				ttyputerr("nmos_Input: cannot instance md_contact for gnd");
	if (newarcinst(pla_da_proto, 3*pla_lam, FIXANG, md_contact, pla_md_proto->firstportproto,
		(INTBIG)(13.5*pla_lam), (17+11+5)*pla_lam+pla_VddWidth, dpin2, pla_dp_proto->firstportproto,
			(INTBIG)(13.5*pla_lam), (INTBIG)((17+11-4.5)*pla_lam)+pla_VddWidth, facet) == NOARCINST)
				ttyputerr("nmos_Input: cannot connect etran2 to gnd pin");

	/*
	 * Instance a metal-ground contact pin between the two poly connections
	 * going into the PLA for running the diff line vertically
	 */
	if ((md_contact1 = newnodeinst(pla_md_proto, 4*pla_lam, 8*pla_lam,
		(17+11+4)*pla_lam+pla_VddWidth, (17+11+4)*pla_lam+pla_VddWidth+pla_GndWidth,
			NOTRANS, NOROT, facet)) == NONODEINST)
				ttyputerr("nmos_Input: cannot instance md contact");

	/* Connect the two md contacts together in metal */
	if (newarcinst(pla_ma_proto, pla_GndWidth, FIXANG, md_contact, pla_md_proto->firstportproto,
		14*pla_lam, (17+11+4)*pla_lam+pla_VddWidth+pla_halfGnd, md_contact1,
			pla_md_proto->firstportproto, 6*pla_lam, (17+11+4)*pla_lam+pla_VddWidth+pla_halfGnd,
				facet) == NOARCINST)
					ttyputerr("nmos_Input: cannot connect md_contacts together");

	/* Export some of the pins and ports for external connections */
	if (newportproto(facet, md_contact, pla_md_proto->firstportproto, "Gnd") == NOPORTPROTO ||
		newportproto(facet, ppin1, pla_pp_proto->firstportproto, "InvInput") == NOPORTPROTO ||
		newportproto(facet, ppin2, pla_pp_proto->firstportproto, "NonInvInput") == NOPORTPROTO ||
		newportproto(facet, etran1, pla_FindPort(etran1, 10*pla_lam, pla_lam), "Input") == NOPORTPROTO  ||
		newportproto(facet, md_contact1,pla_md_proto->firstportproto, "DiffGnd") == NOPORTPROTO)
			ttyputerr("nmos_Input: cannot export connection points");

	/* ensure that the facet is the proper size */
	(*el_curconstraint->solve)(facet);
	return(facet);
}

NODEPROTO *pla_nmos_OutPullup(void)
{
	NODEPROTO *pu;
	INTBIG sizeX, sizeY;			/* Dimensions of the facet */
	NODEINST *dtran, *dpin, *bc;
	PORTPROTO *dtran_dport, *dtran_pport, *bc_pport, *bc_dport;

	sizeX = 10 * pla_lam;
	sizeY =  9 * pla_lam;

	pu = newnodeproto("nmos_OutPullup", el_curlib);
	if (pu == NONODEPROTO)
	{
		ttyputerr("nmos_Output: cannot obtain a pu proto.");
		return(NONODEPROTO);
	}

	/* Instance a depletion load pullup in pu */
	dtran = newnodeinst(pla_dtran_proto, 3*pla_lam, sizeX-pla_lam,
		3*pla_lam, sizeY, NOTRANS, 900, pu);
	if (dtran == NONODEINST)
		ttyputerr("nmos_Output: cannot instance %s in %s",
			describenodeproto(pla_dtran_proto), describenodeproto(pu));

	/* Extend the Left Poly side by 3 lambdas */
	dtran_dport = pla_FindPort(dtran, 4*pla_lam, 6*pla_lam);
	if (dtran_dport == NOPORTPROTO)
		ttyputerr("nmos_Output: dtran diff left port is inaccessible");

	dpin = newnodeinst(pla_dp_proto, 0, 2*pla_lam, 5*pla_lam, 7*pla_lam, NOTRANS, NOROT, pu);
	if (dpin == NONODEINST)
		ttyputerr("nmos_Output: cannot extend diff to left. no dpin");

	/* Export this pin for external connections */
	if (newportproto(pu, dpin, pla_dp_proto->firstportproto, "VddPt") == NOPORTPROTO)
			ttyputerr("nmos_Output: cannot export VddPt");

	if (newarcinst(pla_da_proto, 2*pla_lam, FIXANG, dpin, pla_dp_proto->firstportproto,
		pla_lam, 6*pla_lam, dtran, dtran_dport, 4*pla_lam, 6*pla_lam, pu) == NOARCINST)
			ttyputerr("nmos_Output: cannot extend diff to left. no arc");

	/* Extend Right Poly side by 1 lambda */
	dtran_dport = pla_FindPort(dtran, 8*pla_lam, 6*pla_lam);
	if (dtran_dport == NOPORTPROTO)
		ttyputerr("nmos_Output: dtran diff right port is inaccessible");

	dpin = newnodeinst(pla_dp_proto, 8*pla_lam, sizeX, 5*pla_lam, 7*pla_lam, NOTRANS, NOROT, pu);
	if (dpin == NONODEINST)
		ttyputerr("nmos_Output: cannot extend diff to right. no dpin");

	/* Export this pin for external connections */
	if (newportproto(pu, dpin, pla_dp_proto->firstportproto, "EtranPt") == NOPORTPROTO)
		ttyputerr("nmos_Output: cannot export EtranPt");

	if (newarcinst(pla_da_proto, 2*pla_lam, FIXANG, dpin, pla_dp_proto->firstportproto,
		9*pla_lam, 6*pla_lam, dtran, dtran_dport, 8*pla_lam, 6*pla_lam, pu) == NOARCINST)
			ttyputerr("nmos_Output: cannot extend diff to right. no arc");

	/* Instance butting/buried contact under the dtran */
	dtran_pport = pla_FindPort(dtran, 6*pla_lam, 4*pla_lam);
	if (dtran_pport == NOPORTPROTO)
		ttyputerr("nmos_Output: dtran poly port is inaccessible");

	if (pla_buttingcontact == OFF)
		ttyputerr("nmos_Output: Buried contacts are not yet supported");

	bc = newnodeinst(pla_bc_proto, 4*pla_lam, 10*pla_lam, 0, 4*pla_lam, NOTRANS, 1800, pu);
	if (bc == NONODEINST)
		ttyputerr("nmos_Output: cannot instance butting contact");

	bc_pport = pla_FindPort(bc, 6*pla_lam, 2*pla_lam);
	bc_dport = pla_FindPort(bc, 9*pla_lam, 2*pla_lam);
	if (bc_dport == NOPORTPROTO || bc_pport == NOPORTPROTO)
		ttyputerr("nmos_Output: cannot access but. cont. ports");

	if (newarcinst(pla_da_proto, 2*pla_lam, FIXANG, dpin, pla_dp_proto->firstportproto,
		9*pla_lam, 6*pla_lam, bc, bc_dport, 9*pla_lam, 2*pla_lam, pu) == NOARCINST)
			ttyputerr("nmos_Output: cannot connect but. cont. to dpin");

	if (newarcinst(pla_pa_proto, 2*pla_lam, FIXANG, dtran, dtran_pport, 6*pla_lam, 4*pla_lam,
		bc, bc_pport,  6*pla_lam, 2*pla_lam, pu) == NOARCINST)
			ttyputerr("nmos_Output: cannot connect but. cont. to dtran");

	/* Export bc_dport and bc_pport for external connections */
	if (newportproto(pu, bc, bc_pport, "Output2") == NOPORTPROTO ||
		newportproto(pu, bc, bc_dport, "DiffPt") == NOPORTPROTO)
			ttyputerr("nmos_Output: cannot export butting cont. ports");

	/* ensure that the facet is the proper size */
	(*el_curconstraint->solve)(pu);
	return(pu);
}

NODEPROTO *pla_nmos_Output(void)
{
	NODEPROTO *facet, *pu;
	NODEINST  *pu1,  *pu2, *dpin1, *dpin2, *dpin, *etran1, *etran2,
		*ppin1, *ppin2, *md_cont1, *md_cont2;
	INTBIG sizeX,		/* Dimensions of the facet */
		WorkPtY;		/* Y value of a point below which work is done */

	/* define the pullup */
	pu = pla_nmos_OutPullup();

	sizeX = 15 * pla_lam;

	facet = newnodeproto(nmosOutput, el_curlib);
	if (facet == NONODEPROTO)
	{
		ttyputerr("nmos_Output: cannot create facet");
		return(NONODEPROTO);
	}

	/* Instance the OutPullup twice in facet */
	pu1 = newnodeinst(pu, (INTBIG)(1.5*pla_lam), (INTBIG)(1.5*pla_lam+pu->highx-pu->lowx),
		(INTBIG)((5+2-0.5)*pla_lam)+pla_VddWidth,
			(INTBIG)((5+2-0.5)*pla_lam+pu->highy-pu->lowy)+pla_VddWidth, TRANS, 1800, facet);
	pu2 = newnodeinst(pu, 5*pla_lam, sizeX, 0, pu->highy-pu->lowy, NOTRANS, NOROT, facet);
	if (pu1 == NONODEINST || pu2 == NONODEINST)
		ttyputerr("nmos_Output: cannot instance pullups in facet");

	/*
	 * Create two poly pins near the left most edge of the facet
	 * and connect them together to make Output1.
	 */
	ppin1 = newnodeinst(pla_pp_proto, 0, 2*pla_lam, (7+3)*pla_lam+pla_VddWidth,
		(7+5)*pla_lam+pla_VddWidth, NOTRANS, NOROT, facet);
	ppin2 = newnodeinst(pla_pp_proto, 0, 2*pla_lam, 0, 2*pla_lam, NOTRANS, NOROT, facet);
	if (ppin1 == NONODEINST || ppin2 == NONODEINST)
		ttyputerr("nmos_Output: cannot create Output1 poly run. no ppins");

	if (newarcinst(pla_pa_proto, 2*pla_lam, FIXANG, ppin1, pla_pp_proto->firstportproto,
		pla_lam, (7+4)*pla_lam+pla_VddWidth, ppin2, pla_pp_proto->firstportproto,
			pla_lam, pla_lam, facet) == NOARCINST)
				ttyputerr("nmos_Output: cannot create Output1 poly run. no arc");

	/* Connect ppin1 to pu1 on poly */
	if (newarcinst(pla_pa_proto, 2*pla_lam, FIXANG, ppin1, pla_pp_proto->firstportproto,
		pla_lam, (7+4)*pla_lam+pla_VddWidth, pu1, pla_FindPort(pu1, 4*pla_lam, (7+4)*pla_lam+
			pla_VddWidth), 4*pla_lam, (7+4)*pla_lam+pla_VddWidth, facet) == NOARCINST)
				ttyputerr("nmos_Output: cannot connect ppin1 to pu1");

	/* Export ppin2 as Output1 Point */
	if (newportproto(facet, ppin2, pla_pp_proto->firstportproto, "Output1") == NOPORTPROTO)
		ttyputerr("nmos_Output: cannot export Output1 point");

	/*
	 * Instance a Vdd Connection point in between the two pullups and
	 * connect the pullups to it.  First, find the Vdd points of the
	 * two pullups.
	 */
	md_cont1 = newnodeinst(pla_md_proto, 3*pla_lam, 7*pla_lam, 7*pla_lam, 7*pla_lam+pla_VddWidth,
		NOTRANS, NOROT, facet);
	if (md_cont1 == NONODEINST)
		ttyputerr("nmos_Output: cannot instance Vdd Point");

	/* Export this contact for external Vdd connection */
	if (newportproto(facet, md_cont1, pla_md_proto->firstportproto, "Vdd") == NOPORTPROTO)
		ttyputerr("nmos_Output: cannot export Vdd connection ");

	/* Extend the Diff wires from the pullups to md_cont1 */
	dpin1 = newnodeinst(pla_dp_proto, 3*pla_lam, 5*pla_lam, (7-1)*pla_lam+pla_VddWidth,
		(7-1+2)*pla_lam+pla_VddWidth, NOTRANS, NOROT, facet);
	dpin2 = newnodeinst(pla_dp_proto, 3*pla_lam, 5*pla_lam,
		5*pla_lam, 7*pla_lam, NOTRANS, NOROT, facet);
	if (dpin1 == NONODEINST || dpin2 == NONODEINST)
		ttyputerr("nmos_Output: cannot extend vdd pts of pu. no dpins");

	if (newarcinst(pla_da_proto, 2*pla_lam, FIXANG, dpin1, pla_dp_proto->firstportproto,
		4*pla_lam, 7*pla_lam+pla_VddWidth, pu1, pla_FindPort(pu1, 8*pla_lam, 7*pla_lam+pla_VddWidth),
			8*pla_lam, 7*pla_lam+pla_VddWidth, facet) == NOARCINST)
				ttyputerr("nmos_Output: cannot extend Vdd pt of pu1. no arc");

	if (newarcinst(pla_da_proto, 2*pla_lam, FIXANG, dpin2, pla_dp_proto->firstportproto,
		4*pla_lam, 6*pla_lam, pu2, pla_FindPort(pu2, 6*pla_lam, 6*pla_lam),
			6*pla_lam, 6*pla_lam, facet) == NOARCINST)
				ttyputerr("nmos_Output: cannot extend Vdd pt of pu2. no arc");

	/* Connect these dpins to the Vdd Contact (md_cont1) */
	if (newarcinst(pla_da_proto, 2*pla_lam, FIXANG, dpin1, pla_dp_proto->firstportproto,
		4*pla_lam, 7*pla_lam+pla_VddWidth, md_cont1, pla_md_proto->firstportproto,
			4*pla_lam, 7*pla_lam+pla_halfVdd, facet) == NOARCINST)
				ttyputerr("nmos_Output: cannot connect dpin1 to mdcont1. no arc");

	if (newarcinst(pla_da_proto, 2*pla_lam, FIXANG, dpin2, pla_dp_proto->firstportproto,
		4*pla_lam, 6*pla_lam, md_cont1, pla_md_proto->firstportproto,
			4*pla_lam, 7*pla_lam+pla_halfVdd, facet) == NOARCINST)
				ttyputerr("nmos_Output: cannot connect dpin2 to mdcont1. no arc");

	/* Now instance two enhancement transistors to complete inverter layouts */
	WorkPtY = 7 * pla_lam + pla_VddWidth + pu->highx - pu->lowx;

	etran1 = newnodeinst(pla_etran_proto, 0, 12*pla_lam, WorkPtY+9*pla_lam,
		WorkPtY+(9+6)*pla_lam, NOTRANS, 900, facet);
	etran2 = newnodeinst(pla_etran_proto, 5*pla_lam, 17*pla_lam, WorkPtY+(4-1)*pla_lam,
		WorkPtY+(4+6-1)*pla_lam, NOTRANS, 900, facet);
	if (etran1 == NONODEINST || etran2 == NONODEINST)
		ttyputerr("nmos_Output: cannot instance etrans");

	/* Connect these together on diffusion */
	if (newarcinst(pla_da_proto, 2*pla_lam, FIXANG, etran1,
		pla_FindPort(etran1, 8*pla_lam,WorkPtY+9*pla_lam), 8*pla_lam, WorkPtY+9*pla_lam,
			etran2, pla_FindPort(etran2, 9*pla_lam,WorkPtY+9*pla_lam),
				9*pla_lam, WorkPtY+9*pla_lam, facet) == NOARCINST)
					ttyputerr("nmos_Output: cannot connect etrans on diffusion");

	/*  Instance a diff pin on the left edge of etran1 so that etran1
	 *  can be connected to the butting/buried contact of pu1.
	 */
	dpin1 = newnodeinst(pla_dp_proto, 2*pla_lam, 4*pla_lam,
		WorkPtY+8*pla_lam, WorkPtY+10*pla_lam, NOTRANS, NOROT, facet);
	if (dpin1 == NONODEINST)
		ttyputerr("nmos_Output: cannot connect etran1 to pu1. no dpin");

	if (newarcinst(pla_da_proto, 2*pla_lam, FIXANG, dpin1, pla_dp_proto->firstportproto,
		3*pla_lam, WorkPtY+9*pla_lam, etran1, pla_FindPort(etran1, 4*pla_lam,WorkPtY+9*pla_lam),
			4*pla_lam, WorkPtY+9*pla_lam, facet) == NOARCINST)
				ttyputerr("nmos_Output: cannot connect dpin1 to etran1. no arc");

	if (newarcinst(pla_da_proto, 2*pla_lam, FIXANG, dpin1, pla_dp_proto->firstportproto,
		3*pla_lam, WorkPtY+9*pla_lam, pu1, pla_FindPort(pu1, 3*pla_lam, WorkPtY-2*pla_lam),
			3*pla_lam, WorkPtY-2*pla_lam, facet) == NOARCINST)
				ttyputerr("nmos_Output: cannot connect dpin1 to pu1. no arc");

	/*
	 * Now we are going to connect etran2 to pu2 on diffusion.
	 * Instance a dpin on the rigth edge of dtran2 and connect them
	 * together.  Then connect dpin to pu2.
	 */
	dpin = newnodeinst(pla_dp_proto, sizeX-2*pla_lam, sizeX,
		WorkPtY+8*pla_lam, WorkPtY+10*pla_lam, NOTRANS, NOROT, facet);
	if (dpin == NONODEINST)
		ttyputerr("nmos_Output: cannot connect dtran2 to pu2. no dpin");

	if (newarcinst(pla_da_proto, 2*pla_lam, FIXANG, dpin, pla_dp_proto->firstportproto,
		sizeX-pla_lam, WorkPtY+9*pla_lam, etran2,
			pla_FindPort(etran2, sizeX-2*pla_lam, WorkPtY+9*pla_lam),
				sizeX-2*pla_lam, WorkPtY+9*pla_lam, facet) == NOARCINST)
					ttyputerr("nmos_Output: cannot connect dtran2 to dpin. no arc");

	if (newarcinst(pla_da_proto, 2*pla_lam, FIXANG, dpin, pla_dp_proto->firstportproto,
		sizeX-pla_lam, WorkPtY+9*pla_lam, pu2, pla_FindPort(pu2, sizeX-pla_lam, 6*pla_lam),
			sizeX-pla_lam, 6*pla_lam, facet) == NOARCINST)
				ttyputerr("nmos_Output: cannot connect dpin to pu2. no arc");

	/*
	 * It is time to make a Ground contact.  Instance a ground
	 * contact above and in between the two etrans and connect it
	 * to the ground side of the etrans on diff.
	 */
	WorkPtY = WorkPtY + 12*pla_lam;

	md_cont1 = newnodeinst(pla_md_proto, 8*pla_lam, 12*pla_lam, WorkPtY+2*pla_lam,
		WorkPtY+2*pla_lam+pla_GndWidth, NOTRANS, NOROT, facet);
	if (md_cont1 == NONODEINST)
		ttyputerr("nmos_Output: cannot instance ground contact");

	/*  Export this as the external Ground contact */
	if (newportproto(facet, md_cont1, pla_md_proto->firstportproto, "Gnd") == NOPORTPROTO)
		ttyputerr("nmos_Output: cannot export ground point");

	/* Now connect etran1 to Ground contact */
	if (newarcinst(pla_da_proto, 2*pla_lam, FIXANG, etran1,
		pla_FindPort(etran1, 8*pla_lam, WorkPtY+3*pla_lam), 8*pla_lam, WorkPtY+3*pla_lam,
			md_cont1, pla_md_proto->firstportproto, 9*pla_lam, WorkPtY+3*pla_lam, facet) == NOARCINST)
				ttyputerr("nmos_Output: no arc to connect tran to Gnd contact");

	/*
	 * Let us snake the poly outputs from etrans to top where it will
	 * be available for the PLA
	 */
	ppin1 = newnodeinst(pla_pp_proto, 10*pla_lam, 12*pla_lam, WorkPtY-pla_lam, WorkPtY+pla_lam,
		NOTRANS, NOROT, facet);
	ppin2 = newnodeinst(pla_pp_proto, 13*pla_lam, 15*pla_lam, WorkPtY-pla_lam, WorkPtY+pla_lam,
		NOTRANS, NOROT, facet);
	if (ppin1 == NONODEINST || ppin2 == NONODEINST)
		ttyputerr("nmos_Output: cannot extend etran2 poly. no ppins");

	if (newarcinst(pla_pa_proto, 2*pla_lam, FIXANG, ppin1, pla_pp_proto->firstportproto,
		11*pla_lam, WorkPtY, ppin2, pla_pp_proto->firstportproto, 14*pla_lam, WorkPtY,
			facet) == NOARCINST)
				ttyputerr("nmos_Output: cannot extend etran2 poly. no arc");

	/* Connect ppin1 to etran2 */
	if (newarcinst(pla_pa_proto, 2*pla_lam, FIXANG, ppin1, pla_pp_proto->firstportproto,
		11*pla_lam, WorkPtY, etran2, pla_FindPort(etran2, 11*pla_lam, WorkPtY-pla_lam),
			11*pla_lam, WorkPtY-pla_lam, facet) == NOARCINST)
				ttyputerr("nmos_Output: cannot connect etran2 to ppin1. no arc");

	/*
	 * Instance two metal-poly contacts to allow tapping signals
	 * from within the PLA.  Connect these to the poly extensions
	 * made above.
	 */
	WorkPtY = WorkPtY + 2 * pla_lam + pla_GndWidth;

	md_cont1 = newnodeinst(pla_mp_proto, 3*pla_lam, 7*pla_lam, WorkPtY+4*pla_lam, WorkPtY+8*pla_lam,
		NOTRANS, NOROT, facet);
	md_cont2 = newnodeinst(pla_mp_proto, 11*pla_lam, 15*pla_lam, WorkPtY+4*pla_lam,
		WorkPtY+8*pla_lam, NOTRANS, NOROT, facet);
	if (md_cont1 == NONODEINST || md_cont2 == NONODEINST)
		ttyputerr("nmos_Output: cannot instance metal-poly contact points");

	/* Export these for external connections */
	if (newportproto(facet, md_cont1, pla_mp_proto->firstportproto, "Input1") == NOPORTPROTO ||
		newportproto(facet, md_cont2, pla_mp_proto->firstportproto, "Input2") == NOPORTPROTO)
			ttyputerr("nmos_Output: cannot export PLA tap points ");

	/* Connect these to the etrans */
	if (newarcinst(pla_pa_proto, 2*pla_lam, FIXANG, ppin2, pla_pp_proto->firstportproto,
		14*pla_lam, WorkPtY-(pla_GndWidth+2*pla_lam), md_cont2, pla_mp_proto->firstportproto,
			14*pla_lam, WorkPtY+5*pla_lam, facet) == NOARCINST)
				ttyputerr("nmos_Output: cannot connect ppin2 to md_cont2");

	if (newarcinst(pla_pa_proto, 2*pla_lam, FIXANG, etran1,
		pla_FindPort(etran1,6*pla_lam,WorkPtY-pla_GndWidth+3*pla_lam), 6*pla_lam,
			WorkPtY-pla_GndWidth+3*pla_lam, md_cont1, pla_mp_proto->firstportproto,
				6*pla_lam, WorkPtY+5*pla_lam, facet) == NOARCINST)
					ttyputerr("nmos_Output: cannot connect etran1 to md_cont1");

	/* Export the Output point of pu2 as Output2 */
	if (newportproto(facet, pu2, pla_FindPort(pu2, 11*pla_lam, pla_lam), "Output2") == NOPORTPROTO)
		ttyputerr("nmos_Output: cannot export Output2 from pu2");

	/* ensure that the facet is the proper size */
	(*el_curconstraint->solve)(facet);
	return(facet);
}

NODEPROTO *pla_nmos_Program(void)
{
	NODEPROTO *facet;
	NODEINST *etran, *md_contact, *dpin;

	facet = newnodeproto(nmosProgram, el_curlib);
	if (facet == NONODEPROTO) ttyputerr("nmos_Program: cannot obtain a proto");

	if ((etran = newnodeinst(pla_etran_proto, 2*pla_lam, 10*pla_lam,
		pla_lam, 7*pla_lam, NOTRANS, 900, facet)) == NONODEINST)
			ttyputerr("nmos_Program: cannot instance etran");

	if ((md_contact = newnodeinst(pla_md_proto, 8*pla_lam, 12*pla_lam,
		2*pla_lam, 6*pla_lam, NOTRANS, NOROT, facet)) == NONODEINST)
			ttyputerr("nmos_Program: cannot instace md_contact");

	if ((dpin = newnodeinst(pla_dp_proto, 0, 4*pla_lam, 2*pla_lam, 6*pla_lam,
		NOTRANS, NOROT, facet)) == NONODEINST)
			ttyputerr("nmos_Program: cannot instance dpin");

	if (newarcinst(pla_da_proto, 4*pla_lam, FIXANG, dpin, pla_dp_proto->firstportproto,
		2*pla_lam, 4*pla_lam, etran, pla_FindPort(etran, 4*pla_lam, 4*pla_lam),
			4*pla_lam, 4*pla_lam, facet) == NOARCINST)
				ttyputerr("nmos_Program: cannot connect dpin to etran");

	if (newarcinst(pla_da_proto, 4*pla_lam, FIXANG, etran, pla_FindPort(etran, 8*pla_lam, 4*pla_lam),
		8*pla_lam, 4*pla_lam, md_contact, pla_md_proto->firstportproto,
			10*pla_lam, 4*pla_lam, facet) == NOARCINST)
				ttyputerr("nmos_Program: cannot connect etran to md_contact");

	if (newportproto(facet, dpin, pla_dp_proto->firstportproto, "DiffPt") == NOPORTPROTO ||
		newportproto(facet, etran, pla_FindPort(etran,6*pla_lam,7*pla_lam), "Up") == NOPORTPROTO ||
		newportproto(facet, etran, pla_FindPort(etran,6*pla_lam,pla_lam), "Down") == NOPORTPROTO ||
		newportproto(facet, md_contact, pla_md_proto->firstportproto, "MdPt") == NOPORTPROTO)
			ttyputerr("nmos_Program: cannot export ports");

	/* ensure that the facet is the proper size */
	(*el_curconstraint->solve)(facet);
	return(facet);
}

NODEPROTO *pla_nmos_Pullup(void)
{
	NODEPROTO *pu;
	NODEINST *dtran, *bc, *vdd_line, *md;
	ARCINST *pa, *da;
	PORTPROTO *dtran_pport, *dtran_dport, *bc_pport, *bc_dport, *vpname, *dpname;
	INTBIG sizeX;

	switch (pla_buttingcontact)
	{
		case OFF: sizeX = (10+2)*pla_lam + pla_VddWidth;   break;
		case ON:  sizeX = 10*pla_lam + pla_VddWidth;       break;
	}
	pu = newnodeproto(nmosPullup, el_curlib);
	if (pu == NONODEPROTO)
	{
		ttyputerr("nmos_Pullup: cannot obtain a proto for single pullup");
		return(NONODEPROTO);
	}

	dtran = newnodeinst(pla_dtran_proto, pla_lam+pla_VddWidth, 7*pla_lam+pla_VddWidth,
		-pla_lam,  7*pla_lam, NOTRANS, 900, pu);
	if (dtran == NONODEINST)
	{
		ttyputerr("nmos_Pullup: cannot instance %s in facet %s",
			describenodeproto(pla_dtran_proto), describenodeproto(pu));
		return(NONODEPROTO);
	}
	dtran_dport = pla_FindPort(dtran, 7*pla_lam+pla_VddWidth, 3*pla_lam);
	dtran_pport = pla_FindPort(dtran, 5*pla_lam+pla_VddWidth, 1*pla_lam);
	if (dtran_pport == NOPORTPROTO || dtran_dport == NOPORTPROTO)
	{
		ttyputerr("nmos_Pullup: implant transistor ports inaccessible");
		return(NONODEPROTO);
	}
	if (pla_buttingcontact == ON)
	{
		bc = newnodeinst(pla_bc_proto, 4*pla_lam+pla_VddWidth, sizeX,
			1*pla_lam,  5*pla_lam, NOTRANS, 1800, pu);
		if (bc == NONODEINST)
		{
			ttyputerr("nmos_Pullup: cannot instance butting contact");
			return(NONODEPROTO);
		}
		bc_dport = pla_FindPort(bc, 8*pla_lam+pla_VddWidth, 3*pla_lam);
		bc_pport = pla_FindPort(bc, 5*pla_lam+pla_VddWidth, 3*pla_lam);
		if (bc_pport == NOPORTPROTO || bc_dport == NOPORTPROTO)
		{
			ttyputerr("nmos_Pullup: butting contact ports inaccessible");
			return(NONODEPROTO);
		}
		pa = newarcinst(pla_pa_proto, 2*pla_lam, FIXANG, dtran, dtran_pport,5*pla_lam+pla_VddWidth,
			pla_lam, bc, bc_pport, 5*pla_lam+pla_VddWidth, 3*pla_lam, pu);
		da = newarcinst(pla_da_proto, 2*pla_lam, FIXANG, dtran, dtran_dport,
			7*pla_lam+pla_VddWidth,3*pla_lam, bc, bc_dport, 8*pla_lam+pla_VddWidth, 3*pla_lam, pu);
		if (pa == NOARCINST || da == NOARCINST)
		{
			ttyputerr("nmos_Pullup: cannot create p,d arcs from contact to tran");
			return(NONODEPROTO);
		}
	} else
	{
		bc = newnodeinst(pla_bc_proto, 4*pla_lam+pla_VddWidth, 8*pla_lam+pla_VddWidth,
			0, 6*pla_lam, NOTRANS, 1800, pu);
		if (bc == NONODEINST)
		{
			ttyputerr("nmos_Pullup: cannot instance buried contact");
			return(NONODEPROTO);
		}
		bc_dport = pla_FindPort(bc, 7*pla_lam+pla_VddWidth, 3*pla_lam);
		bc_pport = pla_FindPort(bc, 5*pla_lam+pla_VddWidth, pla_lam);
		if (bc_pport == NOPORTPROTO || bc_dport == NOPORTPROTO)
		{
			ttyputerr("nmos_Pullup: buried contact ports inaccessible");
			return(NONODEPROTO);
		}
		pa = newarcinst(pla_pa_proto, 2*pla_lam, FIXANG, dtran, dtran_pport,5*pla_lam+pla_VddWidth,
			pla_lam, bc, bc_pport, 5*pla_lam+pla_VddWidth, pla_lam,pu);
		da = newarcinst(pla_da_proto,  2*pla_lam, FIXANG, dtran, dtran_dport,
			7*pla_lam+pla_VddWidth,3*pla_lam, bc, bc_dport, 7*pla_lam+pla_VddWidth, 3*pla_lam, pu);
		if (pa == NOARCINST || da == NOARCINST)
		{
			ttyputerr("nmos_Pullup: cannot create p,d arcs from contact to tran");
			return(NONODEPROTO);
		}

		/*
		 * Now add an extension on the right side of the pullup for
		 * connections into the pla only if buried contacts were used.
		 */
		md = newnodeinst(pla_md_proto, 8*pla_lam+pla_VddWidth, sizeX,
			pla_lam, 5*pla_lam, NOTRANS, NOROT, pu);
		if (md == NONODEINST)
		{
			ttyputerr("nmos_Pullup: cannot extend pu to right. no md contact");
			return(NONODEPROTO);
		}

		if (newarcinst(pla_da_proto, 4*pla_lam, FIXANG, bc, bc_dport, 7*pla_lam+pla_VddWidth,
			3*pla_lam, md, pla_md_proto->firstportproto, 10*pla_lam+pla_VddWidth, 3*pla_lam,
				pu) == NOARCINST)
		{
			ttyputerr("nmos_Pullup: cannot connect bc to md extension");
			return(NONODEPROTO);
		}
	}

	/* Now place the Vdd connection on the left */
	vdd_line = newnodeinst(pla_md_proto, 0, pla_VddWidth, -pla_lam, 7*pla_lam, NOTRANS, NOROT, pu);
	if (vdd_line == NONODEINST)
	{
		ttyputerr("nmosPullups: cannot instance vdd_line");
		return(NONODEPROTO);
	}

	/* Now connect the pullup to the vdd_line */
	dtran_dport = pla_FindPort(dtran, pla_lam+pla_VddWidth, 3*pla_lam);
	if (dtran_dport == NOPORTPROTO)
	{
		ttyputerr("nmos_Pullup: cannot access dtran port to connect vdd");
		return(NONODEPROTO);
	}

	da = newarcinst(pla_da_proto, 2*pla_lam, FIXANG, vdd_line,pla_md_proto->firstportproto,
		pla_halfVdd, 3*pla_lam, dtran, dtran_dport, pla_lam+pla_VddWidth, 3*pla_lam, pu);
	if (da == NOARCINST)
	{
		ttyputerr("nmos_Pullup: cannot create d arc to connect vdd");
		return(NONODEPROTO);
	}

	/*
	 * give names to vdd line and diffusion side of the butting/buried
	 * contact so that they are accessible to outside world
	 */
	vpname = newportproto(pu, vdd_line, pla_md_proto->firstportproto, "Vdd");
	dpname = (pla_buttingcontact == ON) ? newportproto(pu, bc, bc_dport, "Pullup") :
		newportproto(pu, md, pla_md_proto->firstportproto, "Pullup");
	if (vpname == NOPORTPROTO || dpname == NOPORTPROTO)
	{
		ttyputerr("nmos_Pullup: cannot export ports from single pullup");
		return(NONODEPROTO);
	}

	/* ensure that the facet is the proper size */
	(*el_curconstraint->solve)(pu);
	return(pu);
}

#endif /* PLAAID - at top */
