| // ***************************************************************************** |
| // ***************************************************************************** |
| // Copyright 2012 - 2015, Cadence Design Systems |
| // |
| // This file is part of the Cadence LEF/DEF Open Source |
| // Distribution, Product Version 5.8. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| // implied. See the License for the specific language governing |
| // permissions and limitations under the License. |
| // |
| // For updates, support, or to become part of the LEF/DEF Community, |
| // check www.openeda.org for details. |
| // |
| // $Author$ |
| // $Revision$ |
| // $Date$ |
| // $State: $ |
| // ***************************************************************************** |
| // ***************************************************************************** |
| |
| // This program is the diffLef core program. It has all the callback |
| // routines and write it out to a temporary file |
| |
| #include <stdio.h> |
| #include <string.h> |
| #ifndef WIN32 |
| # include <unistd.h> |
| #endif /* not WIN32 */ |
| #include "lefrReader.hpp" |
| #include "lefwWriter.hpp" |
| #include "lefiDebug.hpp" |
| |
| char defaultName[128]; |
| char defaultOut[128]; |
| FILE* fout; |
| int printing = 0; // Printing the output. |
| void* userData; |
| |
| // TX_DIR:TRANSLATION ON |
| |
| void dataError() { |
| fprintf(fout, "ERROR: returned user data is not correct!\n"); |
| } |
| |
| |
| void checkType(lefrCallbackType_e c) { |
| if (c >= 0 && c <= lefrLibraryEndCbkType) { |
| // OK |
| } else { |
| fprintf(fout, "ERROR: callback type is out of bounds!\n"); |
| } |
| } |
| |
| // 05/24/2001 - Wanda da Rosa. PCR 373170 |
| // This function is added due to the rounding between machines are |
| // different. For a 5, solaries will round down while hppa will roundup. |
| // This function will make sure it round up for all the machine |
| double chkNum(double num) { |
| long tempNum; |
| if ((num > 1000004) || (num < -1000004)) { |
| tempNum = (long)num; |
| if ((tempNum%5) == 0) |
| return num + 3; |
| } |
| return num; |
| } |
| |
| // Print Via |
| void lefVia(lefiVia* via, char* inName) { |
| int i, j; |
| |
| fprintf(fout, "%s %s", inName, via->name()); |
| if (via->hasDefault()) |
| fprintf(fout, " DEFAULT"); |
| if (via->hasGenerated()) |
| fprintf(fout, " GENERATED"); |
| if (via->hasTopOfStack()) |
| fprintf(fout, " TOPOFSTACKONLY"); |
| if (via->hasForeign()) { |
| fprintf(fout, " FOREIGN %s", via->foreign()); |
| if (via->hasForeignPnt()) { |
| fprintf(fout, " ( %g %g )", chkNum(via->foreignX()), |
| chkNum(via->foreignY())); |
| if (via->hasForeignOrient()) |
| fprintf(fout, " %s", lefiOrientStr(via->foreignOrient())); |
| } |
| } |
| fprintf(fout, "\n"); |
| if (via->hasProperties()) { |
| for (i = 0; i < via->numProperties(); i++) { |
| fprintf(fout, "%s %s PROP", inName, via->name()); |
| fprintf(fout, " %s", via->propName(i)); |
| if (via->propIsNumber(i)) |
| fprintf(fout, " %g", chkNum(via->propNumber(i))); |
| if (via->propIsString(i)) |
| fprintf(fout, " %s", via->propValue(i)); |
| fprintf(fout, "\n"); |
| } |
| } |
| if (via->hasViaRule()) { |
| fprintf(fout, "%s %s %g %g %s %s %s %g %g %g %g %g %g", via->name(), |
| via->viaRuleName(), via->xCutSize(), via->yCutSize(), |
| via->botMetalLayer(), via->cutLayer(), via->topMetalLayer(), |
| via->xCutSpacing(), via->yCutSpacing(), via->xBotEnc(), |
| via->yBotEnc(), via->xTopEnc(), via->yTopEnc()); |
| if (via->hasRowCol()) |
| fprintf(fout, " %d %d", via->numCutRows(), via->numCutCols()); |
| if (via->hasOrigin()) |
| fprintf(fout, " %g %g", via->xOffset(), via->yOffset()); |
| if (via->hasOffset()) |
| fprintf(fout, " %g %g %g %g", via->xBotOffset(), via->yBotOffset(), |
| via->xTopOffset(), via->yTopOffset()); |
| if (via->hasCutPattern()) |
| fprintf(fout, " %s", via->cutPattern()); |
| fprintf(fout, "\n"); |
| } |
| if (via->hasResistance()) |
| fprintf(fout, "%s %s RESISTANCE %g\n",inName, via->name(), |
| chkNum(via->resistance())); |
| if (via->numLayers() > 0) { |
| for (i = 0; i < via->numLayers(); i++) { |
| fprintf(fout, "%s %s LAYER %s\n", inName, via->name(), |
| via->layerName(i)); |
| for (j = 0; j < via->numRects(i); j++) { |
| if (via->rectColorMask(i, j)) { |
| fprintf(fout, "%s %s RECT MASK % d ( %g %g ) ( %g %g )\n", |
| inName, via->name(), via->rectColorMask(i, j), |
| chkNum(via->xl(i, j)), chkNum(via->yl(i, j)), |
| chkNum(via->xh(i, j)), chkNum(via->yh(i, j))); |
| } else { |
| fprintf(fout, "%s %s RECT ( %g %g ) ( %g %g )\n", inName, |
| via->name(), |
| chkNum(via->xl(i, j)), chkNum(via->yl(i, j)), |
| chkNum(via->xh(i, j)), chkNum(via->yh(i, j))); |
| } |
| } |
| for (j = 0; j < via->numPolygons(i); j++) { |
| struct lefiGeomPolygon poly; |
| poly = via->getPolygon(i, j); |
| if (via->polyColorMask(i, j)) { |
| fprintf(fout, "%s %s POLYGON MASK %d", inName, via->name(), |
| via->polyColorMask(i, j)); |
| } else { |
| fprintf(fout, "%s %s POLYGON", inName, via->name()); |
| } |
| for (int k = 0; k < poly.numPoints; k++) |
| fprintf(fout, " %g %g", poly.x[k], poly.y[k]); |
| fprintf(fout, "\n"); |
| } |
| } |
| } |
| return; |
| } |
| |
| // Print Spacing |
| void lefSpacing(lefiSpacing* spacing, char *inName) { |
| fprintf(fout, "%s SAMENET %s %s %g ", inName, spacing->name1(), |
| spacing->name2(), chkNum(spacing->distance())); |
| if (spacing->hasStack()) |
| fprintf(fout, " STACK"); |
| fprintf(fout,"\n"); |
| return; |
| } |
| |
| // Print Via Rule Layer |
| void lefViaRuleLayer(lefiViaRuleLayer* vLayer, char* viaName) { |
| fprintf(fout, "VIARULE %s LAYER %s", viaName, vLayer->name()); |
| if (vLayer->hasDirection()) { |
| if (vLayer->isHorizontal()) |
| fprintf(fout, " DIRECTION HORIZONTAL"); |
| if (vLayer->isVertical()) |
| fprintf(fout, " DIRECTION VERTICAL"); |
| } |
| if (vLayer->hasEnclosure()) |
| fprintf(fout, " ENCLOSURE %g %g\n", chkNum(vLayer->enclosureOverhang1()), |
| chkNum(vLayer->enclosureOverhang2())); |
| if (vLayer->hasWidth()) |
| fprintf(fout, " WIDTH %g TO %g", chkNum(vLayer->widthMin()), |
| chkNum(vLayer->widthMax())); |
| if (vLayer->hasResistance()) |
| fprintf(fout, " RESISTANCE %g", chkNum(vLayer->resistance())); |
| if (vLayer->hasOverhang()) |
| fprintf(fout, " OVERHANG %g", chkNum(vLayer->overhang())); |
| if (vLayer->hasMetalOverhang()) |
| fprintf(fout, " METALOVERHANG %g", chkNum(vLayer->metalOverhang())); |
| if (vLayer->hasSpacing()) |
| fprintf(fout, " SPACING %g BY %g", chkNum(vLayer->spacingStepX()), |
| chkNum(vLayer->spacingStepY())); |
| if (vLayer->hasRect()) |
| fprintf(fout, " RECT ( %g %g ) ( %g %g )", chkNum(vLayer->xl()), |
| chkNum(vLayer->yl()), chkNum(vLayer->xh()), chkNum(vLayer->yh())); |
| fprintf(fout, "\n"); |
| return; |
| } |
| |
| // Print Geometry |
| void prtGeometry(lefiGeometries* geometry, char* inName) { |
| int numItems = geometry->numItems(); |
| int i, j; |
| lefiGeomPath* path; |
| lefiGeomPathIter* pathIter; |
| lefiGeomRect* rect; |
| lefiGeomRectIter* rectIter; |
| lefiGeomPolygon* polygon; |
| lefiGeomPolygonIter* polygonIter; |
| lefiGeomVia* via; |
| lefiGeomViaIter* viaIter; |
| |
| for (i = 0; i < numItems; i++) { |
| switch (geometry->itemType(i)) { |
| case lefiGeomClassE: |
| fprintf(fout, "%s CLASS %s\n", inName, geometry->getClass(i)); |
| break; |
| case lefiGeomLayerE: |
| fprintf(fout, "%s LAYER %s\n", inName, geometry->getLayer(i)); |
| break; |
| case lefiGeomLayerMinSpacingE: |
| fprintf(fout, "%s SPACING %g\n", inName, |
| chkNum(geometry->getLayerMinSpacing(i))); |
| break; |
| case lefiGeomLayerExceptPgNetE: |
| fprintf(fout, "%s EXCEPTPGNET\n", inName); |
| break; |
| case lefiGeomLayerRuleWidthE: |
| fprintf(fout, "%s DESIGNRULEWIDTH %g\n", inName, |
| chkNum(geometry->getLayerRuleWidth(i))); |
| break; |
| case lefiGeomWidthE: |
| fprintf(fout, "%s WIDTH %g\n", inName, |
| chkNum(geometry->getWidth(i))); |
| break; |
| case lefiGeomPathE: |
| path = geometry->getPath(i); |
| if (path->colorMask != 0) { |
| fprintf(fout, "%s PATH MASK %d ", inName, path->colorMask); |
| } else { |
| fprintf(fout, "%s PATH ", inName); |
| } |
| |
| for (j = 0; j < path->numPoints; j++) { |
| if (j+1 == path->numPoints) // last one on the list |
| fprintf(fout, " ( %g %g )\n", chkNum(path->x[j]), |
| chkNum(path->y[j])); |
| else |
| fprintf(fout, " ( %g %g )", chkNum(path->x[j]), |
| chkNum(path->y[j])); |
| } |
| break; |
| case lefiGeomPathIterE: |
| pathIter = geometry->getPathIter(i); |
| if (pathIter->colorMask != 0) { |
| fprintf(fout, "%s PATH MASK %d ITERATED ", inName, |
| pathIter->colorMask); |
| } else { |
| fprintf(fout, "%s PATH ITERATED ", inName); |
| } |
| for (j = 0; j < pathIter->numPoints; j++) |
| fprintf(fout, " ( %g %g )", chkNum(pathIter->x[j]), |
| chkNum(pathIter->y[j])); |
| fprintf(fout, " DO %g BY %g STEP %g %g\n", |
| chkNum(pathIter->xStart), chkNum(pathIter->yStart), |
| chkNum(pathIter->xStep), chkNum(pathIter->yStep)); |
| break; |
| case lefiGeomRectE: |
| rect = geometry->getRect(i); |
| if (rect->colorMask != 0) { |
| fprintf(fout, "%s RECT MASK %d ( %g %g ) ( %g %g )\n", |
| inName, rect->colorMask, |
| chkNum(rect->xl), chkNum(rect->yl), |
| chkNum(rect->xh), chkNum(rect->yh)); |
| } else { |
| fprintf(fout, "%s RECT ( %g %g ) ( %g %g )\n", inName, |
| chkNum(rect->xl), chkNum(rect->yl), |
| chkNum(rect->xh), chkNum(rect->yh)); |
| } |
| break; |
| case lefiGeomRectIterE: |
| rectIter = geometry->getRectIter(i); |
| if (rectIter->colorMask != 0) { |
| fprintf(fout, "%s RECT MASK %d ITERATE ( %g %g ) ( %g %g )", |
| inName, rectIter->colorMask, |
| chkNum(rectIter->xl), chkNum(rectIter->yl), |
| chkNum(rectIter->xh), chkNum(rectIter->yh)); |
| } else { |
| fprintf(fout, "%s RECT ITERATE ( %g %g ) ( %g %g )", inName, |
| chkNum(rectIter->xl), chkNum(rectIter->yl), |
| chkNum(rectIter->xh), chkNum(rectIter->yh)); |
| } |
| fprintf(fout, " DO %g BY %g STEP %g %g ;\n", |
| chkNum(rectIter->xStart), chkNum(rectIter->yStart), |
| chkNum(rectIter->xStep), chkNum(rectIter->yStep)); |
| break; |
| case lefiGeomPolygonE: |
| polygon = geometry->getPolygon(i); |
| if (polygon->colorMask != 0) { |
| fprintf(fout, "%s POLYGON MASK %d ", inName, polygon->colorMask); |
| } else { |
| fprintf(fout, "%s POLYGON ", inName); |
| } |
| for (j = 0; j < polygon->numPoints; j++) { |
| if (j+1 == polygon->numPoints) // last one on the list |
| fprintf(fout, " ( %g %g )\n", chkNum(polygon->x[j]), |
| chkNum(polygon->y[j])); |
| else |
| fprintf(fout, " ( %g %g )", chkNum(polygon->x[j]), |
| chkNum(polygon->y[j])); |
| } |
| break; |
| case lefiGeomPolygonIterE: |
| polygonIter = geometry->getPolygonIter(i); |
| if (polygonIter->colorMask != 0) { |
| fprintf(fout, "%s POLYGON MASK %d ITERATE", inName, |
| polygonIter->colorMask); |
| } else { |
| fprintf(fout, "%s POLYGON ITERATE", inName); |
| } |
| for (j = 0; j < polygonIter->numPoints; j++) |
| fprintf(fout, " ( %g %g )", chkNum(polygonIter->x[j]), |
| chkNum(polygonIter->y[j])); |
| fprintf(fout, " DO %g BY %g STEP %g %g\n", |
| chkNum(polygonIter->xStart), chkNum(polygonIter->yStart), |
| chkNum(polygonIter->xStep), chkNum(polygonIter->yStep)); |
| break; |
| case lefiGeomViaE: |
| via = geometry->getVia(i); |
| if (via->topMaskNum != 0 || via->bottomMaskNum != 0 || via->cutMaskNum !=0) { |
| fprintf(fout, "%s VIA MASK %d%d%d ( %g %g ) %s\n", inName, |
| via->topMaskNum, via->cutMaskNum, via->bottomMaskNum, |
| chkNum(via->x), |
| chkNum(via->y), via->name); |
| } else { |
| fprintf(fout, "%s VIA ( %g %g ) %s\n", inName, chkNum(via->x), |
| chkNum(via->y), via->name); |
| } |
| break; |
| case lefiGeomViaIterE: |
| viaIter = geometry->getViaIter(i); |
| if (viaIter->topMaskNum != 0 || viaIter->cutMaskNum != 0 || viaIter->bottomMaskNum != 0) { |
| fprintf(fout, "%s VIA ITERATE MASK %d%d%d ( %g %g ) %s", inName, |
| viaIter->topMaskNum, viaIter->cutMaskNum, |
| viaIter->bottomMaskNum, |
| chkNum(viaIter->x), chkNum(viaIter->y), viaIter->name); |
| } else { |
| fprintf(fout, "%s VIA ITERATE ( %g %g ) %s", inName, |
| chkNum(viaIter->x), chkNum(viaIter->y), viaIter->name); |
| } |
| fprintf(fout, " DO %g BY %g STEP %g %g\n", |
| chkNum(viaIter->xStart), chkNum(viaIter->yStart), |
| chkNum(viaIter->xStep), chkNum(viaIter->yStep)); |
| break; |
| default: |
| fprintf(fout, "BOGUS geometries type.\n"); |
| break; |
| } |
| } |
| } |
| |
| // Antenna |
| int antennaCB(lefrCallbackType_e c, double value, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| |
| switch (c) { |
| case lefrAntennaInputCbkType: |
| fprintf(fout, "ANTINPUTGATEAREA %g\n", chkNum(value)); |
| break; |
| case lefrAntennaInoutCbkType: |
| fprintf(fout, "ANTINOUTDIFFAREA %g\n", chkNum(value)); |
| break; |
| case lefrAntennaOutputCbkType: |
| fprintf(fout, "ANTOUTPUTDIFFAREA %g\n", chkNum(value)); |
| break; |
| case lefrInputAntennaCbkType: |
| fprintf(fout, "INPUTPINANTENNASIZE %g\n", chkNum(value)); |
| break; |
| case lefrOutputAntennaCbkType: |
| fprintf(fout, "OUTPUTPINANTENNASIZE %g\n", chkNum(value)); |
| break; |
| case lefrInoutAntennaCbkType: |
| fprintf(fout, "INOUTPINANTENNASIZE %g\n", chkNum(value)); |
| break; |
| default: |
| break; |
| } |
| return 0; |
| } |
| |
| // Array |
| int arrayCB(lefrCallbackType_e c, lefiArray* a, lefiUserData ud) { |
| int i, j, defCaps; |
| lefiSitePattern* pattern; |
| lefiTrackPattern* track; |
| lefiGcellPattern* gcell; |
| |
| checkType(c); |
| if (ud != userData) dataError(); |
| |
| if (a->numSitePattern() > 0) { |
| for (i = 0; i < a->numSitePattern(); i++) { |
| pattern = a->sitePattern(i); |
| fprintf(fout, "ARRAY %s SITE %s %g %g %s DO %g BY %g STEP %g %g\n", |
| a->name(), pattern->name(), chkNum(pattern->x()), |
| chkNum(pattern->y()), lefiOrientStr(pattern->orient()), |
| chkNum(pattern->xStart()), chkNum(pattern->yStart()), |
| chkNum(pattern->xStep()), chkNum(pattern->yStep())); |
| } |
| } |
| if (a->numCanPlace() > 0) { |
| for (i = 0; i < a->numCanPlace(); i++) { |
| pattern = a->canPlace(i); |
| fprintf(fout, "ARRAY %s CANPLACE %s %g %g %s DO %g BY %g STEP %g %g\n", |
| a->name(), pattern->name(), chkNum(pattern->x()), |
| chkNum(pattern->y()), lefiOrientStr(pattern->orient()), |
| chkNum(pattern->xStart()), chkNum(pattern->yStart()), |
| chkNum(pattern->xStep()), chkNum(pattern->yStep())); |
| } |
| } |
| if (a->numCannotOccupy() > 0) { |
| for (i = 0; i < a->numCannotOccupy(); i++) { |
| pattern = a->cannotOccupy(i); |
| fprintf(fout, "ARRAY %s CANNOTOCCUPY %s %g %g %s DO %g BY %g STEP %g %g\n", |
| a->name(), pattern->name(), chkNum(pattern->x()), |
| chkNum(pattern->y()), lefiOrientStr(pattern->orient()), |
| chkNum(pattern->xStart()), chkNum(pattern->yStart()), |
| chkNum(pattern->xStep()), chkNum(pattern->yStep())); |
| } |
| } |
| |
| if (a->numTrack() > 0) { |
| for (i = 0; i < a->numTrack(); i++) { |
| track = a->track(i); |
| // 11/22/99 - Wanda da Rosa, PCR 283781. Merge the track with |
| // layer names. This way, if user split the layer into different |
| // line, the diff program won't generate extra lines. |
| if (track->numLayers() == 0) { |
| fprintf(fout, "ARRAY %s TRACKS %s, %g DO %d STEP %g\n", a->name(), |
| track->name(), chkNum(track->start()), track->numTracks(), |
| chkNum(track->space())); |
| } else { |
| fprintf(fout, "ARRAY %s TRACKS %s, %g DO %d STEP %g ", a->name(), |
| track->name(), chkNum(track->start()), track->numTracks(), |
| chkNum(track->space())); |
| for (j = 0; j < track->numLayers(); j++) |
| fprintf(fout, "%s ", track->layerName(j)); |
| fprintf(fout, ";\n"); |
| } |
| } |
| } |
| |
| if (a->numGcell() > 0) { |
| for (i = 0; i < a->numGcell(); i++) { |
| gcell = a->gcell(i); |
| fprintf(fout, "ARRAY %s GCELLGRID %s, %g DO %d STEP %g\n", a->name(), |
| gcell->name(), chkNum(gcell->start()), gcell->numCRs(), |
| chkNum(gcell->space())); |
| } |
| } |
| |
| if (a->numFloorPlans() > 0) { |
| for (i = 0; i < a->numFloorPlans(); i++) { |
| for (j = 0; j < a->numSites(i); j++) { |
| pattern = a->site(i, j); |
| fprintf(fout, |
| "ARRAY %s FLOORPLAN %s %s %s %g %g %s DO %d BY %d STEP %g %g\n", |
| a->name(), a->floorPlanName(i), a->siteType(i, j), |
| pattern->name(), chkNum(pattern->x()), chkNum(pattern->y()), |
| lefiOrientStr(pattern->orient()), pattern->xStart(), |
| pattern->yStart(), chkNum(pattern->xStep()), |
| chkNum(pattern->yStep())); |
| } |
| } |
| } |
| |
| defCaps = a->numDefaultCaps(); |
| if (defCaps > 0) { |
| for (i = 0; i < defCaps; i++) |
| fprintf(fout, "ARRAY %s DEFAULTCAP %d MINPINS %g WIRECAP %g\n", |
| a->name(), defCaps, chkNum(a->defaultCapMinPins(i)), |
| chkNum(a->defaultCap(i))); |
| } |
| return 0; |
| } |
| |
| // Busbitchar |
| int busBitCharsCB(lefrCallbackType_e c, const char* busBit, lefiUserData ud) |
| { |
| checkType(c); |
| if (ud != userData) dataError(); |
| // use the lef writer to write out the data |
| fprintf(fout, "BUSBITCHARS %s\n", busBit); |
| return 0; |
| } |
| |
| // CaseSensitive |
| int caseSensCB(lefrCallbackType_e c, int caseSense, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| |
| if (caseSense == TRUE) |
| fprintf(fout, "NAMESCASESENSITIVE ON\n"); |
| else |
| fprintf(fout, "NAMESCASESENSITIVE OFF\n"); |
| return 0; |
| } |
| |
| // FixedMask |
| int fixedMaskCB(lefrCallbackType_e c, int fixedMask, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| |
| if (fixedMask == 1) |
| fprintf(fout, "FIXEDMASK ;\n"); |
| return 0; |
| } |
| |
| // Crearance |
| int clearanceCB(lefrCallbackType_e c, const char* name, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| |
| fprintf(fout, "CLEARANCEMEASURE %s\n", name); |
| return 0; |
| } |
| |
| // Crosstalk correcttable |
| int correctTableCB(lefrCallbackType_e c, lefiCorrectionTable* table, |
| lefiUserData ud) { |
| int i, j, k, l; |
| lefiCorrectionEdge *edge; |
| lefiCorrectionResistance *resist; |
| lefiCorrectionVictim *victim; |
| |
| checkType(c); |
| if (ud != userData) dataError(); |
| |
| fprintf(fout, "CROSSTALK CORRECTIONTABLE %d\n", table->num()); |
| for (i = 0; i < table->numEdges(); i++) { |
| edge = table->edge(i); |
| // resistances |
| if (edge->numResistances()) { |
| for (j = 0; j < edge->numResistances(); j++) { |
| resist = edge->resistance(j); |
| fprintf(fout, "CROSSTALK CORRECTIONTABLE %d RESISTANCE %g\n", |
| table->num(), chkNum(resist->num(j))); |
| // victims |
| for (k = 0; k < resist->numVictims(); k++) { |
| victim = resist->victim(k); |
| if (victim->length() > 0) |
| fprintf(fout, |
| "CROSSTALK CORRECTIONTABLE %d RESISTANCE %g VICTIMLEN %g\n", |
| table->num(), chkNum(resist->num(j)), |
| chkNum(victim->length())); |
| for (l = 0; l < victim->numCorrections(); l++) |
| fprintf(fout, |
| "CROSSTALK CORRECTIONTABLE %d RESISTANCE %g VICTIM GTH %g CORRECTIONFACTOR %g\n", |
| table->num(), chkNum(resist->num(j)), |
| chkNum(victim->length()), chkNum(victim->correction(l))); |
| } |
| } |
| } |
| } |
| return 0; |
| } |
| |
| // Dielectric |
| int dielectricCB(lefrCallbackType_e c, double dielectric, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| |
| fprintf(fout, "DIELECTRIC %g\n", chkNum(dielectric)); |
| return 0; |
| } |
| |
| // Divider |
| int dividerCB(lefrCallbackType_e c, const char* divideChar, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "DIVIDER %s\n", divideChar); |
| return 0; |
| } |
| |
| // Crosstalk edgeRate |
| int edgeRateCB(lefrCallbackType_e c, double rate, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "CROSSTALK EDGERATESCALEFACTOR %g\n", chkNum(rate)); |
| return 0; |
| } |
| |
| // Callback routine for edgeratethreshold1 |
| int edgeRate1CB(lefrCallbackType_e c, double rate, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "CROSSTALK EDGERATETHRESHOLD1 %g\n", chkNum(rate)); |
| return 0; |
| } |
| |
| // Callback routine for edgeratethreshold2 |
| int edgeRate2CB(lefrCallbackType_e c, double rate, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "CROSSTALK EDGERATETHRESHOLD2 %g\n", chkNum(rate)); |
| return 0; |
| } |
| |
| // InputAntenna |
| int inputAntCB(lefrCallbackType_e c, double antenna, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "INPUTINANTENNASIZE %g\n", chkNum(antenna)); |
| return 0; |
| } |
| |
| // OutputAntenna |
| int outputAntCB(lefrCallbackType_e c, double antenna, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "OUTPUTINANTENNASIZE %g\n", chkNum(antenna)); |
| return 0; |
| } |
| |
| |
| // InOutAntenna |
| int inoutAntCB(lefrCallbackType_e c, double antenna, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "INOUTPUTINANTENNASIZE %g\n", chkNum(antenna)); |
| return 0; |
| } |
| |
| // Irdrop |
| int irdropCB(lefrCallbackType_e c, lefiIRDrop* irdrop, lefiUserData ud) { |
| int i; |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "IRDROP TABLE %s ", irdrop->name()); |
| for (i = 0; i < irdrop->numValues(); i++) |
| fprintf(fout, "%g %g ", chkNum(irdrop->value1(i)), |
| chkNum(irdrop->value2(i))); |
| fprintf(fout, "\n"); |
| return 0; |
| } |
| |
| // Layer |
| int layerCB(lefrCallbackType_e c, lefiLayer* layer, lefiUserData ud) { |
| int i, j, k; |
| double *widths, *current; |
| lefiLayerDensity* density; |
| char pType; |
| int numPoints, propNum; |
| lefiAntennaPWL* pwl; |
| int needHeading; |
| int numMinCut, numMinenclosed; |
| lefiSpacingTable* spTable; |
| lefiInfluence* influence; |
| lefiParallel* parallel; |
| lefiTwoWidths* twoWidths; |
| lefiAntennaModel* aModel; |
| lefiOrthogonal* ortho; |
| |
| checkType(c); |
| if (ud != userData) dataError(); |
| if (layer->hasType()) |
| fprintf(fout, "LAYER %s TYPE %s\n", layer->name(), layer->type()); |
| if (layer->hasMask()) |
| fprintf(fout, "LAYER %s MASK %d\n", layer->name(), layer->mask()); |
| if (layer->hasPitch()) |
| fprintf(fout, "LAYER %s PITCH %g\n", layer->name(), chkNum(layer->pitch())); |
| else if (layer->hasXYPitch()) |
| fprintf(fout, "LAYER %s PITCH %g %g\n", layer->name(), |
| chkNum(layer->pitchX()), chkNum(layer->pitchY())); |
| if (layer->hasOffset()) |
| fprintf(fout, "LAYER %s OFFSET %g\n", layer->name(), |
| chkNum(layer->offset())); |
| else if (layer->hasXYOffset()) |
| fprintf(fout, "LAYER %s OFFSET %g %g\n", layer->name(), |
| chkNum(layer->offsetX()), chkNum(layer->offsetY())); |
| if (layer->hasDiagPitch()) |
| fprintf(fout, "LAYER %s DIAGPITCH %g\n", layer->name(), |
| chkNum(layer->diagPitch())); |
| else if (layer->hasXYDiagPitch()) |
| fprintf(fout, "LAYER %s DIAGPITCH %g %g\n", layer->name(), |
| chkNum(layer->diagPitchX()), chkNum(layer->diagPitchY())); |
| if (layer->hasDiagWidth()) |
| fprintf(fout, "LAYER %s DIAGWIDTH %g\n", layer->name(), |
| chkNum(layer->diagWidth())); |
| if (layer->hasDiagSpacing()) |
| fprintf(fout, "LAYER %s DIAGSPACING %g\n", layer->name(), |
| chkNum(layer->diagSpacing())); |
| if (layer->hasDiagMinEdgeLength()) |
| fprintf(fout, "LAYER %s DIAGMINEDGELENGTH %g\n", layer->name(), |
| chkNum(layer->diagMinEdgeLength())); |
| if (layer->hasWidth()) |
| fprintf(fout, "LAYER %s WIDTH %g\n", layer->name(), |
| chkNum(layer->width())); |
| if (layer->hasArea()) |
| fprintf(fout, "LAYER %s AREA %g\n", layer->name(), |
| chkNum(layer->area())); |
| if (layer->numMinSize()) { |
| fprintf(fout, "LAYER %s MINSIZE", layer->name()); |
| for (i = 0; i < layer->numMinSize(); i++) |
| fprintf(fout, " %g %g", layer->minSizeWidth(i), |
| layer->minSizeLength(i)); |
| fprintf(fout, "\n"); |
| } |
| if (layer->hasSlotWireWidth()) |
| fprintf(fout, "LAYER %s SLOTWIREWIDTH %g\n", layer->name(), |
| chkNum(layer->slotWireWidth())); |
| if (layer->hasSlotWireLength()) |
| fprintf(fout, "LAYER %s SLOTWIRELENGTH %g\n", layer->name(), |
| chkNum(layer->slotWireLength())); |
| if (layer->hasSlotWidth()) |
| fprintf(fout, "LAYER %s SLOTWIDTH %g\n", layer->name(), |
| chkNum(layer->slotWidth())); |
| if (layer->hasSlotLength()) |
| fprintf(fout, "LAYER %s SLOTLENGTH %g\n", layer->name(), |
| chkNum(layer->slotLength())); |
| if (layer->hasMaxAdjacentSlotSpacing()) |
| fprintf(fout, "LAYER %s MAXADJACENTSLOTSPACING %g\n", layer->name(), |
| chkNum(layer->maxAdjacentSlotSpacing())); |
| if (layer->hasMaxCoaxialSlotSpacing()) |
| fprintf(fout, "LAYER %s MAXCOAXIALSLOTSPACING %g\n", layer->name(), |
| chkNum(layer->maxCoaxialSlotSpacing())); |
| if (layer->hasMaxEdgeSlotSpacing()) |
| fprintf(fout, "LAYER %s MAXEDGESLOTSPACING %g\n", layer->name(), |
| chkNum(layer->maxEdgeSlotSpacing())); |
| if (layer->hasArraySpacing()) { |
| fprintf(fout, "LAYER %s ARRAYSPACING", layer->name()); |
| if (layer->hasLongArray()) |
| fprintf(fout, " LONGARRAY"); |
| if (layer->hasViaWidth()) |
| fprintf(fout, " WIDTH %g", chkNum(layer->viaWidth())); |
| fprintf(fout, " CUTSPACING %g", chkNum(layer->cutSpacing())); |
| fprintf(fout, "\n"); |
| for (i = 1; i < layer->numArrayCuts(); i++) { |
| fprintf(fout, "LAYER %s ARRAYCUTS %i SPACING %g\n", layer->name(), |
| layer->arrayCuts(i), |
| layer->arraySpacing(i)); |
| } |
| } |
| if (layer->hasSplitWireWidth()) |
| fprintf(fout, "LAYER %s SPLITWIREWIDTH %g\n", layer->name(), |
| chkNum(layer->splitWireWidth())); |
| if (layer->hasMinimumDensity()) |
| fprintf(fout, "LAYER %s MINIMUMDENSITY %g\n", layer->name(), |
| chkNum(layer->minimumDensity())); |
| if (layer->hasMaximumDensity()) |
| fprintf(fout, "LAYER %s MAXIMUMDENSITY %g\n", layer->name(), |
| chkNum(layer->maximumDensity())); |
| if (layer->hasDensityCheckWindow()) |
| fprintf(fout, "LAYER %s DENSITYCHECKWINDOW %g %g\n", layer->name(), |
| chkNum(layer->densityCheckWindowLength()), |
| chkNum(layer->densityCheckWindowWidth())); |
| if (layer->hasDensityCheckStep()) |
| fprintf(fout, "LAYER %s DENSITYCHECKSTEP %g\n", layer->name(), |
| chkNum(layer->densityCheckStep())); |
| if (layer->hasFillActiveSpacing()) |
| fprintf(fout, "LAYER %s FILLACTIVESPACING %g\n", layer->name(), |
| chkNum(layer->fillActiveSpacing())); |
| numMinCut = layer->numMinimumcut(); // 5.4.1 |
| if (numMinCut > 0) { |
| for (i = 0; i < numMinCut; i++) { |
| fprintf(fout, "LAYER %s MINIMUMCUT %d WIDTH %g", layer->name(), |
| layer->minimumcut(i), |
| layer->minimumcutWidth(i)); |
| if (layer->hasMinimumcutWithin(i)) |
| fprintf(fout, " WITHIN %g", layer->minimumcutWithin(i)); |
| if (layer->hasMinimumcutConnection(i)) |
| fprintf(fout, " %s", layer->minimumcutConnection(i)); |
| if (layer->hasMinimumcutNumCuts(i)) |
| fprintf(fout, " LENGTH %g WITHIN %g", |
| layer->minimumcutLength(i), |
| layer->minimumcutDistance(i)); |
| fprintf(fout, "\n"); |
| } |
| } |
| if (layer->hasMaxwidth()) // 5.4.1 |
| fprintf(fout, "LAYER %s MAXWIDTH %g\n", layer->name(), layer->maxwidth()); |
| if (layer->hasMinwidth()) // 5.5 |
| fprintf(fout, "LAYER %s MINWIDTH %g\n", layer->name(), layer->minwidth()); |
| numMinenclosed = layer->numMinenclosedarea(); |
| if (numMinenclosed > 0) { |
| for (i = 0; i < numMinenclosed; i++) { // 5.5, made it multiples |
| fprintf(fout, "LAYER %s MINENCLOSEDAREA %g", layer->name(), |
| layer->minenclosedarea(i)); |
| if (layer->hasMinenclosedareaWidth(i)) |
| fprintf(fout, " MINENCLOSEDAREAWIDTH %g", |
| layer->minenclosedareaWidth(i)); |
| fprintf(fout,"\n"); |
| } |
| } |
| if (layer->hasMinstep()) { // 5.4.1 & 5.6 |
| for (i = 0; i < layer->numMinstep(); i++) { |
| fprintf(fout, "LAYER %s MINSTEP %g", layer->name(), |
| layer->minstep(i)); |
| if (layer->hasMinstepType(i)) |
| fprintf(fout, " %s", layer->minstepType(i)); |
| if (layer->hasMinstepLengthsum(i)) |
| fprintf(fout, " LENGTHSUM %g", layer->minstepLengthsum(i)); |
| if (layer->hasMinstepMaxedges(i)) |
| fprintf(fout, " MAXEDGES %d", layer->minstepMaxedges(i)); |
| fprintf(fout, "\n"); |
| } |
| } |
| if (layer->hasProtrusion()) // 5.4.1 |
| fprintf(fout, "LAYER %s PROTRUSIONWIDTH %g LENGTH %g WIDTH %g\n", |
| layer->name(), layer->protrusionWidth1(), |
| layer->protrusionLength(), layer->protrusionWidth2()); |
| if (layer->hasSpacingNumber()) { |
| for (i = 0; i < layer->numSpacing(); i++) { |
| fprintf(fout, "LAYER %s SPACING %g", layer->name(), |
| chkNum(layer->spacing(i))); |
| if (layer->spacingName(i)) |
| fprintf(fout, " LAYER %s", layer->spacingName(i)); |
| if (layer->hasSpacingLayerStack(i)) |
| fprintf(fout, " STACK"); |
| fprintf(fout,"\n"); |
| if (layer->hasSpacingAdjacent(i)) |
| fprintf(fout, "LAYER %s ADJACENTCUTS %d WITHIN %g\n", layer->name(), |
| layer->spacingAdjacentCuts(i), |
| chkNum(layer->spacingAdjacentWithin(i))); |
| if (layer->hasSpacingAdjacentExcept(i)) |
| fprintf(fout, "LAYER %s EXCEPTSAMEPGNET\n", layer->name()); |
| if (layer->hasSpacingCenterToCenter(i)) |
| fprintf(fout, "LAYER %s CENTERTOCENTER\n", layer->name()); |
| if (layer->hasSpacingSamenet(i)) { |
| fprintf(fout, "LAYER %s SAMENET", layer->name()); |
| if (layer->hasSpacingSamenetPGonly(i)) |
| fprintf(fout, " PGONLY\n"); |
| else |
| fprintf(fout, "\n"); |
| } |
| if (layer->hasSpacingArea(i)) |
| fprintf(fout, "LAYER %s AREA %g\n", layer->name(), |
| chkNum(layer->spacingArea(i))); |
| if (layer->hasSpacingRange(i)) { |
| fprintf(fout, "LAYER %s RANGE %g %g", layer->name(), |
| chkNum(layer->spacingRangeMin(i)), |
| chkNum(layer->spacingRangeMax(i))); |
| if (layer->hasSpacingRangeUseLengthThreshold(i)) |
| fprintf(fout, "USELENGTHTHRESHOLD "); |
| else if (layer->hasSpacingRangeInfluence(i)) { |
| fprintf(fout, "INFLUENCE %g ", |
| layer->spacingRangeInfluence(i)); |
| if (layer->hasSpacingRangeInfluenceRange(i)) |
| fprintf(fout, "RANGE %g %g ", |
| layer->spacingRangeInfluenceMin(i), |
| layer->spacingRangeInfluenceMax(i)); |
| } else if (layer->hasSpacingRangeRange(i)) |
| fprintf(fout, "RANGE %g %g ", |
| layer->spacingRangeRangeMin(i), |
| layer->spacingRangeRangeMax(i)); |
| fprintf(fout,"\n"); |
| } |
| else if (layer->hasSpacingLengthThreshold(i)) { |
| fprintf(fout, "LAYER %s LENGTHTHRESHOLD %g\n", layer->name(), |
| chkNum(layer->spacingLengthThreshold(i))); |
| if (layer->hasSpacingLengthThresholdRange(i)) |
| fprintf(fout, "RANGE %g %g", |
| layer->spacingLengthThresholdRangeMin(i), |
| layer->spacingLengthThresholdRangeMax(i)); |
| fprintf(fout,"\n"); |
| } |
| else if (layer->hasSpacingNotchLength(i)) { |
| fprintf(fout, "LAYER %s NOTCHLENGTH %g\n", layer->name(), |
| chkNum(layer->spacingNotchLength(i))); |
| } |
| else if (layer->hasSpacingEndOfNotchWidth(i)) { |
| fprintf(fout, "LAYER %s ENDOFNOTCHWIDTH %g NOTCHSPACING %g, NOTCHLENGTH %g\n", |
| layer->name(), |
| chkNum(layer->spacingEndOfNotchWidth(i)), |
| chkNum(layer->spacingEndOfNotchSpacing(i)), |
| chkNum(layer->spacingEndOfNotchLength(i))); |
| } |
| if (layer->hasSpacingParallelOverlap(i)) |
| fprintf(fout, "LAYER %s PARALLELOVERLAP\n", layer->name()); |
| if (layer->hasSpacingEndOfLine(i)) { |
| fprintf(fout, "LAYER %s ENDOFLINE %g WITHIN %g ", layer->name(), |
| chkNum(layer->spacingEolWidth(i)), |
| chkNum(layer->spacingEolWithin(i))); |
| if (layer->hasSpacingParellelEdge(i)) { |
| fprintf(fout, "PARALLELEDGE %g WITHIN %g ", |
| chkNum(layer->spacingParSpace(i)), |
| chkNum(layer->spacingParWithin(i))); |
| if (layer->hasSpacingTwoEdges(i)) { |
| fprintf(fout, "TWOEDGES "); |
| } |
| } |
| fprintf(fout,"\n"); |
| } |
| } |
| } |
| if (layer->hasSpacingTableOrtho()) { |
| fprintf(fout, "LAYER %s SPACINGTABLE ORTHOGONAL\n", layer->name()); |
| ortho = layer->orthogonal(); |
| for (i = 0; i < ortho->numOrthogonal(); i++) { |
| fprintf(fout, "LAYER %s SPACINGTABLE ORTHOGONAL WITHIN %g SPACING %g\n", |
| layer->name(), ortho->cutWithin(i), |
| ortho->orthoSpacing(i)); |
| } |
| fprintf(fout, ";\n"); |
| } |
| if (layer->numEnclosure() > 0) { |
| fprintf(fout, "LAYER %s ENCLOSURE", layer->name()); |
| for (i = 0; i < layer->numEnclosure(); i++) { |
| if (layer->hasEnclosureRule(i)) |
| fprintf(fout, " %s", layer->enclosureRule(i)); |
| fprintf(fout, " %g %g", layer->enclosureOverhang1(i), |
| layer->enclosureOverhang2(i)); |
| if (layer->hasEnclosureWidth(i)) |
| fprintf(fout, " WIDTH %g", layer->enclosureMinWidth(i)); |
| if (layer->hasEnclosureExceptExtraCut(i)) |
| fprintf(fout, " EXCEPTEXTRACUT %g", |
| layer->enclosureExceptExtraCut(i)); |
| if (layer->hasEnclosureMinLength(i)) |
| fprintf(fout, " LENGTH %g", layer->enclosureMinLength(i)); |
| fprintf(fout, "\n"); |
| } |
| } |
| if (layer->numPreferEnclosure() > 0) { |
| fprintf(fout, "LAYER %s PREFERENCLOSURE", layer->name()); |
| for (i = 0; i < layer->numPreferEnclosure(); i++) { |
| if (layer->hasPreferEnclosureRule(i)) |
| fprintf(fout, "%s ", layer->preferEnclosureRule(i)); |
| fprintf(fout, "%g %g ", layer->preferEnclosureOverhang1(i), |
| layer->preferEnclosureOverhang2(i)); |
| if (layer->hasPreferEnclosureWidth(i)) |
| fprintf(fout, "WIDTH %g ",layer->preferEnclosureMinWidth(i)); |
| fprintf(fout, "\n"); |
| } |
| } |
| if (layer->hasResistancePerCut()) |
| fprintf(fout, "LAYER %s RESISTANCE %g\n", layer->name(), |
| chkNum(layer->resistancePerCut())); |
| if (layer->hasCurrentDensityPoint()) |
| fprintf(fout, "LAYER %s CURRENTDEN %g\n", layer->name(), |
| chkNum(layer->currentDensityPoint())); |
| if (layer->hasCurrentDensityArray()) { |
| layer->currentDensityArray(&numPoints, &widths, ¤t); |
| for (i = 0; i < numPoints; i++) |
| fprintf(fout, "LAYER %s CURRENTDEN ( %g %g )\n", layer->name(), |
| chkNum(widths[i]), chkNum(current[i])); |
| } |
| if (layer->hasDirection()) |
| fprintf(fout, "LAYER %s DIRECTION %s\n", layer->name(), |
| layer->direction()); |
| if (layer->hasResistance()) |
| fprintf(fout, "LAYER %s RESISTANCE RPERSQ %g\n", layer->name(), |
| chkNum(layer->resistance())); |
| if (layer->hasCapacitance()) |
| fprintf(fout, "LAYER %s CAPACITANCE CPERSQDIST %g\n", layer->name(), |
| chkNum(layer->capacitance())); |
| if (layer->hasHeight()) |
| fprintf(fout, "LAYER %s HEIGHT %g\n", layer->name(), chkNum(layer->height())); |
| if (layer->hasThickness()) |
| fprintf(fout, "LAYER %s THICKNESS %g\n", layer->name(), |
| chkNum(layer->thickness())); |
| if (layer->hasWireExtension()) |
| fprintf(fout, "LAYER %s WIREEXTENSION %g\n", layer->name(), |
| chkNum(layer->wireExtension())); |
| if (layer->hasShrinkage()) |
| fprintf(fout, "LAYER %s SHRINKAGE %g\n", layer->name(), |
| chkNum(layer->shrinkage())); |
| if (layer->hasCapMultiplier()) |
| fprintf(fout, "LAYER %s CAPMULTIPLIER %g\n", layer->name(), |
| chkNum(layer->capMultiplier())); |
| if (layer->hasEdgeCap()) |
| fprintf(fout, "LAYER %s EDGECAPACITANCE %g\n", layer->name(), |
| chkNum(layer->edgeCap())); |
| if (layer->hasAntennaArea()) |
| fprintf(fout, "LAYER %s ANTAREAFACTOR %g\n", layer->name(), |
| chkNum(layer->antennaArea())); |
| if (layer->hasAntennaLength()) |
| fprintf(fout, "LAYER %s ANTLENGTHFACTOR %g\n", layer->name(), |
| chkNum(layer->antennaLength())); |
| for (j = 0; j < layer->numAntennaModel(); j++) { // 5.5 |
| aModel = layer->antennaModel(j); |
| |
| if (aModel->hasAntennaAreaRatio()) |
| fprintf(fout, "LAYER %s %s ANTAREARATIO %g\n", layer->name(), |
| aModel->antennaOxide(), |
| chkNum(aModel->antennaAreaRatio())); |
| if (aModel->hasAntennaDiffAreaRatio()) |
| fprintf(fout, "LAYER %s %s ANTDIFFAREARATIO %g\n", layer->name(), |
| aModel->antennaOxide(), |
| chkNum(aModel->antennaDiffAreaRatio())); |
| else if (aModel->hasAntennaDiffAreaRatioPWL()) { |
| pwl = aModel->antennaDiffAreaRatioPWL(); |
| fprintf(fout, "LAYER %s %s ANTDIFFAREARATIO PWL", layer->name(), |
| aModel->antennaOxide()); |
| for (i = 0; i < pwl->numPWL(); i++) |
| fprintf(fout, " %g %g", chkNum(pwl->PWLdiffusion(i)), |
| chkNum(pwl->PWLratio(i))); |
| fprintf(fout, "\n"); |
| } |
| if (aModel->hasAntennaCumAreaRatio()) |
| fprintf(fout, "LAYER %s %s ANTCUMAREARATIO %g\n", layer->name(), |
| aModel->antennaOxide(), |
| chkNum(aModel->antennaCumAreaRatio())); |
| if (aModel->hasAntennaCumDiffAreaRatio()) |
| fprintf(fout, "LAYER %s %s ANTCUMDIFFAREARATIO %g\n", layer->name(), |
| aModel->antennaOxide(), |
| chkNum(aModel->antennaCumDiffAreaRatio())); |
| else if (aModel->hasAntennaCumDiffAreaRatioPWL()) { |
| pwl = aModel->antennaCumDiffAreaRatioPWL(); |
| fprintf(fout, "LAYER %s %s ANTCUMDIFFAREARATIO PWL", layer->name(), |
| aModel->antennaOxide()); |
| for (i = 0; i < pwl->numPWL(); i++) |
| fprintf(fout, " %g %g", chkNum(pwl->PWLdiffusion(i)), |
| chkNum(pwl->PWLratio(i))); |
| fprintf(fout, "\n"); |
| } |
| if (aModel->hasAntennaAreaFactor()) { |
| fprintf(fout, "LAYER %s %s ANTAREAFACTOR %g", layer->name(), |
| aModel->antennaOxide(), |
| chkNum(aModel->antennaAreaFactor())); |
| if (aModel->hasAntennaAreaFactorDUO()) |
| fprintf(fout, " DIFFUSEONLY"); |
| fprintf(fout, "\n"); |
| } |
| if (aModel->hasAntennaSideAreaRatio()) |
| fprintf(fout, "LAYER %s %s ANTSIDEAREARATIO %g\n", layer->name(), |
| aModel->antennaOxide(), |
| chkNum(aModel->antennaSideAreaRatio())); |
| if (aModel->hasAntennaDiffSideAreaRatio()) |
| fprintf(fout, "LAYER %s %s ANTDIFFSIDEAREARATIO %g\n", layer->name(), |
| aModel->antennaOxide(), |
| chkNum(aModel->antennaDiffSideAreaRatio())); |
| else if (aModel->hasAntennaDiffSideAreaRatioPWL()) { |
| pwl = aModel->antennaDiffSideAreaRatioPWL(); |
| fprintf(fout, "LAYER %s %s ANTDIFFSIDEAREARATIO PWL", layer->name(), |
| aModel->antennaOxide()); |
| for (i = 0; i < pwl->numPWL(); i++) |
| fprintf(fout, " %g %g", chkNum(pwl->PWLdiffusion(i)), |
| chkNum(pwl->PWLratio(i))); |
| fprintf(fout, "\n"); |
| } |
| if (aModel->hasAntennaCumSideAreaRatio()) |
| fprintf(fout, "LAYER %s %s ANTCUMSIDEAREARATIO %g\n", layer->name(), |
| aModel->antennaOxide(), |
| chkNum(aModel->antennaCumSideAreaRatio())); |
| if (aModel->hasAntennaCumDiffSideAreaRatio()) |
| fprintf(fout, "LAYER %s %s ANTCUMDIFFSIDEAREARATIO %g\n", layer->name(), |
| aModel->antennaOxide(), |
| chkNum(aModel->antennaCumDiffSideAreaRatio())); |
| else if (aModel->hasAntennaCumDiffSideAreaRatioPWL()) { |
| pwl = aModel->antennaCumDiffSideAreaRatioPWL(); |
| fprintf(fout, "LAYER %s %s ANTCUMDIFFSIDEAREARATIO PWL", layer->name(), |
| aModel->antennaOxide()); |
| for (i = 0; i < pwl->numPWL(); i++) |
| fprintf(fout, "%g %g ", chkNum(pwl->PWLdiffusion(i)), |
| chkNum(pwl->PWLratio(i))); |
| fprintf(fout, "\n"); |
| } |
| if (aModel->hasAntennaSideAreaFactor()) { |
| fprintf(fout, " ANTSIDEAREAFACTOR %g ", |
| chkNum(aModel->antennaSideAreaFactor())); |
| if (aModel->hasAntennaSideAreaFactorDUO()) |
| fprintf(fout, " DIFFUSEONLY "); |
| fprintf(fout, "\n"); |
| } |
| } |
| |
| if (layer->numAccurrentDensity()) { |
| for (i = 0; i < layer->numAccurrentDensity(); i++) { |
| density = layer->accurrent(i); |
| fprintf(fout, "LAYER %s ACCURRENTDENSITY %s", layer->name(), |
| density->type()); |
| needHeading = 0; |
| if (density->hasOneEntry()) |
| fprintf(fout, " %g\n", chkNum(density->oneEntry())); |
| else { |
| if (density->numFrequency()) { |
| /* |
| if (needHeading) { |
| fprintf(fout, "LAYER %s ACCURRENTDENSITY %s", layer->name(), |
| density->type()); |
| } |
| */ |
| fprintf(fout, " FREQUENCY"); |
| for (j = 0; j < density->numFrequency(); j++) |
| fprintf(fout, " %g", chkNum(density->frequency(j))); |
| fprintf(fout, "\n"); |
| needHeading = 1; |
| } |
| if (density->numWidths()) { |
| if (needHeading) { |
| fprintf(fout, "LAYER %s ACCURRENTDENSITY %s", layer->name(), |
| density->type()); |
| } |
| fprintf(fout, " WIDTH"); |
| for (j = 0; j < density->numWidths(); j++) |
| fprintf(fout, " %g", chkNum(density->width(j))); |
| fprintf(fout, "\n"); |
| needHeading = 1; |
| } |
| if (density->numTableEntries()) { |
| if (needHeading) { |
| fprintf(fout, "LAYER %s ACCURRENTDENSITY %s", layer->name(), |
| density->type()); |
| k = 0; |
| } |
| else k = 5; |
| fprintf(fout, " TABLEENTRIES"); |
| for (j = 0; j < density->numTableEntries(); j++) { |
| if (k > 4) { |
| fprintf(fout, |
| "\nLAYER %s ACCURRENTDENSITY %s TABLEENTRIES %g", |
| layer->name(), density->type(), |
| chkNum(density->tableEntry(j))); |
| k = 1; |
| } else { |
| fprintf(fout, " %g", chkNum(density->tableEntry(j))); |
| k++; |
| } |
| } |
| fprintf(fout, "\n"); |
| needHeading = 1; |
| } |
| } |
| } |
| } |
| if (layer->numDccurrentDensity()) { |
| for (i = 0; i < layer->numDccurrentDensity(); i++) { |
| density = layer->dccurrent(i); |
| fprintf(fout, "LAYER %s DCCURRENTDENSITY %s", layer->name(), |
| density->type()); |
| needHeading = 0; |
| if (density->hasOneEntry()) |
| fprintf(fout, " %g\n", chkNum(density->oneEntry())); |
| else { |
| if (density->numCutareas()) { |
| /* |
| if (needHeading) { |
| fprintf(fout, "LAYER %s DCCURRENTDENSITY %s", layer->name(), |
| density->type()); |
| } |
| */ |
| fprintf(fout, " CUTAREA"); |
| for (j = 0; j < density->numCutareas(); j++) |
| fprintf(fout, " %g", chkNum(density->cutArea(j))); |
| fprintf(fout, "\n"); |
| needHeading = 1; |
| } |
| if (density->numWidths()) { |
| if (needHeading) { |
| fprintf(fout, "LAYER %s DCCURRENTDENSITY %s", layer->name(), |
| density->type()); |
| } |
| fprintf(fout, " WIDTH"); |
| for (j = 0; j < density->numWidths(); j++) |
| fprintf(fout, " %g", chkNum(density->width(j))); |
| fprintf(fout, "\n"); |
| needHeading = 1; |
| } |
| if (density->numTableEntries()) { |
| if (needHeading) { |
| fprintf(fout, "LAYER %s DCCURRENTDENSITY %s", layer->name(), |
| density->type()); |
| } |
| fprintf(fout, " TABLEENTRIES"); |
| for (j = 0; j < density->numTableEntries(); j++) |
| fprintf(fout, " %g", chkNum(density->tableEntry(j))); |
| fprintf(fout, "\n"); |
| needHeading = 1; |
| } |
| } |
| } |
| } |
| |
| for (i = 0; i < layer->numSpacingTable(); i++) { |
| spTable = layer->spacingTable(i); |
| if (spTable->isInfluence()) { |
| influence = spTable->influence(); |
| for (j = 0; j < influence->numInfluenceEntry(); j++) { |
| fprintf(fout, "LAYER %s SPACINGTABLE INFLUENCE WIDTH %g WITHIN %g SPACING %g\n", |
| layer->name(), influence->width(j), influence->distance(j), |
| influence->spacing(j)); |
| } |
| } else if (spTable->isParallel()) { |
| parallel = spTable->parallel(); |
| fprintf(fout, "LAYER %s SPACINGTABLE PARALLELRUNLENGTH", layer->name()); |
| for (j = 0; j < parallel->numLength(); j++) { |
| fprintf(fout, " %g", parallel->length(j)); |
| } |
| fprintf(fout, "\n"); |
| for (j = 0; j < parallel->numWidth(); j++) { |
| fprintf(fout, "LAYER %s SPACINGTABLE PARALLELRUNLENGTH WIDTH %g", |
| layer->name(), parallel->width(j)); |
| for (k = 0; k < parallel->numLength(); k++) { |
| fprintf(fout, " %g", parallel->widthSpacing(j, k)); |
| } |
| } |
| fprintf(fout, "\n"); |
| } else { |
| twoWidths = spTable->twoWidths(); |
| for (j = 0; j < twoWidths->numWidth(); j++) { |
| fprintf(fout, "LAYER %s TWOWIDTHS", layer->name()); |
| fprintf(fout, " WIDTH %g", twoWidths->width(j)); |
| if (twoWidths->hasWidthPRL(j)) |
| fprintf(fout, " PRL %g", twoWidths->widthPRL(j)); |
| for (k = 0; k < twoWidths->numWidthSpacing(j); k++) |
| fprintf(fout, " %g",twoWidths->widthSpacing(j, k)); |
| fprintf(fout, "\n"); |
| } |
| } |
| } |
| propNum = layer->numProps(); |
| if (propNum > 0) { |
| for (i = 0; i < propNum; i++) { |
| fprintf(fout, "LAYER %s PROP ", layer->name()); |
| // value can either be a string or number |
| fprintf(fout, "%s %s ", layer->propName(i), |
| layer->propValue(i)); |
| pType = layer->propType(i); |
| switch (pType) { |
| case 'R': fprintf(fout, "REAL"); |
| break; |
| case 'I': fprintf(fout, "INTEGER"); |
| break; |
| case 'S': fprintf(fout, "STRING"); |
| break; |
| case 'Q': fprintf(fout, "QUOTESTRING"); |
| break; |
| case 'N': fprintf(fout, "NUMBER"); |
| break; |
| } |
| fprintf(fout, "\n"); |
| } |
| } |
| |
| return 0; |
| } |
| |
| // Macro |
| int macroCB(lefrCallbackType_e c, lefiMacro* macro, lefiUserData ud) { |
| lefiSitePattern* pattern; |
| int propNum, i, hasPrtSym = 0; |
| |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "MACRO %s", macro->name()); |
| if (macro->hasClass()) |
| fprintf(fout, " CLASS %s", macro->macroClass()); |
| if (macro->isFixedMask()) |
| fprintf(fout, " FIXEDMASK "); |
| if (macro->hasEEQ()) |
| fprintf(fout, " EEQ %s", macro->EEQ()); |
| if (macro->hasLEQ()) |
| fprintf(fout, " LEQ %s", macro->LEQ()); |
| if (macro->hasSource()) |
| fprintf(fout, " SOURCE %s", macro->source()); |
| if (macro->hasXSymmetry()) { |
| fprintf(fout, " SYMMETRY X "); |
| hasPrtSym = 1; |
| } |
| if (macro->hasYSymmetry()) { // print X Y & R90 in one line |
| if (!hasPrtSym) { |
| fprintf(fout, " SYMMETRY Y "); |
| hasPrtSym = 1; |
| } |
| else |
| fprintf(fout, "Y "); |
| } |
| if (macro->has90Symmetry()) { |
| if (!hasPrtSym) { |
| fprintf(fout, " SYMMETRY R90 "); |
| hasPrtSym = 1; |
| } |
| else |
| fprintf(fout, "R90 "); |
| } |
| fprintf (fout, "\n"); |
| if (macro->hasSiteName()) |
| fprintf(fout, "MACRO %s SITE %s\n", macro->name(), macro->siteName()); |
| if (macro->hasSitePattern()) { |
| for (i = 0; i < macro->numSitePattern(); i++ ) { |
| pattern = macro->sitePattern(i); |
| if (pattern->hasStepPattern()) |
| fprintf(fout, "MACRO %s SITE %s %g %g %d DO %g BY %g STEP %g %g\n", |
| macro->name(), pattern->name(), chkNum(pattern->x()), |
| chkNum(pattern->y()), pattern->orient(), |
| chkNum(pattern->xStart()), chkNum(pattern->yStart()), |
| chkNum(pattern->xStep()), chkNum(pattern->yStep())); |
| else |
| fprintf(fout, "MACRO %s SITE %s %g %g %d\n", |
| macro->name(), pattern->name(), chkNum(pattern->x()), |
| chkNum(pattern->y()), pattern->orient()); |
| } |
| } |
| if (macro->hasSize()) |
| fprintf(fout, "MACRO %s SIZE %g BY %g\n", macro->name(), |
| chkNum(macro->sizeX()), chkNum(macro->sizeY())); |
| if (macro->hasForeign()) { |
| for (i = 0; i < macro->numForeigns(); i++) { |
| fprintf(fout, "MACRO %s FOREIGN %s", macro->name(), |
| macro->foreignName(i)); |
| if (macro->hasForeignPoint(i)) { |
| fprintf(fout, " ( %g %g )", chkNum(macro->foreignX(i)), |
| chkNum(macro->foreignY(i))); |
| if (macro->hasForeignOrient(i)) |
| fprintf(fout, " %s", lefiOrientStr(macro->foreignOrient(i))); |
| } |
| fprintf(fout, "\n"); |
| } |
| } |
| if (macro->hasOrigin()) |
| fprintf(fout, "MACRO %s ORIGIN ( %g %g )\n", macro->name(), |
| chkNum(macro->originX()), chkNum(macro->originY())); |
| if (macro->hasPower()) |
| fprintf(fout, "MACRO %s POWER %g\n", macro->name(), chkNum(macro->power())); |
| propNum = macro->numProperties(); |
| if (propNum > 0) { |
| for (i = 0; i < propNum; i++) { |
| fprintf(fout, "MACRO %s PROP", macro->name()); |
| // value can either be a string or number |
| if (macro->propValue(i)) { |
| fprintf(fout, " %s %s\n", macro->propName(i), macro->propValue(i)); |
| } |
| else |
| fprintf(fout, " %s %g\n", macro->propName(i), |
| chkNum(macro->propNum(i))); |
| } |
| } |
| return 0; |
| } |
| |
| // Manufacturinggrid |
| int manufacturingCB(lefrCallbackType_e c, double num, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "MANUFACTURINGGRID %g\n", chkNum(num)); |
| return 0; |
| } |
| |
| // Maxviastack |
| int maxStackViaCB(lefrCallbackType_e c, lefiMaxStackVia* maxStack, |
| lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "MAXVIASTACK %d", maxStack->maxStackVia()); |
| if (maxStack->hasMaxStackViaRange()) |
| fprintf(fout, " RANGE %s %s", |
| maxStack->maxStackViaBottomLayer(), |
| maxStack->maxStackViaTopLayer()); |
| fprintf(fout, "\n"); |
| return 0; |
| } |
| |
| // Minfeature |
| int minFeatureCB(lefrCallbackType_e c, lefiMinFeature* min, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "MINFEATURE %g %g\n", chkNum(min->one()), chkNum(min->two())); |
| return 0; |
| } |
| |
| // Universalnoisemargin |
| int noiseMarginCB(lefrCallbackType_e c, lefiNoiseMargin* margin, |
| lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "UNIVERSALNOISEMARGIN %g %g\n", chkNum(margin->high), |
| chkNum(margin->low)); |
| return 0; |
| } |
| |
| // NoiseTable |
| int noiseTableCB(lefrCallbackType_e c, lefiNoiseTable* table, lefiUserData ud) { |
| int i, j, k, l; |
| lefiNoiseEdge *edge; |
| lefiNoiseResistance *resist; |
| lefiNoiseVictim *victim; |
| |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "CROSSTALK NOISETABLE %d\n", table->num()); |
| if (table->numEdges() > 0) { |
| for (i = 0; i < table->numEdges(); i++) { |
| edge = table->edge(i); |
| // resistances |
| if (edge->numResistances()) { |
| for (j = 0; j < edge->numResistances(); j++) { |
| resist = edge->resistance(j); |
| fprintf(fout, "NOISETABLE %d RESISTANCE %g\n", |
| table->num(), chkNum(resist->num(j))); |
| // victims |
| for (k = 0; k < resist->numVictims(); k++) { |
| victim = resist->victim(k); |
| if (victim->length() > 0) |
| fprintf(fout, "CROSSTALK NOISETABLE %d RESISTANCE %g VICTIMLENGTH % g\n", |
| table->num(), chkNum(resist->num(j)), |
| chkNum(victim->length())); |
| for (l = 0; l < victim->numNoises(); l++) |
| fprintf(fout, "CROSSTALK NOISETABLE %d RESISTANCE %g VICTIMLENGT %g NOISEFACTOR %g\n", |
| table->num(), chkNum(resist->num(j)), |
| chkNum(victim->length()), chkNum(victim->noise(l))); |
| } |
| } |
| } |
| } |
| } |
| return 0; |
| } |
| |
| // Nondefault |
| int nonDefaultCB(lefrCallbackType_e c, lefiNonDefault* def, lefiUserData ud) { |
| int i; |
| lefiVia* via; |
| lefiSpacing* spacing; |
| char defName[1024]; |
| |
| checkType(c); |
| if (ud != userData) dataError(); |
| if (def->hasHardspacing()) |
| fprintf(fout, "NONDEFAULTRULE HARDSPACING\n"); |
| for (i = 0; i < def->numLayers(); i++) { |
| fprintf(fout, "NONDEFAULTRULE %s LAYER %s", def->name(), |
| def->layerName(i)); |
| if (def->hasLayerWidth(i)) |
| fprintf(fout, " WIDTH %g", chkNum(def->layerWidth(i))); |
| if (def->hasLayerDiagWidth(i)) |
| fprintf(fout, " DIAGWIDTH %g", chkNum(def->layerDiagWidth(i))); |
| if (def->hasLayerSpacing(i)) |
| fprintf(fout, " SPACING %g", chkNum(def->layerSpacing(i))); |
| if (def->hasLayerWireExtension(i)) |
| fprintf(fout, " WIREEXTENSION %g", chkNum(def->layerWireExtension(i))); |
| if (def->hasLayerResistance(i)) |
| fprintf(fout, " RESISTANCE RPERSQ %g", chkNum(def->layerResistance(i))); |
| if (def->hasLayerCapacitance(i)) |
| fprintf(fout, " CAPACITANCE CPERSQDIST %g", |
| chkNum(def->layerCapacitance(i))); |
| if (def->hasLayerEdgeCap(i)) |
| fprintf(fout, " EDGECAPACITANCE %g", chkNum(def->layerEdgeCap(i))); |
| fprintf(fout, "\n"); |
| } |
| |
| sprintf(defName, "NONDEFAULTRULE %s VIA", def->name()); |
| // handle via in nondefaultrule |
| for (i = 0; i < def->numVias(); i++) { |
| via = def->viaRule(i); |
| lefVia(via, defName); |
| } |
| |
| sprintf(defName, "NONDEFAULTRULE %s SPACING", def->name()); |
| // handle spacing in nondefaultrule |
| for (i = 0; i < def->numSpacingRules(); i++) { |
| spacing = def->spacingRule(i); |
| lefSpacing(spacing, defName); |
| } |
| |
| if (def->numUseVia() > 0) { |
| fprintf(fout, "NONDEFAULTRULE %s USEVIA", def->name()); |
| // handle spacing in nondefaultrule |
| for (i = 0; i < def->numUseVia(); i++) |
| fprintf(fout, " %s", def->viaName(i)); |
| fprintf(fout, "\n"); |
| } |
| |
| if (def->numUseViaRule() > 0) { |
| fprintf(fout, "NONDEFAULTRULE %s USEVIARULE", def->name()); |
| // handle spacing in nondefaultrule |
| for (i = 0; i < def->numUseViaRule(); i++) |
| fprintf(fout, " %s", def->viaRuleName(i)); |
| fprintf(fout, "\n"); |
| } |
| |
| if (def->numMinCuts() > 0) { |
| fprintf(fout, "NONDEFAULTRULE %s MINCUTS", def->name()); |
| // handle spacing in nondefaultrule |
| for (i = 0; i < def->numMinCuts(); i++) |
| fprintf(fout, " %s %d", def->cutLayerName(i), def->numCuts(i)); |
| fprintf(fout, "\n"); |
| } |
| |
| return 0; |
| } |
| |
| // Nowireextension |
| int noWireExtCB(lefrCallbackType_e c, const char* wireExt, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "NOWIREEXTENSION %s\n", wireExt); |
| return 0; |
| } |
| |
| // Obstruction |
| int obstructionCB(lefrCallbackType_e c, lefiObstruction* obs, |
| lefiUserData ud) { |
| lefiGeometries* geometry; |
| |
| checkType(c); |
| if (ud != userData) dataError(); |
| geometry = obs->geometries(); |
| prtGeometry(geometry, (char*)"OBS"); |
| return 0; |
| } |
| |
| // Pin |
| int pinCB(lefrCallbackType_e c, lefiPin* pin, lefiUserData ud) { |
| int numPorts, i, j; |
| lefiGeometries* geometry; |
| lefiPinAntennaModel* aModel; |
| |
| checkType(c); |
| if (ud != userData) dataError(); |
| if (pin->hasForeign()) { |
| if (pin->hasForeignOrient()) |
| fprintf(fout, "PIN %s FOREIGN %s STRUCTURE %g %g %s\n", pin->name(), |
| pin->foreignName(), chkNum(pin->foreignX()), |
| chkNum(pin->foreignY()), lefiOrientStr(pin->foreignOrient())); |
| else if (pin->hasForeignPoint()) |
| fprintf(fout, "PIN %s FOREIGN %s STRUCTURE %g %g", pin->name(), |
| pin->foreignName(), chkNum(pin->foreignX()), |
| chkNum(pin->foreignY())); |
| else |
| fprintf(fout, "PIN %s FOREIGN %s\n", pin->name(), pin->foreignName()); |
| } |
| if (pin->hasLEQ()) |
| fprintf(fout, "PIN %s LEQ %s\n", pin->name(), pin->LEQ()); |
| if (pin->hasDirection()) |
| fprintf(fout, "PIN %s DIRECTION %s\n", pin->name(), pin->direction()); |
| if (pin->hasUse()) |
| fprintf(fout, "PIN %s USE %s\n", pin->name(), pin->use()); |
| if (pin->hasShape()) |
| fprintf(fout, "PIN %s SHAPE %s\n", pin->name(), pin->shape()); |
| if (pin->hasMustjoin()) |
| fprintf(fout, "PIN %s MUSTJOIN %s\n", pin->name(), pin->mustjoin()); |
| if (pin->hasOutMargin()) |
| fprintf(fout, "PIN %s OUTPUTNOISEMARGIN %g %g\n", pin->name(), |
| chkNum(pin->outMarginHigh()), chkNum(pin->outMarginLow())); |
| if (pin->hasOutResistance()) |
| fprintf(fout, "PIN %s OUTPUTRESISTANCE %g %g\n", pin->name(), |
| chkNum(pin->outResistanceHigh()), chkNum(pin->outResistanceLow())); |
| if (pin->hasInMargin()) |
| fprintf(fout, "PIN %s INPUTNOISEMARGIN %g %g\n", pin->name(), |
| chkNum(pin->inMarginHigh()), chkNum(pin->inMarginLow())); |
| if (pin->hasPower()) |
| fprintf(fout, "PIN %s POWER %g\n", pin->name(), chkNum(pin->power())); |
| if (pin->hasLeakage()) |
| fprintf(fout, "PIN %s LEAKAGE %g\n", pin->name(), chkNum(pin->leakage())); |
| if (pin->hasMaxload()) |
| fprintf(fout, "PIN %s MAXLOAD %g\n", pin->name(), chkNum(pin->maxload())); |
| if (pin->hasCapacitance()) |
| fprintf(fout, "PIN %s CAPACITANCE %g\n", pin->name(), |
| chkNum(pin->capacitance())); |
| if (pin->hasResistance()) |
| fprintf(fout, "PIN %s RESISTANCE %g\n", pin->name(), |
| chkNum(pin->resistance())); |
| if (pin->hasPulldownres()) |
| fprintf(fout, "PIN %s PULLDOWNRES %g\n", pin->name(), |
| chkNum(pin->pulldownres())); |
| if (pin->hasTieoffr()) |
| fprintf(fout, "PIN %s TIEOFFR %g\n", pin->name(), chkNum(pin->tieoffr())); |
| if (pin->hasVHI()) |
| fprintf(fout, "PIN %s VHI %g\n", pin->name(), chkNum(pin->VHI())); |
| if (pin->hasVLO()) |
| fprintf(fout, "PIN %s VLO %g\n", pin->name(), chkNum(pin->VLO())); |
| if (pin->hasRiseVoltage()) |
| fprintf(fout, "PIN %s RISEVOLTAGETHRESHOLD %g\n", pin->name(), |
| chkNum(pin->riseVoltage())); |
| if (pin->hasFallVoltage()) |
| fprintf(fout, "PIN %s FALLVOLTAGETHRESHOLD %g\n", pin->name(), |
| chkNum(pin->fallVoltage())); |
| if (pin->hasRiseThresh()) |
| fprintf(fout, "PIN %s RISETHRESH %g\n", pin->name(), |
| chkNum(pin->riseThresh())); |
| if (pin->hasFallThresh()) |
| fprintf(fout, "PIN %s FALLTHRESH %g\n", pin->name(), |
| chkNum(pin->fallThresh())); |
| if (pin->hasRiseSatcur()) |
| fprintf(fout, "PIN %s RISESATCUR %g\n", pin->name(), |
| chkNum(pin->riseSatcur())); |
| if (pin->hasFallSatcur()) |
| fprintf(fout, "PIN %s FALLSATCUR %g\n", pin->name(), |
| chkNum(pin->fallSatcur())); |
| if (pin->hasRiseSlewLimit()) |
| fprintf(fout, "PIN %s RISESLEWLIMIT %g\n", pin->name(), |
| chkNum(pin->riseSlewLimit())); |
| if (pin->hasFallSlewLimit()) |
| fprintf(fout, "PIN %s FALLSLEWLIMIT %g\n", pin->name(), |
| chkNum(pin->fallSlewLimit())); |
| if (pin->hasCurrentSource()) |
| fprintf(fout, "PIN %s CURRENTSOURCE %s\n", pin->name(), |
| pin->currentSource()); |
| if (pin->hasTables()) |
| fprintf(fout, "PIN %s IV_TABLES %s %s\n", pin->name(), |
| pin->tableHighName(), pin->tableLowName()); |
| if (pin->hasTaperRule()) |
| fprintf(fout, "PIN %s TAPERRULE %s\n", pin->name(), pin->taperRule()); |
| if (pin->hasNetExpr()) |
| fprintf(fout, "PIN %s NETEXPR %s\n",pin->name(), pin->netExpr()); |
| if (pin->hasSupplySensitivity()) |
| fprintf(fout, "PIN %s SUPPLYSENSITIVITY %s\n", pin->name(), |
| pin->supplySensitivity()); |
| if (pin->hasGroundSensitivity()) |
| fprintf(fout, "PIN %s GROUNDSENSITIVITY %s\n", pin->name(), |
| pin->groundSensitivity()); |
| if (pin->hasAntennaSize()) { |
| for (i = 0; i < pin->numAntennaSize(); i++) { |
| fprintf(fout, "PIN %s ANTSIZE %g", pin->name(), |
| chkNum(pin->antennaSize(i))); |
| if (pin->antennaSizeLayer(i)) |
| fprintf(fout, " LAYER %s\n", pin->antennaSizeLayer(i)); |
| else |
| fprintf(fout, "\n"); |
| } |
| } |
| if (pin->hasAntennaMetalArea()) { |
| for (i = 0; i < pin->numAntennaMetalArea(); i++) { |
| fprintf(fout, "PIN %s ANTMETALAREA %g", pin->name(), |
| chkNum(pin->antennaMetalArea(i))); |
| if (pin->antennaMetalAreaLayer(i)) |
| fprintf(fout, " LAYER %s\n", pin->antennaMetalAreaLayer(i)); |
| else |
| fprintf(fout, "\n"); |
| } |
| } |
| if (pin->hasAntennaMetalLength()) { |
| for (i = 0; i < pin->numAntennaMetalLength(); i++) { |
| fprintf(fout, "PIN %s ANTMETALLENGTH %g", pin->name(), |
| chkNum(pin->antennaMetalLength(i))); |
| if (pin->antennaMetalLengthLayer(i)) |
| fprintf(fout, " LAYER %s\n", pin->antennaMetalLengthLayer(i)); |
| else |
| fprintf(fout, "\n"); |
| } |
| } |
| if (pin->hasAntennaPartialMetalArea()) { |
| for (i = 0; i < pin->numAntennaPartialMetalArea(); i++) { |
| fprintf(fout, "PIN %s ANTPARTIALMETALAREA %g", pin->name(), |
| chkNum(pin->antennaPartialMetalArea(i))); |
| if (pin->antennaPartialMetalAreaLayer(i)) |
| fprintf(fout, " LAYER %s", |
| pin->antennaPartialMetalAreaLayer(i)); |
| fprintf(fout, "\n"); |
| } |
| } |
| if (pin->hasAntennaPartialMetalSideArea()) { |
| for (i = 0; i < pin->numAntennaPartialMetalSideArea(); i++) { |
| fprintf(fout, "PIN %s ANTPARTIALMETALSIDEAREA %g", pin->name(), |
| chkNum(pin->antennaPartialMetalSideArea(i))); |
| if (pin->antennaPartialMetalSideAreaLayer(i)) |
| fprintf(fout, " LAYER %s ", |
| pin->antennaPartialMetalSideAreaLayer(i)); |
| fprintf(fout, "\n"); |
| } |
| } |
| if (pin->hasAntennaPartialCutArea()) { |
| for (i = 0; i < pin->numAntennaPartialCutArea(); i++) { |
| fprintf(fout, "PIN %s ANTPARTIALCUTAREA %g", pin->name(), |
| chkNum(pin->antennaPartialCutArea(i))); |
| if (pin->antennaPartialCutAreaLayer(i)) |
| fprintf(fout, " LAYER %s ", |
| pin->antennaPartialCutAreaLayer(i)); |
| fprintf(fout, "\n"); |
| } |
| } |
| if (pin->hasAntennaDiffArea()) { |
| for (i = 0; i < pin->numAntennaDiffArea(); i++) { |
| fprintf(fout, "PIN %s ANTDIFFAREA %g", pin->name(), |
| chkNum(pin->antennaDiffArea(i))); |
| if (pin->antennaDiffAreaLayer(i)) |
| fprintf(fout, " LAYER %s ", pin->antennaDiffAreaLayer(i)); |
| fprintf(fout, "\n"); |
| } |
| } |
| |
| for (j = 0; j < pin->numAntennaModel(); j++) { |
| aModel = pin->antennaModel(j); |
| |
| if (aModel->hasAntennaGateArea()) { |
| for (i = 0; i < aModel->numAntennaGateArea(); i++) |
| { |
| fprintf(fout, "PIN %s %s ANTGATEAREA %g", pin->name(), |
| aModel->antennaOxide(), |
| chkNum(aModel->antennaGateArea(i))); |
| if (aModel->antennaGateAreaLayer(i)) |
| fprintf(fout, " LAYER %s ", |
| aModel->antennaGateAreaLayer(i)); |
| fprintf(fout, "\n"); |
| } |
| } |
| if (aModel->hasAntennaMaxAreaCar()) { |
| for (i = 0; i < aModel->numAntennaMaxAreaCar(); |
| i++) { |
| fprintf(fout, "PIN %s %s ANTMAXAREACAR %g", pin->name(), |
| aModel->antennaOxide(), |
| chkNum(aModel->antennaMaxAreaCar(i))); |
| if (aModel->antennaMaxAreaCarLayer(i)) |
| fprintf(fout, " LAYER %s ", |
| aModel->antennaMaxAreaCarLayer(i)); |
| fprintf(fout, "\n"); |
| } |
| } |
| if (aModel->hasAntennaMaxSideAreaCar()) { |
| for (i = 0; i < aModel->numAntennaMaxSideAreaCar(); |
| i++) { |
| fprintf(fout, "PIN %s %s ANTMAXAREACAR %g", pin->name(), |
| aModel->antennaOxide(), |
| chkNum(aModel->antennaMaxSideAreaCar(i))); |
| if (aModel->antennaMaxSideAreaCarLayer(i)) |
| fprintf(fout, " LAYER %s ", |
| aModel->antennaMaxSideAreaCarLayer(i)); |
| fprintf(fout, "\n"); |
| } |
| } |
| if (aModel->hasAntennaMaxCutCar()) { |
| for (i = 0; i < aModel->numAntennaMaxCutCar(); i++) |
| { |
| fprintf(fout, "PIN %s %s ANTMAXCUTCAR %g", pin->name(), |
| aModel->antennaOxide(), |
| chkNum(aModel->antennaMaxCutCar(i))); |
| if (aModel->antennaMaxCutCarLayer(i)) |
| fprintf(fout, " LAYER %s ", |
| aModel->antennaMaxCutCarLayer(i)); |
| fprintf(fout, "\n"); |
| } |
| } |
| } |
| |
| if (pin->numProperties() > 0) { |
| for (i = 0; i < pin->numProperties(); i++) { |
| fprintf(fout, "PIN %s PROP ", pin->name()); |
| // value can either be a string or number |
| if (pin->propValue(i)) { |
| fprintf(fout, "%s %s\n", pin->propName(i), pin->propValue(i)); |
| } |
| else |
| fprintf(fout, "%s %g\n", pin->propName(i), chkNum(pin->propNum(i))); |
| } |
| } |
| |
| numPorts = pin->numPorts(); |
| |
| char pinName[1024]; |
| |
| for (i = 0; i < numPorts; i++) { |
| sprintf(pinName, "PIN %s PORT", pin->name()); |
| geometry = pin->port(i); |
| prtGeometry(geometry, pinName); |
| } |
| return 0; |
| } |
| |
| int densityCB(lefrCallbackType_e c, lefiDensity* density, |
| lefiUserData ud) { |
| struct lefiGeomRect rect; |
| |
| checkType(c); |
| if (ud != userData) dataError(); |
| for (int i = 0; i < density->numLayer(); i++) { |
| for (int j = 0; j < density->numRects(i); j++) { |
| rect = density->getRect(i,j); |
| fprintf(fout, "DENSITY LAYER %s RECT %g %g %g %g %g\n", |
| density->layerName(i), rect.xl, rect.yl, rect.xh, rect.yh, |
| density->densityValue(i,j)); |
| } |
| } |
| return 0; |
| } |
| |
| // Property definition |
| int propDefCB(lefrCallbackType_e c, lefiProp* prop, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "PROPDEF %s %s", |
| prop->propType(), prop->propName()); |
| if (prop->hasRange()) |
| fprintf(fout, " RANGE %g %g", chkNum(prop->left()), chkNum(prop->right())); |
| if (prop->hasNumber()) |
| fprintf(fout, " NUMBER %g", chkNum(prop->number())); |
| switch (prop->dataType()) { |
| case 'I': |
| fprintf(fout, " TYPE I"); |
| break; |
| case 'R': |
| fprintf(fout, " TYPE R"); |
| break; |
| case 'S': |
| fprintf(fout, " TYPE S"); |
| break; |
| case 'Q': |
| fprintf(fout, " TYPE Q"); |
| break; |
| case 'N': |
| fprintf(fout, " TYPE N"); |
| break; |
| } |
| fprintf(fout, "\n"); |
| return 0; |
| } |
| |
| // Site |
| int siteCB(lefrCallbackType_e c, lefiSite* site, lefiUserData ud) { |
| int hasPrtSym = 0; |
| int i; |
| |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "SITE %s", site->name()); |
| if (site->hasClass()) |
| fprintf(fout, " CLASS %s", site->siteClass()); |
| if (site->hasXSymmetry()) { |
| fprintf(fout, " SYMMETRY X "); |
| hasPrtSym = 1; |
| } |
| if (site->hasYSymmetry()) { |
| if (hasPrtSym) |
| fprintf(fout, "Y "); |
| else { |
| fprintf(fout, " SYMMETRY Y "); |
| hasPrtSym = 1; |
| } |
| } |
| if (site->has90Symmetry()) { |
| if (hasPrtSym) |
| fprintf(fout, "R90 "); |
| else { |
| fprintf(fout, " SYMMETRY R90 "); |
| hasPrtSym = 1; |
| } |
| } |
| if (site->hasSize()) |
| fprintf(fout, " SIZE %g BY %g", chkNum(site->sizeX()), |
| chkNum(site->sizeY())); |
| fprintf(fout, "\n"); |
| if (site->hasRowPattern()) { // 5.6, a line for ea rowpattern for sorting |
| for (i = 0; i < site->numSites(); i++) |
| fprintf(fout, "SITE %s ROWPATTERN %s %s\n", site->name(), |
| site->siteName(i), site->siteOrientStr(i)); |
| } |
| |
| return 0; |
| } |
| |
| // Spacing |
| int spacingCB(lefrCallbackType_e c, lefiSpacing* spacing, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| lefSpacing(spacing, (char*)"SPACING"); |
| return 0; |
| } |
| |
| // Timing |
| int timingCB(lefrCallbackType_e c, lefiTiming* timing, lefiUserData ud) { |
| int i; |
| checkType(c); |
| if (ud != userData) dataError(); |
| for (i = 0; i < timing->numFromPins(); i++) |
| fprintf(fout, "TIMING FROMPIN %s\n", timing->fromPin(i)); |
| for (i = 0; i < timing->numToPins(); i++) |
| fprintf(fout, "TIMING TOPIN %s\n", timing->toPin(i)); |
| fprintf(fout, "TIMING RISE SLEW1 %g %g %g %g\n", |
| chkNum(timing->riseSlewOne()), chkNum(timing->riseSlewTwo()), |
| chkNum(timing->riseSlewThree()), chkNum(timing->riseSlewFour())); |
| if (timing->hasRiseSlew2()) |
| fprintf(fout, "TIMING RISE SLEW2 %g %g %g\n", |
| chkNum(timing->riseSlewFive()), chkNum(timing->riseSlewSix()), |
| chkNum(timing->riseSlewSeven())); |
| if (timing->hasFallSlew()) |
| fprintf(fout, "TIMING FALL SLEW1 %g %g %g %g\n", |
| chkNum(timing->fallSlewOne()), chkNum(timing->fallSlewTwo()), |
| chkNum(timing->fallSlewThree()), chkNum(timing->fallSlewFour())); |
| if (timing->hasFallSlew2()) |
| fprintf(fout, "TIMING FALL SLEW2 %g %g %g\n", |
| chkNum(timing->fallSlewFive()), chkNum(timing->fallSlewSix()), |
| chkNum(timing->riseSlewSeven())); |
| if (timing->hasRiseIntrinsic()) { |
| fprintf(fout, "TIMING RISE INTRINSIC %g %g\n", |
| chkNum(timing->riseIntrinsicOne()), |
| chkNum(timing->riseIntrinsicTwo())); |
| fprintf(fout, "TIMING RISE VARIABLE %g %g\n", |
| chkNum(timing->riseIntrinsicThree()), |
| chkNum(timing->riseIntrinsicFour())); |
| } |
| if (timing->hasFallIntrinsic()) { |
| fprintf(fout, "TIMING FALL INTRINSIC %g %g\n", |
| chkNum(timing->fallIntrinsicOne()), |
| chkNum(timing->fallIntrinsicTwo())); |
| fprintf(fout, "TIMING RISE VARIABLE %g %g\n", |
| chkNum(timing->fallIntrinsicThree()), |
| chkNum(timing->fallIntrinsicFour())); |
| } |
| if (timing->hasRiseRS()) |
| fprintf(fout, "TIMING RISERS %g %g\n", |
| chkNum(timing->riseRSOne()), chkNum(timing->riseRSTwo())); |
| if (timing->hasRiseCS()) |
| fprintf(fout, "TIMING RISECS %g %g\n", |
| chkNum(timing->riseCSOne()), chkNum(timing->riseCSTwo())); |
| if (timing->hasFallRS()) |
| fprintf(fout, "TIMING FALLRS %g %g\n", |
| chkNum(timing->fallRSOne()), chkNum(timing->fallRSTwo())); |
| if (timing->hasFallCS()) |
| fprintf(fout, "TIMING FALLCS %g %g\n", |
| chkNum(timing->fallCSOne()), chkNum(timing->fallCSTwo())); |
| if (timing->hasUnateness()) |
| fprintf(fout, "TIMING UNATENESS %s\n", timing->unateness()); |
| if (timing->hasRiseAtt1()) |
| fprintf(fout, "TIMING RISESATT1 %g %g\n", chkNum(timing->riseAtt1One()), |
| chkNum(timing->riseAtt1Two())); |
| if (timing->hasFallAtt1()) |
| fprintf(fout, "TIMING FALLSATT1 %g %g\n", chkNum(timing->fallAtt1One()), |
| chkNum(timing->fallAtt1Two())); |
| if (timing->hasRiseTo()) |
| fprintf(fout, "TIMING RISET0 %g %g\n", chkNum(timing->riseToOne()), |
| chkNum(timing->riseToTwo())); |
| if (timing->hasFallTo()) |
| fprintf(fout, "TIMING FALLT0 %g %g\n", chkNum(timing->fallToOne()), |
| chkNum(timing->fallToTwo())); |
| return 0; |
| } |
| |
| // Units |
| int unitsCB(lefrCallbackType_e c, lefiUnits* unit, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| if (unit->hasDatabase()) |
| fprintf(fout, "UNITS DATABASE %s %g\n", unit->databaseName(), |
| chkNum(unit->databaseNumber())); |
| if (unit->hasCapacitance()) |
| fprintf(fout, "UNITS CAPACITANCE PICOFARADS %g\n", |
| chkNum(unit->capacitance())); |
| if (unit->hasResistance()) |
| fprintf(fout, "UNITS RESISTANCE OHMS %g\n", chkNum(unit->resistance())); |
| if (unit->hasPower()) |
| fprintf(fout, "UNITS POWER MILLIWATTS %g\n", chkNum(unit->power())); |
| if (unit->hasCurrent()) |
| fprintf(fout, "UNITS CURRENT MILLIAMPS %g\n", chkNum(unit->current())); |
| if (unit->hasVoltage()) |
| fprintf(fout, "UNITS VOLTAGE VOLTS %g\n", chkNum(unit->voltage())); |
| if (unit->hasFrequency()) |
| fprintf(fout, "UNITS FREQUENCY MEGAHERTZ %g\n", chkNum(unit->frequency())); |
| return 0; |
| } |
| |
| // UseMinSpacing |
| int useMinSpacingCB(lefrCallbackType_e c, lefiUseMinSpacing* spacing, |
| lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "USEMINSPACING %s ", spacing->name()); |
| if (spacing->value()) |
| fprintf(fout, "USEMINSPACING ON\n"); |
| else |
| fprintf(fout, "USEMINSPACING OFF\n"); |
| return 0; |
| } |
| |
| // Version |
| int versionCB(lefrCallbackType_e c, double num, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "VERSION %g\n", num); |
| return 0; |
| } |
| |
| // Via |
| int viaCB(lefrCallbackType_e c, lefiVia* via, lefiUserData ud) { |
| checkType(c); |
| if (ud != userData) dataError(); |
| lefVia(via, (char*)"VIA"); |
| return 0; |
| } |
| |
| // Viarule |
| int viaRuleCB(lefrCallbackType_e c, lefiViaRule* viaRule, lefiUserData ud) { |
| int numLayers, numVias, i; |
| lefiViaRuleLayer* vLayer; |
| |
| checkType(c); |
| if (ud != userData) dataError(); |
| fprintf(fout, "VIARULE %s", viaRule->name()); |
| if (viaRule->hasGenerate()) |
| fprintf(fout, " GENERATE"); |
| if (viaRule->hasDefault()) |
| fprintf(fout, " DEFAULT"); |
| fprintf(fout, "\n"); |
| |
| numLayers = viaRule->numLayers(); |
| // if numLayers == 2, it is VIARULE without GENERATE and has via name |
| // if numLayers == 3, it is VIARULE with GENERATE, and the 3rd layer is cut |
| for (i = 0; i < numLayers; i++) { |
| vLayer = viaRule->layer(i); |
| lefViaRuleLayer(vLayer, viaRule->name()); |
| } |
| |
| if (numLayers == 2) { // should have vianames |
| numVias = viaRule->numVias(); |
| if (numVias == 0) |
| fprintf(fout, "Should have via names in VIARULE.\n"); |
| else { |
| for (i = 0; i < numVias; i++) |
| fprintf(fout, "VIARULE %s VIA %s ;\n", viaRule->name(), |
| viaRule->viaName(i)); |
| } |
| } |
| if (viaRule->numProps() > 0) { |
| for (i = 0; i < viaRule->numProps(); i++) { |
| fprintf(fout, "VIARULE %s PROP %s ", viaRule->name(), |
| viaRule->propName(i)); |
| if (viaRule->propValue(i)) |
| fprintf(fout, "%s ", viaRule->propValue(i)); |
| switch (viaRule->propType(i)) { |
| case 'R': fprintf(fout, "REAL "); |
| break; |
| case 'I': fprintf(fout, "INTEGER "); |
| break; |
| case 'S': fprintf(fout, "STRING "); |
| break; |
| case 'Q': fprintf(fout, "QUOTESTRING "); |
| break; |
| case 'N': fprintf(fout, "NUMBER "); |
| break; |
| fprintf(fout, "\n"); |
| } |
| } |
| } |
| return 0; |
| } |
| |
| //======== |
| |
| int diffLefReadFile(char* inFile, char* outFile) { |
| FILE* f; |
| int res; |
| |
| userData = (void*)0x01020304; |
| lefrInit(); |
| |
| // Fix of CCR 758312 |
| lefrSetRelaxMode(); |
| |
| lefrSetAntennaInputCbk(antennaCB); |
| lefrSetAntennaInoutCbk(antennaCB); |
| lefrSetAntennaOutputCbk(antennaCB); |
| lefrSetArrayCbk(arrayCB); |
| lefrSetBusBitCharsCbk(busBitCharsCB); |
| lefrSetCaseSensitiveCbk(caseSensCB); |
| lefrSetFixedMaskCbk(fixedMaskCB); |
| lefrSetClearanceMeasureCbk(clearanceCB); |
| lefrSetCorrectionTableCbk(correctTableCB); |
| lefrSetDensityCbk(densityCB); |
| lefrSetDielectricCbk(dielectricCB); |
| lefrSetDividerCharCbk(dividerCB); |
| lefrSetEdgeRateScaleFactorCbk(edgeRateCB); |
| lefrSetEdgeRateThreshold1Cbk(edgeRate1CB); |
| lefrSetEdgeRateThreshold2Cbk(edgeRate2CB); |
| lefrSetInputAntennaCbk(inputAntCB); |
| lefrSetOutputAntennaCbk(outputAntCB); |
| lefrSetInoutAntennaCbk(inoutAntCB); |
| lefrSetIRDropCbk(irdropCB); |
| lefrSetLayerCbk(layerCB); |
| lefrSetMacroCbk(macroCB); |
| lefrSetManufacturingCbk(manufacturingCB); |
| lefrSetMaxStackViaCbk(maxStackViaCB); |
| lefrSetMinFeatureCbk(minFeatureCB); |
| lefrSetNoiseMarginCbk(noiseMarginCB); |
| lefrSetNoiseTableCbk(noiseTableCB); |
| lefrSetNonDefaultCbk(nonDefaultCB); |
| lefrSetNoWireExtensionCbk(noWireExtCB); |
| lefrSetObstructionCbk(obstructionCB); |
| lefrSetPinCbk(pinCB); |
| lefrSetPropCbk(propDefCB); |
| lefrSetSiteCbk(siteCB); |
| lefrSetSpacingCbk(spacingCB); |
| lefrSetTimingCbk(timingCB); |
| lefrSetUnitsCbk(unitsCB); |
| lefrSetUseMinSpacingCbk(useMinSpacingCB); |
| lefrSetUserData((void*)3); |
| lefrSetVersionCbk(versionCB); |
| lefrSetViaCbk(viaCB); |
| lefrSetViaRuleCbk(viaRuleCB); |
| |
| if ((f = fopen(inFile,"r")) == 0) { |
| fprintf(stderr,"Couldn't open input file '%s'\n", inFile); |
| return(2); |
| } |
| |
| if ((fout = fopen(outFile,"w")) == 0) { |
| fprintf(stderr,"Couldn't open output file '%s'\n", outFile); |
| fclose(f); |
| return(2); |
| } |
| |
| res = lefrRead(f, inFile, userData); |
| |
| fclose(f); |
| fclose(fout); |
| |
| return 0; |
| } |