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