1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: iolefo.c
6 * Input/output tool: LEF output
7 * Written by: Steven M. Rubin, Static Free Software
8 *
9 * Copyright (c) 2000 Static Free Software.
10 *
11 * Electric(tm) is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * Electric(tm) is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Electric(tm); see the file COPYING. If not, write to
23 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24 * Boston, Mass 02111-1307, USA.
25 *
26 * Static Free Software
27 * 4119 Alpine Road
28 * Portola Valley, California 94028
29 * info@staticfreesoft.com
30 */
31
32 /*
33 * Note that this reader was built by examining LEF files and reverse-engineering them.
34 * It does not claim to be compliant with the LEF specification, but it also does not
35 * claim to define a new specification. It is merely incomplete.
36 */
37
38 #include "config.h"
39 #include "global.h"
40 #include "eio.h"
41 #include "usr.h"
42 #include "efunction.h"
43
44 /* prototypes for local routines */
45 static void io_lefoutcell(FILE *out, NODEPROTO *cell, BOOLEAN top, XARRAY trans);
46 static CHAR *io_lefoutlayername(TECHNOLOGY *tech, INTBIG layer);
47 static void io_lefoutspread(FILE *out, NODEPROTO *cell, NETWORK *net, NODEINST *ignore);
48 static void io_lefwritepoly(FILE *out, POLYGON *poly, XARRAY trans, TECHNOLOGY *tech);
49
50 static CHAR io_lefoutcurlayer[200];
51
io_writeleflibrary(LIBRARY * lib)52 BOOLEAN io_writeleflibrary(LIBRARY *lib)
53 {
54 CHAR file[100], *truename;
55 REGISTER CHAR *name;
56 REGISTER INTBIG i, tot;
57 REGISTER float xs, ys;
58 REGISTER NODEPROTO *np;
59 REGISTER NODEINST *rni, *ni;
60 REGISTER ARCINST *ai;
61 XARRAY trans, xform, temp;
62 REGISTER PORTPROTO *pp, *rpp;
63 static POLYGON *poly = NOPOLYGON;
64
65 /* get polygon */
66 (void)needstaticpolygon(&poly, 4, io_tool->cluster);
67
68 /* create the proper disk file for the LEF */
69 np = lib->curnodeproto;
70 if (np == NONODEPROTO)
71 {
72 ttyputerr(_("Must be editing a cell to generate LEF output"));
73 return(TRUE);
74 }
75 (void)estrcpy(file, np->protoname);
76 (void)estrcat(file, x_(".lef"));
77 name = truepath(file);
78 io_fileout = xcreate(name, io_filetypelef, _("LEF File"), &truename);
79 if (io_fileout == NULL)
80 {
81 if (truename != 0) ttyputerr(_("Cannot write %s"), truename);
82 return(TRUE);
83 }
84
85 /* write header information */
86 if ((us_useroptions&NODATEORVERSION) == 0)
87 {
88 xprintf(io_fileout, _("# Electric VLSI Design System, version %s\n"), el_version);
89 xprintf(io_fileout, x_("# %s\n\n"), timetostring(getcurrenttime()));
90 } else
91 {
92 xprintf(io_fileout, _("# Electric VLSI Design System\n"));
93 }
94 us_emitcopyright(io_fileout, x_("# "), x_(""));
95 xprintf(io_fileout, x_("NAMESCASESENSITIVE ON ;\n"));
96 xprintf(io_fileout, x_("UNITS\n"));
97 xprintf(io_fileout, x_(" DATABASE MICRONS 1 ;\n"));
98 xprintf(io_fileout, x_("END UNITS\n\n"));
99
100 /* write layer information */
101 for(i=0; i<8; i++)
102 {
103 xprintf(io_fileout, x_("LAYER METAL%ld\n"), i+1);
104 xprintf(io_fileout, x_(" TYPE ROUTING ;\n"));
105 xprintf(io_fileout, x_("END METAL%ld\n\n"), i+1);
106 }
107 xprintf(io_fileout, x_("LAYER CONT\n"));
108 xprintf(io_fileout, x_(" TYPE CUT ;\n"));
109 xprintf(io_fileout, x_("END CONT\n\n"));
110 for(i=0; i<3; i++)
111 {
112 xprintf(io_fileout, x_("LAYER VIA%ld%ld\n"), i+1, i+2);
113 xprintf(io_fileout, x_(" TYPE CUT ;\n"));
114 xprintf(io_fileout, x_("END VIA%ld%l\n\n"), i+1, i+2);
115 }
116 for(i=0; i<3; i++)
117 {
118 xprintf(io_fileout, x_("LAYER POLY%ld\n"), i+1);
119 xprintf(io_fileout, x_(" TYPE MASTERSLICE ;\n"));
120 xprintf(io_fileout, x_("END POLY%l\n\n"), i+1);
121 }
122 xprintf(io_fileout, x_("LAYER PDIFF\n"));
123 xprintf(io_fileout, x_(" TYPE MASTERSLICE ;\n"));
124 xprintf(io_fileout, x_("END PDIFF\n\n"));
125 xprintf(io_fileout, x_("LAYER NDIFF\n"));
126 xprintf(io_fileout, x_(" TYPE MASTERSLICE ;\n"));
127 xprintf(io_fileout, x_("END NDIFF\n\n"));
128
129 /* write main cell header */
130 xprintf(io_fileout, x_("MACRO %s\n"), np->protoname);
131 xprintf(io_fileout, x_(" FOREIGN %s ;\n"), np->protoname);
132 xs = scaletodispunit(np->highx-np->lowx, DISPUNITMIC);
133 ys = scaletodispunit(np->highy-np->lowy, DISPUNITMIC);
134 xprintf(io_fileout, x_(" SIZE %g BY %g ;\n"), xs, ys);
135 xprintf(io_fileout, x_(" SITE %s ;\n"), np->protoname);
136
137 /* write all of the metal geometry and ports */
138 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst) ni->temp1 = 0;
139 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst) ai->temp1 = 0;
140 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
141 {
142 if (pp != np->firstportproto) xprintf(io_fileout, x_("\n"));
143 xprintf(io_fileout, x_(" PIN %s\n"), pp->protoname);
144
145 transid(trans);
146 rpp = pp->subportproto;
147 rni = pp->subnodeinst;
148 makerot(rni, xform); transmult(xform, trans, temp); transcpy(temp, trans);
149 while (rni->proto->primindex == 0)
150 {
151 rni = rpp->subnodeinst;
152 rpp = rpp->subportproto;
153 maketrans(rni, xform); transmult(xform, trans, temp);
154 makerot(rni, xform); transmult(xform, temp, trans);
155 }
156 xprintf(io_fileout, x_(" PORT\n"));
157 io_lefoutcurlayer[0] = 0;
158 tot = nodeEpolys(rni, 0, NOWINDOWPART);
159 for(i=0; i<tot; i++)
160 {
161 shapeEnodepoly(rni, i, poly);
162 if (poly->portproto != rpp) continue;
163 io_lefwritepoly(io_fileout, poly, trans, rni->proto->tech);
164 }
165 io_lefoutspread(io_fileout, np, pp->network, ni);
166 xprintf(io_fileout, x_(" END\n"));
167 if ((pp->userbits&STATEBITS) == PWRPORT)
168 xprintf(io_fileout, x_(" USE POWER ;\n"));
169 if ((pp->userbits&STATEBITS) == GNDPORT)
170 xprintf(io_fileout, x_(" USE GROUND ;\n"));
171 xprintf(io_fileout, x_(" END %s\n"), pp->protoname);
172 }
173
174 /* write the obstructions (all of the metal) */
175 xprintf(io_fileout, x_("\n OBS\n"));
176 io_lefoutcurlayer[0] = 0;
177 io_lefoutcell(io_fileout, np, TRUE, el_matid);
178 xprintf(io_fileout, x_(" END\n\n"));
179
180 /* clean up */
181 xprintf(io_fileout, x_("END %s\n\n"), np->protoname);
182 xprintf(io_fileout, x_("END LIBRARY\n"));
183 xclose(io_fileout);
184
185 /* tell the user that the file is written */
186 ttyputmsg(_("%s written"), truename);
187 return(FALSE);
188 }
189
190 /*
191 * Routine to write all geometry in cell "cell" that is on network "net"
192 * to file "out". Does not write node "ignore".
193 */
io_lefoutspread(FILE * out,NODEPROTO * cell,NETWORK * net,NODEINST * ignore)194 void io_lefoutspread(FILE *out, NODEPROTO *cell, NETWORK *net, NODEINST *ignore)
195 {
196 REGISTER NODEINST *ni;
197 REGISTER ARCINST *ai;
198 REGISTER PORTARCINST *pi;
199 REGISTER INTBIG i, tot, fun;
200 XARRAY trans;
201 static POLYGON *poly = NOPOLYGON;
202
203 /* get polygon */
204 (void)needstaticpolygon(&poly, 4, io_tool->cluster);
205 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
206 {
207 if (ni->proto->primindex == 0) continue;
208 if (ni == ignore) continue;
209 fun = nodefunction(ni);
210 if (fun != NPPIN && fun != NPCONTACT && fun != NPNODE && fun != NPCONNECT)
211 continue;
212 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
213 if (pi->conarcinst->network != net) break;
214 if (pi != NOPORTARCINST) continue;
215
216 /* write all layers on this node */
217 ni->temp1 = 1;
218 makerot(ni, trans);
219 tot = nodepolys(ni, 0, NOWINDOWPART);
220 for(i=0; i<tot; i++)
221 {
222 shapenodepoly(ni, i, poly);
223 io_lefwritepoly(out, poly, trans, ni->proto->tech);
224 }
225 }
226
227 /* write metal layers for all arcs */
228 for(ai = cell->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
229 {
230 if (ai->network != net) continue;
231 ai->temp1 = 1;
232 tot = arcpolys(ai, NOWINDOWPART);
233 for(i=0; i<tot; i++)
234 {
235 shapearcpoly(ai, i, poly);
236 io_lefwritepoly(out, poly, trans, ai->proto->tech);
237 }
238 }
239 }
240
241 /*
242 * Routine to write all geometry in cell "cell" to file "out". The
243 * hierarchy is flattened. The current cell is transformed by "trans".
244 */
io_lefoutcell(FILE * out,NODEPROTO * cell,BOOLEAN top,XARRAY trans)245 void io_lefoutcell(FILE *out, NODEPROTO *cell, BOOLEAN top, XARRAY trans)
246 {
247 REGISTER NODEINST *ni;
248 REGISTER ARCINST *ai;
249 REGISTER INTBIG i, tot;
250 XARRAY localtran, subrot, localrot, thisrot;
251 static POLYGON *poly = NOPOLYGON;
252
253 /* get polygon */
254 (void)needstaticpolygon(&poly, 4, io_tool->cluster);
255 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
256 {
257 if (top && ni->temp1 != 0) continue;
258 makerot(ni, localrot); transmult(localrot, trans, thisrot);
259 if (ni->proto->primindex == 0)
260 {
261 /* subcell: recurse */
262 maketrans(ni, localtran);
263 transmult(localtran, thisrot, subrot);
264 io_lefoutcell(out, ni->proto, FALSE, subrot);
265 } else
266 {
267 /* primitive: find the metal layers */
268 tot = nodepolys(ni, 0, NOWINDOWPART);
269 for(i=0; i<tot; i++)
270 {
271 shapenodepoly(ni, i, poly);
272 io_lefwritepoly(out, poly, trans, ni->proto->tech);
273 }
274 }
275 }
276
277 /* write metal layers for all arcs */
278 for(ai = cell->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
279 {
280 if (top && ai->temp1 != 0) continue;
281 tot = arcpolys(ai, NOWINDOWPART);
282 for(i=0; i<tot; i++)
283 {
284 shapearcpoly(ai, i, poly);
285 io_lefwritepoly(out, poly, trans, ai->proto->tech);
286 }
287 }
288 }
289
290 /*
291 * Routine to write polygon "poly" from technology "tech", transformed by "trans",
292 * to "out".
293 */
io_lefwritepoly(FILE * out,POLYGON * poly,XARRAY trans,TECHNOLOGY * tech)294 void io_lefwritepoly(FILE *out, POLYGON *poly, XARRAY trans, TECHNOLOGY *tech)
295 {
296 INTBIG lx, hx, ly, hy;
297 REGISTER float flx, fhx, fly, fhy;
298 REGISTER CHAR *layername;
299
300 layername = io_lefoutlayername(tech, poly->layer);
301 if (*layername == 0) return;
302 xformpoly(poly, trans);
303 if (!isbox(poly, &lx, &hx, &ly, &hy)) return;
304 flx = scaletodispunit(lx, DISPUNITMIC);
305 fhx = scaletodispunit(hx, DISPUNITMIC);
306 fly = scaletodispunit(ly, DISPUNITMIC);
307 fhy = scaletodispunit(hy, DISPUNITMIC);
308 if (estrcmp(layername, io_lefoutcurlayer) != 0)
309 {
310 xprintf(out, x_(" LAYER %s ;\n"), layername);
311 estrcpy(io_lefoutcurlayer, layername);
312 }
313 xprintf(out, x_(" RECT %g %g %g %g ;\n"), flx, fly, fhx, fhy);
314 }
315
io_lefoutlayername(TECHNOLOGY * tech,INTBIG layer)316 CHAR *io_lefoutlayername(TECHNOLOGY *tech, INTBIG layer)
317 {
318 REGISTER INTBIG fun;
319
320 fun = layerfunction(tech, layer);
321 switch (fun&LFTYPE)
322 {
323 case LFMETAL1: return(x_("METAL1"));
324 case LFMETAL2: return(x_("METAL2"));
325 case LFMETAL3: return(x_("METAL3"));
326 case LFMETAL4: return(x_("METAL4"));
327 case LFMETAL5: return(x_("METAL5"));
328 case LFMETAL6: return(x_("METAL6"));
329 case LFMETAL7: return(x_("METAL7"));
330 case LFMETAL8: return(x_("METAL8"));
331 case LFMETAL9: return(x_("METAL9"));
332 case LFMETAL10: return(x_("METAL10"));
333 case LFMETAL11: return(x_("METAL11"));
334 case LFMETAL12: return(x_("METAL12"));
335 case LFCONTACT1: return(x_("CONT"));
336 case LFCONTACT2: return(x_("VIA12"));
337 case LFCONTACT3: return(x_("VIA23"));
338 case LFCONTACT4: return(x_("VIA34"));
339 case LFCONTACT5: return(x_("VIA45"));
340 case LFCONTACT6: return(x_("VIA56"));
341 case LFCONTACT7: return(x_("VIA67"));
342 case LFCONTACT8: return(x_("VIA78"));
343 case LFCONTACT9: return(x_("VIA89"));
344 case LFCONTACT10: return(x_("VIA9"));
345 case LFCONTACT11: return(x_("VIA10"));
346 case LFCONTACT12: return(x_("VIA11"));
347 case LFPOLY1: return(x_("POLY1"));
348 case LFPOLY2: return(x_("POLY2"));
349 case LFPOLY3: return(x_("POLY3"));
350 case LFDIFF:
351 if ((fun&LFPTYPE) != 0) return(x_("PDIFF"));
352 if ((fun&LFNTYPE) != 0) return(x_("NDIFF"));
353 return(x_("DIFF"));
354 }
355 return(x_(""));
356 }
357