/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: ROMGenerator.java
 * Written by: David Harris (David_Harris@hmc.edu)
 * Based on code developed by Frank Lee <chlee@hmc.edu> and Jason Imada <jimada@hmc.edu>
 *
 * Copyright (c) 2003, Static Free Software. All rights reserved.
 *
 * 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 3 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.sun.electric.tool.generator;

import com.sun.electric.database.EditingPreferences;
import com.sun.electric.database.geometry.Poly;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Export;
import com.sun.electric.database.hierarchy.Library;
import com.sun.electric.database.prototype.NodeProto;
import com.sun.electric.database.prototype.PortCharacteristic;
import com.sun.electric.database.prototype.PortProto;
import com.sun.electric.database.topology.ArcInst;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.technology.ArcProto;
import com.sun.electric.technology.Technology;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.JobException;
import com.sun.electric.tool.io.FileType;
import com.sun.electric.tool.user.User;
import com.sun.electric.tool.user.dialogs.OpenFile;
import com.sun.electric.tool.user.ui.WindowFrame;
import com.sun.electric.util.math.Orientation;

import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/**
 * Class to build ROMs from personality tables.
 */
public class ROMGenerator
{
	private int globalbits;
	private int folds;
	private double lambda = 1;
	private Technology tech;
    private EditingPreferences ep;

    /**
	 * Main entry point for ROM generation.
	 * The method creates layout for a pseudo-nMOS ROM array.
	 *
	 * The personality file has this format:
	 * The first line lists the degree of folding.  For example,
	 * a 256-word x 10-bit ROM with a folding degree of 4 will
	 * be implemented as a 64 x 40 array with 4:1 column multiplexers
	 * to return 10 bits of data while occupying more of a square form
	 * factor. The number of words and degree of folding should be
	 * powers of 2.  The remaining lines of the file list the contents
	 * of each word.  The parser is pretty picky.  There should
	 * be a carriage return after the list word, but no other blank
	 * lines in the file.
	 *
	 * Here is a sample personality file:
	 *     1
	 *     010101
	 *     011001
	 *     100101
	 *     101010
	 *     4
	 *     00000000
	 *     10000000
	 *     01000000
	 *     11000000
	 *
	 * The tool may be slow, especially for large ROMs.  When done, there may be some
	 * extraneous and bad pins left over; using "Edit / Cleanup Cell / Cleanup
	 * Pins Everywhere" will fix these (though this isn't strictly necessary).
	 *
	 * The ROMs produced should pass DRC and ERC and simulate with IRSIM.  One
	 * was successfully fabricated Spring of 2002 by Genevieve Breed and Matthew
	 * Erler in the MOSIS 0.6 micron AMI process.
	 */
	public static void generateROM()
	{
		// get the personality file
		String romFile = OpenFile.chooseInputFile(FileType.TEXT, null, null);
		if (romFile == null) return;

		// build the ROM (in a separate Job thread)
		new DoROM(Library.getCurrent(), romFile);
	}

	/**
	 * Method to generate a ROM from a given ROM file.
     * @param destLib destination library.
	 * @param romFile the file to use.
     * @param ep EditingPreferences
	 */
	public static void generateROM(Library destLib, String romFile, EditingPreferences ep)
	{
		// build the ROM (in a separate Job thread)
//		new DoROM(destLib, romFile);
        new ROMGenerator(ep).makeAROM(destLib, romFile, "ROMCELL");
	}

	/**
	 * Class to generate a ROM in a separate Job thread.
	 */
	private static class DoROM extends Job
	{
        private Library destLib;
		private String romfile;
		private Cell topLevel;

		private DoROM(Library destLib, String romfile)
		{
			super("ROM Generator", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
            this.destLib = destLib;
			this.romfile = romfile;
			startJob();
		}

        @Override
		public boolean doIt() throws JobException
		{
			// Set the root name of the cells
			String romcell = "ROMCELL";

			// build the ROM
			topLevel = new ROMGenerator(getEditingPreferences()).makeAROM(destLib, romfile, romcell);
			fieldVariableChanged("topLevel");
			return true;
		}

        @Override
        public void terminateOK()
        {
            if (topLevel != null)
            {
                WindowFrame wf = WindowFrame.getCurrentWindowFrame();
    			if (User.isShowCellsInNewWindow()) wf = null;
    			if (wf == null) wf = WindowFrame.createEditWindow(topLevel);
                wf.setCellWindow(topLevel, null);
            }
        }
	}

    private ROMGenerator(EditingPreferences ep) {
        this.ep = ep;
    }
    
	/**
	 * Main method to build a ROM.
     * @param destLib destination library.
	 * @param romfile the disk file with the ROM personality.
	 * @param romcell the root name of all ROM cells.
	 * @return the top-level cell.
	 */
	public Cell makeAROM(Library destLib, String romfile, String romcell)
	{
		NodeInst ap1, ap2, ap3, ap4;
		PortProto apport1, apport2, apport3, apport4;
		double[] appos1, appos2, appos3, appos4;

		// presume MOSIS CMOS
		tech = Technology.getMocmosTechnology();

        int[][] romarray = romarraygen(romfile);

		String dpr  = new String(romcell+"_decoderpmos");
		String dnr  = new String(romcell+"_decodernmos");
		String dpm  = new String(romcell+"_decoderpmosmux");
		String dnm  = new String(romcell+"_decodernmosmux");
		String invt = new String(romcell+"_invertertop");
		String invb = new String(romcell+"_inverterbot");
		String romname =  new String(romcell+"_rom");
		String rp =   new String(romcell+"_romplane");
		String ip =   new String(romcell+"_inverterplane");
		String mp =   new String(romcell+"_muxplane");

		if (folds > 1)
		{
			romarray = romfold(romarray);
		}
		romplane(destLib, lambda, romarray, rp);

		int bits =
			(Double.valueOf(Math.ceil(Math.log(globalbits)/Math.log(2.0)))).intValue();
		int words = (int) (Math.pow(2.0, bits));
		int foldbits =
			(Double.valueOf(Math.ceil(Math.log(folds)/Math.log(2.0)))).intValue();

		boolean top = true;
		boolean bot = false;

		// make subcells
		decoderpmos(destLib, lambda, bits, dpr, top);
		decodernmos(destLib, lambda, bits, dnr, top);
		inverterplane(destLib, lambda, romarray.length, folds, ip);
		ininverterplane(destLib, lambda, bits, invt, top, bits);

		ArcProto m1arc = tech.findArcProto("Metal-1");
		ArcProto m2arc = tech.findArcProto("Metal-2");

		////////////// decoderpmos
		Cell decp = destLib.findNodeProto(dpr+"{lay}");
		Rectangle2D decpBounds = decp.getBounds();
		PortProto[] decpin = new PortProto[words];
		PortProto[] decpout = new PortProto[words];
		PortProto[] decpbit = new PortProto[2*bits];
		PortProto decpvdd = decp.findPortProto("vdd");
		PortProto decpvddb = decp.findPortProto("vddb");
		for (int i=0; i<words; i++)
		{
			decpin[i] = decp.findPortProto("wordin"+i);
			decpout[i] = decp.findPortProto("word"+i);
		}
		for (int i=0; i<bits; i++)
		{
			decpbit[2*i] = decp.findPortProto("top_in"+i);
			decpbit[(2*i)+1] = decp.findPortProto("top_in"+i+"_b");
		}

		////////////// decodernmos
		Cell decn = destLib.findNodeProto(dnr+"{lay}");
		Rectangle2D decnBounds = decn.getBounds();
	 	PortProto[] decnout = new PortProto[words];
	 	PortProto[] decnin = new PortProto[words];
	 	PortProto[] decnbit = new PortProto[2*bits];

		for (int i=0; i<words; i++)
		{
			decnin[i] = decn.findPortProto("mid"+i);
			decnout[i] = decn.findPortProto("word"+i);
		}
		for (int i=0; i<bits; i++)
		{
			decnbit[2*i] = decn.findPortProto("top_in"+i);
			decnbit[(2*i)+1] = decn.findPortProto("top_in"+i+"_b");
		}

		////////////////////// romplane
		Cell romp = destLib.findNodeProto(rp+"{lay}");
		Rectangle2D rompBounds = romp.getBounds();
		PortProto[] rompin = new PortProto[globalbits];
		PortProto[] rompout = new PortProto[romarray.length];
		PortProto[] rompgnd = new PortProto[romarray.length/2];
		PortProto rompvdd = romp.findPortProto("vdd");
		PortProto rompgndc = romp.findPortProto("gndc");
		for (int i=0; i<globalbits; i++)
		{
			rompin[i] = romp.findPortProto("wordline_"+i);
		}
		for (int i=0; i<romarray.length; i++)
		{
			rompout[i] = romp.findPortProto("out_"+i);
		}
		for (int i=0; i<romarray.length/2; i++)
		{
			rompgnd[i] = romp.findPortProto("romgnd"+i);
		}

		////////////////////// inverterplane
		Cell invp = destLib.findNodeProto(ip+"{lay}");
		Rectangle2D invpBounds = invp.getBounds();
		PortProto[] invin = new PortProto[romarray.length];
		PortProto[] invout = new PortProto[romarray.length];
		PortProto[] invgnd = new PortProto[romarray.length/2];
		PortProto invvddc = invp.findPortProto("vdd");
		PortProto invgndc = invp.findPortProto("gnd");
		for (int i=0; i<romarray.length/folds; i++)
		{
			invin[i] = invp.findPortProto("invin"+i);
			invout[i] = invp.findPortProto("invout"+i);
		}

		int invplanegnd = romarray.length/folds;
		if (folds == 1)
		{
			invplanegnd = invplanegnd / 2;
		}

		for (int i=0; i<invplanegnd; i++)
		{
			invgnd[i] = invp.findPortProto("invgnd"+i);
		}

		////////////////////// ininverterplane top
		Cell ininvtp = destLib.findNodeProto(invt+"{lay}");
		Rectangle2D ininvtpBounds = ininvtp.getBounds();
		PortProto[] ivttop  = new PortProto[bits];
		PortProto[] ivtbot = new PortProto[bits];
		PortProto[] ivtbar = new PortProto[bits];
		PortProto ivtvdd = ininvtp.findPortProto("vdd");
		PortProto ivtgnd = ininvtp.findPortProto("gnd");
		for (int i=0; i<bits; i++)
		{
			ivttop[i] = ininvtp.findPortProto("in_top"+i);
			ivtbot[i] = ininvtp.findPortProto("in_bot"+i);
			ivtbar[i] = ininvtp.findPortProto("in_b"+i);
		}

		// create new layout named "rom{lay}" in destination library
		Cell rom = Cell.newInst(destLib, romname+"{lay}");

		////////// calculate pplane offset
		double offset = (2*bits*(8*lambda)) + (16*lambda);
		double rompoffset = (8*lambda)*2*bits + (12*lambda) + offset;
		double rompoffsety = 8*lambda*(globalbits+1);
		double foldoffsetx = (2*(bits-foldbits)*(8*lambda));
		double muxpoffsety = -6*lambda;
		double foldoffsety = -8*lambda*(folds+1);
		double ininvtoffset = (globalbits+2)*8*lambda+48*lambda;

		// smr added this line to make things line-up properly
		ininvtoffset += 44*lambda;

		double invpoffsety = -8*lambda*(folds+1)-16*lambda;
		if (folds == 1)
		{
			invpoffsety = invpoffsety + 24*lambda;
		}

		NodeInst nplane =
			makeCStyleNodeInst(decn, decnBounds.getMinX()+offset, decnBounds.getMaxX()+offset, decnBounds.getMinY(),
								 decnBounds.getMaxY(), 0, 0, rom);
		NodeInst pplane =
			makeCStyleNodeInst(decp, decpBounds.getMinX(), decpBounds.getMaxX(), decpBounds.getMinY(), decpBounds.getMaxY(),
								 0, 0, rom);
		NodeInst rompln =
			makeCStyleNodeInst(romp, rompBounds.getMinX()+rompoffset, rompBounds.getMaxX()+rompoffset,
								 rompBounds.getMinY()+rompoffsety, rompBounds.getMaxY()+rompoffsety,
								 0, 2700, rom);
		NodeInst invpln =
			makeCStyleNodeInst(invp, invpBounds.getMinX()+rompoffset, invpBounds.getMaxX()+rompoffset,
								 invpBounds.getMinY()+invpoffsety, invpBounds.getMaxY()+invpoffsety, 0, 0, rom);
		NodeInst ininvtop1 =
			makeCStyleNodeInst(ininvtp,ininvtpBounds.getMinX(),ininvtpBounds.getMaxX(),
								 ininvtpBounds.getMinY()+ininvtoffset, ininvtpBounds.getMaxY()+ininvtoffset,
								 0, 0, rom);
		NodeInst ininvtop2 =
			makeCStyleNodeInst(ininvtp,ininvtpBounds.getMinX()+offset, ininvtpBounds.getMaxX()+offset,
								 ininvtpBounds.getMinY()+ininvtoffset,
								 ininvtpBounds.getMaxY()+ininvtoffset, 0, 0, rom);

		////////////// exports on top level
		for (int i=0; i<bits; i++)
		{
			ap1 = ininvtop1;
			apport1 = ivttop[i];
			makeCStyleExport(rom, ap1, apport1, ("sel"+i), PortCharacteristic.IN);
		}
		for (int i=0; i<romarray.length/folds; i++)
		{
			ap1 = invpln;
			apport1 = invout[i];
			makeCStyleExport(rom, ap1, apport1, ("out"+i), PortCharacteristic.OUT);
		}

		ap2 = rompln;
		apport2 = rompvdd;
		makeCStyleExport(rom, ap2, apport2, ("vdd"), PortCharacteristic.PWR);

		// TODO: this arc comes out diagonal!!!
		ap1 = nplane;
		apport1 = decn.findPortProto("gnd");
		appos1 = getCStylePortPosition(ap1, apport1);
		ap2 = rompln;
		apport2 = rompgndc;
		appos2 = getCStylePortPosition(ap2, apport2);
		makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
							appos1[1], ap2, apport2, appos2[0], appos2[1]);

		apport2 = romp.findPortProto("gnd");

		// decnout, decpin
		for (int i=0; i<words; i++)
		{
			ap1 = pplane;
			apport1 = decpout[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = nplane;
			apport2 = decnin[i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
		}

		for (int i=0; i<words; i++)
		{
			if (i >= globalbits) continue;

			ap1 = nplane;
			apport1 = decnout[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = rompln;
			apport2 = rompin[i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
		}

		/////// connect rompgnd to invgnd
		if (folds > 1)
		{
			for (int i=0; i<romarray.length/folds; i++)
			{
				ap1 = invpln;
				apport1 = invgnd[i];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = rompln;
				apport2 = rompgnd[i*folds/2];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
									appos1[1], ap2,apport2,appos2[0], appos2[1]);
			}
		} else
		{
			for (int i=0; i<romarray.length/(2*folds); i++)
			{
				ap1 = invpln;
				apport1 = invgnd[i];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = rompln;
				apport2 = rompgnd[i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
									appos1[1], ap2,apport2,appos2[0], appos2[1]);
			}
		}

		/////// connect top ininv1 to ininv2
		for (int i=0; i<bits; i++)
		{
			ap1 = ininvtop1;
			apport1 = ivttop[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = ininvtop2;
			apport2 = ivttop[i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
		}

		/////// connect top ininv1 to ndecoder
		for (int i=0; i<bits; i++)
		{
			ap1 = ininvtop1;
			apport1 = ivtbot[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = pplane;
			apport2 = decpbit[i*2];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
			ap1 = ininvtop1;
			apport1 = ivtbar[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = pplane;
			apport2 = decpbit[(i*2)+1];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
		}

		/////// connect top ininv2 to pdecoder
		for (int i=0; i<bits; i++)
		{
			ap1 = ininvtop2;
			apport1 = ivtbot[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = nplane;
			apport2 = decnbit[i*2];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
			ap1 = ininvtop2;
			apport1 = ivtbar[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = nplane;
			apport2 = decnbit[(i*2)+1];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
		}

		//////// connect two top decoder inverterplanes and decoder together (vdd)
		ap1 = ininvtop1;
		apport1 = ivtvdd;
		appos1 = getCStylePortPosition(ap1, apport1);
		ap2 = ininvtop2;
		apport2 = ivtvdd;
		appos2 = getCStylePortPosition(ap2, apport2);
		ap3 = pplane;
		apport3 = decpvdd;
		appos3 = getCStylePortPosition(ap3, apport3);
		makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1, appos1[0],
							appos1[1], ap2, apport2, appos2[0], appos2[1]);
		makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1, appos1[0],
							appos1[1], ap3, apport3, appos3[0], appos3[1]);

		//////// connect two top decoder inverterplanes and romplane together (gnd)
		ap1 = ininvtop1;
		apport1 = ivtgnd;
		appos1 = getCStylePortPosition(ap1, apport1);
		ap2 = ininvtop2;
		apport2 = ivtgnd;
		appos2 = getCStylePortPosition(ap2, apport2);
		ap3 = rompln;
		apport3 = rompgndc;
		appos3 = getCStylePortPosition(ap3, apport3);

		makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1, appos1[0],
							appos1[1], ap2, apport2, appos2[0], appos2[1]);
		makeCStyleArcInst(m1arc, 4*lambda, ap2, apport2, appos2[0],
							appos2[1], ap3, apport3, appos3[0], appos3[1]);
		makeCStyleExport(rom, ap2, apport2, "gnd", PortCharacteristic.GND);

		//////// connect decoder inverter vdd to rom vdd
		ap1 = ininvtop2;
		apport1 = ivtvdd;
		appos1 = getCStylePortPosition(ap1, apport1);
		ap2 = rompln;
		apport2 = rompvdd;
		appos2 = getCStylePortPosition(ap2, apport2);

		makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1, appos1[0],
							appos1[1], ap2, apport2, appos2[0], appos2[1]);

		// begin (folds > 1)
		if (folds > 1)
		{
			decoderpmos(destLib, lambda, foldbits, dpm, bot);
			decodernmos(destLib, lambda, foldbits, dnm, bot);
			ininverterplane(destLib, lambda, foldbits, invb, bot, bits);
			muxplane(destLib, lambda, folds, romarray.length, mp);

			////////////// decodernmosmux
			Cell decpmux = destLib.findNodeProto(dpm+"{lay}");
			Rectangle2D decpmuxBounds = decpmux.getBounds();
		 	PortProto[] decpmuxin = new PortProto[folds];
		 	PortProto[] decpmuxout = new PortProto[folds];
		 	PortProto[] decpmuxbit = new PortProto[2*foldbits];
		 	PortProto decpmuxvdd = decpmux.findPortProto("vdd");
			PortProto decpmuxvddb = decpmux.findPortProto("vddb");

			for (int i=0; i<folds; i++)
			{
				decpmuxin[i] = decpmux.findPortProto("wordin"+i);
				decpmuxout[i] = decpmux.findPortProto("word"+i);
			}
			for (int i=0; i<foldbits; i++)
			{
				decpmuxbit[2*i] = decpmux.findPortProto("bot_in"+i);
				decpmuxbit[(2*i)+1] = decpmux.findPortProto("bot_in"+i+"_b");
			}

			////////////// decoderpmosmux
			Cell decnmux = destLib.findNodeProto(dnm+"{lay}");
			Rectangle2D decnmuxBounds = decnmux.getBounds();
		 	PortProto[] decnmuxout = new PortProto[folds];
		 	PortProto[] decnmuxin = new PortProto[folds];
		 	PortProto[] decnmuxbit = new PortProto[2*foldbits];
			for (int i=0; i<folds; i++)
			{
				decnmuxin[i] = decnmux.findPortProto("mid"+i);
				decnmuxout[i] = decnmux.findPortProto("word"+i);
			}
			for (int i=0; i<foldbits; i++)
			{
				decnmuxbit[2*i] = decnmux.findPortProto("bot_in"+i);
				decnmuxbit[(2*i)+1] = decnmux.findPortProto("bot_in"+i+"_b");
			}

			////////////////////// muxplane
			Cell muxp = destLib.findNodeProto(mp+"{lay}");
			Rectangle2D muxpBounds = muxp.getBounds();
			PortProto[] muxin = new PortProto[romarray.length];
			PortProto[] muxout = new PortProto[romarray.length/folds];
			PortProto[] muxsel = new PortProto[folds];
			for (int i=0; i<romarray.length; i++)
			{
				muxin[i] = muxp.findPortProto("muxin"+i);
			}
			for (int i=0; i<romarray.length/folds; i++)
			{
				muxout[i] = muxp.findPortProto("muxout"+i);
			}
			for (int i=0; i<folds; i++)
			{
				muxsel[i] = muxp.findPortProto("sel"+i);
			}

			////////////////////// ininverterplane bottom
			Cell ininvbp = destLib.findNodeProto(invb+"{lay}");
			Rectangle2D ininvbpBounds = ininvbp.getBounds();
			PortProto[] ivbtop  = new PortProto[foldbits];
			PortProto[] ivbbot = new PortProto[foldbits];
			PortProto[] ivbbar = new PortProto[foldbits];
			PortProto ivbvdd = ininvbp.findPortProto("vdd");
			PortProto ivbgnd = ininvbp.findPortProto("gnd");
			for (int i=0; i<foldbits; i++)
			{
				ivbtop[i] = ininvbp.findPortProto("in_top"+i);
				ivbbot[i] = ininvbp.findPortProto("in_bot"+i);
				ivbbar[i] = ininvbp.findPortProto("in_b"+i);
			}

			NodeInst muxpln =
				makeCStyleNodeInst(muxp, muxpBounds.getMinX()+rompoffset, muxpBounds.getMaxX()+rompoffset,
									 muxpBounds.getMinY()+muxpoffsety, muxpBounds.getMaxY()+muxpoffsety,
									 0, 2700, rom);
			NodeInst pplnmx =
				makeCStyleNodeInst(decpmux, decpmuxBounds.getMinX()+foldoffsetx,
											decpmuxBounds.getMaxX()+foldoffsetx,
											decpmuxBounds.getMinY()+muxpoffsety+foldoffsety,
											decpmuxBounds.getMaxY()+muxpoffsety+foldoffsety, 0, 0, rom);

			NodeInst nplnmx =
				makeCStyleNodeInst(decnmux, decnmuxBounds.getMinX()+foldoffsetx+offset,
									 decnmuxBounds.getMaxX()+foldoffsetx+offset,
									 decnmuxBounds.getMinY()+muxpoffsety+foldoffsety,
									 decnmuxBounds.getMaxY()+muxpoffsety+foldoffsety, 0, 0, rom);
			NodeInst ininvbot1 =
				makeCStyleNodeInst(ininvbp,ininvbpBounds.getMinX()+foldoffsetx,
									 ininvbpBounds.getMaxX()+foldoffsetx, ininvbpBounds.getMinY()+invpoffsety,
									 ininvbpBounds.getMaxY()+invpoffsety, 0, 0, rom);
			NodeInst ininvbot2 =
				makeCStyleNodeInst(ininvbp, ininvbpBounds.getMinX()+foldoffsetx+offset,
									 ininvbpBounds.getMaxX()+foldoffsetx+offset,
									 ininvbpBounds.getMinY()+invpoffsety,
									 ininvbpBounds.getMaxY()+invpoffsety, 0, 0, rom);

			for (int i=0; i<foldbits; i++)
			{
				ap1 = ininvbot1;
				apport1 = ivbbot[i];
				makeCStyleExport(rom, ap1, apport1, "colsel"+i, PortCharacteristic.IN);
			}

			ap1 = nplane;
			apport1 = decn.findPortProto("gnd");
			appos1 = getCStylePortPosition(ap1, apport1);
			ap3 = pplnmx;
			apport3 = decpmuxvdd;
			appos3 = getCStylePortPosition(ap3, apport3);
			ap4 = pplane;
			apport4 = decpvddb;
			appos4 = getCStylePortPosition(ap4, apport4);
			makeCStyleArcInst(m1arc, 4*lambda, ap4, apport4, appos4[0],
								appos4[1], ap3, apport3, appos3[0], appos3[1]);

			ap3 = nplnmx;
			apport3 = decnmux.findPortProto("gnd");
			appos3 = getCStylePortPosition(ap3, apport3);

			makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap3, apport3, appos3[0], appos3[1]);

			// decnmuxout, decpmuxin
			for (int i=0; i<folds; i++)
			{
				ap1 = pplnmx;
				apport1 = decpmuxout[i];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = nplnmx;
				apport2 = decnmuxin[i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1,appos1[0],
									appos1[1],ap2,apport2,appos2[0], appos2[1]);
			}

			for (int i=0; i<folds; i++)
			{
				ap1 = nplnmx;
				apport1 = decnmuxout[i];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = muxpln;
				apport2 = muxsel[i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1,appos1[0],
									appos1[1],ap2,apport2,appos2[0], appos2[1]);
			}

			///////connect rompout to muxin
			for (int i=0; i<romarray.length; i++)
			{
				ap1 = rompln;
				apport1 = rompout[i];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = muxpln;
				apport2 = muxin[i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1,appos1[0],
									appos1[1],ap2,apport2,appos2[0], appos2[1]);
			}

			/////// connect muxout to invin
			for (int i=0; i<romarray.length/folds; i++)
			{
				ap1 = invpln;
				apport1 = invin[i];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = muxpln;
				apport2 = muxout[i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1,appos1[0],
									appos1[1],ap2,apport2,appos2[0], appos2[1]);
			}

			/////// connect bot ininv1 to ininv2
			for (int i=0; i<foldbits; i++)
			{
				ap1 = ininvbot1;
				apport1 = ivbbot[i];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = ininvbot2;
				apport2 = ivbbot[i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1,appos1[0],
									appos1[1],ap2,apport2,appos2[0], appos2[1]);
			}

			/////// connect bot ininv1 to nmuxdecoder
			for (int i=0; i<foldbits; i++)
			{
				ap1 = ininvbot1;
				apport1 = ivbtop[i];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = pplnmx;
				apport2 = decpmuxbit[i*2];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
									appos1[1], ap2, apport2, appos2[0], appos2[1]);
				ap1 = ininvbot1;
				apport1 = ivbbar[i];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = pplnmx;
				apport2 = decpmuxbit[(i*2)+1];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
									appos1[1], ap2, apport2, appos2[0], appos2[1]);
			}

			/////// connect bot ininv2 to pmuxdecoder
			for (int i=0; i<foldbits; i++)
			{
				ap1 = ininvbot2;
				apport1 = ivbtop[i];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = nplnmx;
				apport2 = decnmuxbit[i*2];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
									appos1[1], ap2, apport2, appos2[0], appos2[1]);
				ap1 = ininvbot2;
				apport1 = ivbbar[i];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = nplnmx;
				apport2 = decnmuxbit[(i*2)+1];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
									appos1[1], ap2, apport2, appos2[0], appos2[1]);
			}

			//////// connect two mux decoder inverterplanes and mux decoder together (vdd)
			ap1 = ininvbot1;
			apport1 = ivbvdd;
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = ininvbot2;
			apport2 = ivbvdd;
			appos2 = getCStylePortPosition(ap2, apport2);
			ap3 = pplnmx;
			apport3 = decpmuxvddb;
			appos3 = getCStylePortPosition(ap3, apport3);

			makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);

			makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap3, apport3, appos3[0], appos3[1]);

			//////// connect two mux decoder inverterplanes and inverterplane together (gnd)
			ap1 = ininvbot1;
			apport1 = ivbgnd;
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = ininvbot2;
			apport2 = ivbgnd;
			appos2 = getCStylePortPosition(ap2, apport2);
			ap3 = invpln;
			apport3 = invgndc;
			appos3 = getCStylePortPosition(ap3, apport3);
			makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
			makeCStyleArcInst(m2arc, 4*lambda, ap3, apport3, appos3[0],
								appos3[1], ap2, apport2, appos2[0], appos2[1]);

			//////// connect mux decoder to inverter vdd
			ap1 = invpln;
			apport1 = invvddc;
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = ininvbot2;
			apport2 = ivbvdd;
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
		}
		// end (folds > 1)

		// begin (folds == 1)
		if (folds == 1)
		{
			for (int i=0; i<romarray.length; i++)
			{
				ap1 = invpln;
				apport1 = invin[i];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = rompln;
				apport2 = rompout[i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
									appos1[1], ap2, apport2, appos2[0], appos2[1]);
			}

			// connect vdd of decoderpmos to vdd of inverterplane
			NodeProto m1m2c = tech.findNodeProto("Metal-1-Metal-2-Con");
			PortProto m1m2cport = m1m2c.getPort(0);
			double[] m1m2cbox = {-5*lambda/2, 5*lambda/2, -5*lambda/2, 5*lambda/2};

			double vddoffsetx = offset - 4*lambda;
			double vddoffsety = invpoffsety - 26*lambda;

			NodeInst vddbot =
				makeCStyleNodeInst(m1m2c, m1m2cbox[0]+vddoffsetx, m1m2cbox[1]+vddoffsetx,
									 m1m2cbox[2]+vddoffsety, m1m2cbox[3]+vddoffsety, 0, 0, rom);

			ap1 = invpln;
			apport1 = invvddc;
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = vddbot;
			apport2 = m1m2cport;
			appos2 = getCStylePortPosition(ap2, apport2);
			ap3 = pplane;
			apport3 = decpvddb;
			appos3 = getCStylePortPosition(ap3, apport3);
			makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
			makeCStyleArcInst(m1arc, 4*lambda, ap2, apport2, appos2[0],
								appos2[1], ap3, apport3, appos3[0], appos3[1]);
		}

		// return the top-level
		return rom;
	}

	/**
	 */
	private void romplane(Library destLib, double lambda, int romarray[][], String rp)
	{
		int i, m;
		double x, y;
		NodeInst ap1, ap2, ap3, ap4, gnd1, gnd2, intgnd;
		PortProto apport1, apport2, apport3, apport4, gndport1, gndport2,
						   intgndport;
		double[] appos1, appos2, appos3, appos4, gndpos1, gndpos2, intgndpos;

		int inputs = romarray[0].length;
		int wordlines = romarray.length;

		NodeInst[][] andtrans = new NodeInst[wordlines+2][inputs+2];
		NodeInst[] pulluptrans = new NodeInst[wordlines+2];
		NodeInst[] nwellc = new NodeInst[(wordlines+2)/2];
		NodeInst[][] minpins = new NodeInst[wordlines+2][inputs+2];
		NodeInst[][] diffpins = new NodeInst[wordlines+2][inputs+2];
		NodeInst[][] gndpins = new NodeInst[wordlines/2][inputs+2];
		NodeInst[] gnd_2pins = new NodeInst[wordlines/2];
		NodeInst[] m1polypins = new NodeInst[inputs+2];
		NodeInst[] m1m2pins = new NodeInst[inputs+2];
		NodeInst[] m1m2_2pins = new NodeInst[wordlines+2];
		NodeInst[] m1m2_3pins = new NodeInst[wordlines+2];
		NodeInst[] m1m2_4pins = new NodeInst[wordlines+2];
		NodeInst[] mpac_1pins = new NodeInst[wordlines+2];
		NodeInst[] mpac_2pins = new NodeInst[wordlines+2];
		NodeInst gndpex[] = new NodeInst[1];
		NodeInst gndm1ex[] = new NodeInst[1];
		NodeInst gnd1pin = null;
		NodeInst vdd2pin = null;

		PortProto[] nwellcports = new PortProto[(wordlines+2)/2];
		PortProto[][] minports = new PortProto[wordlines+2][inputs+2];
		PortProto[][] gndports = new PortProto[wordlines/2][inputs+2];
		PortProto[] gnd_2ports = new PortProto[wordlines/2];
		PortProto[] m1m2_2ports = new PortProto[wordlines+2];
		PortProto[] m1m2_3ports = new PortProto[wordlines+2];
		PortProto[] m1m2_4ports = new PortProto[wordlines+2];
		PortProto[] mpac_1ports = new PortProto[wordlines+2];
		PortProto[] mpac_2ports = new PortProto[wordlines+2];
		PortProto gndpexport[] = new PortProto[1];
		PortProto gndm1export[] = new PortProto[1];
		PortProto gnd1port = null;
		PortProto vdd2port = null;

		// get pointers to primitives
		NodeProto nmos = tech.findNodeProto("N-Transistor");
		PortProto nmosg1port = nmos.findPortProto("poly-right");
		PortProto nmosg2port = nmos.findPortProto("poly-left");
		PortProto nmosd1port = nmos.findPortProto("diff-top");
		PortProto nmosd2port = nmos.findPortProto("diff-bottom");
		double[] nmosbox = {-nmos.getDefWidth(ep)/2-lambda/2,
							nmos.getDefWidth(ep)/2+lambda/2,
							-nmos.getDefHeight(ep)/2,
							nmos.getDefHeight(ep)/2};

		NodeProto pmos = tech.findNodeProto("P-Transistor");
		PortProto pmosg1port = pmos.findPortProto("poly-right");
		PortProto pmosg2port = pmos.findPortProto("poly-left");
		PortProto pmosd1port = pmos.findPortProto("diff-top");
		PortProto pmosd2port = pmos.findPortProto("diff-bottom");
		double bbb = 15;
		double ccc = 23;
		double[] pmosbox = {-bbb*lambda/2, bbb*lambda/2, -ccc*lambda/2, ccc*lambda/2};

		NodeProto ppin = tech.findNodeProto("Polysilicon-1-Pin");
		PortProto ppinport = ppin.getPort(0);
		double[] ppinbox = {-ppin.getDefWidth(ep)/2,
						 ppin.getDefWidth(ep)/2,
						 -ppin.getDefHeight(ep)/2,
						 ppin.getDefHeight(ep)/2};

		NodeProto m1pin = tech.findNodeProto("Metal-1-Pin");
		PortProto m1pinport = m1pin.getPort(0);
		double[] m1pinbox = {-m1pin.getDefWidth(ep)/2-lambda/2,
						  m1pin.getDefWidth(ep)/2+lambda/2,
						  -m1pin.getDefHeight(ep)/2-lambda/2,
						  m1pin.getDefHeight(ep)/2+lambda/2};

		NodeProto m2pin = tech.findNodeProto("Metal-2-Pin");
		PortProto m2pinport = m2pin.getPort(0);
		double[] m2pinbox = {-m2pin.getDefWidth(ep)/2-lambda/2,
						  m2pin.getDefWidth(ep)/2+lambda/2,
						  -m2pin.getDefHeight(ep)/2-lambda/2,
						  m2pin.getDefHeight(ep)/2+lambda/2};

		NodeProto diffpin = tech.findNodeProto("Active-Pin");
		PortProto diffpinport = diffpin.getPort(0);
		double[] diffpinbox =
			{-diffpin.getDefWidth(ep)/2-lambda/2,
			 diffpin.getDefWidth(ep)/2+lambda/2,
			 -diffpin.getDefHeight(ep)/2-lambda/2,
			 diffpin.getDefHeight(ep)/2+lambda/2};

		NodeProto nwnode = tech.findNodeProto("N-Well-Node");

		NodeProto pwnode = tech.findNodeProto("P-Well-Node");

		NodeProto psnode = tech.findNodeProto("P-Select-Node");

		NodeProto mnac = tech.findNodeProto("Metal-1-N-Active-Con");
		PortProto mnacport = mnac.getPort(0);
		double aaa = 17;
		double[] mnacbox = {-aaa*lambda/2, aaa*lambda/2, -aaa*lambda/2, aaa*lambda/2};

		NodeProto mpac = tech.findNodeProto("Metal-1-P-Active-Con");
		PortProto mpacport = mpac.getPort(0);
		double[] mpacbox = {-aaa*lambda/2, aaa*lambda/2, -aaa*lambda/2, aaa*lambda/2};

		NodeProto mpwc = tech.findNodeProto("Metal-1-P-Well-Con");
		PortProto mpwcport = mpwc.getPort(0);
		double[] mpwcbox = {-17*lambda/2, 17*lambda/2, -17*lambda/2, 17*lambda/2};

		NodeProto mnwc = tech.findNodeProto("Metal-1-N-Well-Con");
		PortProto mnwcport = mnwc.getPort(0);
		double nwellx = 29;
		double nwelly = 17;
		double[] mnwcbox ={-nwellx*lambda/2,nwellx*lambda/2,-nwelly*lambda/2,nwelly*lambda/2};

		NodeProto mpc = tech.findNodeProto("Metal-1-Polysilicon-1-Con");
		PortProto mpcport = mpc.getPort(0);
		double mx = 5;
		double[] mpcbox = {-mx*lambda/2, mx*lambda/2, -mx*lambda/2, mx*lambda/2};

		NodeProto m1m2c = tech.findNodeProto("Metal-1-Metal-2-Con");
		PortProto m1m2cport = m1m2c.getPort(0);
		double[] m1m2cbox = {-mx*lambda/2, mx*lambda/2, -mx*lambda/2, mx*lambda/2};

		NodeProto nsnode = tech.findNodeProto("N-Select-Node");

		ArcProto parc = tech.findArcProto("Polysilicon-1");
		ArcProto m1arc = tech.findArcProto("Metal-1");
		ArcProto m2arc = tech.findArcProto("Metal-2");
		ArcProto ndiffarc = tech.findArcProto("N-Active");
		ArcProto pdiffarc = tech.findArcProto("P-Active");

		// create a cell called "romplane{lay}" in the destination library
		Cell romplane = Cell.newInst(destLib, rp+"{lay}");

		makeCStyleNodeInst(pwnode,-4*lambda,(8*lambda*(inputs+2)),
										-4*lambda,3*8*lambda*(wordlines)/2,0,0,romplane);

		double ptranssize = 20;

		makeCStyleNodeInst(psnode,-28*lambda,(ptranssize-28)*lambda,4*lambda,
								 (4+3*8*wordlines/2)*lambda,0,0,romplane);
		makeCStyleNodeInst(nsnode,0*lambda,(8*lambda*inputs),4*lambda,
								 (4+3*8*wordlines/2)*lambda,0,0,romplane);
		makeCStyleNodeInst(nwnode,-38*lambda,(ptranssize-38)*lambda,20*lambda,
								 (4+3*8*wordlines/2)*lambda,0,0,romplane);

		// Create instances of objects on rom plane
		x = 0;
		for (i=0; i<inputs+1; i++)
		{
			x += 8*lambda;
			y = 0;
			if (i < inputs)
			{
				andtrans[0][i] =
					makeCStyleNodeInst(ppin, ppinbox[0]+x, ppinbox[1]+x, ppinbox[2],
										 ppinbox[3], 0, 0, romplane);
				m1polypins[i] =
					makeCStyleNodeInst(mpc, mpcbox[0]+x, mpcbox[1]+x, mpcbox[2],
										 mpcbox[3], 0, 0, romplane);
				m1m2pins[i] =
					makeCStyleNodeInst(m1m2c, m1m2cbox[0]+x, m1m2cbox[1]+x,
										 m1m2cbox[2], m1m2cbox[3], 0, 0, romplane);
				ap1 = m1m2pins[i];
				apport1 = m1m2cport;
				makeCStyleExport(romplane, ap1, apport1, "wordline_"+(inputs-i-1), PortCharacteristic.IN);
			}
			for (m=0; m<wordlines; m++)
			{
				y += 8*lambda;
				if (m%2 == 1)
				{
					if (i%2 == 1)
					{
						gndpins[m/2][i] =
							makeCStyleNodeInst(mnac, mnacbox[0]+x-4*lambda,
												 mnacbox[1]+x-4*lambda, mnacbox[2]+y,
												 mnacbox[3]+y, 0, 0, romplane);
						gndports[m/2][i] = mnacport;
					} else
					{
						if (i == inputs)
						{
							gndpins[m/2][i] =
								makeCStyleNodeInst(mpwc, mpwcbox[0]+x-4*lambda,
													 mpwcbox[1]+x-4*lambda, mpwcbox[2]+y,
													 mpwcbox[3]+y, 0, 0, romplane);
							gndports[m/2][i] = mpwcport;
						} else
						{
							gndpins[m/2][i] =
								makeCStyleNodeInst(m1pin, m1pinbox[0]+x-4*lambda,
								m1pinbox[1]+x-4*lambda, m1pinbox[2]+y, m1pinbox[3]+y,
								0, 0, romplane);
							gndports[m/2][i] = m1pinport;
						}
					}
					if (i == 0)
					{
						gnd_2pins[m/2] =
							makeCStyleNodeInst(m1pin, m1pinbox[0]+x-12*lambda,
								m1pinbox[1]+x-12*lambda, m1pinbox[2]+y, m1pinbox[3]+y,
								0, 0, romplane);
						gnd_2ports[m/2] = m1pinport;
						if (m == 1)
						{
							gndm1ex[m/2] =
								makeCStyleNodeInst(m1pin, m1pinbox[0]+x-12*lambda,
													 m1pinbox[1]+x-12*lambda,
													 m1pinbox[2]+y-16*lambda,
													 m1pinbox[3]+y-16*lambda, 0, 0, romplane);
							gndm1export[m/2] = m1pinport;
							gnd1pin =
								makeCStyleNodeInst(m1pin, m1pinbox[0]+x-8*lambda,
													 m1pinbox[1]+x-8*lambda,
													 m1pinbox[2]+y-16*lambda,
													 m1pinbox[3]+y-16*lambda, 0, 0, romplane);
							gnd1port = m1pinport;
							vdd2pin =
								makeCStyleNodeInst(m2pin, m2pinbox[0]+x-32*lambda,
													 m2pinbox[1]+x-32*lambda,
													 m2pinbox[2]+y-16*lambda,
													 m2pinbox[3]+y-16*lambda, 0, 0, romplane);
							vdd2port = m2pinport;
						}
					}
					y+= 8*lambda;
				}
				if (i < inputs)
				{
					if (romarray[m][i] == 1)
					{
						// create a transistor
						andtrans[m+1][i] =
							makeCStyleNodeInst(nmos, nmosbox[0]+x, nmosbox[1]+x,
												 nmosbox[2]+y, nmosbox[3]+y,1,0,romplane);
					} else
					{
						andtrans[m+1][i] =
							makeCStyleNodeInst(ppin, ppinbox[0]+x, ppinbox[1]+x,
												 ppinbox[2]+y,ppinbox[3]+y,0,0,romplane);
					}
				}
				boolean transcont = false;
				if (i < inputs) transcont = (romarray[m][i] == 1);
				if (i > 1) transcont |= (romarray[m][i-1] == 1);
				if (i%2 == 0 && transcont)
				{
					minpins[m][i] =
						makeCStyleNodeInst(mnac, mnacbox[0]+x-4*lambda,
											 mnacbox[1]+x-4*lambda, mnacbox[2]+y,
											 mnacbox[3]+y, 0, 0, romplane);
					diffpins[m][i] =
						makeCStyleNodeInst(m1pin, m1pinbox[0]+x-4*lambda,
											 m1pinbox[1]+x-4*lambda, m1pinbox[2]+y,
											 m1pinbox[3]+y, 0, 0, romplane);
					minports[m][i] = mnacport;
				} else
				{
					minpins[m][i] =
						makeCStyleNodeInst(m1pin, m1pinbox[0]+x-4*lambda,
											 m1pinbox[1]+x-4*lambda, m1pinbox[2]+y,
											 m1pinbox[3]+y, 0, 0, romplane);
					if ((transcont) || ((i==1) && (romarray[m][0] == 1))) {
						diffpins[m][i] =
							makeCStyleNodeInst(diffpin, diffpinbox[0]+x-4*lambda,
												 diffpinbox[1]+x-4*lambda, diffpinbox[2]+y,
												 diffpinbox[3]+y, 0, 0, romplane);
					} else
					{
						diffpins[m][i] =
							makeCStyleNodeInst(m1pin, m1pinbox[0]+x-4*lambda,
								m1pinbox[1]+x-4*lambda,m1pinbox[2]+y,m1pinbox[3]+y,
								0, 0, romplane);
					}
					minports[m][i] = m1pinport;
				}
				if (i == inputs)
				{
					ap1 = minpins[m][i];
					apport1 = minports[m][i];
					makeCStyleExport(romplane, ap1, apport1, "out_"+m, PortCharacteristic.OUT);
				}
				if (i == 0)
				{
					if (m%2 == 1)
					{
						nwellc[m/2] =
							makeCStyleNodeInst(mnwc, m1m2cbox[0]+x-46*lambda,
												 mnwcbox[1]+x-46*lambda, mnwcbox[2]+y,
												 mnwcbox[3]+y, 0, 0, romplane);
						nwellcports[m/2] = mnwcport;
					}
					m1m2_2pins[m] =
						makeCStyleNodeInst(m1m2c, m1m2cbox[0]+x-4*lambda,
											 m1m2cbox[1]+x-4*lambda, m1m2cbox[2]+y,
											 m1m2cbox[3]+y, 0, 0, romplane);
					m1m2_2ports[m] = m1m2cport;
					m1m2_3pins[m] =
						makeCStyleNodeInst(m1m2c, m1m2cbox[0]+x-20*lambda,
											 m1m2cbox[1]+x-20*lambda, m1m2cbox[2]+y,
											 m1m2cbox[3]+y, 0, 0, romplane);
					m1m2_3ports[m] = m1m2cport;
					mpac_1pins[m] =
						makeCStyleNodeInst(mpac, mpacbox[0]+x-20*lambda,
											 mpacbox[1]+x-20*lambda, mpacbox[2]+y,
											 mpacbox[3]+y, 0, 0, romplane);
					mpac_1ports[m] = mpacport;
					pulluptrans[m] =
						makeCStyleNodeInst(pmos, pmosbox[0]+x-26*lambda,
											 pmosbox[1]+x-26*lambda, pmosbox[2]+y,
											 pmosbox[3]+y, 1, 0, romplane);
					mpac_2pins[m] =
						makeCStyleNodeInst(mpac, mpacbox[0]+x-32*lambda,
											 mpacbox[1]+x-32*lambda, mpacbox[2]+y,
											 mpacbox[3]+y, 0, 0, romplane);
					mpac_2ports[m] = mpacport;
					m1m2_4pins[m] =
						makeCStyleNodeInst(m1m2c, m1m2cbox[0]+x-32*lambda,
											 m1m2cbox[1]+x-32*lambda, m1m2cbox[2]+y,
											 m1m2cbox[3]+y, 0, 0, romplane);
					m1m2_4ports[m] = m1m2cport;
					if (m == 0) {
						gndpex[m] =
							makeCStyleNodeInst(mpc, mpcbox[0]+x-26*lambda,
												 mpcbox[1]+x-26*lambda,
												 mpcbox[2]+y-8*lambda,
												 mpcbox[3]+y-8*lambda, 0, 0, romplane);
						gndpexport[m] = mpcport;
					}
				}
			}
		}

		// finished placing objects, start wiring arcs
		for (i=0; i<inputs; i++)
		{
			ap1 = andtrans[0][i];
			apport1 = ppinport;
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = m1polypins[i];
			apport2 = mpcport;
			appos2 = getCStylePortPosition(ap2, apport2);
			ap3 = m1m2pins[i];
			apport3 = m1m2cport;
			appos3 = getCStylePortPosition(ap3, apport3);
			makeCStyleArcInst(parc, 2*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
			makeCStyleArcInst(m1arc, 4*lambda, ap2, apport2, appos2[0],
								appos2[1], ap3, apport3, appos3[0], appos3[1]);
		}

		for (i=0; i<inputs; i++)
		{
			ap1 = andtrans[0][i];
			apport1 = ppinport;
			appos1 = getCStylePortPosition(ap1, apport1);
			for (m=1; m<wordlines+1; m++)
			{
				ap2 = andtrans[m][i];
				if (romarray[m-1][i] == 1)
				{
					apport2 = nmosg1port;
					apport3 = nmosg2port;
				} else
				{
					apport2 = ppinport;
					apport3 = ppinport;
				}
				appos2 = getCStylePortPosition(ap2, apport2);
				appos3 = getCStylePortPosition(ap2, apport3);
				makeCStyleArcInst(parc, 2*lambda, ap1, apport1, appos1[0],
									appos1[1], ap2, apport2,
									appos2[0], appos2[1]);
				ap1 = ap2;
				apport1 = apport3;
				appos1 = appos3;
			}
		}

		// connect m1 wordline lines
		for (m=0; m<wordlines; m++)
		{
			ap1 = minpins[m][0];
			apport1 = minports[m][0];
			appos1 = getCStylePortPosition(ap1, apport1);
			for (i=1; i<inputs+1; i++)
			{
				ap2 = minpins[m][i];
				apport2 = minports[m][i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
									appos1[1], ap2, apport2,
									appos2[0], appos2[1]);
				ap1 = ap2;
				apport1 = apport2;
				appos1 = appos2;
			}
		}

		// connect transistors to wordline lines
		for (m=0; m<wordlines; m++)
		{
			for (i=0; i<inputs; i++)
			{
				if (romarray[m][i] == 1)
				{
					// connect transistor
					ap1 = andtrans[m+1][i];
					gnd1 = ap1;
					if (i%2 == 0)
					{
						apport1 = nmosd1port;
						gndport1 = nmosd2port;
						ap2 = minpins[m][i];
						gnd2 = gndpins[m/2][i+1];
						intgnd = diffpins[m][i+1];
					} else
					{
						apport1 = nmosd2port;
						gndport1 = nmosd1port;
						ap2 = minpins[m][i+1];
						gnd2 = gndpins[m/2][i];
						intgnd = diffpins[m][i];
					}
					appos1 = getCStylePortPosition(ap1, apport1);
					gndpos1 = getCStylePortPosition(gnd1, gndport1);
					apport2 = mnacport;
					appos2 = getCStylePortPosition(ap2, apport2);
					gndport2 = mnacport;
					gndpos2 = getCStylePortPosition(gnd2, gndport2);
					intgndport = diffpinport;
					intgndpos = getCStylePortPosition(intgnd, intgndport);
					makeCStyleArcInst(ndiffarc, 4/*16*/*lambda, ap1, apport1,
										appos1[0], appos1[1],
										ap2, apport2, appos2[0],
										appos2[1]);
					makeCStyleArcInst(ndiffarc, 4/*16*/*lambda, gnd1, gndport1,
										gndpos1[0], gndpos1[1],
										intgnd, intgndport, intgndpos[0],
										intgndpos[1]);
					makeCStyleArcInst(ndiffarc, 4/*16*/*lambda, intgnd, intgndport,
										intgndpos[0], intgndpos[1],
										gnd2, gndport2, gndpos2[0],
										gndpos2[1]);
				}
			}
		}

		// connect ground lines
		for (m=0; m<wordlines/2; m++)
		{
			ap1 = gndpins[m][0];
			apport1 = gndports[m][0];
			appos1 = getCStylePortPosition(ap1, apport1);
			for (i=1; i<inputs+1; i++)
			{
				ap2 = gndpins[m][i];
				apport2 = gndports[m][i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
									appos1[1], ap2, apport2,
									appos2[0], appos2[1]);
				if (i == inputs)
				{
					makeCStyleExport(romplane, ap1, apport1, "romgnd"+m, PortCharacteristic.GND);
				}
				ap1 = ap2;
				apport1 = apport2;
				appos1 = appos2;
			}
		}

		// extend the gnd plane
		for (m=0; m<wordlines/2; m++)
		{
	 		ap1 = gndpins[m][0];
			apport1 = gndports[m][0];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = gnd_2pins[m];
			apport2 = gnd_2ports[m];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0],
								appos2[1]);
		}

		// tie up all the gndlines
		ap1 = gnd_2pins[0];
		apport1 = gnd_2ports[0];
		appos1 = getCStylePortPosition(ap1, apport1);
		for (m=0; m<wordlines/2; m++)
		{
			ap2 = gnd_2pins[m];
			apport2 = gnd_2ports[m];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
			if (m == (wordlines/2 - 1))
			{
				makeCStyleExport(romplane, ap2, apport2, "gnd", PortCharacteristic.GND);
			}
		}

		ap2 = gndm1ex[0];
		apport2 = gndm1export[0];
		appos2 = getCStylePortPosition(ap2, apport2);
		makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
							appos1[1], ap2, apport2, appos2[0], appos2[1]);
		ap1 = gnd1pin;
		apport1 = gnd1port;
		appos1 = getCStylePortPosition(ap1, apport1);
		makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
							appos1[1], ap2, apport2, appos2[0], appos2[1]);
		makeCStyleExport(romplane, ap1, apport1, "gndc", PortCharacteristic.GND);

		ap1 = gndpex[0];
		apport1 = gndpexport[0];
		appos1 = getCStylePortPosition(ap1, apport1);
		makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
							appos1[1], ap2, apport2, appos2[0], appos2[1]);

		ap2 = pulluptrans[0];
		apport2 = pmosg1port;
		appos2 = getCStylePortPosition(ap2, apport2);
		makeCStyleArcInst(parc, 3*lambda, ap1, apport1, appos1[0],
							appos1[1], ap2, apport2, appos2[0], appos2[1]);

		// connect m1m2contact from romplane to m1m2contact before pull-up trans
		for (m=0; m<wordlines; m++)
		{
			ap1 = minpins[m][0];
			apport1 = minports[m][0];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = m1m2_2pins[m];
			apport2 = m1m2_2ports[m];
			appos2 = getCStylePortPosition(ap2, apport2);
			ap3 = m1m2_3pins[m];
			apport3 = m1m2_3ports[m];
			appos3 = getCStylePortPosition(ap3, apport3);
			makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
			makeCStyleArcInst(m2arc, 4*lambda, ap2, apport2, appos2[0],
								appos2[1], ap3, apport3, appos3[0], appos3[1]);
		}

		// connect m1m2contact from romplane to mpac of pull-up trans
		for (m=0; m<wordlines; m++)
		{
			ap1 = m1m2_3pins[m];
			apport1 = m1m2_3ports[m];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = mpac_1pins[m];
			apport2 = mpac_1ports[m];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
		}

		// connect pull-up transistors to the mpac
		for (m=0; m<wordlines; m++)
		{
			ap1 = pulluptrans[m];
			ap4 = ap1;
			apport4 = pmosd1port;
			apport1 = pmosd2port;
			ap2= mpac_1pins[m];
			ap3= mpac_2pins[m];
			apport2 = mpacport;
			apport3 = mpacport;
			appos1 = getCStylePortPosition(ap1, apport1);
			appos4 = getCStylePortPosition(ap4, apport4);
			appos2 = getCStylePortPosition(ap2, apport2);
			appos3 = getCStylePortPosition(ap3, apport3);
			makeCStyleArcInst(pdiffarc, 3/*15*/*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
			makeCStyleArcInst(pdiffarc, 3/*15*/*lambda, ap4, apport4, appos4[0],
								appos4[1], ap3, apport3, appos3[0], appos3[1]);
		}

		// connect mpac of pull-up trans to m1m2c
		for (m=0; m<wordlines; m++)
		{
			ap1 = m1m2_4pins[m];
			apport1 = m1m2_4ports[m];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = mpac_2pins[m];
			apport2 = mpac_2ports[m];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
		}

		// connect mpac of pull-up trans to m1m2c
		for (m=0; m<wordlines; m++)
		{
			if (m%2 ==1)
			{
				ap1 = nwellc[m/2];
				apport1 = nwellcports[m/2];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = mpac_2pins[m];
				apport2 = mpac_2ports[m];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
									appos1[1], ap2, apport2, appos2[0], appos2[1]);
			}
		}

		// tie up all the vddlines
		ap1 = m1m2_4pins[0];
		apport1 = m1m2_4ports[0];
		appos1 = getCStylePortPosition(ap1, apport1);
		for (m=0; m<wordlines; m++)
		{
	 		ap2 = m1m2_4pins[m];
			apport2 = m1m2_4ports[m];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
		}

		ap2 = vdd2pin;
		apport2 = vdd2port;
		appos2 = getCStylePortPosition(ap2, apport2);
		makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1, appos1[0],
							appos1[1], ap2, apport2, appos2[0], appos2[1]);

		makeCStyleExport(romplane, ap2, apport2, "vdd", PortCharacteristic.PWR);

		// connect poly for the pull-up transistor
		for (m=0; m<wordlines-1; m++)
		{
		 	ap1 = pulluptrans[m];
			apport1 = pmosg2port;
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = pulluptrans[m+1];
			apport2 = pmosg1port;
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(parc, 3*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
		}
	}

	/**
	 */
	private void decodernmos(Library destLib, double lambda, int bits, String cellname, boolean top)
	{
		int[][] romplane = generateplane(bits);
		int i, m;
		double x, y;
		NodeInst ap1, ap2, ap3, vdd1, vdd2;
		PortProto apport1, apport2, apport3, vddport1, vddport2;
		double[] appos1, appos2, appos3, vddpos1, vddpos2;

		int inputs = romplane[0].length;
		int wordlines = romplane.length;

		NodeInst[][] ortrans = new NodeInst[wordlines+3][inputs+2];
		NodeInst[][] minpins = new NodeInst[wordlines+2][inputs+2];
		NodeInst[][] vddpins = new NodeInst[wordlines][inputs/2];
		NodeInst[] pwrpins = new NodeInst[inputs/2];
		NodeInst[][] m1m2pins = new NodeInst[wordlines+2][inputs+2];


		PortProto[][] minports = new PortProto[wordlines+2][inputs+2];
		PortProto[][] vddports = new PortProto[wordlines][inputs/2];
		PortProto[] pwrports = new PortProto[inputs/2];
		PortProto[][] m1m2ports = new PortProto[wordlines+2][inputs+2];

		// get pointers to primitives
		NodeProto nmos = tech.findNodeProto("N-Transistor");
		PortProto nmosg1port = nmos.findPortProto("poly-right");
		PortProto nmosg2port = nmos.findPortProto("poly-left");
		PortProto nmosd1port = nmos.findPortProto("diff-top");
		PortProto nmosd2port = nmos.findPortProto("diff-bottom");
		double[] nmosbox = {-nmos.getDefWidth(ep)/2-lambda/2,
	 					 nmos.getDefWidth(ep)/2+lambda/2,
						 -nmos.getDefHeight(ep)/2,
						 nmos.getDefHeight(ep)/2};

		NodeProto ppin = tech.findNodeProto("Polysilicon-1-Pin");
		PortProto ppinport = ppin.getPort(0);
		double[] ppinbox = {-ppin.getDefWidth(ep)/2,
						 ppin.getDefWidth(ep)/2,
						 -ppin.getDefHeight(ep)/2,
						 ppin.getDefHeight(ep)/2};

		NodeProto m1pin = tech.findNodeProto("Metal-1-Pin");
		PortProto m1pinport = m1pin.getPort(0);
		double[] m1pinbox = {-m1pin.getDefWidth(ep)/2-lambda/2,
						 m1pin.getDefWidth(ep)/2+lambda/2,
						 -m1pin.getDefHeight(ep)/2-lambda/2,
						 m1pin.getDefHeight(ep)/2+lambda/2};

		NodeProto m2pin = tech.findNodeProto("Metal-2-Pin");
		PortProto m2pinport = m2pin.getPort(0);
		double[] m2pinbox = {-m1pin.getDefWidth(ep)/2-lambda/2,
						 m1pin.getDefWidth(ep)/2+lambda/2,
						 -m1pin.getDefHeight(ep)/2-lambda/2,
						 m1pin.getDefHeight(ep)/2+lambda/2};


		NodeProto pwnode = tech.findNodeProto("P-Well-Node");

		double mx = 5;
		NodeProto mpc = tech.findNodeProto("Metal-1-Polysilicon-1-Con");
		PortProto mpcport = mpc.getPort(0);
		double[] mpcbox = {-mx*lambda/2, mx*lambda/2, -mx*lambda/2, mx*lambda/2};

		NodeProto m1m2c = tech.findNodeProto("Metal-1-Metal-2-Con");
		PortProto m1m2cport = m1m2c.getPort(0);
		double[] m1m2cbox = {-5*lambda/2, 5*lambda/2, -5*lambda/2, 5*lambda/2};

		NodeProto mnac = tech.findNodeProto("Metal-1-N-Active-Con");
		PortProto mnacport = mnac.getPort(0);
		double aaa = 17;
		double[] mnacbox = {-aaa*lambda/2, aaa*lambda/2, -aaa*lambda/2, aaa*lambda/2};
		// centers around 6 goes up by multiples of 2

		ArcProto parc = tech.findArcProto("Polysilicon-1");
		ArcProto m1arc = tech.findArcProto("Metal-1");
		ArcProto m2arc = tech.findArcProto("Metal-2");
		ArcProto ndiffarc = tech.findArcProto("N-Active");

		// create a cell called cellname+"{lay}" in the destination library
		Cell decn = Cell.newInst(destLib, cellname+"{lay}");

		NodeProto nsnode = tech.findNodeProto("N-Select-Node");

		makeCStyleNodeInst(pwnode,0,(8*lambda*(2*bits+1)), 0,8*lambda*(wordlines+1),0,0,decn);
		makeCStyleNodeInst(nsnode,0,(8*lambda*(2*bits+1)), 0,8*lambda*(wordlines+1),0,0,decn);

		// Create instances of objects on decoder nmos plane
		x = 0;
		for (i=0; i<inputs+1; i++)
		{
			x += 8*lambda;
			y = 0;
			if (i%2 ==1)
			{
				x += 0*lambda;
			}
			if (i < inputs)
			{
				if (top == true)
				{
					ortrans[0][i] =
						makeCStyleNodeInst(ppin, ppinbox[0]+x, ppinbox[1]+x,
												   ppinbox[2], ppinbox[3], 0, 0, decn);
				} else
				{
					ortrans[0][i] =
						makeCStyleNodeInst(mpc, mpcbox[0]+x, mpcbox[1]+x,
												  mpcbox[2], mpcbox[3], 0, 0, decn);
				}
			}
			for (m=0; m<wordlines; m++)
			{
				y += 8*lambda;
				if (i%2 == 1)
				{
					vddpins[m][i/2] =
						makeCStyleNodeInst(mnac, mnacbox[0]+x-4*lambda,
											 mnacbox[1]+x-4*lambda,
											 mnacbox[2]+y, mnacbox[3]+y, 0, 0, decn);
					vddports[m][i/2] = mnacport;
					if (m == (wordlines-1))
					{
						pwrpins[i/2] =
							makeCStyleNodeInst(m1pin, m1pinbox[0]+x-4*lambda,
												 m1pinbox[1]+x-4*lambda,
												 m1pinbox[2]+y+(8*lambda),
												 m1pinbox[3]+y+(8*lambda), 0, 0, decn);
						pwrports[i/2] = m1pinport;
					}
				}
				if (i < inputs)
				{
					if (romplane[m][i] == 1)
					{
						// create a transistor
						ortrans[m+1][i] =
							makeCStyleNodeInst(nmos, nmosbox[0]+x, nmosbox[1]+x,
												 nmosbox[2]+y, nmosbox[3]+y, 1, 0, decn);
					} else
					{
						ortrans[m+1][i] =
							makeCStyleNodeInst(ppin, ppinbox[0]+x, ppinbox[1]+x,
												 ppinbox[2]+y, ppinbox[3]+y, 0, 0, decn);
					}
					if (m == wordlines-1)
					{
						if (top == true)
						{
								ortrans[m+2][i] =
									makeCStyleNodeInst(mpc, mpcbox[0]+x, mpcbox[1]+x,
														 mpcbox[2]+y+16*lambda,
														 mpcbox[3]+y+16*lambda,
														 0, 0, decn);
						} else
						{
							ortrans[m+2][i] =
								makeCStyleNodeInst(ppin, ppinbox[0]+x, ppinbox[1]+x,
													 ppinbox[2]+y+4*lambda, ppinbox[3]+y+4*lambda,
													 0, 0, decn);
						}
					}
				}
				boolean transcont = false;
				if (i < inputs) transcont = (romplane[m][i] == 1);
				if (i > 1) transcont |= (romplane[m][i-1] == 1);
				if (i%2 == 0 && transcont)
				{
					minpins[m][i] =
						makeCStyleNodeInst(mnac, mnacbox[0]+x-4*lambda,
											 mnacbox[1]+x-4*lambda, mnacbox[2]+y,
											 mnacbox[3]+y, 0, 0, decn);
					minports[m][i] = mnacport;
					m1m2pins[m][i] =
						makeCStyleNodeInst(m1m2c, m1m2cbox[0]+x-4*lambda,
											 m1m2cbox[1]+x-4*lambda, m1m2cbox[2]+y,
											 m1m2cbox[3]+y, 0, 0, decn);
					m1m2ports[m][i] = m1m2cport;
				} else
				{
					minpins[m][i] =
						makeCStyleNodeInst(m2pin, m2pinbox[0]+x-4*lambda,
											 m2pinbox[1]+x-4*lambda, m2pinbox[2]+y,
											 m2pinbox[3]+y, 0, 0, decn);
					minports[m][i] = m2pinport;
					if (i==0)
					{
						m1m2pins[m][i] =
							makeCStyleNodeInst(m1m2c, m1m2cbox[0]+x-4*lambda,
												 m1m2cbox[1]+x-4*lambda, m1m2cbox[2]+y,
												 m1m2cbox[3]+y, 0, 0, decn);
						m1m2ports[m][i] = m1m2cport;
					} else
					{
						m1m2pins[m][i] =
							makeCStyleNodeInst(m2pin, m2pinbox[0]+x-4*lambda,
												 m2pinbox[1]+x-4*lambda, m2pinbox[2]+y,
												 m2pinbox[3]+y, 0, 0, decn);
						m1m2ports[m][i] = m2pinport;
					}
				}
				if (i==0)
				{
					ap1 = m1m2pins[m][i];
					apport1 = m1m2ports[m][i];
					makeCStyleExport(decn, ap1, apport1, "mid"+m, PortCharacteristic.IN);
				}
			}
		}

		// finished making instances, start making arcs
		ap1 = pwrpins[0];
		apport1 = pwrports[0];
		appos1 = getCStylePortPosition(ap1, apport1);
		for (i=1; i<inputs/2; i++)
		{
			ap2 = pwrpins[i];
			apport2 = pwrports[i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc, 4*lambda,
								ap1, apport1, appos1[0], appos1[1],
								ap2, apport2, appos2[0], appos2[1]);
			ap1 = ap2;
			apport1 = apport2;
			appos1 = appos2;
		}
		makeCStyleExport(decn, ap1, apport1, "gnd", PortCharacteristic.GND);

		m = wordlines - 1;
		for (i=0; i<inputs/2; i++)
		{
			ap1 = vddpins[m][i];
			apport1 = vddports[m][i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = pwrpins[i];
			apport2 = pwrports[i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc, 4*lambda,
								ap1, apport1, appos1[0], appos1[1],
								ap2, apport2, appos2[0], appos2[1]);
		}

		// connect polysilicon gates
		for (i=0; i<inputs; i++)
		{
			ap1 = ortrans[wordlines+1][i];
			if (top == true)
			{
				apport1 = mpcport;
			} else
			{
				apport1 = ppinport;
			}
			appos1 = getCStylePortPosition(ap1, apport1);
			if (i%2 == 0)
			{
				makeCStyleExport(decn, ap1, apport1, "top_in"+(i/2), PortCharacteristic.IN);
			} else
			{
				makeCStyleExport(decn, ap1, apport1, "top_in"+((i-1)/2)+"_b", PortCharacteristic.IN);
			}

			ap1 = ortrans[0][i];
			if (top == true)
			{
				apport1 = ppinport;
			} else
			{
				apport1 = mpcport;
			}
			appos1 = getCStylePortPosition(ap1, apport1);

			if (i%2 == 0)
			{
				makeCStyleExport(decn, ap1, apport1, "bot_in"+(i/2), PortCharacteristic.IN);
			} else
			{
				makeCStyleExport(decn, ap1, apport1, "bot_in"+((i-1)/2)+"_b", PortCharacteristic.IN);
			}

			for (m=1; m<wordlines+1; m++)
			{
				ap2 = ortrans[m][i];
				if (romplane[m-1][i] == 1)
				{
					apport2 = nmosg1port;
					apport3 = nmosg2port;
				} else
				{
					apport2 = ppinport;
					apport3 = ppinport;
				}
				appos2 = getCStylePortPosition(ap2, apport2);
				appos3 = getCStylePortPosition(ap2, apport3);
				makeCStyleArcInst(parc, 2*lambda,
									ap1,apport1,appos1[0],appos1[1],
									ap2,apport2,appos2[0],appos2[1]);
				ap1 = ap2;
				apport1 = apport3;
				appos1 = appos3;
			}

			ap2 = ortrans[wordlines+1][i];
			if (top == true)
			{
				apport2 = mpcport;
				apport3 = mpcport;
			} else
			{
				apport2 = ppinport;
				apport3 = ppinport;
			}
			appos2 = getCStylePortPosition(ap2, apport2);
			appos3 = getCStylePortPosition(ap2, apport3);
			makeCStyleArcInst(parc, 2*lambda,
								ap1, apport1, appos1[0], appos1[1],
								ap2, apport2, appos2[0], appos2[1]);
		}

		// connect m2 wordline lines
		for (m=0; m<wordlines; m++)
		{
			ap1 = m1m2pins[m][0];
			apport1 = m1m2ports[m][0];
			appos1 = getCStylePortPosition(ap1, apport1);
			for (i=1; i<inputs+1; i++)
			{
				ap2 = m1m2pins[m][i];
				apport2 = m1m2ports[m][i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1,
									appos1[0], appos1[1], ap2, apport2, appos2[0], appos2[1]);
				ap1 = ap2;
				apport1 = apport2;
				appos1 = appos2;
			}
			makeCStyleExport(decn, ap1, apport1, "word"+m, PortCharacteristic.OUT);
		}

		// connect transistors to wordline lines
		for (m=0; m<wordlines; m++)
		{
			for (i=0; i<inputs; i++)
			{
				if (romplane[m][i] == 1)
				{
					// connect transistor
					ap1 = ortrans[m+1][i];
					vdd1 = ap1;
					if (i%2 == 0)
					{
						apport1 = nmosd1port;
						vddport1 = nmosd2port;
						ap2 = minpins[m][i];
						ap3 = m1m2pins[m][i];
						vdd2 = vddpins[m][i/2];
					} else
					{
						apport1 = nmosd2port;
						vddport1 = nmosd1port;
						ap2 = minpins[m][i+1];
						ap3 = m1m2pins[m][i+1];
						vdd2 = vddpins[m][i/2];
					}
					apport2 = mnacport;
					apport3 = m1m2cport;
					vddport2 = mnacport;

					appos1 = getCStylePortPosition(ap1, apport1);
					vddpos1 = getCStylePortPosition(vdd1, vddport1);
					appos2 = getCStylePortPosition(ap2, apport2);
					appos3 = getCStylePortPosition(ap3, apport3);
					vddpos2 = getCStylePortPosition(vdd2, vddport2);

					// ndiffarc size centers around 12 and goes up by multiples of 2
					makeCStyleArcInst(ndiffarc, 4/*16*/*lambda, ap1, apport1,
										appos1[0], appos1[1], ap2,
										apport2, appos2[0], appos2[1]);
					makeCStyleArcInst(ndiffarc, 4/*16*/*lambda, vdd1, vddport1,
										vddpos1[0], vddpos1[1], vdd2,
										vddport2, vddpos2[0], vddpos2[1]);

					makeCStyleArcInst(m1arc, 4*lambda, ap2, apport2,
										appos2[0], appos2[1], ap3,
										apport3, appos3[0], appos3[1]);
				}
			}
		}

		// connect vdd lines
		for (i=0; i<inputs/2; i++)
		{
			ap1 = vddpins[0][i];
			apport1 = vddports[0][i];
			appos1 = getCStylePortPosition(ap1, apport1);
			for (m=1; m<wordlines; m++)
			{
				ap2 = vddpins[m][i];
				apport2 = vddports[m][i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1,
									appos1[0], appos1[1],
									ap2, apport2, appos2[0], appos2[1]);
				ap1 = ap2;
				apport1 = apport2;
				appos1 = appos2;
			}
		}
	}


	/**
	 */
	private void decoderpmos(Library destLib, double lambda, int bits, String cellname, boolean top)
	{
		int[][] romplane = generateplane(bits);
		int i, m;
		double x, y;
		NodeInst ap1, ap2, ap3, apx, apy;
		PortProto apport1, apport2, apport3, apportx, apporty;
		double[] appos1, appos2, appos3, apposx, apposy;
		int inputs = romplane[0].length;
		int wordlines = romplane.length;

		NodeInst[][] andtrans = new NodeInst[wordlines+2][inputs+2];
		NodeInst[][] minpins = new NodeInst[wordlines+3][inputs+2];
		NodeInst[] m1m2pins = new NodeInst[wordlines+2];
		NodeInst[] m2pins = new NodeInst[wordlines+2];
		NodeInst vddpin = null;
		NodeInst vddbpin = null;
		NodeInst vddcpin = null;

		PortProto[][] minports = new PortProto[wordlines+2][inputs+2];
		PortProto[] m1m2ports = new PortProto[wordlines+2];
		PortProto[] m2ports = new PortProto[wordlines+2];
		PortProto vddport = null;
		PortProto vddbport = null;
		PortProto vddcport = null;

		// get pointers to primitives
		NodeProto pmos = tech.findNodeProto("P-Transistor");
		PortProto pmosg1port = pmos.findPortProto("poly-right");
		PortProto pmosg2port = pmos.findPortProto("poly-left");
		PortProto pmosd1port = pmos.findPortProto("diff-top");
		PortProto pmosd2port = pmos.findPortProto("diff-bottom");
		double[] pmosbox = {-pmos.getDefWidth(ep)/2-lambda/2,
						 pmos.getDefWidth(ep)/2+lambda/2,
						 -pmos.getDefHeight(ep)/2,
						 pmos.getDefHeight(ep)/2};

		NodeProto ppin = tech.findNodeProto("Polysilicon-1-Pin");
		PortProto ppinport = ppin.getPort(0);
		double[] ppinbox = {-ppin.getDefWidth(ep)/2,
						 ppin.getDefWidth(ep)/2,
						 -ppin.getDefHeight(ep)/2,
						 ppin.getDefHeight(ep)/2};

		NodeProto m1pin = tech.findNodeProto("Metal-1-Pin");
		PortProto m1pinport = m1pin.getPort(0);
		double[] m1pinbox = {-m1pin.getDefWidth(ep)/2-lambda/2,
						  m1pin.getDefWidth(ep)/2+lambda/2,
						  -m1pin.getDefHeight(ep)/2-lambda/2,
						  m1pin.getDefHeight(ep)/2+lambda/2};

		NodeProto m2pin = tech.findNodeProto("Metal-2-Pin");
		PortProto m2pinport = m2pin.getPort(0);
		double[] m2pinbox = {-m1pin.getDefWidth(ep)/2-lambda/2,
						  m1pin.getDefWidth(ep)/2+lambda/2,
						  -m1pin.getDefHeight(ep)/2-lambda/2,
						  m1pin.getDefHeight(ep)/2+lambda/2};

		double mx = 5;
		NodeProto mpc = tech.findNodeProto("Metal-1-Polysilicon-1-Con");
		PortProto mpcport = mpc.getPort(0);
		double[] mpcbox = {-mx*lambda/2, mx*lambda/2, -mx*lambda/2, mx*lambda/2};

		NodeProto m1m2c = tech.findNodeProto("Metal-1-Metal-2-Con");
		PortProto m1m2cport = m1m2c.getPort(0);
		double[] m1m2cbox = {-5*lambda/2, 5*lambda/2, -5*lambda/2, 5*lambda/2};

		NodeProto mpac = tech.findNodeProto("Metal-1-P-Active-Con");
		PortProto mpacport = mpac.getPort(0);
		double[] mpacbox = {-17*lambda/2, 17*lambda/2, -17*lambda/2, 17*lambda/2};
		// centers around 6 goes up my multiple of 2

		NodeProto mnwc = tech.findNodeProto("Metal-1-N-Well-Con");
		PortProto mnwcport = mnwc.getPort(0);
		double[] mnwcbox = {-17*lambda/2, 17*lambda/2, -17*lambda/2, 17*lambda/2};

		ArcProto parc = tech.findArcProto("Polysilicon-1");
		ArcProto m1arc = tech.findArcProto("Metal-1");
		ArcProto m2arc = tech.findArcProto("Metal-2");
		ArcProto pdiffarc = tech.findArcProto("P-Active");

		NodeProto nwnode = tech.findNodeProto("N-Well-Node");

		// create a cell called cellname+"{lay}" in the destination library
		Cell decp = Cell.newInst(destLib, cellname+"{lay}");

		NodeProto psnode = tech.findNodeProto("P-Select-Node");

		makeCStyleNodeInst(nwnode,0,(8*lambda*(2*bits)),
										0,8*lambda*(wordlines+1),0,0,decp);
		makeCStyleNodeInst(psnode,0,(8*lambda*(2*bits)),
										0,8*lambda*(wordlines+1),0,0,decp);

		// Create instances of objects on decoder pmos plane
		x = 0;
		for (i=0; i<inputs+1; i++)
		{
			x += 8*lambda;
			y = 0;

			if (i < inputs)
			{
				if (top == true)
				{
					andtrans[0][i] =
						makeCStyleNodeInst(ppin, ppinbox[0]+x, ppinbox[1]+x,
												   ppinbox[2], ppinbox[3], 0, 0, decp);

				} else
				{
					andtrans[0][i] =
						makeCStyleNodeInst(mpc, mpcbox[0]+x, mpcbox[1]+x,
												  mpcbox[2], mpcbox[3], 0, 0, decp);
				}
			}
			for (m=0; m<wordlines; m++)
			{
				y += 8*lambda;
				if (i < inputs)
				{
					if (romplane[m][i] == 1)
					{
						// create a transistor
						andtrans[m+1][i] =
							makeCStyleNodeInst(pmos, pmosbox[0]+x, pmosbox[1]+x,
												 pmosbox[2]+y, pmosbox[3]+y, 1, 0, decp);
					} else
					{
						andtrans[m+1][i] =
							makeCStyleNodeInst(ppin, ppinbox[0]+x, ppinbox[1]+x,
												 ppinbox[2]+y, ppinbox[3]+y, 0, 0, decp);
					}
					if (m == wordlines-1)
					{
						if (top == true)
						{
							andtrans[m+2][i] =
								makeCStyleNodeInst(mpc, mpcbox[0]+x, mpcbox[1]+x,
													 mpcbox[2]+y+16*lambda,
													 mpcbox[3]+y+16*lambda,0,0,decp);
						} else
						{
							andtrans[m+2][i] =
								makeCStyleNodeInst(ppin, ppinbox[0]+x, ppinbox[1]+x,
													 ppinbox[2]+y+4*lambda, ppinbox[3]+y+4*lambda,
													 0, 0, decp);
						}
					}
				}

				boolean transcont = false;
				if (i < inputs) transcont = (romplane[m][i] == 1);
				if (i == 0)
				{
					m1m2pins[m] =
						makeCStyleNodeInst(m1m2c, m1m2cbox[0]+x-4*lambda,
											 m1m2cbox[1]+x-4*lambda, m1m2cbox[2]+y,
											 m1m2cbox[3]+y, 0, 0, decp);
					m1m2ports[m] = m1m2cport;
				}
				if (i == (inputs))
				{
					m2pins[m] =
						makeCStyleNodeInst(m2pin, m2pinbox[0]+x-4*lambda,
											 m2pinbox[1]+x-4*lambda, m2pinbox[2]+y,
											 m2pinbox[3]+y, 0, 0, decp);
					m2ports[m] = m2pinport;
				}
				if (i >= 1) transcont |= (romplane[m][i-1] == 1);
				if (transcont)
				{
					minpins[m][i] =
						makeCStyleNodeInst(mpac, mpacbox[0]+x-4*lambda,
											 mpacbox[1]+x-4*lambda, mpacbox[2]+y,
											 mpacbox[3]+y, 0, 0, decp);
					minports[m][i] = mpacport;
				} else
				{
					if (i == inputs)
					{
						minpins[m][i] =
							makeCStyleNodeInst(mnwc, mnwcbox[0]+x-4*lambda,
												 mnwcbox[1]+x-4*lambda, mnwcbox[2]+y,
												 mnwcbox[3]+y, 0, 0, decp);
						minports[m][i] = mnwcport;
					} else
					{
						minpins[m][i] =
							makeCStyleNodeInst(m1pin, m1pinbox[0]+x-4*lambda,
												 m1pinbox[1]+x-4*lambda, m1pinbox[2]+y,
												 m1pinbox[3]+y, 0, 0, decp);
						minports[m][i] = m1pinport;
					}
				}
				if (i == inputs)
				{
					vddpin =
						makeCStyleNodeInst(m1pin, m1pinbox[0]+x-4*lambda,
											 m1pinbox[1]+x-4*lambda,
											 m1pinbox[2]+y+8*lambda,
											 m1pinbox[3]+y+8*lambda, 0, 0, decp);
					vddport = m1pinport;
					if (m == 0)
					{
						vddbpin =
							makeCStyleNodeInst(m1pin, m1pinbox[0]+x+4*lambda,
												 m1pinbox[1]+x+4*lambda,
												 m1pinbox[2]+y+0*lambda,
												 m1pinbox[3]+y+0*lambda, 0, 0, decp);
							vddbport = m1pinport;
					}
					if (m == wordlines-1)
					{
						vddcpin =
							makeCStyleNodeInst(m1m2c, m1m2cbox[0]+x+4*lambda,
												 m1m2cbox[1]+x+4*lambda,
												 m1m2cbox[2]+y+8*lambda,
												 m1m2cbox[3]+y+8*lambda, 0, 0, decp);
						vddcport = m1m2cport;
					}
				}
			}
		}

		// connect polysilicon gates
		for (i=0; i<inputs; i++)
		{
			ap1 = andtrans[wordlines+1][i];
			if (top == true)
			{
				apport1 = mpcport;
			} else
			{
				apport1 = ppinport;
			}
			appos1 = getCStylePortPosition(ap1, apport1);
			if (i%2 == 0)
			{
				makeCStyleExport(decp, ap1, apport1, "top_in"+(i/2), PortCharacteristic.IN);
			} else
			{
				makeCStyleExport(decp, ap1, apport1, "top_in"+((i-1)/2)+"_b", PortCharacteristic.IN);
			}
			ap1 = andtrans[0][i];
			if (top == true)
			{
				apport1 = ppinport;
			} else
			{
				apport1 = mpcport;
			}
			appos1 = getCStylePortPosition(ap1, apport1);
			if (i%2 == 0)
			{
				makeCStyleExport(decp, ap1, apport1, "bot_in"+(i/2), PortCharacteristic.IN);
			} else
			{
				makeCStyleExport(decp, ap1, apport1, "bot_in"+((i-1)/2)+"_b", PortCharacteristic.IN);
			}
			for (m=1; m<wordlines+1; m++)
			{
				ap2 = andtrans[m][i];
				if (romplane[m-1][i] == 1)
				{
					apport2 = pmosg1port;
					apport3 = pmosg2port;
				} else
				{
					apport2 = ppinport;
					apport3 = ppinport;
				}
				appos2 = getCStylePortPosition(ap2, apport2);
				appos3 = getCStylePortPosition(ap2, apport3);
				makeCStyleArcInst(parc,2*lambda,ap1,apport1,appos1[0],
									appos1[1],ap2,apport2,appos2[0], appos2[1]);
				ap1 = ap2;
				apport1 = apport3;
				appos1 = appos3;
			}

			ap2 = andtrans[wordlines+1][i];
			if (top == true)
			{
				apport2 = mpcport;
				apport3 = mpcport;
			} else
			{
				apport2 = ppinport;
				apport3 = ppinport;
			}
			appos2 = getCStylePortPosition(ap2, apport2);
			appos3 = getCStylePortPosition(ap2, apport3);
			makeCStyleArcInst(parc,2*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
		}

		// connect m1 wordline lines
		for (m=0; m<wordlines; m++)
		{
			ap1 = minpins[m][0];
			apport1 = minports[m][0];
			appos1 = getCStylePortPosition(ap1, apport1);
			for (i=1; i<inputs+1; i++)
			{
				ap2 = minpins[m][i];
				apport2 = minports[m][i];
				appos2 = getCStylePortPosition(ap2, apport2);
				if (romplane[m][i-1] != 1)
				{
					makeCStyleArcInst(m1arc,4*lambda,ap1,apport1,appos1[0],
										appos1[1],ap2,apport2, appos2[0], appos2[1]);
				}
				ap1 = ap2;
				apport1 = apport2;
				appos1 = appos2;
			}
		}

		// connect transistors to wordline lines
		for (m=0; m<wordlines; m++)
		{
			for (i=0; i<inputs; i++)
			{
				if (romplane[m][i] == 1)
				{
					ap1 = andtrans[m+1][i];
					apport1 = pmosd1port;
					apport2 = pmosd2port;
					appos1 = getCStylePortPosition(ap1, apport1);
					appos2 = getCStylePortPosition(ap1, apport2);
					apx = minpins[m][i];
					apy = minpins[m][i+1];
					apportx = mpacport;
					apporty = mpacport;
					apposx = getCStylePortPosition(apx, apportx);
					apposy = getCStylePortPosition(apy, apporty);
					// pdiffarc size centers around 12 and goes up by multiples of 2
					makeCStyleArcInst(pdiffarc,4/*16*/*lambda,ap1,apport1,
										appos1[0], appos1[1],apx,
										apportx,apposx[0],apposx[1]);
					makeCStyleArcInst(pdiffarc,4/*16*/*lambda,ap1,apport2,
										appos2[0], appos2[1],apy,
										apporty,apposy[0],apposy[1]);
				}
			}
		}

		// connect ground lines
		i = inputs;
		ap1 = minpins[0][i];
		apport1 = minports[0][i];
		appos1 = getCStylePortPosition(ap1, apport1);
		for (m=1; m<wordlines; m++)
		{
			ap2 = minpins[m][i];
			apport2 = minports[m][i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc,4*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
			ap1 = ap2;
			apport1 = apport2;
			appos1 = appos2;
		}

		ap1 = vddpin;
		apport1 = vddport;
		appos1 = getCStylePortPosition(ap1, apport1);
		ap2 = minpins[wordlines-1][inputs];
		apport2 = minports[wordlines-1][inputs];
		appos2 = getCStylePortPosition(ap2, apport2);
		makeCStyleArcInst(m1arc,4*lambda,ap1,apport1,appos1[0],
							appos1[1],ap2,apport2,appos2[0], appos2[1]);

		ap1 = vddcpin;
		apport1 = vddcport;
		appos1 = getCStylePortPosition(ap1, apport1);
		ap2 = vddpin;
		apport2 = vddport;
		appos2 = getCStylePortPosition(ap2, apport2);
		makeCStyleArcInst(m1arc,4*lambda,ap1,apport1,appos1[0],
							appos1[1],ap2,apport2,appos2[0], appos2[1]);
		makeCStyleExport(decp, ap1, apport1, "vdd", PortCharacteristic.PWR);

		ap1 = vddbpin;
		apport1 = vddbport;
		appos1 = getCStylePortPosition(ap1, apport1);
		ap2 = minpins[0][inputs];
		apport2 = minports[0][inputs];
		appos2 = getCStylePortPosition(ap2, apport2);
		makeCStyleArcInst(m1arc,4*lambda,ap1,apport1,appos1[0],
							appos1[1],ap2,apport2,appos2[0], appos2[1]);
		makeCStyleExport(decp, ap1, apport1, "vddb", PortCharacteristic.PWR);

		// connect metal 2 lines
		for (m=0; m<wordlines; m++)
		{
			ap1 = m1m2pins[m];
			apport1 = m1m2ports[m];
			appos1 = getCStylePortPosition(ap1,apport1);
			ap2 = m2pins[m];
			apport2 = m2ports[m];
			appos2 = getCStylePortPosition(ap2, apport2);
			ap3 = minpins[m][0];
			apport3 = minports[m][0];
			appos3 = getCStylePortPosition(ap3, apport3);
			makeCStyleArcInst(m2arc,4*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
			makeCStyleArcInst(m1arc,4*lambda,ap1,apport1,appos1[0],
								appos1[1],ap3,apport3,appos3[0], appos3[1]);
			makeCStyleExport(decp, ap2, apport2, "word"+m, PortCharacteristic.OUT);
			makeCStyleExport(decp, ap1, apport1, "wordin"+m, PortCharacteristic.IN);
		}
	}

	/**
	 */
	private static int[][] generatemuxarray(int folds, int romoutputs)
	{
		int muxes = romoutputs/folds;
		int[][] muxarray = new int[romoutputs][folds];
		for (int i=0; i<muxes; i++)
		{
			for (int j=0; j<folds; j++)
			{
				for (int k=0; k<folds; k++)
				{
					if (j == k)
					{
						muxarray[i*folds+j][k] = 1;
					} else
					{
						muxarray[i*folds+j][k] = 0;
					}
				}
			}
		}
		StringBuffer sb = new StringBuffer();
		for (int i=0; i<romoutputs; i++)
		{
			sb = new StringBuffer();
			for (int j=0; j<folds; j++)
			{
				sb.append(Integer.toString(muxarray[i][j]));
			}
		}
		return muxarray;
	}


	/**
	 */
	private void muxplane(Library destLib, double lambda, int folds, int romoutputs, String mp)
	{
		int[][] muxarray = generatemuxarray(folds,romoutputs);
		int muxnumber = folds;
		int selects = folds;
		int outputbits = romoutputs;

		int i, m;
		double x, y;
		NodeInst ap1, ap2, ap3, apx, apy;
		PortProto apport1, apport2, apport3, apportx, apporty;
		double[] appos1, appos2, appos3, apposx, apposy;

		NodeInst[][] ntrans = new NodeInst[outputbits+2][selects+2];
		NodeInst[][] minpins = new NodeInst[outputbits+2][selects+2];
		NodeInst[] m1m2pins2 = new NodeInst[outputbits+2];
		NodeInst[] m1m2pins = new NodeInst[selects+2];
		NodeInst[] m1polypins = new NodeInst[outputbits+2];

		PortProto[][] minports = new PortProto[outputbits+2][selects+2];
		PortProto[] m1m2ports2 = new PortProto[outputbits+2];

		// get pointers to primitives
		NodeProto nmos = tech.findNodeProto("N-Transistor");
		PortProto nmosg1port = nmos.findPortProto("poly-right");
		PortProto nmosg2port = nmos.findPortProto("poly-left");
		PortProto nmosd1port = nmos.findPortProto("diff-top");
		PortProto nmosd2port = nmos.findPortProto("diff-bottom");
		double[] nmosbox = {-nmos.getDefWidth(ep)/2-lambda/2,
						 nmos.getDefWidth(ep)/2+lambda/2,
						 -nmos.getDefHeight(ep)/2,
						 nmos.getDefHeight(ep)/2};

		NodeProto ppin = tech.findNodeProto("Polysilicon-1-Pin");
		PortProto ppinport = ppin.getPort(0);
		double[] ppinbox = {-ppin.getDefWidth(ep)/2,
						 ppin.getDefWidth(ep)/2,
						 -ppin.getDefHeight(ep)/2,
						 ppin.getDefHeight(ep)/2};

		NodeProto m1pin = tech.findNodeProto("Metal-1-Pin");
		PortProto m1pinport = m1pin.getPort(0);
		double[] m1pinbox = {-m1pin.getDefWidth(ep)/2-lambda/2,
						  m1pin.getDefWidth(ep)/2+lambda/2,
						  -m1pin.getDefHeight(ep)/2-lambda/2,
						  m1pin.getDefHeight(ep)/2+lambda/2};

		NodeProto m1m2c = tech.findNodeProto("Metal-1-Metal-2-Con");
		PortProto m1m2cport = m1m2c.getPort(0);
		double[] m1m2cbox = {-5*lambda/2, 5*lambda/2, -5*lambda/2, 5*lambda/2};

		NodeProto mnac = tech.findNodeProto("Metal-1-N-Active-Con");
		PortProto mnacport = mnac.getPort(0);
		double mult = 17;
		double[] mnacbox = {-1*mult*lambda/2, mult*lambda/2, -1*mult*lambda/2, mult*lambda/2};

		NodeProto mpc = tech.findNodeProto("Metal-1-Polysilicon-1-Con");
		PortProto mpcport = mpc.getPort(0);
		double mx = 5;
		double[] mpcbox = {-mx*lambda/2, mx*lambda/2, -mx*lambda/2, mx*lambda/2};

		ArcProto parc = tech.findArcProto("Polysilicon-1");
		ArcProto m1arc = tech.findArcProto("Metal-1");
		ArcProto m2arc = tech.findArcProto("Metal-2");
		ArcProto ndiffarc = tech.findArcProto("N-Active");

		NodeProto pwnode = tech.findNodeProto("P-Well-Node");

		// create a cell called "muxplane{lay}" in the destination library
		Cell muxplane = Cell.newInst(destLib, mp+"{lay}");

		makeCStyleNodeInst(pwnode,-8*lambda,lambda*8*(folds+1),
										-8*lambda,8*lambda*3*romoutputs/2,0,0,muxplane);

		// Create instances of objects in mux plane
		x = 0;
		for (i=0; i<selects+1; i++)
		{
			x += 8*lambda;
			y = 0;
			if (i < selects)
			{
				ntrans[0][i] =
					makeCStyleNodeInst(ppin, ppinbox[0]+x, ppinbox[1]+x, ppinbox[2],
										 ppinbox[3], 0, 0, muxplane);
				m1polypins[i] =
					makeCStyleNodeInst(mpc, mpcbox[0]+x, mpcbox[1]+x, mpcbox[2],
										 mpcbox[3], 0, 0, muxplane);
				m1m2pins[i] =
					makeCStyleNodeInst(m1m2c, m1m2cbox[0]+x, m1m2cbox[1]+x, m1m2cbox[2],
										 m1m2cbox[3], 0, 0, muxplane);
				ap1 = m1m2pins[i];
				apport1 = m1m2cport;
				makeCStyleExport(muxplane, ap1, apport1, "sel"+(selects-i-1), PortCharacteristic.IN);
			}

			for (m=0; m<outputbits; m++)
			{
				y += 8*lambda;
				if (m%2 == 1)
				{
					y += 8*lambda;
				}
				if (i < selects)
				{
					if (muxarray[m][i] == 1)
					{
						// create a transistor
						ntrans[m+1][i] =
							makeCStyleNodeInst(nmos, nmosbox[0]+x, nmosbox[1]+x,
												 nmosbox[2]+y, nmosbox[3]+y,1,0,muxplane);
					} else
					{
						ntrans[m+1][i] =
							makeCStyleNodeInst(ppin, ppinbox[0]+x, ppinbox[1]+x,
												 ppinbox[2]+y,ppinbox[3]+y,0,0,muxplane);
					}
				}
				boolean transcont = false;
				if (i < selects) transcont = (muxarray[m][i] == 1);
				if (i == (selects))
				{
					m1m2pins2[m] =
						makeCStyleNodeInst(m1m2c, m1m2cbox[0]+x-4*lambda,
											 m1m2cbox[1]+x-4*lambda, m1m2cbox[2]+y,
											 m1m2cbox[3]+y, 0, 0, muxplane);
					m1m2ports2[m] = m1m2cport;
				}
				if (i >= 1) transcont |= (muxarray[m][i-1] == 1);
				if (transcont)
				{
					minpins[m][i] =
						makeCStyleNodeInst(mnac, mnacbox[0]+x-4*lambda,
											 mnacbox[1]+x-4*lambda, mnacbox[2]+y,
											 mnacbox[3]+y, 0, 0, muxplane);
					minports[m][i] = mnacport;
				} else
				{
					minpins[m][i] =
						makeCStyleNodeInst(m1pin, m1pinbox[0]+x-4*lambda,
											 m1pinbox[1]+x-4*lambda, m1pinbox[2]+y,
											 m1pinbox[3]+y, 0, 0, muxplane);
					minports[m][i] = m1pinport;
				}
			}
		}

		// finished placing objects, now wire arcs

		// connect polysilicon gates
		for (i=0; i<selects; i++)
		{
			ap1 = ntrans[0][i];
			apport1 = ppinport;
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = m1polypins[i];
			apport2 = mpcport;
			appos2 = getCStylePortPosition(ap2, apport2);
			ap3 = m1m2pins[i];
			apport3 = m1m2cport;
			appos3 = getCStylePortPosition(ap3, apport3);
			makeCStyleArcInst(parc, 2*lambda, ap1, apport1, appos1[0],
								appos1[1],ap2, apport2, appos2[0], appos2[1]);
			makeCStyleArcInst(m1arc, 4*lambda, ap2, apport2, appos2[0],
								appos2[1],ap3, apport3, appos3[0], appos3[1]);
		}

		// connect polysilicon gates
		for (i=0; i<selects; i++)
		{
			ap1 = ntrans[0][i];
			apport1 = ppinport;
			appos1 = getCStylePortPosition(ap1, apport1);
			for (m=1; m<outputbits+1; m++)
			{
				ap2 = ntrans[m][i];
				if (muxarray[m-1][i] == 1)
				{
					apport2 = nmosg1port;
					apport3 = nmosg2port;
				} else
				{
					apport2 = ppinport;
					apport3 = ppinport;
				}
				appos2 = getCStylePortPosition(ap2, apport2);
				appos3 = getCStylePortPosition(ap2, apport3);
				makeCStyleArcInst(parc, 2*lambda, ap1, apport1, appos1[0],
									appos1[1], ap2, apport2, appos2[0], appos2[1]);
				ap1 = ap2;
				apport1 = apport3;
				appos1 = appos3;
			}
		}

		// connect m1 wordline lines
		for (m=0; m<outputbits; m++)
		{
			ap1 = minpins[m][0];
			apport1 = minports[m][0];
			appos1 = getCStylePortPosition(ap1, apport1);
			for (i=1; i<selects+1; i++)
			{
				ap2 = minpins[m][i];
				apport2 = minports[m][i];
				appos2 = getCStylePortPosition(ap2, apport2);
				if (muxarray[m][i-1] != 1)
				{
					makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1,
										appos1[0], appos1[1],
										ap2, apport2, appos2[0], appos2[1]);
				}
				if (i == 1)
				{
					makeCStyleExport(muxplane, ap1, apport1, "muxin"+m, PortCharacteristic.IN);
				}
				ap1 = ap2;
				apport1 = apport2;
				appos1 = appos2;
			}
		}

		// connect transistors to wordline lines
		for (m=0; m<outputbits; m++)
		{
			for (i=0; i<selects; i++)
			{
				if (muxarray[m][i] == 1)
				{
					// connect transistor
					ap1 = ntrans[m+1][i];
					apport1 = nmosd1port;
					apport2 = nmosd2port;
					appos1 = getCStylePortPosition(ap1, apport1);
					appos2 = getCStylePortPosition(ap1, apport2);
					apx = minpins[m][i];
					apy = minpins[m][i+1];
					apportx = mnacport;
					apporty = mnacport;
					apposx = getCStylePortPosition(apx, apportx);
					apposy = getCStylePortPosition(apy, apporty);
					makeCStyleArcInst(ndiffarc, 4/*16*/*lambda, ap1, apport1,
										appos1[0], appos1[1],
										apx, apportx, apposx[0], apposx[1]);
					makeCStyleArcInst(ndiffarc, 4/*16*/*lambda, ap1, apport2,
										appos2[0], appos2[1],
										apy, apporty, apposy[0], apposy[1]);
				}
			}
		}

		for(int j = 0 ; j < outputbits; j++)
		{
			i = selects;
			ap1 = minpins[j][i];
			apport1 = minports[j][i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = m1m2pins2[j];
			apport2 = m1m2ports2[j];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
		}

		// connect mux together
		for(int j = 0 ; j < outputbits/muxnumber; j++)
		{
			ap1 = m1m2pins2[j*muxnumber];
			apport1 = m1m2ports2[j*muxnumber];
			appos1 = getCStylePortPosition(ap1, apport1);
			for (m=1+j*muxnumber; m<muxnumber+j*muxnumber; m++) {
				ap2 = m1m2pins2[m];
				apport2 = m1m2ports2[m];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1, appos1[0],
									appos1[1],ap2, apport2, appos2[0], appos2[1]);
			}
			makeCStyleExport(muxplane, ap1, apport1, "muxout"+j, PortCharacteristic.OUT);
		}
	}

	/**
	 */
	private void inverterplane(Library destLib, double lambda, int outs, int folds, String ip)
	{
		int i;
		double x, y;
		NodeInst ap1, ap2, ap3;
		PortProto apport1, apport2, apport3, gndport1, vddport1;
		double[] appos1, appos2, appos3, gndpos1, vddpos1;

		NodeInst[] ntrans = new NodeInst[outs/folds];
		NodeInst[] ptrans = new NodeInst[outs/folds];
		NodeInst[] inpins = new NodeInst[outs/folds];
		NodeInst[] polypins = new NodeInst[outs/folds];
		NodeInst[] intppins = new NodeInst[outs/folds];
		NodeInst[] nmospins = new NodeInst[outs/folds];
		NodeInst[] pmospins = new NodeInst[outs/folds];
		NodeInst[] gndpins = new NodeInst[outs/2];
		NodeInst[] vddpins = new NodeInst[outs/2];
		NodeInst[] midvddpins = new NodeInst[outs/2];
		NodeInst[] gndpins2 = new NodeInst[outs/folds];
		NodeInst[] pwellpins2 = new NodeInst[outs/folds];
		NodeInst[] vddpins2 = new NodeInst[outs/folds];
		NodeInst[] midvddpins2 = new NodeInst[outs/folds];
		NodeInst gndc = null;
		NodeInst nwellc = null;
		NodeInst nwellm = null;

		PortProto[] inports = new PortProto[outs/folds];
		PortProto[] polyports = new PortProto[outs/folds];
		PortProto[] intpports = new PortProto[outs/folds];
		PortProto[] nmosports = new PortProto[outs/folds];
		PortProto[] pmosports = new PortProto[outs/folds];
		PortProto[] gndports = new PortProto[outs/2];
		PortProto[] vddports = new PortProto[outs/2];
		PortProto[] midvddports = new PortProto[outs/2];
		PortProto[] pwellports2 = new PortProto[outs/folds];
		PortProto[] gndports2 = new PortProto[outs/folds];
		PortProto[] vddports2 = new PortProto[outs/folds];
		PortProto[] midvddports2 = new PortProto[outs/folds];
		PortProto gndcport = null;
		PortProto nwellcport = null;
		PortProto nwellmport = null;

		// get pointers to primitives
		NodeProto nmos = tech.findNodeProto("N-Transistor");
		PortProto nmosg1port = nmos.findPortProto("poly-right");
		PortProto nmosg2port = nmos.findPortProto("poly-left");
		PortProto nmosd1port = nmos.findPortProto("diff-top");
		PortProto nmosd2port = nmos.findPortProto("diff-bottom");
		double[] nmosbox = {-nmos.getDefWidth(ep)/2-lambda/2,
						 nmos.getDefWidth(ep)/2+lambda/2,
						 -nmos.getDefHeight(ep)/2,
						 nmos.getDefHeight(ep)/2};

		NodeProto pmos = tech.findNodeProto("P-Transistor");
		PortProto pmosg2port = pmos.findPortProto("poly-left");
		PortProto pmosd1port = pmos.findPortProto("diff-top");
		PortProto pmosd2port = pmos.findPortProto("diff-bottom");
		double[] pmosbox = {-pmos.getDefWidth(ep)/2-lambda/2,
						 pmos.getDefWidth(ep)/2+lambda/2,
						 -pmos.getDefHeight(ep)/2,
						 pmos.getDefHeight(ep)/2};

		NodeProto ppin = tech.findNodeProto("Polysilicon-1-Pin");
		PortProto ppinport = ppin.getPort(0);
		double[] ppinbox = {-ppin.getDefWidth(ep)/2,
						 ppin.getDefWidth(ep)/2,
						 -ppin.getDefHeight(ep)/2,
						 ppin.getDefHeight(ep)/2};

		NodeProto nwnode = tech.findNodeProto("N-Well-Node");

		NodeProto pwnode = tech.findNodeProto("P-Well-Node");

		NodeProto m1m2c = tech.findNodeProto("Metal-1-Metal-2-Con");
		PortProto m1m2cport = m1m2c.getPort(0);
		double[] m1m2cbox = {-5*lambda/2, 5*lambda/2, -5*lambda/2, 5*lambda/2};

		NodeProto mnac = tech.findNodeProto("Metal-1-N-Active-Con");
		PortProto mnacport = mnac.getPort(0);
		double aaa = 17;
		double[] mnacbox = {-aaa*lambda/2, aaa*lambda/2, -aaa*lambda/2, aaa*lambda/2};

		NodeProto mpac = tech.findNodeProto("Metal-1-P-Active-Con");
		PortProto mpacport = mpac.getPort(0);
		double[] mpacbox = {-aaa*lambda/2, aaa*lambda/2, -aaa*lambda/2, aaa*lambda/2};   //

		NodeProto mpc = tech.findNodeProto("Metal-1-Polysilicon-1-Con");
		PortProto mpcport = mpc.getPort(0);
		double mx = -7;
		double my = 5;
		double[] mpcbox = {-mx*lambda/2, mx*lambda/2, -my*lambda/2, my*lambda/2};

		NodeProto mpwc = tech.findNodeProto("Metal-1-P-Well-Con");
		PortProto mpwcport = mpwc.getPort(0);
		double[] mpwcbox = {-17*lambda/2, 17*lambda/2, -17*lambda/2, 17*lambda/2};

		NodeProto mnwc = tech.findNodeProto("Metal-1-N-Well-Con");
		PortProto mnwcport = mnwc.getPort(0);
		double[] mnwcbox = {-17*lambda/2, 17*lambda/2, -17*lambda/2, 17*lambda/2};

		ArcProto parc = tech.findArcProto("Polysilicon-1");
		ArcProto m1arc = tech.findArcProto("Metal-1");
		ArcProto m2arc = tech.findArcProto("Metal-2");
		ArcProto ndiffarc = tech.findArcProto("N-Active");
		ArcProto pdiffarc = tech.findArcProto("P-Active");

		// create a cell called "inverterplane{lay}" in the destination library
		Cell invp = Cell.newInst(destLib, ip+"{lay}");

		makeCStyleNodeInst(pwnode,-32*lambda,(3*lambda*8*outs/2)+8*lambda,
										-18*lambda,16*lambda,0,0,invp);

		makeCStyleNodeInst(nwnode,-32*lambda,(3*lambda*8*outs/2)+8*lambda,
										-34*lambda,-18*lambda,0,0,invp);

		// Create instances of objects on inverter plane
		x = 0*lambda;
		for (i=0; i<outs; i++)
		{
			x += 8*lambda;
			y = 0;
			if (folds > 1)
			{
				if (i % folds == 1)
				{
					pwellpins2[i/folds] =
						makeCStyleNodeInst(mpwc, mpwcbox[0]+x, mpwcbox[1]+x,
											 mpwcbox[2]+y, mpwcbox[3]+y, 0, 0, invp);
					pwellports2[i/folds] = mpwcport;
					gndpins2[i/folds] =
						makeCStyleNodeInst(mnac, mnacbox[0]+x, mnacbox[1]+x,
											 mnacbox[2]+y-10*lambda,
											 mnacbox[3]+y-10*lambda, 0, 0, invp);
					gndports2[i/folds] = mnacport;
					midvddpins2[i/folds] =
						makeCStyleNodeInst(mpac, mpacbox[0]+x, mpacbox[1]+x,
											 mpacbox[2]+y-26*lambda,
											 mpacbox[3]+y-26*lambda, 0, 0, invp);
					midvddports2[i/folds] = mpacport;
					vddpins2[i/folds] =
						makeCStyleNodeInst(m1m2c, m1m2cbox[0]+x, m1m2cbox[1]+x,
											 m1m2cbox[2]+y-26*lambda,
											 m1m2cbox[3]+y-26*lambda, 0, 0, invp);
					vddports2[i/folds] = m1m2cport;
					if (i == 1)
					{
						gndc =
							makeCStyleNodeInst(m1m2c, m1m2cbox[0]+x, m1m2cbox[1]+x,
												 m1m2cbox[2]+y-10*lambda,
												 m1m2cbox[3]+y-10*lambda, 0, 0, invp);
						gndcport = m1m2cport;
						makeCStyleExport(invp, gndc, gndcport, "gnd", PortCharacteristic.GND);
					}
				}
			} else
			{
				if (i%2 == 1)
				{
					// place gnd, intvdd, vddpins
	//				pwellpins[i/2] =
	//					makeCStyleNodeInst(mpwc, mpwcbox[0]+x, mpwcbox[1]+x,
	//										 mpwcbox[2]+y-10*lambda,
	//										 mpwcbox[3]+y-10*lambda, 0, 0, invp);
	//				pwellports[i/2] = mpwcport;
					gndpins[i/2] =
						makeCStyleNodeInst(mnac, mnacbox[0]+x, mnacbox[1]+x,
											 mnacbox[2]+y-10*lambda,
											 mnacbox[3]+y-10*lambda, 0, 0, invp);
					gndports[i/2] = mnacport;
					midvddpins[i/2] =
						makeCStyleNodeInst(mpac, mpacbox[0]+x, mpacbox[1]+x,
											 mpacbox[2]+y-26*lambda,
											 mpacbox[3]+y-26*lambda, 0, 0, invp);
					midvddports[i/2] = mpacport;
					vddpins[i/2] =
						makeCStyleNodeInst(m1m2c, m1m2cbox[0]+x, m1m2cbox[1]+x,
											 m1m2cbox[2]+y-26*lambda,
											 m1m2cbox[3]+y-26*lambda, 0, 0, invp);
					vddports[i/2] = m1m2cport;

					if (i == 1)
					{
						nwellc =
							makeCStyleNodeInst(mnwc, mnwcbox[0]+x-24*lambda,
												 mnwcbox[1]+x-24*lambda,
												 mnwcbox[2]+y-26*lambda,
											 	 mnwcbox[3]+y-26*lambda, 0, 0, invp);
						nwellcport = mnwcport;

						nwellm =
							makeCStyleNodeInst(m1m2c, m1m2cbox[0]+x-24*lambda,
												 m1m2cbox[1]+x-24*lambda,
												 m1m2cbox[2]+y-26*lambda,
												 m1m2cbox[3]+y-26*lambda, 0, 0, invp);
						nwellmport = m1m2cport;

						gndc =
							makeCStyleNodeInst(m1m2c, m1m2cbox[0]+x, m1m2cbox[1]+x,
												 m1m2cbox[2]+y-10*lambda,
												 m1m2cbox[3]+y-10*lambda, 0, 0, invp);
						gndcport = m1m2cport;
						makeCStyleExport(invp, gndc, gndcport, "gnd", PortCharacteristic.GND);
					}
				}
			}
			if (i%2 == 1)
			{
				x += 8*lambda;
			}
			if (folds > 1)
			{
				if (i%folds == 0)
				{
					inpins[i/folds] =
						makeCStyleNodeInst(mpc, mpcbox[0]+x-6*lambda,
											 mpacbox[1]+x-6*lambda, mpcbox[2]+y,
											 mpcbox[3]+y, 0, 0, invp);
					inports[i/folds] = mpcport;
					polypins[i/folds] =
						makeCStyleNodeInst(ppin, ppinbox[0]+x, ppinbox[1]+x,
											 ppinbox[2]+y-6*lambda, ppinbox[3]+y-6*lambda,
											 0, 0, invp);
					polyports[i/folds] = ppinport;
					nmospins[i/folds] =
						makeCStyleNodeInst(mnac, mnacbox[0]+x, mnacbox[1]+x,
											 mnacbox[2]+y-10*lambda, mnacbox[3]+y-10*lambda,
											 0, 0, invp);
					nmosports[i/folds] = mnacport;
					pmospins[i/folds] =
						makeCStyleNodeInst(mpac, mpacbox[0]+x, mpacbox[1]+x,
											 mpacbox[2]+y-26*lambda, mpacbox[3]+y-26*lambda,
											 0, 0, invp);
					pmosports[i/folds] = mpacport;
				}
			} else
			{
				// place inpins, polypins, nmospins, pmospins
				inpins[i] =
					makeCStyleNodeInst(mpc, mpcbox[0]+x-6*lambda, mpacbox[1]+x-6*lambda,
										 mpcbox[2]+y, mpcbox[3]+y, 0, 0, invp);
				inports[i] = mpcport;
				polypins[i] =
					makeCStyleNodeInst(ppin, ppinbox[0]+x, ppinbox[1]+x,
										 ppinbox[2]+y-6*lambda, ppinbox[3]+y-6*lambda,
										 0, 0, invp);
				polyports[i] = ppinport;
				nmospins[i] =
					makeCStyleNodeInst(mnac, mnacbox[0]+x, mnacbox[1]+x,
										 mnacbox[2]+y-10*lambda, mnacbox[3]+y-10*lambda,
										 0, 0, invp);
				nmosports[i] = mnacport;
				pmospins[i] =
					makeCStyleNodeInst(mpac, mpacbox[0]+x, mpacbox[1]+x,
										 mpacbox[2]+y-26*lambda, mpacbox[3]+y-26*lambda,
										 0, 0, invp);
				pmosports[i] = mpacport;
			}

			if (folds > 1)
			{
				if (i%folds == 0)
				{
					double off = 4*lambda;
					ptrans[i/folds] =
						makeCStyleNodeInst(pmos, pmosbox[0]+x+off, pmosbox[1]+x+off,
											 pmosbox[2]+y-26*lambda,
											 pmosbox[3]+y-26*lambda, 1, 0, invp);
					ntrans[i/folds] =
						makeCStyleNodeInst(nmos, nmosbox[0]+x+off, nmosbox[1]+x+off,
											 nmosbox[2]+y-10*lambda,
											 nmosbox[3]+y-10*lambda, 1, 0, invp);
					intppins[i/folds] =
						makeCStyleNodeInst(ppin, ppinbox[0]+x+off, ppinbox[1]+x+off,
											 ppinbox[2]+y-6*lambda, ppinbox[3]+y-6*lambda,
											 0, 0, invp);
					intpports[i/folds] = ppinport;
				}
			} else
			{
				double off = 0;
				if (i%2 == 0)
				{
					off = 4*lambda;
				} else
				{
					off = -4*lambda;
				}
				ptrans[i] =
					makeCStyleNodeInst(pmos, pmosbox[0]+x+off, pmosbox[1]+x+off,
										 pmosbox[2]+y-26*lambda, pmosbox[3]+y-26*lambda,
										 1, 0, invp);
				ntrans[i] =
					makeCStyleNodeInst(nmos, nmosbox[0]+x+off, nmosbox[1]+x+off,
										 nmosbox[2]+y-10*lambda, nmosbox[3]+y-10*lambda,
										 1, 0, invp);
				intppins[i] =
					makeCStyleNodeInst(ppin, ppinbox[0]+x+off, ppinbox[1]+x+off,
										 ppinbox[2]+y-6*lambda, ppinbox[3]+y-6*lambda,
										 0, 0, invp);
				intpports[i] = ppinport;
			}
		}

		// connect transistors to diffusion lines
		if (folds > 1)
		{
			for (i=0; i<outs/folds; i++)
			{
				ap2 = nmospins[i];
				ap3 = gndpins2[i];
				ap1 = ntrans[i];
				apport1 = nmosd1port;
				gndport1 = nmosd2port;
				appos1 = getCStylePortPosition(ap1, apport1);
				gndpos1 = getCStylePortPosition(ap1, gndport1);
				apport2 = mnacport;
				appos2 = getCStylePortPosition(ap2, apport2);
				apport3 = mnacport;
				appos3 = getCStylePortPosition(ap3, apport3);
				// ndiffarc size centers around 12 and goes up by multiples of 2
				makeCStyleArcInst(ndiffarc, 4/*16*/*lambda, ap1, apport1,
									appos1[0], appos1[1],
									ap2, apport2, appos2[0], appos2[1]);
				makeCStyleArcInst(ndiffarc, 4/*16*/*lambda, ap1, gndport1,
									gndpos1[0], gndpos1[1],
									ap3, apport3, appos3[0], appos3[1]);
			}
		} else
		{
			for (i=0; i<outs; i++)
			{
				if (i%2 == 0)
				{
					ap2 = nmospins[i];
					ap3 = gndpins[i/2];
				} else
				{
					ap2 = gndpins[i/2];
					ap3 = nmospins[i];
				}
				ap1 = ntrans[i];
				apport1 = nmosd1port;
				gndport1 = nmosd2port;
				appos1 = getCStylePortPosition(ap1, apport1);
				gndpos1 = getCStylePortPosition(ap1, gndport1);
				apport2 = mnacport;
				appos2 = getCStylePortPosition(ap2, apport2);
				apport3 = mnacport;
				appos3 = getCStylePortPosition(ap3, apport3);
				makeCStyleArcInst(ndiffarc, 4/*16*/*lambda, ap1, apport1,
									appos1[0], appos1[1],
									ap2, apport2, appos2[0], appos2[1]);
				makeCStyleArcInst(ndiffarc, 4/*16*/*lambda, ap1, gndport1,
									gndpos1[0], gndpos1[1],
									ap3, apport3, appos3[0], appos3[1]);
			}
		}

		if (folds >1)
		{
			for (i=0; i<outs/folds; i++)
			{
				ap2 = pmospins[i];
				ap3 = midvddpins2[i];
				ap1 = ptrans[i];
				ap1 = ptrans[i];
				apport1 = pmosd1port;
				vddport1 = pmosd2port;
				appos1 = getCStylePortPosition(ap1, apport1);
				vddpos1 = getCStylePortPosition(ap1, vddport1);
				apport2 = mpacport;
				appos2 = getCStylePortPosition(ap2, apport2);
				apport3 = mpacport;
				appos3 = getCStylePortPosition(ap3, apport3);
				makeCStyleArcInst(pdiffarc, 4/*16*/*lambda, ap1, apport1,
									appos1[0], appos1[1],
									ap2, apport2, appos2[0], appos2[1]);
				makeCStyleArcInst(pdiffarc, 4/*16*/*lambda, ap1, vddport1,
									vddpos1[0], vddpos1[1],
									ap3, apport3, appos3[0], appos3[1]);
			}
		} else
		{
			// connect transistors to diffusion lines
			for (i=0; i<outs; i++)
			{
				if (i%2 == 0)
				{
					ap2 = pmospins[i];
					ap3 = midvddpins[i/2];
				} else
				{
					ap2 = midvddpins[i/2];
					ap3 = pmospins[i];
				}
				ap1 = ptrans[i];
				apport1 = pmosd1port;
				vddport1 = pmosd2port;
				appos1 = getCStylePortPosition(ap1, apport1);
				vddpos1 = getCStylePortPosition(ap1, vddport1);
				apport2 = mpacport;
				appos2 = getCStylePortPosition(ap2, apport2);
				apport3 = mpacport;
				appos3 = getCStylePortPosition(ap3, apport3);
				makeCStyleArcInst(pdiffarc, 4/*16*/*lambda, ap1, apport1,
									appos1[0], appos1[1],
									ap2, apport2, appos2[0], appos2[1]);
				makeCStyleArcInst(pdiffarc, 4/*16*/*lambda, ap1, vddport1,
									vddpos1[0], vddpos1[1],
									ap3, apport3, appos3[0], appos3[1]);
			}
		}

		// metal-1 mpac to mnac
		for (i=0; i<outs/folds; i++)
		{
			ap1 = nmospins[i];
			apport1 = nmosports[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = pmospins[i];
			apport2 = pmosports[i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
		}

		// poly inpins to polypins
		for (i=0; i<outs/folds; i++)
		{
			ap1 = inpins[i];
			apport1 = inports[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = polypins[i];
			apport2 = polyports[i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(parc, 2*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
		}

		// poly polypins to intppins
		for (i=0; i<outs/folds; i++)
		{
			ap1 = polypins[i];
			apport1 = polyports[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = intppins[i];
			apport2 = intpports[i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(parc, 2*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
		}

		// poly intppins to ntrans
		for (i=0; i<outs/folds; i++)
		{
			ap1 = intppins[i];
			apport1 = intpports[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = ntrans[i];
			apport2 = nmosg2port;
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(parc, 2*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
		}

		// poly ntrans to ptrans
		for (i=0; i<outs/folds; i++)
		{
			ap1 = ntrans[i];
			apport1 = nmosg1port;
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = ptrans[i];
			apport2 = pmosg2port;
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(parc, 2*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
		}

		if (folds > 1)
		{
			for (i=0; i < outs/folds; i++)
			{
				ap1 = pwellpins2[i];
				apport1 = pwellports2[i];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = gndpins2[i];
				apport2 = gndports2[i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
									appos1[1], ap2, apport2, appos2[0], appos2[1]);
			}
			for (i=0; i < outs/folds; i++)
			{
				ap1 = midvddpins2[i];
				apport1 = midvddports2[i];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = vddpins2[i];
				apport2 = vddports2[i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
									appos1[1], ap2, apport2, appos2[0], appos2[1]);
			}

			// metal 2 vddpins
			ap1 = vddpins2[0];
			apport1 = vddports2[0];
			appos1 = getCStylePortPosition(ap1, apport1);
			for (i=1; i<outs/folds; i++)
			{
				ap2 = vddpins2[i];
				apport2 = vddports2[i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1, appos1[0],
									appos1[1], ap2, apport2, appos2[0], appos2[1]);
			}
			makeCStyleExport(invp, ap1, apport1, "vdd", PortCharacteristic.PWR);

			for (i=0; i<outs/folds; i++)
			{
				ap1 = gndpins2[i];
				apport1 = gndports2[i];
				makeCStyleExport(invp, ap1, apport1, "invgnd" + i, PortCharacteristic.GND);
			}
			ap1 = gndpins2[0];
			apport1 = gndports2[0];
			appos1 = getCStylePortPosition(ap1, apport1);

		} else
		{
			// metal 1 midvddpins to vddpins
			for (i=0; i<outs/2; i++)
			{
				ap1 = midvddpins[i];
				apport1 = midvddports[i];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = vddpins[i];
				apport2 = vddports[i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc, 4*lambda, ap1, apport1, appos1[0],
									appos1[1], ap2, apport2, appos2[0], appos2[1]);
			}

			ap1 = vddpins[0];
			apport1 = vddports[0];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = nwellm;
			apport2 = nwellmport;
			appos2 = getCStylePortPosition(ap2, apport2);
			ap3 = nwellc;
			apport3 = nwellcport;
			appos3 = getCStylePortPosition(ap3, apport3);
			makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1, appos1[0],
								appos1[1], ap2, apport2, appos2[0], appos2[1]);
			makeCStyleArcInst(m1arc, 4*lambda, ap3, apport3, appos3[0],
								appos3[1], ap2, apport2, appos2[0], appos2[1]);

			// metal 2 vddpins
			ap1 = vddpins[0];
			apport1 = vddports[0];
			appos1 = getCStylePortPosition(ap1, apport1);
			for (i=1; i<outs/2; i++)
			{
				ap2 = vddpins[i];
				apport2 = vddports[i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m2arc, 4*lambda, ap1, apport1, appos1[0],
									appos1[1], ap2, apport2, appos2[0], appos2[1]);
			}
			makeCStyleExport(invp, ap1, apport1, "vdd", PortCharacteristic.PWR);

			for (i=0; i<outs/2; i++)
			{
				ap1 = gndpins[i];
				apport1 = gndports[i];
				makeCStyleExport(invp, ap1, apport1, "invgnd" + i, PortCharacteristic.GND);
			}

			ap1 = gndpins[0];
			apport1 = gndports[0];
			appos1 = getCStylePortPosition(ap1, apport1);
		}

		ap2 = gndc;
		apport2 = gndcport;
		appos2 = getCStylePortPosition(ap2, apport2);
		makeCStyleArcInst(m1arc,4*lambda,ap1,apport1,appos1[0],
							appos1[1], ap2, apport2, appos2[0], appos2[1]);
		for (i=0; i<outs/folds; i++)
		{
			ap1 = inpins[i];
			apport1 = inports[i];
			makeCStyleExport(invp, ap1, apport1, "invin" + i, PortCharacteristic.IN);
		}

		for (i=0; i<outs/folds; i++)
		{
			ap1 = pmospins[i];
			apport1 = pmosports[i];
			makeCStyleExport(invp, ap1, apport1, "invout"+((outs/folds - 1) - i), PortCharacteristic.OUT);
		}

	}

	/**
	 */
	private void ininverterplane(Library destLib, double lambda, int outs, String layoutname, boolean top,
						   int lengthbits)
	{
		int i;
		double x, y;
		NodeInst ap1, ap2, ap3;
		PortProto apport1, apport2, apport3, gndport1, vddport1;
		double[] appos1, appos2, appos3, gndpos1, vddpos1;

		NodeInst[] ntrans = new NodeInst[outs];
		NodeInst[] ptrans = new NodeInst[outs];
		NodeInst[] inpins = new NodeInst[outs];
		NodeInst[] inpins2 = new NodeInst[outs];
		NodeInst[] outpins = new NodeInst[outs];
		NodeInst[] outpins2 = new NodeInst[outs];
		NodeInst[] polypins = new NodeInst[outs];
		NodeInst[] intppins = new NodeInst[outs];
		NodeInst[] polypins2 = new NodeInst[outs];
		NodeInst[] intppins2 = new NodeInst[outs];
		NodeInst[] gndpins = new NodeInst[outs];
		NodeInst[] midvddpins = new NodeInst[outs];
		NodeInst[] nmospins = new NodeInst[outs];
		NodeInst[] gndpins2 = new NodeInst[outs];
		NodeInst[] vddpins = new NodeInst[outs];
		NodeInst[] pmospins = new NodeInst[outs];
		NodeInst vddc = null;
		NodeInst nwellc = null;
		NodeInst gndc = null;
		NodeInst pwellc = null;

		PortProto[] inports = new PortProto[outs];
		PortProto[] outports = new PortProto[outs];
		PortProto[] inports2 = new PortProto[outs];
		PortProto[] outports2 = new PortProto[outs];
		PortProto[] polyports = new PortProto[outs];
		PortProto[] intpports = new PortProto[outs];
		PortProto[] polyports2 = new PortProto[outs];
		PortProto[] intpports2 = new PortProto[outs];
		PortProto[] nmosports = new PortProto[outs];
		PortProto[] pmosports = new PortProto[outs];
		PortProto[] gndports = new PortProto[outs];
		PortProto[] gndports2 = new PortProto[outs];
		PortProto[] vddports = new PortProto[outs];
		PortProto[] midvddports = new PortProto[outs];
		PortProto vddcport = null;
		PortProto nwellport = null;
		PortProto gndcport = null;
		PortProto pwellport = null;

		// get pointers to primitives
		NodeProto nmos = tech.findNodeProto("N-Transistor");
		PortProto nmosg1port = nmos.findPortProto("poly-right");
		PortProto nmosg2port = nmos.findPortProto("poly-left");
		PortProto nmosd1port = nmos.findPortProto("diff-top");
		PortProto nmosd2port = nmos.findPortProto("diff-bottom");
		double[] nmosbox = {-nmos.getDefWidth(ep)/2-lambda/2,
						 nmos.getDefWidth(ep)/2+lambda/2,
						 -nmos.getDefHeight(ep)/2,
						 nmos.getDefHeight(ep)/2};

		NodeProto pmos = tech.findNodeProto("P-Transistor");
		PortProto pmosg1port = pmos.findPortProto("poly-right");
		PortProto pmosg2port = pmos.findPortProto("poly-left");
		PortProto pmosd1port = pmos.findPortProto("diff-top");
		PortProto pmosd2port = pmos.findPortProto("diff-bottom");
		double[] pmosbox = {-pmos.getDefWidth(ep)/2-lambda/2,
						 pmos.getDefWidth(ep)/2+lambda/2,
						 -pmos.getDefHeight(ep)/2,
						 pmos.getDefHeight(ep)/2};

		NodeProto ppin = tech.findNodeProto("Polysilicon-1-Pin");
		PortProto ppinport = ppin.getPort(0);
		double[] ppinbox = {-ppin.getDefWidth(ep)/2,
						 ppin.getDefWidth(ep)/2,
						 -ppin.getDefHeight(ep)/2,
						 ppin.getDefHeight(ep)/2};

		NodeProto m1pin = tech.findNodeProto("Metal-1-Pin");

		NodeProto m2pin = tech.findNodeProto("Metal-2-Pin");
		PortProto m2pinport = m2pin.getPort(0);
		double[] m2pinbox = {-m1pin.getDefWidth(ep)/2-lambda/2,
						  m1pin.getDefWidth(ep)/2+lambda/2,
						  -m1pin.getDefHeight(ep)/2-lambda/2,
						  m1pin.getDefHeight(ep)/2+lambda/2};

		NodeProto nwnode = tech.findNodeProto("N-Well-Node");

		NodeProto pwnode = tech.findNodeProto("P-Well-Node");

		NodeProto m1m2c = tech.findNodeProto("Metal-1-Metal-2-Con");
		PortProto m1m2cport = m1m2c.getPort(0);
		double[] m1m2cbox = {-5*lambda/2, 5*lambda/2, -5*lambda/2, 5*lambda/2};

		NodeProto mnac = tech.findNodeProto("Metal-1-N-Active-Con");
		PortProto mnacport = mnac.getPort(0);
		double aaa = 17;
		double[] mnacbox = {-aaa*lambda/2, aaa*lambda/2, -aaa*lambda/2, aaa*lambda/2};
		// centers around 6 goes up by multiples of 2

		NodeProto mpac = tech.findNodeProto("Metal-1-P-Active-Con");
		PortProto mpacport = mpac.getPort(0);
		double[] mpacbox = {-aaa*lambda/2, aaa*lambda/2, -aaa*lambda/2, aaa*lambda/2};
		// centers around 6 goes up by multiples of 2

		double mx = -7;
		double my = 5;
		NodeProto mpc = tech.findNodeProto("Metal-1-Polysilicon-1-Con");
		PortProto mpcport = mpc.getPort(0);
		double[] mpcbox = {-mx*lambda/2, mx*lambda/2, -my*lambda/2, my*lambda/2};

		NodeProto mpwc = tech.findNodeProto("Metal-1-P-Well-Con");
		PortProto mpwcport = mpwc.getPort(0);
		double[] mpwcbox = {-17*lambda/2, 17*lambda/2, -17*lambda/2, 17*lambda/2};

		NodeProto mnwc = tech.findNodeProto("Metal-1-N-Well-Con");
		PortProto mnwcport = mnwc.getPort(0);
		double[] mnwcbox = {-17*lambda/2, 17*lambda/2, -17*lambda/2, 17*lambda/2};

		ArcProto parc = tech.findArcProto("Polysilicon-1");
		ArcProto m1arc = tech.findArcProto("Metal-1");
		ArcProto m2arc = tech.findArcProto("Metal-2");
		ArcProto ndiffarc = tech.findArcProto("N-Active");
		ArcProto pdiffarc = tech.findArcProto("P-Active");

		// create a cell called layoutname+lay}" in the destination library
		Cell ininvp = Cell.newInst(destLib, layoutname+"{lay}");

		double lowX = -8*lambda;
lowX += 7*lambda;
		double highX = (4*lambda*8*lengthbits)+24*lambda;
highX -= 64*lambda;
		makeCStyleNodeInst(pwnode, lowX,highX, -18*lambda,10*lambda, 0,0,ininvp);
		makeCStyleNodeInst(nwnode, lowX,highX, -36*lambda,-18*lambda, 0,0,ininvp);

		// Create instances of objects on input inverter plane
		x = 0;
		for (i=0; i<outs; i++)
		{
			x += 8*lambda;
			y = 0;

			// place inpins, polypins, gndpins, midvddpins
			gndpins[i] =
				makeCStyleNodeInst(mnac,mnacbox[0]+x,mnacbox[1]+x,mnacbox[2]+y-10*lambda,
									 mnacbox[3]+y-10*lambda,0,0,ininvp);
			gndports[i] = mnacport;
			midvddpins[i] =
				makeCStyleNodeInst(mpac,mpacbox[0]+x,mpacbox[1]+x,mpacbox[2]+y-26*lambda,
									 mpacbox[3]+y-26*lambda,0,0,ininvp);
			midvddports[i] = mpacport;

			double off = 4*lambda;
			ptrans[i] =
				makeCStyleNodeInst(pmos,pmosbox[0]+x+off,pmosbox[1]+x+off,
									 pmosbox[2]+y-26*lambda,pmosbox[3]+y-26*lambda,
									 1,0,ininvp);
			ntrans[i] =
				makeCStyleNodeInst(nmos,nmosbox[0]+x+off,nmosbox[1]+x+off,
									 nmosbox[2]+y-10*lambda,nmosbox[3]+y-10*lambda,
									 1,0,ininvp);

			// place gnd, intvdd, vddpins
			x += 8*lambda;
			polypins[i] =
				makeCStyleNodeInst(ppin,ppinbox[0]+x-8*lambda,ppinbox[1]+x-8*lambda,
									 ppinbox[2]+y-6*lambda,ppinbox[3]+y-6*lambda,
									 0,0,ininvp);
			polyports[i] = ppinport;
			inpins[i] =
				makeCStyleNodeInst(mpc,mpcbox[0]+x-14*lambda,mpacbox[1]+x-14*lambda,
									 mpcbox[2]+y,mpcbox[3]+y,0,0,ininvp);
			inports[i] = mpcport;
			if (top == true)
			{
				inpins2[i] =
					makeCStyleNodeInst(m1m2c,m1m2cbox[0]+x-8*lambda,
										 m1m2cbox[1]+x-8*lambda,
										 m1m2cbox[2]+y+(8*lambda*(i+1)),
										 m1m2cbox[3]+y+(8*lambda*(i+1)),0,0,ininvp);
				inports2[i] = m1m2cport;
			}
			intppins[i] =
				makeCStyleNodeInst(ppin,ppinbox[0]+x-off,ppinbox[1]+x-off,
									 ppinbox[2]+y-6*lambda,ppinbox[3]+y-6*lambda,
									 0,0,ininvp);
			intpports[i] = ppinport;
			pmospins[i] =
				makeCStyleNodeInst(mpac,mpacbox[0]+x,mpacbox[1]+x,mpacbox[2]+y-26*lambda,
									 mpacbox[3]+y-26*lambda,0,0,ininvp);
			pmosports[i] = mpacport;
			vddpins[i] = makeCStyleNodeInst(m1m2c,m1m2cbox[0]+x-8*lambda,
											  m1m2cbox[1]+x-8*lambda,
											  m1m2cbox[2]+y-26*lambda,
											  m1m2cbox[3]+y-26*lambda,0,0,ininvp);
			vddports[i] = m1m2cport;
			nmospins[i] =
				makeCStyleNodeInst(mnac,mnacbox[0]+x,mnacbox[1]+x,mnacbox[2]+y-10*lambda,
									 mnacbox[3]+y-10*lambda,0,0,ininvp);
			nmosports[i] = mnacport;
			gndpins2[i] =
				makeCStyleNodeInst(m1m2c,m1m2cbox[0]+x-8*lambda,m1m2cbox[1]+x-8*lambda,
									 m1m2cbox[2]+y-10*lambda,m1m2cbox[3]+y-10*lambda,
									 0,0,ininvp);
			gndports2[i] = m1m2cport;
			outpins[i] =
				makeCStyleNodeInst(mpc,mpcbox[0]+x-14*lambda,mpacbox[1]+x-14*lambda,
									 mpcbox[2]+y-36*lambda,mpcbox[3]+y-36*lambda,
									 0,0,ininvp);
			outports[i] = mpcport;
			if (top == false)
			{
				outpins2[i] =
					makeCStyleNodeInst(m1m2c,m1m2cbox[0]+x-8*lambda,
										 m1m2cbox[1]+x-8*lambda,
										 m1m2cbox[2]+y-(8*lambda*(i+1))-36*lambda,
										 m1m2cbox[3]+y-(8*lambda*(i+1))-36*lambda,
										 0,0,ininvp);
				outports2[i] = m1m2cport;
			}
			polypins2[i] =
				makeCStyleNodeInst(ppin,ppinbox[0]+x-8*lambda,ppinbox[1]+x-8*lambda,
									 ppinbox[2]+y-30*lambda,ppinbox[3]+y-30*lambda,
									 0,0,ininvp);
			polyports2[i] = ppinport;
			intppins2[i] =
				makeCStyleNodeInst(ppin,ppinbox[0]+x-off,ppinbox[1]+x-off,
									 ppinbox[2]+y-30*lambda,ppinbox[3]+y-30*lambda,
									 0,0,ininvp);
			intpports2[i] = ppinport;

			if (i == (outs-1))
			{
				if (top == true)
				{
					vddc =
						makeCStyleNodeInst(m2pin,m2pinbox[0]+x+12*lambda,
											 m2pinbox[1]+x+12*lambda,
											 m2pinbox[2]+y-26*lambda,
											 m2pinbox[3]+y-26*lambda,0,0,ininvp);
					vddcport = m2pinport;
					gndc =
						makeCStyleNodeInst(m1m2c,m1m2cbox[0]+x+12*lambda,
											 m1m2cbox[1]+x+12*lambda,
											 m1m2cbox[2]+y-10*lambda,
											 m1m2cbox[3]+y-10*lambda,0,0,ininvp);
					gndcport = m1m2cport;
					pwellc =
						makeCStyleNodeInst(mpwc,mpwcbox[0]+x+12*lambda,
											 mpwcbox[1]+x+12*lambda,mpwcbox[2]+y-10*lambda,
											 mpwcbox[3]+y-10*lambda,0,0,ininvp);
					pwellport = mpwcport;
				} else
				{
					vddc =
						makeCStyleNodeInst(m1m2c,m1m2cbox[0]+x+12*lambda,
											 m1m2cbox[1]+x+12*lambda,
											 m1m2cbox[2]+y-26*lambda,
											 m1m2cbox[3]+y-26*lambda,0,0,ininvp);
					vddcport = m1m2cport;
					nwellc =
						makeCStyleNodeInst(mnwc,mnwcbox[0]+x+12*lambda,
											 mnwcbox[1]+x+12*lambda,mnwcbox[2]+y-26*lambda,
											 mnwcbox[3]+y-26*lambda,0,0,ininvp);
					nwellport = mnwcport;
					gndc =
						makeCStyleNodeInst(m2pin,m2pinbox[0]+x+12*lambda,
											 m2pinbox[1]+x+12*lambda,
											 m2pinbox[2]+y-10*lambda,
											 m2pinbox[3]+y-10*lambda,0,0,ininvp);
					gndcport = m2pinport;
				}
			}
		}

		// connect transistors to diffusion lines
		for (i=0; i<outs; i++)
		{
			ap2 = gndpins[i];
			ap3 = nmospins[i];
			ap1 = ntrans[i];
			apport1 = nmosd1port;
			gndport1 = nmosd2port;
			appos1 = getCStylePortPosition(ap1, apport1);
			gndpos1 = getCStylePortPosition(ap1, gndport1);
			apport2 = mnacport;
			appos2 = getCStylePortPosition(ap2, apport2);
			apport3 = mnacport;
			appos3 = getCStylePortPosition(ap3, apport3);
			// ndiffarc size centers around 12 and goes up by multiples of 2
			makeCStyleArcInst(ndiffarc,4/*16*/*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
			makeCStyleArcInst(ndiffarc,4/*16*/*lambda,ap1,gndport1,gndpos1[0],
								gndpos1[1],ap3,apport3,appos3[0], appos3[1]);
		}

		// connect transistors to diffusion lines
		for (i=0; i<outs; i++)
		{
			ap2 = midvddpins[i];
			ap3 = pmospins[i];
			ap1 = ptrans[i];
			apport1 = pmosd1port;
			vddport1 = pmosd2port;
			appos1 = getCStylePortPosition(ap1, apport1);
			vddpos1 = getCStylePortPosition(ap1, vddport1);
			apport2 = mpacport;
			appos2 = getCStylePortPosition(ap2, apport2);
			apport3 = mpacport;
			appos3 = getCStylePortPosition(ap3, apport3);
			// pdiffarc size centers around 12 and goes up by multiples of 2
			makeCStyleArcInst(pdiffarc,4/*16*/*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
			makeCStyleArcInst(pdiffarc,4/*16*/*lambda,ap1,vddport1,vddpos1[0],
								vddpos1[1],ap3,apport3,appos3[0], appos3[1]);
		}

		// metal-1 mpac to mnac
		for (i=0; i<outs; i++)
		{
			ap1 = nmospins[i];
			apport1 = nmosports[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = pmospins[i];
			apport2 = pmosports[i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc,4*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
		}

		if (top == true)
		{
			ap1 = gndc;
			apport1 = gndcport;
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = pwellc;
			apport2 = pwellport;
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc,4*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
		} else
		{
			ap1 = vddc;
			apport1 = vddcport;
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = nwellc;
			apport2 = nwellport;
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc,4*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
		}

		if (top == true)
		{
			for (i=0; i<outs; i++)
			{
				ap1 = inpins[i];
				apport1 = inports[i];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = inpins2[i];
				apport2 = inports2[i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc,4*lambda,ap1,apport1,appos1[0],
									appos1[1],ap2,apport2,appos2[0], appos2[1]);
			}
		} else
		{
			for (i=0; i<outs; i++)
			{
				ap1 = outpins[i];
				apport1 = outports[i];
				appos1 = getCStylePortPosition(ap1, apport1);
				ap2 = outpins2[i];
				apport2 = outports2[i];
				appos2 = getCStylePortPosition(ap2, apport2);
				makeCStyleArcInst(m1arc,4*lambda,ap1,apport1,appos1[0],
									appos1[1],ap2,apport2,appos2[0], appos2[1]);
			}
		}

		// poly inpins to polypins
		for (i=0; i<outs; i++)
		{
			ap1 = inpins[i];
			apport1 = inports[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = polypins[i];
			apport2 = polyports[i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(parc,2*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
		}

		// poly polypins to intppins
		for (i=0; i<outs; i++)
		{
			ap1 = polypins[i];
			apport1 = polyports[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = intppins[i];
			apport2 = intpports[i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(parc,2*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
		}

		// poly intppins to ntrans
		for (i=0; i<outs; i++)
		{
			ap1 = intppins[i];
			apport1 = intpports[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = ntrans[i];
			apport2 = nmosg2port;
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(parc,2*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
		}

		// poly ntrans to ptrans
		for (i=0; i<outs; i++)
		{
			ap1 = ntrans[i];
			apport1 = nmosg1port;
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = ptrans[i];
			apport2 = pmosg2port;
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(parc,2*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
		}

		// poly outpins to polypins
		for (i=0; i<outs; i++)
		{
			ap1 = outpins[i];
			apport1 = outports[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = polypins2[i];
			apport2 = polyports2[i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(parc,2*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
		}

		// poly polypins to intppins
		for (i=0; i<outs; i++)
		{
			ap1 = polypins2[i];
			apport1 = polyports2[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = intppins2[i];
			apport2 = intpports2[i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(parc,2*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
		}

		// poly outtppins to ptrans
		for (i=0; i<outs; i++)
		{
			ap1 = intppins2[i];
			apport1 = intpports2[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = ptrans[i];
			apport2 = pmosg1port;
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(parc,2*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
		}

		// metal 1 pmospins to vddpins
		for (i=0; i<outs; i++)
		{
			ap1 = midvddpins[i];
			apport1 = midvddports[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = vddpins[i];
			apport2 = vddports[i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc,4*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
		}

		// metal 1 nmospins to nmospins2
		for (i=0; i<outs; i++)
		{
			ap1 = gndpins[i];
			apport1 = gndports[i];
			appos1 = getCStylePortPosition(ap1, apport1);
			ap2 = gndpins2[i];
			apport2 = gndports2[i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m1arc,4*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
		}

		// metal 2 nmospins
		ap1 = gndpins2[0];
		apport1 = gndports2[0];
		appos1 = getCStylePortPosition(ap1, apport1);
		for (i=1; i<outs; i++)
		{
			ap2 = gndpins2[i];
			apport2 = gndports2[i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m2arc,4*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
		}

		// metal 2 vddpins
		ap1 = vddpins[0];
		apport1 = vddports[0];
		appos1 = getCStylePortPosition(ap1, apport1);
		for (i=1; i<outs; i++)
		{
			ap2 = vddpins[i];
			apport2 = vddports[i];
			appos2 = getCStylePortPosition(ap2, apport2);
			makeCStyleArcInst(m2arc,4*lambda,ap1,apport1,appos1[0],
								appos1[1],ap2,apport2,appos2[0], appos2[1]);
		}

		ap1 = vddpins[0];
		apport1 = vddports[0];
		appos1 = getCStylePortPosition(ap1, apport1);
		ap2 = vddc;
		apport2 = vddcport;
		appos2 = getCStylePortPosition(ap2, apport2);
		makeCStyleArcInst(m2arc,4*lambda,ap1,apport1,appos1[0],
							appos1[1],ap2,apport2,appos2[0], appos2[1]);
		makeCStyleExport(ininvp, ap2, apport2, "vdd", PortCharacteristic.PWR);

		ap1 = gndpins2[0];
		apport1 = gndports2[0];
		appos1 = getCStylePortPosition(ap1, apport1);
		ap2 = gndc;
		apport2 = gndcport;
		appos2 = getCStylePortPosition(ap2, apport2);
		makeCStyleArcInst(m2arc,4*lambda,ap1,apport1,appos1[0],
							appos1[1],ap2,apport2,appos2[0], appos2[1]);
		makeCStyleExport(ininvp, ap2, apport2, "gnd", PortCharacteristic.GND);

		if (top == true)
		{
			for (i=0; i<outs; i++)
			{
				ap1 = inpins2[i];
				apport1 = inports2[i];
				makeCStyleExport(ininvp, ap1, apport1, "in_top" + i, PortCharacteristic.IN);
			}
		} else
		{
			for (i=0; i<outs; i++)
			{
				ap1 = inpins[i];
				apport1 = inports[i];
				makeCStyleExport(ininvp, ap1, apport1, "in_top" + i, PortCharacteristic.IN);
			}
		}
		if (top == true)
		{
			for (i=0; i<outs; i++)
			{
				ap1 = outpins[i];
				apport1 = outports[i];
				makeCStyleExport(ininvp, ap1, apport1, "in_bot" + i, PortCharacteristic.IN);
			}
		} else
		{
			for (i=0; i<outs; i++)
			{
				ap1 = outpins2[i];
				apport1 = outports2[i];
				makeCStyleExport(ininvp, ap1, apport1, "in_bot" + i, PortCharacteristic.IN);
			}
		}

		for (i=0; i<outs; i++)
		{
			ap1 = pmospins[i];
			apport1 = pmosports[i];
			makeCStyleExport(ininvp, ap1, apport1, "in_b" + i, PortCharacteristic.IN);
		}
	}

	/**
	 */
	private int[][] romarraygen(String romfile)
	{
		boolean end = false;
		int[][] returnarray = new int[1][1];

		BufferedReader in;
		try
		{
			in = new BufferedReader(new FileReader(romfile));
			try
			{
				int w = -1;
				int bits = 0;
				StringBuffer sb;
				StringBuffer allfile = new StringBuffer();
				while (!end)
				{
					w++;
					String temp = in.readLine();
					if (temp == null)
					{
						end = true;
					} else
					{
						sb = new StringBuffer(temp);
						if (w==1)
						{
							bits = sb.length();
						}
						if (w==0)
						{
							folds = Integer.parseInt(temp,10);
						} else
						{
							allfile.append(sb);
						}
					}
				}
				w--;

				// set globalbits
				globalbits = w/folds;
				returnarray = new int[bits][w];
				for (int r=0; r<w; r++)
				{
					for (int s=0; s<bits; s++)
					{
						if (allfile.charAt(r*bits + s) == '1')
						{
							returnarray[s][w-r-1] = 1;
						} else
						{
							returnarray[s][w-r-1] = 0;
						}
					}
				}
			} catch (IOException e)
			{
			}
		} catch(FileNotFoundException e)
		{
			System.out.println(e.toString());
		}
		return returnarray;
	}

	/**
	 */
	private static int[][] generateplane(int bits)
	{
		int lines = (int) (Math.pow(2.0, bits));
		char[][] wordlines = new char[lines][bits];
		for (int i = 0; i<lines; i++)
		{
			int len = Integer.toBinaryString(i).length();
			int leadingz = bits - len;
			int h;
			for (h=0; h<leadingz; h++)
			{
				wordlines[i][h] = '0';
			}
			for (int j=h; j<bits; j++)
			{
				wordlines[i][j] = Integer.toBinaryString(i).charAt(j-h);
			}
		}
		int[][] x =  new int[lines][bits];
		for (int j = 0; j<lines; j++)
		{
			for (int k = 0; k<bits; k++)
			{
				x[j][k] = Character.getNumericValue(wordlines[j][k]);
			}
		}
		int[][] wcomp = new int[lines][2*bits];
		for (int j = 0; j<lines; j++)
		{
			for (int k = 0; k<bits; k++)
			{
				wcomp[j][(2*k)] = x[j][k];
				int complement;
				if (x[j][k] == 1)
				{
					complement = 0;
				} else
				{
					complement = 1;
				}
				wcomp[j][(2*k)+1] = complement;
			}
		}
		int[][] wcompb = new int[lines][2*bits];
		for (int j = 0; j<lines; j++)
		{
			for (int k = 0; k<(2*bits); k++)
			{
				wcompb[j][k] = wcomp[j][(2*bits)-1-k];
			}
		}
		return wcompb;
	}

	/**
	 * Method to fold the ROM data.
	 */
	private int[][] romfold(int[][] romarray)
	{
		int roma = romarray.length*folds;
		int romb = romarray[1].length/folds;
		int[][] foldedrom = new int[roma][romb];

		for (int i=0; i<romarray.length; i++)
		{
			for (int j=0; j<folds; j++)
			{
				for (int k=0; k<romb; k++)
				{
					foldedrom[folds*i+j][k] = romarray[i][j*romb+k];
				}
			}
		}
		return foldedrom;
	}

	/**
	 * Method to convert C-style node creation parameters into the real thing.
	 */
	private NodeInst makeCStyleNodeInst(NodeProto np, double lX, double hX, double lY, double hY, int trn, int rot, Cell parent)
	{
		double cX = (lX+hX)/2;
		double cY = (lY+hY)/2;
		if (np instanceof Cell)
		{
			// adjust center according to anchor of the cell
			Rectangle2D bounds = ((Cell)np).getBounds();
			cX -= bounds.getCenterX();
			cY -= bounds.getCenterY();
		}
		double width = hX - lX;
		double height = hY - lY;
		Orientation orient = Orientation.fromC(rot, trn != 0);
		NodeInst ni = NodeInst.makeInstance(np, ep, new Point2D.Double(cX, cY), width, height, parent, orient, null);
// 		if (trn != 0)
// 		{
// 			height = -height;
// 			rot = (rot + 900) % 3600;
// 		}
// 		NodeInst ni = NodeInst.makeInstance(np, new Point2D.Double(cX, cY), width, height, parent, rot, null, 0);
		return ni;
	}

	/**
	 * Method to convert C-style Arc creation parameters into the real thing.
	 */
	private void makeCStyleArcInst(ArcProto ap, double wid, NodeInst hNI, PortProto hPP, double hX, double hY,
		NodeInst tNI, PortProto tPP, double tX, double tY)
	{
		PortInst head = hNI.findPortInstFromProto(hPP);
		PortInst tail = tNI.findPortInstFromProto(tPP);
		ArcInst.makeInstanceBase(ap, ep, wid, head, tail, new Point2D.Double(hX, hY), new Point2D.Double(tX, tY), null);
//		ArcInst.makeInstanceFull(ap, wid, head, tail, new Point2D.Double(hX, hY), new Point2D.Double(tX, tY), null);
	}

	/**
	 * Method to create an export on a cell.
	 * @param parent the Cell in which to create the Export.
	 * @param ni the NodeInst in the Cell from which to export a port.
	 * @param pp the PortProto on that NodeInst to export.
	 * @param name the name of the new Export.
	 * @param exporttype the Characteristic (in, out, etc.) of the new Export.
	 */
	private void makeCStyleExport(Cell parent, NodeInst ni, PortProto pp, String name, PortCharacteristic exporttype)
	{
		PortInst pi = ni.findPortInstFromProto(pp);
		Export.newInst(parent, pi, name, ep, exporttype);
	}

	/**
	 * Method to return an array of two doubles that describes the center of a port.
	 * @param ni the NodeInst with the port.
	 * @param pp the PortProto on that NodeInst.
	 * @return an array of two doubles that describes the X/Y of the center of a port.
	 */
	private static double [] getCStylePortPosition(NodeInst ni, PortProto pp)
	{
		PortInst pi = ni.findPortInstFromProto(pp);
		Poly poly = pi.getPoly();
		double [] ret = new double[2];
		ret[0] = poly.getCenterX();
		ret[1] = poly.getCenterY();
		return ret;
	}

}
