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