1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: iogdso.c
6  * Input/output tool: GDS-II output
7  * Written by: Sid Penstone, Queens University
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 #include "config.h"
33 #include "global.h"
34 #include "eio.h"
35 #include "efunction.h"
36 #include "egraphics.h"
37 #include "tech.h"
38 #include "dbcontour.h"
39 #include "tecgen.h"
40 #include "tecart.h"
41 #include "edialogs.h"
42 
43 /* #define OLDGDS 1 */
44 
45 #define GDSVERSION            3
46 #define BYTEMASK           0xFF
47 #define NAMSIZE             100
48 #define DSIZE               512		/* data block */
49 #define MAXPOINTS           510		/* maximum points in a polygon */
50 #define EXPORTPRESENTATION    0		/* centered (was 8 for bottomleft) */
51 
52 /* GDSII bit assignments in STRANS record */
53 #define STRANS_REFLX     0x8000
54 #define STRANS_ABSA         0x2
55 
56 /* data type codes */
57 #define DTYP_NONE             0
58 
59 /* header codes */
60 #define HDR_HEADER       0x0002
61 #define HDR_BGNLIB       0x0102
62 #define HDR_LIBNAME      0x0206
63 #define HDR_UNITS        0x0305
64 #define HDR_ENDLIB       0x0400
65 #define HDR_BGNSTR       0x0502
66 #define HDR_STRNAME      0x0606
67 #define HDR_ENDSTR       0x0700
68 #define HDR_BOUNDARY     0x0800
69 #define HDR_PATH         0x0900
70 #define HDR_SREF         0x0A00
71 #define HDR_AREF	     0x0B00
72 #define HDR_TEXT	     0x0C00
73 #define HDR_LAYER        0x0D02
74 #define HDR_DATATYPE     0x0E02
75 #define HDR_XY           0x1003
76 #define HDR_ENDEL        0x1100
77 #define HDR_SNAME        0x1206
78 #define HDR_TEXTTYPE     0x1602
79 #define HDR_PRESENTATION 0x1701
80 #define HDR_STRING	     0x1906
81 #define HDR_STRANS       0x1A01
82 #define HDR_MAG          0x1B05
83 #define HDR_ANGLE        0x1C05
84 
85 /* Header byte counts */
86 #define HDR_N_BGNLIB         28
87 #define HDR_N_UNITS          20
88 #define HDR_N_ANGLE          12
89 #define HDR_N_MAG            12
90 
91 /* Maximum string sizes  */
92 #define HDR_M_SNAME          32
93 #define HDR_M_STRNAME        32
94 #define HDR_M_ASCII         256
95 
96 /* contour gathering thresholds for polygon accumulation */
97 #define BESTTHRESH           0.001			/* 1/1000 of a millimeter */
98 #define WORSTTHRESH          0.1			/* 1/10 of a millimeter */
99 
100 typedef struct
101 {
102 	INTBIG layernumber;
103 	INTBIG pinnumber;
104 	INTBIG textnumber;
105 } LAYERNUMBERS;
106 
107 static UCHAR1  *io_dbuffer= 0, *io_empty;	/* for buffering output data  */
108 static INTBIG  io_gds_curlayer;				/* Current layer for gds output */
109 static INTBIG  io_gds_pos;					/* Position of next byte in the buffer */
110 static INTBIG  io_gds_block;				/* Number data buffers output so far */
111 static FILE   *io_gds_outfd;				/* File descriptor for output */
112 static INTBIG *io_gds_outputstate;			/* current output state */
113 static INTBIG  io_gds_polypoints;			/* number of allowable points on a polygon */
114 static double  io_gds_scale;				/* constant */
115 static INTBIG  io_gds_layerkey;				/* key for "IO_gds_layer" */
116 static INTBIG  io_gds_exportlayer;			/* layer for export text */
117 
118 /* working memory for "io_gds_bgnstr()" */
119 static INTBIG  io_gdscellnamecount;
120 static INTBIG  io_gdscellnametotal = 0;
121 static CHAR  **io_gdscellnames;
122 
123 /* prototypes for local routines */
124 static void  io_gdswritecell(NODEPROTO*);
125 static void  io_outputgdspoly(TECHNOLOGY*, POLYGON*, INTBIG, INTBIG, INTBIG, XARRAY, INTBIG);
126 static void  io_gds_set_layer(INTBIG);
127 static void  io_gds_initialize(void);
128 static void  io_gds_closefile(void);
129 static void  io_gds_bgnlib(NODEPROTO*);
130 static void  io_gds_bgnstr(NODEPROTO*);
131 static void  io_gds_date(time_t*);
132 static void  io_gds_header(INTBIG, INTBIG);
133 static void  io_gds_name(INTBIG, CHAR*, INTBIG);
134 static void  io_gds_angle(INTBIG);
135 static void  io_gds_mag(double scale);
136 static void  io_gds_boundary(POLYGON*);
137 static void  io_gds_path(POLYGON*);
138 static void  io_gds_byte(UCHAR1);
139 static void  io_gds_int2(INTSML);
140 static void  io_gds_int4(INTBIG);
141 static void  io_gds_int2_arr(INTSML*, INTBIG);
142 static void  io_gds_int4_arr(INTBIG*, INTBIG);
143 static void  io_gds_string(CHAR*, INTBIG);
144 static void  io_gds_write_polygon(INTBIG, TECHNOLOGY*, INTBIG*, INTBIG*, INTBIG);
145 static CHAR *io_gds_makename(CHAR*);
146 static void  io_gds_cvfloat8(double*, UINTBIG*, UINTBIG*);
147 static void  io_gdsoptionsdlog(void);
148 static CHAR *io_gds_uniquename(NODEPROTO *np);
149 static void  io_gds_parselayerstring(CHAR *string, CHAR **val, CHAR **pinval, CHAR **textval);
150 
151 /*
152  * Routine to free all memory associated with this module.
153  */
io_freegdsoutmemory(void)154 void io_freegdsoutmemory(void)
155 {
156 	REGISTER INTBIG i;
157 
158 	if (io_dbuffer != 0) efree((CHAR *)io_dbuffer);
159 	if (io_empty != 0) efree((CHAR *)io_empty);
160 
161 	for(i=0; i<io_gdscellnametotal; i++)
162 		if (io_gdscellnames[i] != 0)
163 			efree((CHAR *)io_gdscellnames[i]);
164 	if (io_gdscellnametotal > 0)
165 		efree((CHAR *)io_gdscellnames);
166 }
167 
168 /*
169  * Routine to initialize GDS I/O.
170  */
io_initgds(void)171 void io_initgds(void)
172 {
173 	extern COMCOMP io_gdsp;
174 
175 	DiaDeclareHook(x_("gdsopt"), &io_gdsp, io_gdsoptionsdlog);
176 }
177 
io_writegdslibrary(LIBRARY * lib)178 BOOLEAN io_writegdslibrary(LIBRARY *lib)
179 {
180 	CHAR *name, *truename, *val, *pinval, *textval;
181 	REGISTER NODEPROTO *np;
182 	REGISTER VARIABLE *var;
183 	REGISTER INTBIG i, varlen;
184 	REGISTER LAYERNUMBERS *layernumbers;
185 	REGISTER TECHNOLOGY *tech;
186 	REGISTER LIBRARY *olib;
187 	REGISTER void *infstr;
188 
189 	/* create the proper disk file for the GDS II */
190 	if (lib->curnodeproto == NONODEPROTO)
191 	{
192 		ttyputerr(_("Must be editing a cell to generate GDS output"));
193 		return(TRUE);
194 	}
195 
196 	/* construct file name */
197 	infstr = initinfstr();
198 	addstringtoinfstr(infstr, lib->curnodeproto->protoname);
199 	addstringtoinfstr(infstr, x_(".gds"));
200 	(void)allocstring(&name, truepath(returninfstr(infstr)), el_tempcluster);
201 
202 	/* get the file */
203 	io_gds_outfd = xcreate(name, io_filetypegds, _("GDS File"), &truename);
204 	if (io_gds_outfd == NULL)
205 	{
206 		if (truename != 0) ttyputerr(_("Cannot write %s"), truename);
207 		efree(name);
208 		return(TRUE);
209 	}
210 
211 	/* get current output state */
212 	io_gds_outputstate = io_getstatebits();
213 	var = getval((INTBIG)el_curtech, VTECHNOLOGY, VINTEGER|VISARRAY,
214 		x_("IO_gds_export_layer"));
215 	if (var == NOVARIABLE) io_gds_exportlayer = 230; else
216 		io_gds_exportlayer = var->addr;
217 
218 	/* get the number of allowable points on a polygon */
219 	var = getval((INTBIG)el_curtech, VTECHNOLOGY, VINTEGER, x_("IO_gds_polypoints"));
220 	if (var == NOVARIABLE) io_gds_polypoints = 200; else /* 200 is the MAX allowed in GDS-II */
221 		io_gds_polypoints = var->addr;
222 
223 	/* initialize cache of layer information */
224 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
225 	{
226 		tech->temp1 = 0;
227 		var = getval((INTBIG)tech, VTECHNOLOGY, -1, x_("IO_gds_layer_numbers"));
228 		if (var != NOVARIABLE && (var->type&VISARRAY) != 0)
229 			tech->temp1 = var->addr;
230 
231 		/* if ignoring DRC mask layer, delete Generic technology layer names */
232 		if (tech == gen_tech && (io_gds_outputstate[0]&GDSOUTADDDRC) == 0) tech->temp1 = 0;
233 
234 		/* create an array of layer numbers from the string names */
235 		if (tech->temp1 != 0)
236 		{
237 			layernumbers = (LAYERNUMBERS *)emalloc(tech->layercount * (sizeof (LAYERNUMBERS)), io_tool->cluster);
238 			if (layernumbers == 0) return(TRUE);
239 			varlen = getlength(var);
240 			for(i=0; i<tech->layercount; i++)
241 			{
242 				if ((var->type&VTYPE) == VSTRING && i < varlen)
243 				{
244 					io_gds_parselayerstring(((CHAR **)tech->temp1)[i], &val, &pinval, &textval);
245 					layernumbers[i].layernumber = myatoi(val);
246 					if (*pinval == 0) layernumbers[i].pinnumber = -1; else
247 						layernumbers[i].pinnumber = myatoi(pinval);
248 					if (*textval == 0) layernumbers[i].textnumber = -1; else
249 						layernumbers[i].textnumber = myatoi(textval);
250 				} else
251 				{
252 					layernumbers[i].layernumber = ((INTBIG *)tech->temp1)[i];
253 					layernumbers[i].pinnumber = 0;
254 					layernumbers[i].textnumber = 0;
255 				}
256 			}
257 			tech->temp1 = (INTBIG)layernumbers;
258 		}
259 
260 		/* layer names for bloating */
261 		var = getval((INTBIG)tech, VTECHNOLOGY, VSTRING|VISARRAY, x_("TECH_layer_names"));
262 		tech->temp2 = (var == NOVARIABLE ? 0 : var->addr);
263 	}
264 
265 	/* make sure key for individual layer overrides is set */
266 	io_gds_layerkey = makekey(x_("IO_gds_layer"));
267 
268 	/* warn if current technology has no GDS layers */
269 	if (el_curtech->temp1 == 0)
270 		ttyputmsg(_("Warning: there are no GDS II layers defined for the %s technology"),
271 			el_curtech->techname);
272 
273 	if ((io_gds_outputstate[0]&GDSOUTMERGE) != 0) mrginit();
274 
275 	io_gds_initialize();
276 	io_gds_bgnlib(lib->curnodeproto);
277 
278 	/* write the GDS-II */
279 	for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
280 		for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
281 			np->temp1 = 0;
282 	io_gdswritecell(lib->curnodeproto);
283 
284 	/* clean up */
285 	io_gds_header(HDR_ENDLIB, 0);
286 	io_gds_closefile();
287 
288 	if ((io_gds_outputstate[0]&GDSOUTMERGE) != 0) mrgterm();
289 	for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
290 	{
291 		for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
292 		{
293 			if (np->temp1 != 0) efree((CHAR *)np->temp1);
294 		}
295 	}
296 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
297 	{
298 		if (tech->temp1 != 0) efree((CHAR *)tech->temp1);
299 	}
300 
301 	/* tell the user that the file is written */
302 	ttyputmsg(_("%s written"), truename);
303 	efree(name);
304 	return(FALSE);
305 }
306 
io_gdswritecell(NODEPROTO * np)307 void io_gdswritecell(NODEPROTO *np)
308 {
309 	REGISTER NODEINST *subno, *bottomni;
310 	REGISTER ARCINST *subar;
311 	REGISTER NODEPROTO *subnt, *onp;
312 	REGISTER PORTPROTO *pp, *bottompp;
313 	REGISTER VARIABLE *var;
314 	REGISTER INTBIG i, j, tot, fun, displaytotal, layeroverride, oldbits,
315 		offx, offy, bestthresh, worstthresh, textlayer, pinlayer,
316 		angle, transvalue, gatherpolygon;
317 	INTBIG xpos, ypos, bx, by, fx, fy, tx, ty;
318 	XARRAY trans, localtran, temptrans;
319 	REGISTER LAYERNUMBERS *laynum;
320 	static POLYGON *poly = NOPOLYGON;
321 	CHAR str[513];
322 	REGISTER CONTOUR *con, *nextcon, *contourlist;
323 	REGISTER CONTOURELEMENT *conel;
324 #ifdef OLDGDS
325 	REGISTER NODEPROTO *bodysubnt;
326 	INTBIG cx, cy;
327 #endif
328 
329 	/* if there are any sub-cells that have not been written, write them */
330 	for(subno = np->firstnodeinst; subno != NONODEINST; subno = subno->nextnodeinst)
331 	{
332 		subnt = subno->proto;
333 		if (subnt->primindex != 0) continue;
334 
335 		/* ignore recursive references (showing icon in contents) */
336 		if (isiconof(subnt, np)) continue;
337 
338 		/* convert body cells to contents cells */
339 		onp = contentsview(subnt);
340 		if (onp != NONODEPROTO) subnt = onp;
341 
342 		/* don't recurse if this cell has already been written */
343 		if (subnt->temp1 != 0) continue;
344 
345 		/* recurse to the bottom */
346 		io_gdswritecell(subnt);
347 	}
348 
349 	/* get polygon */
350 	(void)needstaticpolygon(&poly, 4, io_tool->cluster);
351 
352 	/* write this cell */
353 	io_gds_set_layer(0);
354 	(void)allocstring((CHAR **)&np->temp1, io_gds_uniquename(np), io_tool->cluster);
355 #ifdef OLDGDS
356 	offx = (np->lowx + np->highx) / 2;
357 	offy = (np->lowy + np->highy) / 2;
358 #else
359 	offx = offy = 0;
360 #endif
361 	io_gds_bgnstr(np);
362 
363 	/* see if there are any outline nodes (opened polygon or circle arcs) */
364 	gatherpolygon = 0;
365 	for(subno = np->firstnodeinst; subno != NONODEINST; subno = subno->nextnodeinst)
366 	{
367 		if (subno->proto == art_openedpolygonprim || subno->proto == art_circleprim ||
368 			subno->proto == art_thickcircleprim)
369 		{
370 			gatherpolygon = 1;
371 			break;
372 		}
373 	}
374 	if (gatherpolygon != 0)
375 	{
376 		bestthresh = scalefromdispunit((float)BESTTHRESH, DISPUNITMM);
377 		worstthresh = scalefromdispunit((float)WORSTTHRESH, DISPUNITMM);
378 		contourlist = gathercontours(np, 0, bestthresh, worstthresh);
379 
380 		/* mark all nodes not in contours as not-written */
381 		for(subno = np->firstnodeinst; subno != NONODEINST; subno = subno->nextnodeinst)
382 			subno->temp1 = 0;
383 
384 		/* write the contour polygons */
385 		for(con = contourlist; con != NOCONTOUR; con = con->nextcontour)
386 		{
387 			poly->count = 0;
388 			poly->style = OPENED;
389 			poly->layer = 0;
390 
391 			/* add in first point of contour */
392 			if (poly->count+1 >= poly->limit)
393 				(void)extendpolygon(poly, poly->count+1);
394 			poly->xv[poly->count] = con->firstcontourelement->sx;
395 			poly->yv[poly->count] = con->firstcontourelement->sy;
396 			poly->count++;
397 			layeroverride = -1;
398 			for(conel = con->firstcontourelement; conel != NOCONTOURELEMENT; conel = conel->nextcontourelement)
399 			{
400 				conel->ni->temp1 = 1;
401 				switch (conel->elementtype)
402 				{
403 					case ARCSEGMENTTYPE:
404 					case REVARCSEGMENTTYPE:
405 					case CIRCLESEGMENTTYPE:
406 						initcontoursegmentgeneration(conel);
407 						for(;;)
408 						{
409 							if (nextcontoursegmentgeneration(&fx, &fy, &tx, &ty)) break;
410 							if (poly->count+1 >= poly->limit)
411 								(void)extendpolygon(poly, poly->count+1);
412 							poly->xv[poly->count] = tx;
413 							poly->yv[poly->count] = ty;
414 							poly->count++;
415 						}
416 						break;
417 					case LINESEGMENTTYPE:
418 						if (poly->count+1 >= poly->limit)
419 							(void)extendpolygon(poly, poly->count+1);
420 						poly->xv[poly->count] = conel->ex;
421 						poly->yv[poly->count] = conel->ey;
422 						poly->count++;
423 						break;
424 					default:
425 						break;
426 				}
427 				var = getvalkey((INTBIG)conel->ni, VNODEINST, VINTEGER, io_gds_layerkey);
428 				if (var != NOVARIABLE) layeroverride = var->addr;
429 			}
430 			io_outputgdspoly(art_tech, poly, 0, offx, offy, el_matid, layeroverride);
431 		}
432 
433 		/* dispose the data */
434 		for(con = contourlist; con != NOCONTOUR; con = nextcon)
435 		{
436 			nextcon = con->nextcontour;
437 			killcontour(con);
438 		}
439 	} else
440 	{
441 		/* mark all nodes as not-written */
442 		for(subno = np->firstnodeinst; subno != NONODEINST; subno = subno->nextnodeinst)
443 			subno->temp1 = 0;
444 	}
445 
446 	/* write all nodes in the cell */
447 	for(subno = np->firstnodeinst; subno != NONODEINST; subno = subno->nextnodeinst)
448 	{
449 		if (subno->temp1 != 0) continue;
450 		subno->temp1 = 1;
451 
452 		layeroverride = -1;
453 		var = getvalkey((INTBIG)subno, VNODEINST, VINTEGER, io_gds_layerkey);
454 		if (var != NOVARIABLE) layeroverride = var->addr;
455 		subnt = subno->proto;
456 		angle = subno->rotation;
457 		if (subno->transpose != 0) angle = (angle + 900) % 3600;
458 		makerot(subno, trans);
459 		if (subnt->primindex != 0)
460 		{
461 			/* don't draw anything if the node is wiped out */
462 			if ((subno->userbits&WIPED) != 0) continue;
463 
464 			/* check for displayable variables */
465 			displaytotal = tech_displayablenvars(subno, NOWINDOWPART, &tech_oneprocpolyloop);
466 			if (displaytotal != 0)
467 			{
468 				/* get the first polygon off the node, this is the text layer */
469 				shapenodepoly(subno, 0, poly);
470 
471 				/* determine the layer name for this polygon */
472 				if (poly->layer < 0 || subnt->tech->temp1 == 0) continue;
473 				laynum = &((LAYERNUMBERS *)subnt->tech->temp1)[poly->layer];
474 				io_gds_set_layer(laynum->layernumber);
475 
476 				for (i=0; i<displaytotal; i++)
477 				{
478 					(void)tech_filldisplayablenvar(subno, poly, NOWINDOWPART, 0, &tech_oneprocpolyloop);
479 
480 					/* dump this text field */
481 					io_gds_header(HDR_TEXT, 0);
482 					io_gds_header(HDR_LAYER, io_gds_curlayer);
483 					io_gds_header(HDR_TEXTTYPE, 0);
484 					io_gds_header(HDR_PRESENTATION, EXPORTPRESENTATION);
485 
486 					/* now the orientation */
487 					transvalue = 0;
488 					if (subno->transpose != 0)
489 					{
490 						/* Angles are reversed  */
491 						transvalue |= STRANS_REFLX;
492 						angle = (3600 - angle)%3600;
493 					}
494 					io_gds_header(HDR_STRANS, transvalue);
495 					io_gds_angle(angle);
496 					io_gds_int2(12);
497 					io_gds_int2(HDR_XY);
498 					io_gds_int4(rounddouble(io_gds_scale*(double)poly->xv[0]));
499 					io_gds_int4(rounddouble(io_gds_scale*(double)poly->yv[0]));
500 
501 					/* now the string */
502 					j = estrlen (poly->string);
503 					if (j > 512) j = 512;
504 					estrncpy (str, poly->string, j);
505 
506 					/* pad with a blank */
507 					if (j&1) str[j++] = ' ';
508 					str[j] = '\0';
509 					io_gds_int2((INTSML)(4+j));
510 					io_gds_int2(HDR_STRING);
511 					io_gds_string(str, j);
512 					io_gds_header(HDR_ENDEL, 0);
513 
514 					/* write out the node the text is attached to */
515 					/* RLW - Queen's */
516 					i = nodepolys(subno, 0, NOWINDOWPART);
517 					for (j=0; j<i; j++)
518 					{
519 						shapenodepoly(subno, j, poly);
520 						io_outputgdspoly(subnt->tech, poly, angle, offx, offy, trans, layeroverride);
521 					}
522 				}
523 			} else
524 			{
525 				/* write a primitive nodeinst */
526 				i = nodepolys(subno, 0, NOWINDOWPART);
527 				for(j=0; j<i; j++)
528 				{
529 					shapenodepoly(subno, j, poly);
530 					io_outputgdspoly(subnt->tech, poly, angle, offx, offy, trans, layeroverride);
531 				}
532 			}
533 		} else
534 		{
535 			/* ignore recursive references (showing icon in contents) */
536 			if (isiconof(subno->proto, np)) continue;
537 
538 			/* write a call to a cell */
539 #ifdef OLDGDS
540 			xpos = (subno->lowx + subno->highx) / 2 - offx;
541 			ypos = (subno->lowy + subno->highy) / 2 - offy;
542 
543 			/* convert body cells to contents cells */
544 			onp = contentsview(subnt);
545 			if (onp != NONODEPROTO)
546 			{
547 				/* look for grab points in contents and body cells */
548 				bodysubnt = subnt;
549 				subnt = onp;
550 				corneroffset(subno, bodysubnt, subno->rotation, subno->transpose, &bx, &by, FALSE);
551 				corneroffset(NONODEINST, subnt, subno->rotation, subno->transpose, &cx, &cy, FALSE);
552 				xpos = subno->lowx + bx - cx + (subnt->highx-subnt->lowx)/2 - offx;
553 				ypos = subno->lowy + by - cy + (subnt->highy-subnt->lowy)/2 - offy;
554 			}
555 #else
556 			/* now origin, normal placement */
557 			bx = (subno->lowx - subno->proto->lowx);
558 			by = (subno->lowy - subno->proto->lowy);
559 			xform(bx, by, &xpos, &ypos, trans);
560 #endif
561 
562 			/* Generate a symbol reference  */
563 			io_gds_header(HDR_SREF, 0);
564 			io_gds_name(HDR_SNAME, (CHAR *)subnt->temp1, HDR_M_SNAME);
565 			transvalue = 0;
566 			if (subno->transpose != 0)
567 			{
568 				/* Angles are reversed */
569 				transvalue |= STRANS_REFLX;
570 				angle = (3600 - angle)%3600;
571 			}
572 #ifdef OLDGDS
573 			if (angle != 0) transvalue |= STRANS_ABSA;
574 			if (transvalue != 0) io_gds_header(HDR_STRANS, transvalue);
575 			if (angle != 0) io_gds_angle(angle);
576 #else
577 			/* always output the angle and transvalue */
578 			io_gds_header(HDR_STRANS, transvalue);
579 			io_gds_angle(angle);
580 #endif
581 			io_gds_int2(12);
582 			io_gds_int2(HDR_XY);
583 			io_gds_int4(rounddouble(io_gds_scale*(double)xpos));
584 			io_gds_int4(rounddouble(io_gds_scale*(double)ypos));
585 			io_gds_header(HDR_ENDEL, 0);
586 		}
587 	}
588 
589 	/* now do the arcs in the cell */
590 	for(subar = np->firstarcinst; subar != NOARCINST; subar = subar->nextarcinst)
591 	{
592 		/* arcinst: ask the technology how to draw it */
593 		i = arcpolys(subar, NOWINDOWPART);
594 		var = getvalkey((INTBIG)subar, VARCINST, VINTEGER, io_gds_layerkey);
595 		if (var != NOVARIABLE) layeroverride = var->addr;
596 
597 		/* plot each layer of the arcinst */
598 		for(j=0; j<i; j++)
599 		{
600 			/* write the box describing the layer */
601 			shapearcpoly(subar, j, poly);
602 			io_outputgdspoly(subar->proto->tech, poly, 0, offx, offy, el_matid, layeroverride);
603 		}
604 	}
605 
606 	/* now write exports */
607 	if (io_gds_exportlayer >= 0)
608 	{
609 		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
610 		{
611 			/* find the node at the bottom of this export */
612 			bottomni = pp->subnodeinst;
613 			bottompp = pp->subportproto;
614 			makerot(bottomni, trans);
615 			while (bottomni->proto->primindex == 0)
616 			{
617 				maketrans(bottomni, localtran);
618 				transmult(localtran, trans, temptrans);
619 				bottomni = bottompp->subnodeinst;
620 				bottompp = bottompp->subportproto;
621 				makerot(bottomni, localtran);
622 				transmult(localtran, temptrans, trans);
623 			}
624 
625 			/* find the layer associated with this node */
626 			oldbits = bottomni->userbits;
627 			bottomni->userbits &= ~WIPED;
628 			tot = nodepolys(bottomni, 0, NOWINDOWPART);
629 			shapenodepoly(bottomni, 0, poly);
630 			bottomni->userbits = oldbits;
631 			fun = layerfunction(poly->tech, poly->layer);
632 			if ((fun&LFPSEUDO) != 0)
633 				poly->layer = nonpseudolayer(poly->layer, poly->tech);
634 
635 			textlayer = pinlayer = io_gds_exportlayer;
636 			if (poly->layer >= 0 && poly->tech->temp1 != 0)
637 			{
638 				laynum = &((LAYERNUMBERS *)poly->tech->temp1)[poly->layer];
639 				if (laynum->pinnumber >= 0) pinlayer = laynum->pinnumber;
640 				if (laynum->textnumber >= 0) textlayer = laynum->textnumber;
641 			}
642 
643 			/* put out a pin if requested */
644 			if ((io_gds_outputstate[1]&GDSOUTPINS) != 0)
645 			{
646 				io_outputgdspoly(poly->tech, poly, 0, offx, offy, trans, pinlayer);
647 			}
648 
649 			io_gds_header(HDR_TEXT, 0);
650 			io_gds_header(HDR_LAYER, textlayer);
651 			io_gds_header(HDR_TEXTTYPE, 0);
652 			io_gds_header(HDR_PRESENTATION, EXPORTPRESENTATION);
653 
654 			/* now the orientation */
655 			subno = pp->subnodeinst;
656 			transvalue = 0;
657 			if (subno->transpose != 0)
658 			{
659 				/* Angles are reversed  */
660 				transvalue |= STRANS_REFLX;
661 				angle = (3600 - angle)%3600;
662 			}
663 			io_gds_header(HDR_STRANS, transvalue);
664 			io_gds_mag(0.5);
665 			io_gds_angle(angle);
666 			io_gds_int2(12);
667 			io_gds_int2(HDR_XY);
668 			portposition(subno, pp->subportproto, &bx, &by);
669 			io_gds_int4(rounddouble(io_gds_scale*(double)bx));
670 			io_gds_int4(rounddouble(io_gds_scale*(double)by));
671 
672 			/* now the string */
673 			j = estrlen(pp->protoname);
674 			if (j > 512) j = 512;
675 			estrncpy(str, pp->protoname, j);
676 
677 			/* pad with a blank */
678 			if (j&1) str[j++] = ' ';
679 			str[j] = '\0';
680 			io_gds_int2((INTSML)(4+j));
681 			io_gds_int2(HDR_STRING);
682 			io_gds_string(str, j);
683 			io_gds_header(HDR_ENDEL, 0);
684 		}
685 	}
686 
687 	if ((io_gds_outputstate[0]&GDSOUTMERGE) != 0)
688 		mrgdonecell(io_gds_write_polygon);
689 
690 	io_gds_header(HDR_ENDSTR, 0);
691 }
692 
693 /*
694  * routine to write polygon "poly" to the GDS-II file.  The polygon is from
695  * technology "tech", is rotated by the angle "angle", and is offset
696  * by "offx" and "offy" in its parent cell.  If "layeroverride" is not -1,
697  * it is the layer number to use (an override).
698  */
io_outputgdspoly(TECHNOLOGY * tech,POLYGON * poly,INTBIG angle,INTBIG offx,INTBIG offy,XARRAY trans,INTBIG layeroverride)699 void io_outputgdspoly(TECHNOLOGY *tech, POLYGON *poly, INTBIG angle, INTBIG offx,
700 	INTBIG offy, XARRAY trans, INTBIG layeroverride)
701 {
702 	REGISTER INTBIG r, bloat;
703 	INTBIG i, layernumber, xl, xh, yl, yh, xpos, ypos;
704 	REGISTER LAYERNUMBERS *laynum;
705 	static POLYGON *poly2 = NOPOLYGON;
706 	REGISTER void *infstr;
707 
708 	(void)needstaticpolygon(&poly2, 4, io_tool->cluster);
709 
710 	/* determine the layer name for this polygon */
711 	if (layeroverride != -1) layernumber = layeroverride; else
712 	{
713 		if (poly->layer < 0 || tech->temp1 == 0) return;
714 		laynum = &((LAYERNUMBERS *)tech->temp1)[poly->layer];
715 		layernumber = laynum->layernumber;
716 		if (layernumber < 0) return;
717 	}
718 	io_gds_set_layer(layernumber);
719 
720 	/* determine bloat factor */
721 	if (poly->layer < 0 || tech->temp2 == 0) bloat = 0; else
722 	{
723 		infstr = initinfstr();
724 		addstringtoinfstr(infstr, tech->techname);
725 		addtoinfstr(infstr, ':');
726 		addstringtoinfstr(infstr, ((CHAR **)tech->temp2)[poly->layer]);
727 		bloat = io_getoutputbloat(returninfstr(infstr));
728 	}
729 
730 	switch (poly->style)
731 	{
732 		case DISC:      /* Make a square of the size of the diameter  */
733 			xformpoly(poly, trans);
734 			r = computedistance(poly->xv[0], poly->yv[0], poly->xv[1], poly->yv[1]);
735 			if (r <= 0) break;
736 			xform(poly->xv[0], poly->yv[0], &xpos, &ypos, trans);
737 			xl = xpos - offx - (r + bloat/2);
738 			xh = xl + 2*r + bloat;
739 			yl = ypos - offy - (r + bloat/2);
740 			yh = yl + 2*r + bloat;
741 			makerectpoly(xl, xh, yl, yh, poly2);
742 			io_gds_boundary(poly2);
743 			return;
744 
745 		default:
746 			if (isbox(poly, &xl,&xh, &yl,&yh))
747 			{
748 				/* rectangular manhattan shape */
749 				if (xh == xl || yh == yl) return;
750 
751 				/* find the center of this polygon, inside the cell */
752 				xform((xl+xh)/2, (yl+yh)/2, &xpos, &ypos, trans);
753 
754 				if ((io_gds_outputstate[0]&GDSOUTMERGE) != 0 && angle%900 == 0)
755 				{
756 					/* do polygon format output */
757 					if (angle%1800 == 0)
758 						mrgstorebox(layernumber, tech, xh-xl+bloat, yh-yl+bloat, xpos-offx, ypos-offy);
759 					else	/* rotated by 90 degrees */
760 						mrgstorebox(layernumber, tech, yh-yl+bloat, xh-xl+bloat, xpos-offx, ypos-offy);
761 				} else    /* Output as a single box */
762 				{
763 					makerectpoly(xl-bloat/2, xh+bloat/2, yl-bloat/2, yh+bloat/2, poly2);
764 					switch(poly->style)
765 					{
766 						case FILLEDRECT: poly2->style = FILLED;    break;
767 						case CLOSEDRECT: poly2->style = CLOSED;    break;
768 						default:         poly2->style = poly->style;
769 					}
770 					xformpoly(poly2, trans); /* in 4.05, did this only for angle = 0 */
771 
772 					/* Now output the box as a set of points  */
773 					for (i = 0; i < poly2->count; i++)
774 					{
775 						poly2->xv[i] = poly2->xv[i] - offx;
776 						poly2->yv[i] = poly2->yv[i] - offy;
777 					}
778 					io_gds_boundary(poly2);
779 				}
780 				break;
781 			}
782 
783 			/* non-manhattan or worse .. direct output */
784 			if (bloat != 0 && poly->count > 4)
785 				ttyputmsg(_("Warning: complex polygon cannot be bloated"));
786 			xformpoly(poly, trans); /* was missing in 4.05 (SRP) */
787 			if (poly->count == 1)
788 			{
789 				ttyputerr(_("Single point cannot be written in GDS-II"));
790 				break;
791 			}
792 
793 			/* polygonally defined shape or a line */
794 			if (poly2->limit < poly->count)	 /* SRP */
795 				(void)extendpolygon(poly2, poly->count);
796 
797 			for (i = 0; i < poly->count; i++)
798 			{
799 				poly2->xv[i] = poly->xv[i] - offx;
800 				poly2->yv[i] = poly->yv[i] - offy;
801 			}
802 			poly2->count = poly->count;
803 			if (poly->count == 2) io_gds_path(poly2); else
804 				io_gds_boundary(poly2);
805 			break;
806 	}
807 }
808 
809 /*
810  * routine to set the correct layer in "layer" for later output.
811  */
io_gds_set_layer(INTBIG layer)812 void io_gds_set_layer(INTBIG layer)
813 {
814 	io_gds_curlayer = layer;
815 }
816 
817 /*************************** GDS OUTPUT ROUTINES ***************************/
818 
819 /* Initialize various fields, get some standard values */
io_gds_initialize(void)820 void io_gds_initialize(void)
821 {
822 	INTBIG i;
823 
824 	io_gds_block = 0;
825 	io_gds_pos = 0;
826 	io_gds_set_layer(0);
827 	if (io_dbuffer == 0)
828 	{
829 		io_dbuffer = (UCHAR1 *)emalloc(DSIZE, io_tool->cluster);
830 		io_empty = (UCHAR1 *)emalloc(DSIZE, io_tool->cluster);
831 
832 		/* all zeroes, even if malloc() did it  */
833 		for (i=0; i<DSIZE; i++) io_empty[i] = 0;
834 	}
835 	io_gds_scale = 1000.0 / (double)scalefromdispunit(1.0, DISPUNITMIC);
836 }
837 
838 /*
839  * Close the file, pad to make the file match the tape format
840  */
io_gds_closefile(void)841 void io_gds_closefile(void)
842 {
843 	INTBIG i;
844 
845 	/* Write out the current buffer */
846 	if (io_gds_pos > 0)
847 	{
848 		/* Pack with zeroes */
849 		for (i = io_gds_pos; i < DSIZE; i++) io_dbuffer[i] = 0;
850 		(void)xfwrite(io_dbuffer, DSIZE, 1, io_gds_outfd);
851 		io_gds_block++;
852 	}
853 
854 	/*  Pad to 2048  */
855 	while (io_gds_block%4 != 0)
856 	{
857 		(void)xfwrite(io_empty, DSIZE, 1, io_gds_outfd);
858 		io_gds_block++;
859 	}
860 	xclose(io_gds_outfd);
861 }
862 
863 /* Write a library header, get the date information */
io_gds_bgnlib(NODEPROTO * np)864 void io_gds_bgnlib(NODEPROTO *np)
865 {
866 	CHAR name[NAMSIZE];
867 	double xnum;
868 	static INTBIG units[4];
869 	/* GDS floating point values - -
870 	 * 0x3E418937,0x4BC6A7EF = 0.001
871 	 * 0x3944B82F,0xA09B5A53 = 1e-9
872 	 * 0x3F28F5C2,0x8F5C28F6 = 0.01
873 	 * 0x3A2AF31D,0xC4611874 = 1e-8
874 	 */
875 
876 	/* set units */
877 	/* modified 9 april 92 - RLW */
878 	xnum = 1e-3;
879 	io_gds_cvfloat8(&xnum, (UINTBIG *)&units[0], (UINTBIG *)&units[1]);
880 	xnum = 1.0e-9;
881 	io_gds_cvfloat8(&xnum, (UINTBIG *)&units[2], (UINTBIG *)&units[3]);
882 
883 	io_gds_header(HDR_HEADER, GDSVERSION);
884 	io_gds_header(HDR_BGNLIB, 0);
885 	io_gds_date((time_t *)&np->creationdate);
886 	io_gds_date((time_t *)&np->revisiondate);
887 	(void)estrcpy(name, np->protoname);
888 	io_gds_name(HDR_LIBNAME, io_gds_makename(name), HDR_M_ASCII);
889 	io_gds_int2(HDR_N_UNITS);
890 	io_gds_int2(HDR_UNITS);
891 	io_gds_int4_arr(units, 4);
892 }
893 
io_gds_uniquename(NODEPROTO * np)894 CHAR *io_gds_uniquename(NODEPROTO *np)
895 {
896 	static CHAR name[NAMSIZE];
897 	REGISTER INTBIG len, index, i, newtotal;
898 	REGISTER CHAR **newlist;
899 
900 	(void)estrcpy(name, io_gds_makename(np->protoname));
901 	if (np->newestversion != np)
902 	{
903 		len = strlen(name);
904 		sprintf(&name[len], x_("_%ld"), np->version);
905 	}
906 
907 	/* see if the name is unique */
908 	len = strlen(name);
909 	for(index = 1; ; index++)
910 	{
911 		for(i=0; i<io_gdscellnamecount; i++)
912 			if (namesame(name, io_gdscellnames[i]) == 0) break;
913 		if (i >= io_gdscellnamecount) break;
914 		sprintf(&name[len], x_("_%ld"), index);
915 	}
916 
917 	/* add this name to the list */
918 	if (io_gdscellnamecount >= io_gdscellnametotal)
919 	{
920 		newtotal = io_gdscellnametotal * 2;
921 		if (io_gdscellnamecount >= newtotal) newtotal = io_gdscellnamecount + 10;
922 		newlist = (CHAR **)emalloc(newtotal * (sizeof (CHAR *)), io_tool->cluster);
923 		if (newlist == 0) return("");
924 		for(i=0; i<io_gdscellnametotal; i++)
925 			newlist[i] = io_gdscellnames[i];
926 		for(i=io_gdscellnametotal; i<newtotal; i++) newlist[i] = 0;
927 		if (io_gdscellnametotal > 0) efree((CHAR *)io_gdscellnames);
928 		io_gdscellnames = newlist;
929 		io_gdscellnametotal = newtotal;
930 	}
931 	if (io_gdscellnames[io_gdscellnamecount] != 0)
932 		efree((CHAR *)io_gdscellnames[io_gdscellnamecount]);
933 	allocstring(&io_gdscellnames[io_gdscellnamecount], name, io_tool->cluster);
934 	io_gdscellnamecount++;
935 	return(name);
936 }
937 
io_gds_bgnstr(NODEPROTO * np)938 void io_gds_bgnstr(NODEPROTO *np)
939 {
940 	time_t cdate, rdate;
941 
942 	io_gds_header(HDR_BGNSTR, 0);
943 	cdate = (time_t)np->creationdate;
944 	io_gds_date(&cdate);
945 	rdate = (time_t)np->revisiondate;
946 	io_gds_date(&rdate);
947 
948 	io_gds_name(HDR_STRNAME, (CHAR *)np->temp1, HDR_M_STRNAME);
949 }
950 
951 /* Utilities to put the data into the output file */
952 
953 /* Output date array, converted from a date integer */
io_gds_date(time_t * val)954 void io_gds_date(time_t *val)
955 {
956 	CHAR buffer[28], save;
957 	INTSML date[6];
958 
959 	(void)estrcpy(buffer, timetostring(*val));
960 	date[0] = (INTSML)myatoi(&buffer[20]);      /* year */
961 	save = buffer[7];   buffer[7] = 0;
962 	date[1] = (INTSML)parsemonth(&buffer[4]);	/* month */
963 	buffer[7] = save;
964 	date[2] = (INTSML)myatoi(&buffer[8]);       /* day */
965 	date[3] = (INTSML)myatoi(&buffer[11]);      /* hours */
966 	date[4] = (INTSML)myatoi(&buffer[14]);      /* minutes */
967 	date[5] = (INTSML)myatoi(&buffer[17]);      /* seconds */
968 	io_gds_int2_arr(date, 6);
969 }
970 
971 /*
972  * Write a simple header, with a fixed length
973  * Enter with the header as argument, the routine will output
974  * the count, the header, and the argument (if present) in p1.
975  */
io_gds_header(INTBIG header,INTBIG p1)976 void io_gds_header(INTBIG header, INTBIG p1)
977 {
978 	INTBIG type, count;
979 
980 	/* func = (header>>8) & BYTEMASK; */
981 	type = header & BYTEMASK;
982 	if (type == DTYP_NONE) count = 4; else
983 		switch(header)
984 	{
985 		case HDR_HEADER:
986 		case HDR_LAYER:
987 		case HDR_DATATYPE:
988 		case HDR_TEXTTYPE:
989 		case HDR_STRANS:
990 		case HDR_PRESENTATION:
991 			count = 6;
992 			break;
993 		case HDR_BGNSTR:
994 		case HDR_BGNLIB:
995 			count = HDR_N_BGNLIB;
996 			break;
997 		case HDR_UNITS:
998 			count = HDR_N_UNITS;
999 			break;
1000 		default:
1001 			ttyputerr(_("No entry for header 0x%x"), header);
1002 			return;
1003 	}
1004 	io_gds_int2((INTSML)count);
1005 	io_gds_int2((INTSML)header);
1006 	if (type == DTYP_NONE) return;
1007 	if (count == 6) io_gds_int2((INTSML)p1);
1008 	if (count == 8) io_gds_int4(p1);
1009 }
1010 
1011 /*
1012  * Add a name (STRNAME, LIBNAME, etc.) to the file. The header
1013  * to be used is in header; the string starts at p1
1014  * if there is an odd number of bytes, then output the 0 at
1015  * the end of the string as a pad. The maximum length of string is "max"
1016  */
io_gds_name(INTBIG header,CHAR * p1,INTBIG max)1017 void io_gds_name(INTBIG header, CHAR *p1, INTBIG max)
1018 {
1019 	INTBIG count;
1020 
1021 	count = mini(estrlen(p1), max);
1022 	if ((count&1) != 0) count++;
1023 	io_gds_int2((INTSML)(count+4));
1024 	io_gds_int2((INTSML)header);
1025 	io_gds_string(p1, count);
1026 }
1027 
1028 /* Output an angle as part of a STRANS */
io_gds_angle(INTBIG ang)1029 void io_gds_angle(INTBIG ang)
1030 {
1031 	double gdfloat;
1032 	static INTBIG units[2];
1033 
1034 	gdfloat = (double)ang / 10.0;
1035 	io_gds_int2(HDR_N_ANGLE);
1036 	io_gds_int2(HDR_ANGLE);
1037 	io_gds_cvfloat8(&gdfloat, (UINTBIG *)&units[0], (UINTBIG *)&units[1]);
1038 	io_gds_int4_arr(units, 2);
1039 }
1040 
1041 /* Output a magnification as part of a STRANS */
io_gds_mag(double scale)1042 void io_gds_mag(double scale)
1043 {
1044 	static INTBIG units[2];
1045 
1046 	io_gds_int2(HDR_N_MAG);
1047 	io_gds_int2(HDR_MAG);
1048 	io_gds_cvfloat8(&scale, (UINTBIG *)&units[0], (UINTBIG *)&units[1]);
1049 	io_gds_int4_arr(units, 2);
1050 }
1051 
1052 /* Output the pairs of XY points to the file  */
io_gds_boundary(POLYGON * poly)1053 void io_gds_boundary(POLYGON *poly)
1054 {
1055 	INTBIG count, i, j, sofar;
1056 	REGISTER INTBIG *xv, *yv;
1057 	INTBIG lx, hx, ly, hy;
1058 	POLYGON *side1, *side2;
1059 
1060 	if (poly->count > MAXPOINTS)
1061 	{
1062 		getbbox(poly, &lx, &hx, &ly, &hy);
1063 		if (hx-lx > hy-ly)
1064 		{
1065 			if (polysplitvert((lx+hx)/2, poly, &side1, &side2)) return;
1066 		} else
1067 		{
1068 			if (polysplithoriz((ly+hy)/2, poly, &side1, &side2)) return;
1069 		}
1070 		io_gds_boundary(side1);
1071 		io_gds_boundary(side2);
1072 		freepolygon(side1);
1073 		freepolygon(side2);
1074 		return;
1075 	}
1076 
1077 	xv = poly->xv;   yv = poly->yv;
1078 	count = poly->count;
1079 	for(;;)
1080 	{
1081 		/* look for a closed section */
1082 		for(sofar=1; sofar<count; sofar++)
1083 			if (xv[sofar] == xv[0] && yv[sofar] == yv[0]) break;
1084 		if (sofar < count) sofar++;
1085 
1086 		io_gds_header(HDR_BOUNDARY, 0);
1087 		io_gds_header(HDR_LAYER, io_gds_curlayer);
1088 		io_gds_header(HDR_DATATYPE, 0);
1089 		io_gds_int2((INTSML)(8 * (sofar+1) + 4));
1090 		io_gds_int2(HDR_XY);
1091 		for (i = 0; i <= sofar; i++)
1092 		{
1093 			if (i == sofar) j = 0; else j = i;
1094 			io_gds_int4(rounddouble(io_gds_scale*(double)xv[j]));
1095 			io_gds_int4(rounddouble(io_gds_scale*(double)yv[j]));
1096 		}
1097 		io_gds_header(HDR_ENDEL, 0);
1098 		if (sofar >= count) break;
1099 		count -= sofar;
1100 		xv = &xv[sofar];
1101 		yv = &yv[sofar];
1102 	}
1103 }
1104 
io_gds_path(POLYGON * poly)1105 void io_gds_path(POLYGON *poly)
1106 {
1107 	INTBIG count, i;
1108 
1109 	io_gds_header(HDR_PATH, 0);
1110 	io_gds_header(HDR_LAYER, io_gds_curlayer);
1111 	io_gds_header(HDR_DATATYPE, 0);
1112 	count = 8 * poly->count + 4;
1113 	io_gds_int2((INTSML)count);
1114 	io_gds_int2(HDR_XY);
1115 	for (i = 0; i < poly->count; i ++)
1116 	{
1117 		io_gds_int4(rounddouble(io_gds_scale*(double)poly->xv[i]));
1118 		io_gds_int4(rounddouble(io_gds_scale*(double)poly->yv[i]));
1119 	}
1120 	io_gds_header(HDR_ENDEL, 0);
1121 }
1122 
1123 /*  Primitive output routines : */
1124 
1125 /* Add one byte to the file io_gds_outfd */
io_gds_byte(UCHAR1 val)1126 void io_gds_byte(UCHAR1 val)
1127 {
1128 	io_dbuffer[io_gds_pos++] = val;
1129 	if (io_gds_pos >= DSIZE)
1130 	{
1131 		(void)xfwrite(io_dbuffer, DSIZE, 1, io_gds_outfd);
1132 		io_gds_block++;
1133 		io_gds_pos = 0;
1134 	}
1135 }
1136 
1137 /* Add a 2-byte integer */
io_gds_int2(INTSML val)1138 void io_gds_int2(INTSML val)
1139 {
1140 	io_gds_byte((UCHAR1)((val>>8)&BYTEMASK));
1141 	io_gds_byte((UCHAR1)(val&BYTEMASK));
1142 }
1143 
1144 /* Four byte integer */
io_gds_int4(INTBIG val)1145 void io_gds_int4(INTBIG val)
1146 {
1147 	io_gds_int2((INTSML)(val>>16));
1148 	io_gds_int2((INTSML)val);
1149 }
1150 
1151 /* Array of 2 byte integers in array ptr, count n */
io_gds_int2_arr(INTSML * ptr,INTBIG n)1152 void io_gds_int2_arr(INTSML *ptr, INTBIG n)
1153 {
1154 	INTBIG i;
1155 
1156 	for (i = 0; i < n; i++) io_gds_int2(ptr[i]);
1157 }
1158 
1159 /* Array of 4-byte integers or floating numbers in array  ptr, count n */
io_gds_int4_arr(INTBIG * ptr,INTBIG n)1160 void io_gds_int4_arr(INTBIG *ptr, INTBIG n)
1161 {
1162 	INTBIG i;
1163 
1164 	for (i = 0; i < n; i++) io_gds_int4(ptr[i]);
1165 }
1166 
1167 /*
1168  * String of n bytes, starting at ptr
1169  * Revised 90-11-23 to convert to upper case (SRP)
1170  */
io_gds_string(CHAR * ptr,INTBIG n)1171 void io_gds_string(CHAR *ptr, INTBIG n)
1172 {
1173 	INTBIG i;
1174 
1175 	if ((io_gds_outputstate[1]&GDSOUTUC) != 0)
1176 	{
1177 		/* convert to upper case */
1178 		for (i = 0; i < n; i++)
1179 			io_gds_byte((UCHAR1)toupper(ptr[i]));
1180 	} else
1181 	{
1182 		for (i = 0; i < n; i++)
1183 			io_gds_byte((UCHAR1)ptr[i]);
1184 	}
1185 }
1186 
1187 /*
1188  * Write out a merged polygon created by the merging algorithm
1189  * we have to scan it to make sure that it is closed
1190  * We assume that it does not exceed 200 points.
1191  */
io_gds_write_polygon(INTBIG layer,TECHNOLOGY * tech,INTBIG * xbuf,INTBIG * ybuf,INTBIG count)1192 void io_gds_write_polygon(INTBIG layer, TECHNOLOGY *tech, INTBIG *xbuf, INTBIG *ybuf,
1193 	INTBIG count)
1194 {
1195 	static POLYGON *gds_poly = NOPOLYGON;
1196 	INTBIG i;
1197 
1198 	/* check the number of points on the polygon */
1199 	if (count > io_gds_polypoints)
1200 		ttyputerr(_("WARNING: Polygon has too many points (%ld)"), count);
1201 
1202 	(void)needstaticpolygon(&gds_poly, 4, io_tool->cluster);
1203 	if (count > gds_poly->limit) (void)extendpolygon(gds_poly, count);
1204 	gds_poly->count = count;
1205 	for (i = 0; i < count; i++)
1206 	{
1207 		gds_poly->xv[i] = xbuf[i];
1208 		gds_poly->yv[i] = ybuf[i];
1209 	}
1210 	io_gds_set_layer(layer);
1211 	io_gds_boundary(gds_poly);       /* Now write it out */
1212 }
1213 
1214 /*
1215  * function to create proper GDSII names with restricted character set
1216  * from input string str.
1217  * Uses only 'A'-'Z', '_', $, ?, and '0'-'9'
1218  */
io_gds_makename(CHAR * str)1219 CHAR *io_gds_makename(CHAR *str)
1220 {
1221 	CHAR *k, ch;
1222 	REGISTER void *infstr;
1223 
1224 	/* filter the name string for the GDS output cell */
1225 	infstr = initinfstr();
1226 	for (k = str; *k != 0; k++)
1227 	{
1228 		ch = *k;
1229 		if ((io_gds_outputstate[1]&GDSOUTUC) != 0)
1230 			ch = toupper(ch);
1231 		if (ch != '$' && !isdigit(ch) && ch != '?' && !isalpha(ch))
1232 			ch = '_';
1233 		addtoinfstr(infstr, ch);
1234 	}
1235 	return(returninfstr(infstr));
1236 }
1237 
1238 /*
1239  * Create 8-byte GDS representation of a floating point number
1240  */
io_gds_cvfloat8(double * a,UINTBIG * m,UINTBIG * n)1241 void io_gds_cvfloat8(double *a, UINTBIG *m, UINTBIG *n)
1242 {
1243 	double temp, top, frac;
1244 	BOOLEAN negsign;
1245 	INTBIG exponent, i;
1246 	UINTBIG highmantissa;
1247 
1248 	/* handle default */
1249 	if (*a == 0)
1250 	{
1251 		*m = 0x40000000;
1252 		*n = 0;
1253 		return;
1254 	}
1255 
1256 	/* identify sign */
1257 	temp = *a;
1258 	if (temp < 0)
1259 	{
1260 		negsign = TRUE;
1261 		temp = -temp;
1262 	} else negsign = FALSE;
1263 
1264 	/* establish the excess-64 exponent value */
1265 	exponent = 64;
1266 
1267 	/* scale the exponent and mantissa */
1268 	for (; temp < 0.0625 && exponent > 0; exponent--) temp *= 16.0;
1269 
1270 	if (exponent == 0) ttyputerr(_("Exponent underflow"));
1271 
1272 	for (; temp >= 1 && exponent < 128; exponent++) temp /= 16.0;
1273 
1274 	if (exponent > 127) ttyputerr(_("Exponent overflow"));
1275 
1276 	/* set the sign */
1277 	if (negsign) exponent |= 0x80;
1278 
1279 	/* convert temp to 7-byte binary integer */
1280 	top = temp;
1281 	for (i = 0; i < 24; i++) top *= 2;
1282 	highmantissa = (UINTBIG)top;
1283 	frac = top - highmantissa;
1284 	for (i = 0; i < 32; i++) frac *= 2;
1285 	*n = (UINTBIG)frac;   *m = highmantissa | (exponent<<24);
1286 }
1287 
1288 /* GDS Options */
1289 static DIALOGITEM io_gdsoptionsdialogitems[] =
1290 {
1291  /*  1 */ {0, {308,140,332,212}, BUTTON, N_("OK")},
1292  /*  2 */ {0, {308,32,332,104}, BUTTON, N_("Cancel")},
1293  /*  3 */ {0, {8,8,296,232}, SCROLL, x_("")},
1294  /*  4 */ {0, {8,240,24,336}, MESSAGE, N_("GDS Layer(s):")},
1295  /*  5 */ {0, {8,340,24,444}, EDITTEXT, x_("")},
1296  /*  6 */ {0, {80,240,96,464}, CHECK, N_("Input Includes Text")},
1297  /*  7 */ {0, {104,240,120,464}, CHECK, N_("Input Expands Cells")},
1298  /*  8 */ {0, {128,240,144,464}, CHECK, N_("Input Instantiates Arrays")},
1299  /*  9 */ {0, {176,240,192,464}, CHECK, N_("Output Merges Boxes")},
1300  /* 10 */ {0, {272,240,288,428}, MESSAGE, N_("Output Arc Conversion:")},
1301  /* 11 */ {0, {296,248,312,424}, MESSAGE, N_("Maximum arc angle:")},
1302  /* 12 */ {0, {296,428,312,496}, EDITTEXT, x_("")},
1303  /* 13 */ {0, {320,248,336,424}, MESSAGE, N_("Maximum arc sag:")},
1304  /* 14 */ {0, {320,428,336,496}, EDITTEXT, x_("")},
1305  /* 15 */ {0, {152,240,168,464}, CHECK, N_("Input Ignores Unknown Layers")},
1306  /* 16 */ {0, {248,240,264,424}, MESSAGE, N_("Output default text layer:")},
1307  /* 17 */ {0, {248,428,264,496}, EDITTEXT, x_("")},
1308  /* 18 */ {0, {32,256,48,336}, MESSAGE, N_("Pin layer:")},
1309  /* 19 */ {0, {32,340,48,444}, EDITTEXT, x_("")},
1310  /* 20 */ {0, {56,256,72,336}, MESSAGE, N_("Text layer:")},
1311  /* 21 */ {0, {56,340,72,444}, EDITTEXT, x_("")},
1312  /* 22 */ {0, {200,240,216,464}, CHECK, N_("Output Writes Export Pins")},
1313  /* 23 */ {0, {224,240,240,464}, CHECK, N_("Output All Upper Case")}
1314 };
1315 static DIALOG io_gdsoptionsdialog = {{50,75,395,581}, N_("GDS Options"), 0, 23, io_gdsoptionsdialogitems, 0, 0};
1316 
1317 /* special items for the "GDS Options" dialog: */
1318 #define DGDO_LAYERLIST       3		/* Layer list (scroll list) */
1319 #define DGDO_NEWLAYER        5		/* New layer (edit text) */
1320 #define DGDO_IINCLUDETEXT    6		/* Input Includes Text (check) */
1321 #define DGDO_IEXPANDCELL     7		/* Input Expands Cells (check) */
1322 #define DGDO_IINSTARRAY      8		/* Input Instantiates Arrays (check) */
1323 #define DGDO_OMERGEBOX       9		/* Output Merges Boxes (check) */
1324 #define DGDO_OARCANGLE      12		/* Output Arc Angle (edit text) */
1325 #define DGDO_OARCSAG        14		/* Output Arc Sag (edit text) */
1326 #define DGDO_IIGNOREUNKNOWN 15		/* Input Ignores unknown layers (check) */
1327 #define DGDO_EXPORTLAYER    17		/* Output default text layer (edit text) */
1328 #define DGDO_PINLAYER       19		/* Pin layer (edit text) */
1329 #define DGDO_TEXTLAYER      21		/* Text layer (edit text) */
1330 #define DGDO_WRITEEXPORTPIN 22		/* Write Export Pins (check) */
1331 #define DGDO_OUPPERCASE     23		/* Output Upper Case (check) */
1332 
io_gdsoptionsdlog(void)1333 void io_gdsoptionsdlog(void)
1334 {
1335 	REGISTER INTBIG i, v, itemHit, *curstate, newres, newsag, numberschanged,
1336 		explayer, varlen;
1337 	INTBIG arcres, arcsag, newstate[NUMIOSTATEBITWORDS];
1338 	CHAR buf[50], **layernumbers, **pinnumbers, **textnumbers, *val, *pinval, *textval;
1339 	REGISTER VARIABLE *gdsvar, *expvar;
1340 	REGISTER void *infstr, *dia;
1341 
1342 	dia = DiaInitDialog(&io_gdsoptionsdialog);
1343 	if (dia == 0) return;
1344 	DiaInitTextDialog(dia, DGDO_LAYERLIST, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0,
1345 		SCSELMOUSE|SCREPORT);
1346 	layernumbers = (CHAR **)emalloc(el_curtech->layercount * (sizeof (CHAR *)), el_tempcluster);
1347 	if (layernumbers == 0) return;
1348 	pinnumbers = (CHAR **)emalloc(el_curtech->layercount * (sizeof (CHAR *)), el_tempcluster);
1349 	if (pinnumbers == 0) return;
1350 	textnumbers = (CHAR **)emalloc(el_curtech->layercount * (sizeof (CHAR *)), el_tempcluster);
1351 	if (textnumbers == 0) return;
1352 	gdsvar = getval((INTBIG)el_curtech, VTECHNOLOGY, -1, x_("IO_gds_layer_numbers"));
1353 	if (gdsvar != NOVARIABLE && (gdsvar->type&VISARRAY) == 0) gdsvar = NOVARIABLE;
1354 	if (gdsvar != NOVARIABLE) varlen = getlength(gdsvar);
1355 	for(i=0; i<el_curtech->layercount; i++)
1356 	{
1357 		val = pinval = textval = x_("");
1358 		if (gdsvar != NOVARIABLE && i < varlen)
1359 		{
1360 			if ((gdsvar->type&VTYPE) == VSTRING)
1361 			{
1362 				io_gds_parselayerstring(((CHAR **)gdsvar->addr)[i], &val, &pinval, &textval);
1363 			} else
1364 			{
1365 				v = ((INTBIG *)gdsvar->addr)[i];
1366 				if (v >= 0)
1367 				{
1368 					esnprintf(buf, 50, x_("%ld"), v);
1369 					val = buf;
1370 				}
1371 			}
1372 		}
1373 		allocstring(&layernumbers[i], val, io_tool->cluster);
1374 		allocstring(&pinnumbers[i], pinval, io_tool->cluster);
1375 		allocstring(&textnumbers[i], textval, io_tool->cluster);
1376 		infstr = initinfstr();
1377 		formatinfstr(infstr, x_("%s (%s"), layername(el_curtech, i), layernumbers[i]);
1378 		if (*pinnumbers[i] != 0) formatinfstr(infstr, x_(",%sP"), pinnumbers[i]);
1379 		if (*textnumbers[i] != 0) formatinfstr(infstr, x_(",%sT"), textnumbers[i]);
1380 		addstringtoinfstr(infstr, x_(")"));
1381 		DiaStuffLine(dia, DGDO_LAYERLIST, returninfstr(infstr));
1382 	}
1383 	DiaSelectLine(dia, DGDO_LAYERLIST, 0);
1384 	DiaSetText(dia, DGDO_NEWLAYER, layernumbers[0]);
1385 	DiaSetText(dia, DGDO_PINLAYER, pinnumbers[0]);
1386 	DiaSetText(dia, DGDO_TEXTLAYER, textnumbers[0]);
1387 
1388 	expvar = getval((INTBIG)el_curtech, VTECHNOLOGY, VINTEGER, x_("IO_gds_export_layer"));
1389 	if (expvar == NOVARIABLE) explayer = 230; else
1390 		explayer = expvar->addr;
1391 	esnprintf(buf, 50, x_("%ld"), explayer);
1392 	DiaSetText(dia, DGDO_EXPORTLAYER, buf);
1393 
1394 	curstate = io_getstatebits();
1395 	for(i=0; i<NUMIOSTATEBITWORDS; i++) newstate[i] = curstate[i];
1396 	if ((curstate[0]&GDSINTEXT) != 0) DiaSetControl(dia, DGDO_IINCLUDETEXT, 1);
1397 	if ((curstate[0]&GDSINEXPAND) != 0) DiaSetControl(dia, DGDO_IEXPANDCELL, 1);
1398 	if ((curstate[0]&GDSINARRAYS) != 0) DiaSetControl(dia, DGDO_IINSTARRAY, 1);
1399 	if ((curstate[0]&GDSOUTMERGE) != 0) DiaSetControl(dia, DGDO_OMERGEBOX, 1);
1400 	if ((curstate[0]&GDSINIGNOREUKN) != 0) DiaSetControl(dia, DGDO_IIGNOREUNKNOWN, 1);
1401 	if ((curstate[1]&GDSOUTPINS) != 0) DiaSetControl(dia, DGDO_WRITEEXPORTPIN, 1);
1402 	if ((curstate[1]&GDSOUTUC) != 0) DiaSetControl(dia, DGDO_OUPPERCASE, 1);
1403 	getcontoursegmentparameters(&arcres, &arcsag);
1404 	DiaSetText(dia, DGDO_OARCANGLE, frtoa(arcres*WHOLE/10));
1405 	DiaSetText(dia, DGDO_OARCSAG, latoa(arcsag, 0));
1406 
1407 	/* loop until done */
1408 	numberschanged = 0;
1409 	for(;;)
1410 	{
1411 		itemHit = DiaNextHit(dia);
1412 		if (itemHit == OK || itemHit == CANCEL) break;
1413 		if (itemHit == DGDO_IINCLUDETEXT || itemHit == DGDO_IEXPANDCELL ||
1414 			itemHit == DGDO_IINSTARRAY || itemHit == DGDO_OMERGEBOX ||
1415 			itemHit == DGDO_IIGNOREUNKNOWN || itemHit == DGDO_WRITEEXPORTPIN ||
1416 			itemHit == DGDO_OUPPERCASE)
1417 		{
1418 			DiaSetControl(dia, itemHit, 1 - DiaGetControl(dia, itemHit));
1419 			continue;
1420 		}
1421 		if (itemHit == DGDO_LAYERLIST)
1422 		{
1423 			i = DiaGetCurLine(dia, DGDO_LAYERLIST);
1424 			DiaSetText(dia, DGDO_NEWLAYER, layernumbers[i]);
1425 			DiaSetText(dia, DGDO_PINLAYER, pinnumbers[i]);
1426 			DiaSetText(dia, DGDO_TEXTLAYER, textnumbers[i]);
1427 			continue;
1428 		}
1429 		if (itemHit == DGDO_NEWLAYER || itemHit == DGDO_PINLAYER ||
1430 			itemHit == DGDO_TEXTLAYER)
1431 		{
1432 			i = DiaGetCurLine(dia, DGDO_LAYERLIST);
1433 			if (itemHit == DGDO_NEWLAYER)
1434 			{
1435 				val = DiaGetText(dia, DGDO_NEWLAYER);
1436 				if (namesame(val, layernumbers[i]) == 0) continue;
1437 				reallocstring(&layernumbers[i], val, io_tool->cluster);
1438 			} else if (itemHit == DGDO_PINLAYER)
1439 			{
1440 				val = DiaGetText(dia, DGDO_PINLAYER);
1441 				if (namesame(val, pinnumbers[i]) == 0) continue;
1442 				reallocstring(&pinnumbers[i], val, io_tool->cluster);
1443 			} else
1444 			{
1445 				val = DiaGetText(dia, DGDO_TEXTLAYER);
1446 				if (namesame(val, textnumbers[i]) == 0) continue;
1447 				reallocstring(&textnumbers[i], val, io_tool->cluster);
1448 			}
1449 			numberschanged++;
1450 			infstr = initinfstr();
1451 			formatinfstr(infstr, x_("%s (%s"), layername(el_curtech, i), layernumbers[i]);
1452 			if (*pinnumbers[i] != 0) formatinfstr(infstr, x_(",%sP"), pinnumbers[i]);
1453 			if (*textnumbers[i] != 0) formatinfstr(infstr, x_(",%sT"), textnumbers[i]);
1454 			addstringtoinfstr(infstr, x_(")"));
1455 			DiaSetScrollLine(dia, DGDO_LAYERLIST, i, returninfstr(infstr));
1456 			continue;
1457 		}
1458 	}
1459 
1460 	if (itemHit != CANCEL)
1461 	{
1462 		if (DiaGetControl(dia, DGDO_IINCLUDETEXT) != 0) newstate[0] |= GDSINTEXT; else
1463 			newstate[0] &= ~GDSINTEXT;
1464 		if (DiaGetControl(dia, DGDO_IEXPANDCELL) != 0) newstate[0] |= GDSINEXPAND; else
1465 			newstate[0] &= ~GDSINEXPAND;
1466 		if (DiaGetControl(dia, DGDO_IINSTARRAY) != 0) newstate[0] |= GDSINARRAYS; else
1467 			newstate[0] &= ~GDSINARRAYS;
1468 		if (DiaGetControl(dia, DGDO_OMERGEBOX) != 0) newstate[0] |= GDSOUTMERGE; else
1469 			newstate[0] &= ~GDSOUTMERGE;
1470 		if (DiaGetControl(dia, DGDO_IIGNOREUNKNOWN) != 0) newstate[0] |= GDSINIGNOREUKN; else
1471 			newstate[0] &= ~GDSINIGNOREUKN;
1472 		if (DiaGetControl(dia, DGDO_WRITEEXPORTPIN) != 0) newstate[1] |= GDSOUTPINS; else
1473 			newstate[1] &= ~GDSOUTPINS;
1474 		if (DiaGetControl(dia, DGDO_OUPPERCASE) != 0) newstate[1] |= GDSOUTUC; else
1475 			newstate[1] &= ~GDSOUTUC;
1476 		for(i=0; i<NUMIOSTATEBITWORDS; i++) if (curstate[i] != newstate[i]) break;
1477 		if (i < NUMIOSTATEBITWORDS) io_setstatebits(newstate);
1478 		if (numberschanged != 0)
1479 		{
1480 			for(i=0; i<el_curtech->layercount; i++)
1481 			{
1482 				if (*pinnumbers[i] != 0 || *textnumbers[i] != 0)
1483 				{
1484 					infstr = initinfstr();
1485 					addstringtoinfstr(infstr, layernumbers[i]);
1486 					if (*pinnumbers[i] != 0)
1487 						formatinfstr(infstr, x_(",%sP"), pinnumbers[i]);
1488 					if (*textnumbers[i] != 0)
1489 						formatinfstr(infstr, x_(",%sT"), textnumbers[i]);
1490 					reallocstring(&layernumbers[i], returninfstr(infstr), io_tool->cluster);
1491 				}
1492 			}
1493 			setval((INTBIG)el_curtech, VTECHNOLOGY, x_("IO_gds_layer_numbers"),
1494 				(INTBIG)layernumbers, VSTRING|VISARRAY|
1495 					(el_curtech->layercount<<VLENGTHSH));
1496 		}
1497 		newres = atofr(DiaGetText(dia, DGDO_OARCANGLE)) * 10 / WHOLE;
1498 		newsag = atola(DiaGetText(dia, DGDO_OARCSAG), 0);
1499 		if (newres != arcres || newsag != arcsag)
1500 			setcontoursegmentparameters(newres, newsag);
1501 		i = myatoi(DiaGetText(dia, DGDO_EXPORTLAYER));
1502 		if (i != explayer)
1503 			setval((INTBIG)el_curtech, VTECHNOLOGY, x_("IO_gds_export_layer"), i, VINTEGER);
1504 	}
1505 	for(i=0; i<el_curtech->layercount; i++)
1506 	{
1507 		efree((CHAR *)pinnumbers[i]);
1508 		efree((CHAR *)textnumbers[i]);
1509 	}
1510 	efree((CHAR *)layernumbers);
1511 	efree((CHAR *)pinnumbers);
1512 	efree((CHAR *)textnumbers);
1513 	DiaDoneDialog(dia);
1514 }
1515 
io_gds_parselayerstring(CHAR * string,CHAR ** val,CHAR ** pinval,CHAR ** textval)1516 void io_gds_parselayerstring(CHAR *string, CHAR **val, CHAR **pinval, CHAR **textval)
1517 {
1518 	REGISTER void *infstrv, *infstrp, *infstrt;
1519 	REGISTER BOOLEAN havev, havep, havet;
1520 	REGISTER INTBIG number;
1521 
1522 	infstrv = initinfstr();
1523 	infstrp = initinfstr();
1524 	infstrt = initinfstr();
1525 	havev = havep = havet = FALSE;
1526 	for(;;)
1527 	{
1528 		while (*string == ' ') string++;
1529 		if (*string == 0) break;
1530 		number = myatoi(string);
1531 		while (isdigit(*string)) string++;
1532 		if (tolower(*string) == 't')
1533 		{
1534 			if (havet) addtoinfstr(infstrt, ',');
1535 			formatinfstr(infstrt, x_("%ld"), number);
1536 			havet = TRUE;
1537 			string++;
1538 		} else if (tolower(*string) == 'p')
1539 		{
1540 			if (havep) addtoinfstr(infstrp, ',');
1541 			formatinfstr(infstrp, x_("%ld"), number);
1542 			havep = TRUE;
1543 			string++;
1544 		} else
1545 		{
1546 			if (havev) addtoinfstr(infstrv, ',');
1547 			formatinfstr(infstrv, x_("%ld"), number);
1548 			havev = TRUE;
1549 		}
1550 		while (*string == ' ') string++;
1551 		if (*string == 0) break;
1552 		if (*string == ',') string++;
1553 	}
1554 	*val = returninfstr(infstrv);
1555 	*pinval = returninfstr(infstrp);
1556 	*textval = returninfstr(infstrt);
1557 }
1558