📄 stdcellparams.java
字号:
PortInst thisDiff = moss[i].getSrcDrn(j); net.connect(thisDiff); if (lastDiff!=null) { // Check to see if we just created a notch. double leftX = LayoutLib.roundCenterX(lastDiff); double rightX = LayoutLib.roundCenterX(thisDiff); error(leftX>rightX, "wireVddGnd: trans not sorted left to right"); double deltaX = rightX - leftX; if (deltaX>0 && deltaX < m1OverhangsDiffCont*2+m1Space) { // Fill notches, sigh! (This is starting to lose // it's novelty value.) // // Make height integral number of lambdas so // centerY will be on .5 lambda grid and connecting // to center won't generate CIF resolution errors. double dY = Math.ceil(notchHiY - notchLoY); NodeInst patchNode = LayoutLib.newNodeInst(tech.m1Node(), (leftX+rightX)/2, notchLoY+dY/2, deltaX, dY, 0, f); PortInst patch = patchNode.getOnlyPortInst(); LayoutLib.newArcInst(tech.m1(), DEF_SIZE, patch, thisDiff); } } lastDiff = thisDiff; } } } } public void wireVddGnd(FoldedMos mos, SelectSrcDrn select, Cell p) { wireVddGnd(new FoldedMos[] { mos }, select, p); } public boolean nccEnabled() { return schemLib != null; } /** Perform Network Consistency Check if the user has so requested */ public void doNCC(Cell layout, String schemNm) { if (schemLib == null) return; Cell schem = schemLib.findNodeProto(schemNm); error(schem == null, "can't find schematic: " + schemNm); NccOptions options = new NccOptions(); options.howMuchStatus = 0; NccResults results = Ncc.compare(schem, null, layout, null, options); error(!results.match(), "layout not topologically identical to schematic!"); } public static double getSize(NodeInst iconInst, VarContext context) { Variable var = iconInst.getParameterOrVariable(ATTR_X); if (var==null) var = iconInst.getParameterOrVariable(ATTR_S); if (var==null) var = iconInst.getParameterOrVariable(ATTR_SP); if (var==null) var = iconInst.getParameterOrVariable(ATTR_SN); if (var==null) { System.out.println("can't find size, using 40"); return 40; } Object val = context.evalVar(var); if (val instanceof Number) return ((Number)val).doubleValue(); error(true, "an Icon's size isn't a numeric value"); return 0; } /** Look for parts in layoutLib */ public Cell findPart(String partNm, double sz) { return findPart(sizedName(partNm, sz)); } public Cell findPart(String partNm) { return layoutLib.findNodeProto(partNm); } public Cell newPart(String partNm, double sz) { return newPart(sizedName(partNm, sz)); } public Cell newPart(String partNm) { error(findPart(partNm) != null, "Cell already exists: " + partNm); Cell p = Cell.newInstance(layoutLib, partNm); return p; } public static double getRightDiffX(FoldedMos m) { return LayoutLib.roundCenterX(m.getSrcDrn(m.nbSrcDrns() - 1)); } public static double getRightDiffX(FoldedMos[] moss) { return getRightDiffX(getRightMos(moss)); } /** Find the X coordinate of the right most diffusion. Objects a and * b may be either a FoldedMos or an array of FoldedMos'es */ public static double getRightDiffX(Object a, Object b) { FoldedMos ra = getRightMos(a); FoldedMos rb = getRightMos(b); return Math.max(getRightDiffX(ra), getRightDiffX(rb)); } public static void addEssentialBoundsFromChildren(Cell cell, TechType tech) { double loX, loY, hiX, hiY; loX = loY = Double.MAX_VALUE; hiX = hiY = Double.MIN_VALUE; for (Iterator<NodeInst> it=cell.getNodes(); it.hasNext();) { Rectangle2D b = it.next().getBounds(); loX = Math.min(loX, b.getMinX()); loY = Math.min(loY, b.getMinY()); hiX = Math.max(hiX, b.getMaxX()); hiY = Math.max(hiY, b.getMaxY()); } LayoutLib.newNodeInst(tech.essentialBounds(), loX, loY, DEF_SIZE, DEF_SIZE, 180, cell); LayoutLib.newNodeInst(tech.essentialBounds(), hiX, hiY, DEF_SIZE, DEF_SIZE, 0, cell); } public HashMap<String,Object> getSchemTrackAssign(Cell schem) { HashMap<String,Object> schAsgn = new HashMap<String,Object>(); for (Iterator<PortProto> it = schem.getPorts(); it.hasNext();) { Export e = (Export) it.next(); Object val = e.getParameterOrVariable("ATTR_track"); String key = e.getName(); if (val == null) continue; schAsgn.put(key, val); } validateTrackAssign(schAsgn, schem); return schAsgn; } public void validateTrackAssign(HashMap<String,Object> asgn, Cell s) { HashMap<Object,String> trkToExp = new HashMap<Object,String>(); for (String k : asgn.keySet()) { Object v = asgn.get(k); // check types of key and value error(!(v instanceof Integer), trkMsg(k,s)+"Value not Integer: "+v); // range check track number int track = ((Integer) v).intValue(); error(track==0, trkMsg(k,s)+"Track must be <=-1 or >=1, 0 is illegal"); /* error(track<min, trkMsg(k,s) + "Track too negative: "+track+ ". Only: "+(-min)+" NMOS tracks are available in this cell."); error(track>max, trkMsg(k,s) + "Track too positive: "+track+ ". Only: "+max+" PMOS tracks are available in this cell."); */ String oldK = trkToExp.get(v); if (oldK != null) { // Issue warning if two exports assigned to the same track System.out.println( trkMsg(k, s) + "Track: " + v + " is shared by export: " + oldK); } trkToExp.put(v, k); } } /** Add select node to ensure there is select surrounding the * specified diffusion node*/ public void addSelAroundDiff(NodeProto prot, Rectangle2D diffNodeBnd, double activeGateDiff, Cell cell) { error(prot!=tech.pdNode() && prot!=tech.ndNode(), "addSelectAroundDiff: only works with MOSIS CMOS diff nodes"); NodeProto sel = prot == tech.pdNode() ? tech.pselNode() : tech.nselNode(); // Note that transistors are rotated in 90 degrees with res double w = diffNodeBnd.getWidth(); double h = diffNodeBnd.getHeight(); // add the select surround if gate is longer than contact h += tech.selectSurroundDiffAlongGateInTrans() * 2; if (activeGateDiff > 0) h -= activeGateDiff;// w =+ tech.getSelectSurroundDiffInTrans() * 2; NodeInst node = LayoutLib.newNodeInst(sel, diffNodeBnd.getCenterX(), diffNodeBnd.getCenterY(), w, h, 0, cell); System.out.println(node.getParent().getName() + " Node " + node + " " + h + " cent " + diffNodeBnd.getCenterY()); } public static class SelectFill { public final NodeInst nselNode; public final NodeInst pselNode; public SelectFill(NodeInst nselNode, NodeInst pselNode) { this.nselNode = nselNode; this.pselNode = pselNode; } } /** * This fills the cell with N/P select over current N/P select areas, and over * poly. This assumes that all Pmos devices and PWell is at y > 0, and all * Nmos devices and NWell is at y < 0. * @param cell the cell to fill @param pSelect * @param nSelect * @param includePoly */ public SelectFill fillSelect(Cell cell, boolean pSelect, boolean nSelect, boolean includePoly) { double selSurroundPoly = tech.getSelectSurroundOverPoly(); if (selSurroundPoly < 0) return null;// do nothing. Rectangle2D pselectBounds = LayoutLib.getBounds(cell, Layer.Function.IMPLANTP); Rectangle2D nselectBounds = LayoutLib.getBounds(cell, Layer.Function.IMPLANTN); if (includePoly) { Rectangle2D polyBounds = LayoutLib.getBounds(cell, Layer.Function.POLY1); polyBounds.setRect(polyBounds.getX()-selSurroundPoly, polyBounds.getY()-selSurroundPoly, polyBounds.getWidth() + 2*selSurroundPoly, polyBounds.getHeight() + 2*selSurroundPoly); // merge select and poly bounds pselectBounds = pselectBounds.createUnion(polyBounds); nselectBounds = nselectBounds.createUnion(polyBounds); } // pselect above y=0, nselect below pselectBounds.setRect(pselectBounds.getMinX(), 0, pselectBounds.getMaxX()-pselectBounds.getMinX(), pselectBounds.getMaxY()); nselectBounds.setRect(nselectBounds.getMinX(), nselectBounds.getMinY(), nselectBounds.getMaxX()-nselectBounds.getMinX(), -nselectBounds.getMinY()); // fill it in pselectBounds = LayoutLib.roundBounds(pselectBounds); nselectBounds = LayoutLib.roundBounds(nselectBounds); NodeInst pni = null, nni = null; if (pSelect) { pni = LayoutLib.newNodeInst(tech.pselNode(), pselectBounds.getCenterX(), pselectBounds.getCenterY(), pselectBounds.getWidth(), pselectBounds.getHeight(), 0, cell); pni.setHardSelect(); } if (nSelect) { nni = LayoutLib.newNodeInst(tech.nselNode(), nselectBounds.getCenterX(), nselectBounds.getCenterY(), nselectBounds.getWidth(), nselectBounds.getHeight(), 0, cell); nni.setHardSelect(); } return new SelectFill(nni, pni); } /** * Note that nwellX denotes the X coord of the nwell contact cut, which * goes in the Nwell (well that holds PMOS devices). */ public boolean addWellCon(SelectFill selFill, PortInst gndPort, PortInst vddPort, Cell cell) { // see if there is space double nselMaxY = Math.abs(selFill.nselNode.getYSize()); double pselMaxY = Math.abs(selFill.pselNode.getYSize()); boolean added = false; double pspace = getNmosWellHeight() - nselMaxY; // the space needed is the well contact select height plus the metal1-metal1 spacing, // or plus the select to select spacing, whichever is greater. double m1m1_sp = 2.4; double psel_sp = 4.8; double nsel_sp = 4.8; Technology techy = cell.getTechnology(); if (pspace > (wellConSelectHeight+m1m1_sp) + 2*gridResolution) { // there is space, create it double pwellX = roundToGrid(gndPort.getBounds().getCenterX()); double pwellY = -roundToGrid(nselMaxY + 0.5*wellConSelectHeight + wellConSelectOffset) - gridResolution; SizeOffset so = tech.pwm1Y().getProtoSizeOffset(); NodeInst ni = LayoutLib.newNodeInst(tech.pwm1Y(), pwellX, pwellY, tech.pwm1Y().getDefWidth() - so.getHighXOffset() - so.getLowXOffset(), tech.pwm1Y().getDefHeight() -so.getHighYOffset() - so.getLowYOffset(), 0, cell); LayoutLib.newArcInst(tech.m1(), getM1TrackWidth(), ni.getOnlyPortInst(), gndPort); added = true; // if the space to the end of the cell is less than the select to select spacing, // fill it in with the appropriate select. double distFromEdge = getNmosWellHeight() - (Math.abs(pwellY) + 0.5*wellConSelectHeight); if (distFromEdge < psel_sp) { // get size of select layer Poly [] polys = techy.getShapeOfNode(ni); if (polys != null) { Layer.Function function = Layer.Function.IMPLANTP; Rectangle2D bounds = null; for (int i=0; i<polys.length; i++) { if (polys[i] == null) continue; if (polys[i].getLayer().getFunction() == function) { bounds = polys[i].getBox(); } } if (bounds != null) { // fill over the well contact. Round up bottom of fill so it is on lambda grid double fillBot = (int)(Math.abs(pwellY) - 0.5*wellConSelectHeight) + 1; double fillH = getNmosWellHeight() - fillBot; ni = LayoutLib.newNodeInst(tech.pselNode(), pwellX, -1*roundToGrid(fillH/2 + fillBot), bounds.getWidth(), roundToGrid(fillH), 0, cell); ni.setHardSelect(); } } } } double nspace = getPmosWellHeight() - pselMaxY; if (nspace > (wellConSelectHeight+m1m1_sp) + 2*gridResolution) { double nwellX = roundToGrid(vddPort.getBounds().getCenterX()); double nwellY = roundToGrid(pselMaxY + 0.5*wellConSelectHeight + wellConSelectOffset) + gridResolution; SizeOffset so = tech.nwm1Y().getProtoSizeOffset(); NodeInst ni = LayoutLib.newNodeInst(tech.nwm1Y(), nwellX, nwellY, tech.nwm1Y().getDefWidth() - so.getHighXOffset() - so.getLowXOffset(), tech.nwm1Y().getDefHeight() - so.getHighYOffset() - so.getLowYOffset(), 0, cell); LayoutLib.newArcInst(tech.m1(), getM1TrackWidth(), ni.getOnlyPortInst(), vddPort); added = true; // if the space to the end of the cell is less than the select to select spacing, // fill it in with the appropriate select. double distFromEdge = getPmosWellHeight() - (Math.abs(nwellY) + 0.5*wellConSelectHeight); if (distFromEdge < nsel_sp) { // get size of select layer Poly [] polys = techy.getShapeOfNode(ni); if (polys != null) { Layer.Function function = Layer.Function.IMPLANTN; Rectangle2D bounds = null; for (int i=0; i<polys.length; i++) { if (polys[i] == null) continue; if (polys[i].getLayer().getFunction() == function) { bounds = polys[i].getBox(); } } if (bounds != null) { // fill over the well contact. Round up bottom of fill so it is on lambda grid double fillBot = (int)(Math.abs(nwellY) - 0.5*wellConSelectHeight) + 1; double fillH = getPmosWellHeight() - fillBot; ni = LayoutLib.newNodeInst(tech.nselNode(), nwellX, roundToGrid(fillH/2 + fillBot), bounds.getWidth(), roundToGrid(fillH), 0, cell); ni.setHardSelect(); } } } } return added; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -