1 /****************************************************************************
2     Copyright (C) 1987-2015 by Jeffery P. Hansen
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 
18     Last edit by hansen on Wed Jan 28 08:41:34 2009
19 ****************************************************************************/
20 
21 /*****************************************************************************
22  * Postscript Generator for TkGate.
23  *
24  * This file contains the basic functions for generating postscript files
25  * for circuit descriptions.  Some of the most important data structures
26  * use by the postscript generator are:
27  *
28  * GPrint	Contains the context for the generation of a single document.
29  *		This includes where the document should be printed, the current
30  *		document data, and the any options settings.
31  *
32  * GPrintOpt	Data structure with option values (in string format) used to create
33  *		the GPrint object.  This data structure is normally filled in
34  *  		based on the values in the print dialog box.
35  *
36  * GModLayout	This data structure represents a module with layout information.
37  *		The layout information determines where on the page the module
38  *		will be printed.
39  *
40  * GPage	This data structure represents a page.
41  *
42  *****************************************************************************/
43 
44 #ifdef __cplusplus
45 #include <cstdlib>
46 #include <cassert>
47 #include <cmath>
48 #else
49 #include <stdlib.h>
50 #include <assert.h>
51 #include <math.h>
52 #endif
53 
54 #include <pwd.h>
55 
56 #include "tkgate.h"
57 #include "print.h"
58 
59 
60 /*
61  * Font change codes
62  */
63 #define FCC_BEGINKANJI	0201
64 #define FCC_ENDKANJI	0201
65 
66 /*
67  * Hierarchy graph constants
68  */
69 #define HG_FONTSIZE	12	/* Font size for heirarchy graph */
70 #define HG_ROOTX	50	/* Root x position */
71 #define HG_ROOTY	475	/* Root y position */
72 #define HG_BOTTOMY	50	/* Lowest y position */
73 #define HG_INDENT	20	/* Amount to indent for children */
74 #define HG_LINE		25	/* Hieght of a line */
75 #define HG_LINEINDENT	10	/* Indent for heirarchy line */
76 #define HG_BOXHEIGHT	20	/* Height of the module name box */
77 #define HG_NEXTCOLUMN	225	/* Space between columns */
78 /*
79 
80 Folio          8.27 x 13 in.
81 Statement      5.5 x 8.5
82 C0		917mm  x 1297mm
83 C5		162 x 229 mm
84 C10		28 x 40 mm
85 
86 A		8.5 x 11
87 B		11 x 17
88 C		17 x 22
89 D		22 x 34
90 E		34 x 44
91 
92 yotsugiri	10 x 12in
93 mutsugiri	8 x 10 in
94 yatsugiri	6.5 x 8.5 in
95 
96 kiku 4		227 x 306 mm
97 kiku 5		151 x 227 mm
98  */
99 
100 /*****************************************************************************
101  *
102  * Postscript font name and metrics data from metrics.c
103  *
104  *****************************************************************************/
105 extern short fontmetrics_Courier;
106 extern short fontmetrics_Kanji;
107 extern short *psFontWidthTable[FF_MAX][FP_MAX];
108 extern char *psFontNameTable[FF_MAX][FP_MAX];
109 
110 /*****************************************************************************
111  *
112  * Font to use for displaying hdl module.
113  *
114  *****************************************************************************/
115 HtmlFont hdl_font = {.gateFont = {FF_COURIER,FP_ROMAN,0}, 10};
116 
117 typedef struct hgnode HGNode;
118 struct hgnode {
119   GModuleDef	*hg_module;		/* Module this node corresponds to */
120   int		hg_maxDepth;		/* Maximum depth of tree */
121   int		hg_expanded;		/* Non-zero if graph is expanded at this point */
122   HGNode	*hg_nextSibling;	/* Next node in sibling list */
123   HGNode	*hg_children;		/* Children of this node */
124 };
125 
126 
127 char *gateprolog[] = {
128 #include "psprolog.h"
129   0
130 };
131 
132 char *gateps_copyright[] = {
133   "%",
134   "% Copyright (C) 1987-2015 by Jeffery P. Hansen",
135   "%    This program (the Postscript Prolog) is free software; you can redistribute",
136   "%    it and/or modify it under the terms of the GNU General Public License",
137   "%    as published by the Free Software Foundation; either version 2 of the",
138   "%    License, or (at your option) any later version.",
139   "%",
140   "%    This program is distributed in the hope that it will be useful,",
141   "%    but WITHOUT ANY WARRANTY; without even the implied warranty of",
142   "%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the",
143   "%    GNU General Public License for more details.",
144   "%",
145   "%    You should have received a copy of the GNU General Public License along",
146   "%    with this program; if not, write to the Free Software Foundation, Inc.,",
147   "%    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.",
148   "%",
149   0
150 };
151 
152 char *kanji_support_prolog[] = {
153   "%",
154   "% Replacement for regular show that switches between current font",
155   "% and kanji font each time a special 'kanji swap' character is encountered",
156   "%",
157   "/kanji_show {",
158   "  FCCToggleKanji search {",
159   "    orig_show ",
160   "    pop",
161   "    in_kanji_text {",
162   "      /in_kanji_text false def",
163   "      swap_font setfont",
164   "    } {",
165   "      /in_kanji_text true def",
166   "      /swap_font currentfont def",
167   "      14 kfont",
168   "    } ifelse",
169   "    kanji_show",
170   "  } {",
171   "    orig_show",
172   "  } ifelse",
173   "} def",
174   "",
175   "%",
176   "% v /s accum",
177   "%",
178   "/accum { dup cvx exec 3 -1 roll add def } def",
179   "%",
180   "% Replacement for regular stringwidth that switches between current font",
181   "% and kanji font each time a special 'kanji swap' character is encountered",
182   "%",
183   "/kanji_stringwidth {",
184   "  FCCToggleKanji search {",
185   "    orig_stringwidth pop /accum_width accum",
186   "    pop",
187   "    in_kanji_text {",
188   "      /in_kanji_text false def",
189   "      swap_font setfont",
190   "    } {",
191   "      /in_kanji_text true def",
192   "      /swap_font currentfont def",
193   "      14 kfont",
194   "    } ifelse",
195   "    kanji_stringwidth",
196   "  } {",
197   "    orig_stringwidth pop /accum_width accum",
198   "  } ifelse",
199   "} def",
200   "",
201   "%",
202   "% Override definition of show with kanji_show",
203   "%",
204   "/orig_show /show load def",
205   "/show {",
206   "  /in_kanji_text false def",
207   "  /swap_font currentfont def",
208   "  kanji_show",
209   "} def",
210   "",
211   "%",
212   "% Override definition of stringwidth with kanji_stringwidth",
213   "%",
214   "/orig_stringwidth /stringwidth load def",
215   "/stringwidth {",
216   "  /in_kanji_text false def",
217   "  /swap_font currentfont def",
218   "  /accum_width 0 def",
219   "  kanji_stringwidth",
220   "  accum_width 0",
221   "} def",
222   "",
223   0
224 };
225 
226 PaperSize paperSizes[] = {
227   {"Letter",	"lettertray",	INCH(8.5),	INCH(11)},
228   {"Legal",	"legaltray",	INCH(8.5),	INCH(14)},
229   {"Tabloid",	"11x17tray",	INCH(11),	INCH(17)},
230   {"Executive",	"executivetray",INCH(7.5),	INCH(10)},
231   {"A6",	"a6tray",	MM(105),	MM(148)},
232   {"A5",	"a5tray",	MM(148),	MM(210)},
233   {"A4",	"a4tray",	MM(210),	MM(297)},
234   {"A3",	"a3tray",	MM(297),	MM(420)},
235   {"A2",	"a2tray",	MM(420),	MM(594)},
236   {"A1",	"a1tray",	MM(594),	MM(841)},
237   {"B5",	"b5tray",	MM(176),	MM(250)},
238   {"B4",	"b4tray",	MM(250),	MM(353)},
239   {"B3",	"b3tray",	MM(353),	MM(500)},
240   {"B2",	"b2tray",	MM(500),	MM(707)},
241   {"SRA2",	"sra2tray",	MM(450),	MM(640)},
242   {"RA2",	"ra2tray",	MM(430),	MM(610)},
243   {"yatsugiri",	"yatsugiri",	INCH(6.5),	INCH(8.5)},
244   {"mutsugiri",	"mutsugiri",	INCH(8),	INCH(10)},
245   {"yotsugiri",	"yotsugiri",	INCH(10),	INCH(12)},
246   {0}
247 };
248 
249 
250 const char *recipe_list[] = {
251   /* Receipe 1 */
252     "%	Pancakes - one serving\n"
253     "%\n"
254     "%  1 cup     Flour\n"
255     "%  1 cup     Milk\n"
256     "%  2         Eggs\n"
257     "%  1   tbs   Melted Butter\n"
258     "%  2   tsp   Sugar\n"
259     "%  1/2 tsp   Salt\n"
260     "%  1/2 tsp   Baking Soda\n"
261     "%\n"
262     "% Separate eggs placing whites aside in a clean bowl.  Combine flour and\n"
263     "% milk in a separate bowl and mix until smooth.   Stir in melted butter,\n"
264     "% sugar, salt and one of the egg yolks.  Now, using a clean mixer, whip\n"
265     "% the egg whites until stiff.  Gently stir the egg whites into the batter.\n"
266     "% This must be done by hand, or the pancakes will become flat.  Finally,\n"
267     "% stir in the baking soda.\n",
268 
269   /* Receipe 2 */
270     "% Okonomiyaki - one serving\n"
271     "%\n"
272     "%  3 tbs     Flour\n"
273     "%  3 tbs     Water\n"
274     "%  1         Egg\n"
275     "%  1/8 head  Cabbage (shredded)\n"
276     "%  1 tbs     Tororo-imo (Japanese potato) [optional]\n"
277     "%  1 tsp     Benishoga (Pickled ginger)\n"
278     "%  1 tbs     carrot (shredded)\n"
279     "%  1 tbs     leeks (shredded)\n"
280     "%  1 tbs     green pepper (shredded)\n"
281     "%\n"
282     "%  Fillings: beef, pork, vegtables\n"
283     "%\n"
284     "%  Toppings:\n"
285     "%            Aonori (seaweed flakes)\n"
286     "%            Katsuo-bushi (dried fish flakes)\n"
287     "%            Japanese Tonkatsu Sauce\n"
288     "%            Mayonaise\n"
289     "%\n"
290     "% Mix all of the basic ingedients together in a small bowl.  Place a small\n"
291     "% quantity of filling on an oiled hot plate or griddle and fry for a few seconds.\n"
292     "% Pour the okonomiyaki mixture from the bowl on top of the filling and smooth\n"
293     "% out into a thick pancake-like shape.  Let cook for 5-7 min.  Turn over and cook\n"
294     "% another 2-3 min.  Spread the tokatsu sauce and mayonaise on top of the okonomiyaki\n"
295     "% then sprinkle with katuo-bushi and aonori.  Cut into 1/6ths and serve.\n",
296 
297   /* Receipe 3 */
298   "% Tofu\n"
299   "% \n"
300   "% Ingredients (Japanese names in parentheses): \n"
301   "% \n"
302   "%      500g Soy Beans (Daizu) \n"
303   "%      20g Bittern (Nigari) \n"
304   "% \n"
305   "% You will also need: \n"
306   "% \n"
307   "%      Cheesecloth \n"
308   "%      Molds (milk cartons work fine) \n"
309   "%      Press (rolled up newspaper wrapped in plastic wrap) \n"
310   "%      Weights (plates, etc.) \n"
311   "%      Cooking thermometer \n"
312   "% \n"
313   "% Soak the soy beans in water overnight (10-20 hours). Be sure to\n"
314   "% use enough water so the beans can double in size. Prepare the molds\n"
315   "% using one milk carton per mold (you can use cheese molds if you have\n"
316   "% them). Cut off one side of the carton, and punch numerous holes in the\n"
317   "% sides and bottom to allow liquid to escape. Reinforce the molds by\n"
318   "% using a pair of longs sticks (one on each side) holding them together\n"
319   "% with rubber bands on the ends. You should have one piece of\n"
320   "% cheesecloth per mold which should be big enough to fit squarely into\n"
321   "% the mold and cover the tofu inside.\n"
322   "% \n"
323   "% The next day, pour out the water, and pulverize the beans in a blender\n"
324   "% using enough water to cover the beans (you will probably need to do\n"
325   "% this in four to five batches). Pour the bean mixture into a very large\n"
326   "% pot and add enough water to double the quantity of liquid. Bring the\n"
327   "% liquid to a low boil and lower the temperature, skimming off any foam\n"
328   "% that collects on the top. Boil for 20-30 min. stiring (and skimming)\n"
329   "% constently. While it is boiling, disolve the bittern (the leftover\n"
330   "% \"stuff\" that is formed when you extract salt from seawater) in a small\n"
331   "% quantity of water. Place a piece of cheesecloth in a colander, and\n"
332   "% pour the liquid through it into a large bowel. The liquid that passes\n"
333   "% through is called \"soy milk\" and will become the tofu. The solid\n"
334   "% material that remains in the cheesecloth is called \"okara\" and is\n"
335   "% useful for various Japanese dishes (recipes will come later). For each\n"
336   "% of the molds, fit the cheesecloth squarely into the corners. When the\n"
337   "% temperature of the soy milk cools to 70C (158F) pour in the bittern\n"
338   "% and stir genetly. When the tofu starts to separate from the water\n"
339   "% (almost immediately), pour the mixture into the molds and cover with\n"
340   "% cheesecloth. Next, place the plastic wrap covered newspapers on top of\n"
341   "% the tofu (it should fit squarely) and place weights on top to press\n"
342   "% out the liquid. After about 30 min., remove the tofu from the\n"
343   "% molds. This should be done under water in a large pot or tub. Store\n"
344   "% the tofu submerged in water.\n"
345 };
346 int recipe_count = sizeof(recipe_list)/sizeof(recipe_list[0]);
347 
348 
349 /*
350   Protect an postscript special charcters with a backslash.  Also, if
351   we have enabled Japanese support, insert codes to switch fonts when
352   we find bytes with the high bit set.
353  */
filterParen(char * buf,const char * s)354 char *filterParen(char *buf,const char *s)
355 {
356   if (!s) {
357     *buf = 0;
358     return buf;
359   }
360 
361   if (TkGate.japaneseMode) {
362     char *p;
363     int in_kanji = 0;
364 
365     p = buf;
366     while (*s) {
367       char c;
368 
369       if ((*s & 0x80)) {
370 	if (!in_kanji)
371 	  p += sprintf(p,"\\%03o",FCC_BEGINKANJI);
372 	in_kanji = 1;
373       } else {
374 	if (in_kanji)
375 	  p += sprintf(p,"\\%03o",FCC_ENDKANJI);
376 	in_kanji = 0;
377       }
378 
379       c = (*s++ & 0x7f);
380 
381       if (strchr("()\\",c))
382 	*p++ = '\\';
383 
384       *p++ = c;
385     }
386 
387     if (in_kanji)
388       p += sprintf(p,"\\%03o",FCC_ENDKANJI);
389 
390     *p = 0;
391     return buf;
392   } else {
393     char *p;
394 
395     p = buf;
396     while (*s) {
397       if (strchr("()\\",*s))
398 	*p++ = '\\';
399       if (isprint(*s))
400 	*p++ = *s++;
401       else
402 	p += sprintf(p,"\\%03o",((*s++)&0xff));
403     }
404     *p = 0;
405     return buf;
406   }
407 }
408 
409 /*
410   Return s with all characters in trim removed.
411  */
trimChars(char * buf,char * s,char * trim)412 char *trimChars(char *buf,char *s,char *trim)
413 {
414   char *p;
415 
416   p = buf;
417   while (*s) {
418     if (!strchr(trim,*s))
419       *p++ = *s++;
420     else
421       s++;
422   }
423   *p = 0;
424   return buf;
425 }
426 
427 
428 /*****************************************************************************
429  *
430  * Get the width of a postscript string in points.
431  *
432  * Parameters:
433  *     F		Font to use for text width calculation
434  *     s		Pointer to beginning of string
435  *     len		Length of string
436  *
437  * Returns:		String width in points.
438  *
439  *****************************************************************************/
PSStringWidth(HtmlFont * F,const char * s,int len)440 int PSStringWidth(HtmlFont *F,const char *s,int len)
441 {
442   int width = 0;
443   int i;
444 
445   if (F->gateFont.family == FF_COURIER) {
446     width = fontmetrics_Courier*len*F->gateFont.size;
447   } else if (F->gateFont.family == FF_KANJI) {
448     width = fontmetrics_Kanji*len/2*F->gateFont.size;
449   } else {
450     for (i = 0;i < len;i++) {
451       unsigned char c = s[i];
452       width += psFontWidthTable[F->gateFont.family][F->gateFont.prop][c]*F->points;
453     }
454   }
455 
456   return width/1000;
457 }
458 
PSSetFont(GPrint * P,HtmlFont * font)459 void PSSetFont(GPrint *P,HtmlFont *font)
460 {
461   char *encoding = "";
462 
463   if (font->gateFont.family < FF_NOKANJI_MAX)
464     encoding = "-Latin1";
465 
466   fprintf(P->p_f,"/%s%s findfont %d scalefont setfont\n",
467 	  psFontNameTable[font->gateFont.family][font->gateFont.prop],encoding,font->points);
468 }
469 
PSDrawText(GPrint * P,HtmlFont * font,int x,int y,const char * text,int just)470 void PSDrawText(GPrint *P,HtmlFont *font,int x,int y,const char *text,int just)
471 {
472   static HtmlFont curFont = {.gateFont = {-1, -1, -1}};
473   char buf[STRMAX];
474   char vjust = 'R';
475   char hjust = 'L';
476 
477   if ((just & BetweenLeftAndRight)) hjust = 'C';
478   if ((just & AtRight)) hjust = 'R';
479   if ((just & AtLeft)) hjust = 'L';
480 
481   if ((just & BetweenTopAndBottom)) vjust = 'C';
482   if ((just & AtBaseline)) vjust = 'L';
483   if ((just & AtTop)) vjust = 'T';
484   if ((just & AtBottom)) vjust = 'B';
485 
486   if (!HtmlFont_isEqual(&curFont, font)) {
487     PSSetFont(P,font);
488     curFont = *font;
489   }
490 
491   fprintf(P->p_f,"(%s) /%c /%c %d %d pjshow\n",filterParen(buf,text),hjust,vjust,x,y);
492 }
493 
GPrintOpt_init(GPrintOpt * PO)494 void GPrintOpt_init(GPrintOpt *PO)
495 {
496   PO->po_cmd = 0;
497   PO->po_file = 0;
498   PO->po_paper = 0;
499   PO->po_orient = 0;
500   PO->po_style = 0;
501   PO->po_select = 0;
502   PO->po_modlist = 0;
503   PO->po_epsf = 0;
504   PO->po_index = 0;
505   PO->po_graph = 0;
506   PO->po_4up = 0;
507   PO->po_isDuplex = 0;
508   PO->po_start = 0;
509   PO->po_end = 0;
510   PO->po_scaleLength = 0;
511   PO->po_incLib = 0;
512 }
513 
514 /*
515  * Set up defaults for command line printing
516  */
GPrintOpt_clDefault(GPrintOpt * PO)517 void GPrintOpt_clDefault(GPrintOpt *PO)
518 {
519   PO->po_title = "";
520   PO->po_cmd = 0;
521   PO->po_file = 0;
522   PO->po_paper = "Letter";
523   PO->po_orient = "landscape";
524   PO->po_style = "partition";
525   PO->po_select = "all";
526   PO->po_modlist = "";
527   PO->po_epsf = "0";
528   PO->po_index = "0";
529   PO->po_graph = "0";
530   PO->po_4up = "1";
531   PO->po_isDuplex = "0";
532   PO->po_start = 0;
533   PO->po_end = 0;
534   PO->po_scaleLength = 0;
535   PO->po_incLib = "0";
536 }
537 
new_GModLayout(GModuleDef * M)538 GModLayout *new_GModLayout(GModuleDef *M)
539 {
540   GModLayout *L = (GModLayout *) ob_malloc(sizeof(GModLayout),"GModLayout");
541   assert(L);
542 
543   L->l_xbase = L->l_ybase = L->l_width = L->l_height = 0.0;
544   L->l_isSmall = 0;
545   L->l_xmin = L->l_xmax = L->l_ymin = L->l_ymax = 0;
546 
547   L->l_numRows = L->l_numCols = 1;
548 
549   L->l_mod = M;
550 
551   return L;
552 }
553 
copyNew_GModLayout(GModLayout * L)554 GModLayout *copyNew_GModLayout(GModLayout *L)
555 {
556   GModLayout *cL = (GModLayout *) ob_malloc(sizeof(GModLayout),"GModLayout");
557   assert(cL);
558 
559   *cL = *L;
560 
561   return cL;
562 }
563 
delete_GModLayout(GModLayout * L)564 void delete_GModLayout(GModLayout *L)
565 {
566   ob_free(L);
567 }
568 
new_GPage(int tp,int pn)569 GPage *new_GPage(int tp,int pn)
570 {
571   GPage *P = (GPage *) ob_malloc(sizeof(GPage),"GPage");
572   assert(P);
573 
574   P->pg_num = pn;
575   P->pg_type = tp;
576   P->pg_nmod = 0;
577 
578   return P;
579 }
580 
delete_GPage(GPage * P)581 void delete_GPage(GPage *P)
582 {
583   ob_free(P);
584 }
585 
586 /*****************************************************************************
587  *
588  * Get set of all modules used in the current circuit.
589  *
590  * Parameters:
591  *     H	Return of set of modules used in the current circuit
592  *     L	Array of layouts of used modules.
593  *     M	Top-level module to search.
594  *     incLib	Non-zero if top-level modules should be included.
595  *
596  *****************************************************************************/
GPrint_getUsedMods(PHash * H,GModLayout ** L,GModuleDef * M,int incLib)597 static int GPrint_getUsedMods(PHash *H,GModLayout **L,GModuleDef *M,int incLib)
598 {
599   int num = 0;
600   HashElem *E;
601 
602   if (PHash_find(H,M)) return 0;
603   PHash_insert(H,M,M);
604 
605   if (!M->m_isLib || incLib)
606     L[num++] = new_GModLayout(M);
607 
608   for (E = Hash_first(M->m_gates);E;E = Hash_next(M->m_gates,E)) {
609     GCElement *g = (GCElement*) HashElem_obj(E);
610     if (GCElement_isModule(g)) {
611       GModuleDef *CM = env_findModule(g->u.block.moduleName);
612       if (CM) {
613 	num += GPrint_getUsedMods(H,L+num,CM,incLib);
614       }
615     }
616   }
617 
618   return num;
619 }
620 
621 /*****************************************************************************
622  *
623  * Create print context
624  *
625  * Parameters:
626  *     PO		Printer options
627  *
628  * Returns:		New print context.
629  *
630  *****************************************************************************/
new_GPrint(GPrintOpt * PO)631 GPrint *new_GPrint(GPrintOpt *PO)
632 {
633   GPrint *P = (GPrint *) ob_malloc(sizeof(GPrint),"GPrint");
634   PaperSize *size = 0;
635   int i;
636   int incLib = 0;
637 
638   assert(P);
639 
640   P->p_opts = *PO;
641 
642   PHash_init_noob(&P->p_genSymbols);
643 
644   /*
645    * Basic initialize so object is deletable.
646    */
647   P->p_isFile = 0;
648   P->p_f = 0;
649   P->p_mods = 0;
650 
651   P->p_isDuplex = (strcmp(PO->po_isDuplex,"1") == 0);
652   P->p_isepsf   = (strcmp(PO->po_epsf,"1") == 0);
653   P->p_style    = (PO->po_style && strcmp(PO->po_style,"fit") == 0) ? PS_FIT : PS_PARTITION;
654 
655   /*
656    * Trace related parameters
657    */
658   P->p_trace.ti_start = P->p_trace.ti_end = 0;
659   if (PO->po_start) sscanf(PO->po_start,"%llu",&P->p_trace.ti_start);
660   if (PO->po_end) sscanf(PO->po_end,"%llu",&P->p_trace.ti_end);
661   if (PO->po_scaleLength) sscanf(PO->po_scaleLength,"%llu",&P->p_trace.ti_scaleLength);
662 
663 
664   if (PO->po_incLib) sscanf(PO->po_incLib,"%d",&incLib);
665 
666   /*
667     If this is a scope trace then there must be a positive range.
668    */
669   if (PO->po_start) {
670     if (P->p_trace.ti_start >= P->p_trace.ti_end) {
671       message(1,msgLookup("err.badrange"));		/* Non-positive range for scope trace is not allowed. */
672       delete_GPrint(P);
673       return 0;
674     }
675   }
676 
677   /*
678     Open printer or file.
679    */
680   if (PO->po_cmd) {
681     if (!(P->p_f = popen(PO->po_cmd,"w"))) {
682       message(1,msgLookup("err.badlprcmd"),PO->po_cmd);		/* Unable to exectute printer command '%s'. */
683       delete_GPrint(P);
684       return 0;
685     }
686     P->p_isFile = 0;
687   } else {
688     if (!(P->p_f = fopen(PO->po_file,"w"))) {
689       message(1,msgLookup("err.badpsopen"),PO->po_file);	/* Unable to open file '%s' for postscript output. */
690       delete_GPrint(P);
691       return 0;
692     }
693     P->p_isFile = 1;
694   }
695 
696   /*
697     Find paper size and orientation
698    */
699   for (i = 0;paperSizes[i].ps_size;i++) {
700     size = &paperSizes[i];
701     if (strcmp(size->ps_size,PO->po_paper) == 0)
702       break;
703   }
704   P->p_size = size;
705 
706   if (strcmp(PO->po_orient,"landscape") == 0 && !P->p_isepsf) {
707     P->p_orient = 1;
708     P->p_width = size->ps_height;
709     P->p_height = size->ps_width;
710   } else {
711     P->p_orient = 0;
712     P->p_width = size->ps_width;
713     P->p_height = size->ps_height;
714   }
715 
716   P->p_uWidth = P->p_width - PAGE_LMARGIN - PAGE_RMARGIN;
717   P->p_uHeight = P->p_height- PAGE_TMARGIN - PAGE_BMARGIN - PAGE_LBLOCK;
718 
719   P->p_mods = 0;
720   P->p_numMods = 0;
721 
722   if (P->p_isepsf) {
723     /* EPSF implies that we use the current module */
724     P->p_numMods = 1;
725     P->p_mods = (GModLayout**) ob_malloc(sizeof(GModLayout*),"GModLayout*");
726     assert(P->p_mods);
727     P->p_mods[0] = new_GModLayout(TkGate.circuit->es->env);
728   } else if (PO->po_select) {
729     if (strcmp(PO->po_select,"all") == 0) {
730       HashElem *E;
731       P->p_mods = (GModLayout**) ob_malloc(Hash_numElems(TkGate.circuit->moduleTable)*sizeof(GModLayout*),"GModLayout*[]");
732       assert(P->p_mods);
733 
734       for (E = Hash_first(TkGate.circuit->moduleTable);E;E = Hash_next(TkGate.circuit->moduleTable,E)) {
735 	GModuleDef *M = (GModuleDef *) HashElem_obj(E);
736 	if (!M->m_isLib || incLib) {
737 	  GModLayout *L = new_GModLayout(M);
738 	  P->p_mods[P->p_numMods++] = L;
739 	}
740       }
741     } else if (strcmp(PO->po_select,"use") == 0) {
742       PHash *H = new_PHash();
743 
744       P->p_mods = (GModLayout**) ob_malloc(Hash_numElems(TkGate.circuit->moduleTable)*sizeof(GModLayout*),"GModLayout*[]");
745       assert(P->p_mods);
746 
747       P->p_numMods = GPrint_getUsedMods(H,P->p_mods,TkGate.circuit->root_mod,incLib);
748       delete_PHash(H);
749 
750     } else if (strcmp(PO->po_select,"sel") == 0) {
751       char *T, *buf;
752 
753       P->p_numMods = 0;
754       P->p_mods = (GModLayout**) ob_malloc(Hash_numElems(TkGate.circuit->moduleTable)*sizeof(GModLayout*),"GModLayout*");
755       assert(P->p_mods);
756 
757       buf = strdup(PO->po_modlist);
758       for (T = strtok(buf," ,");T;T = strtok(0," ,")) {
759 	char buf2[STRMAX];
760 	GModuleDef *M = env_findModule(trimChars(buf2,T,"()+"));
761 	if (M)
762 	  P->p_mods[P->p_numMods++] = new_GModLayout(M);
763       }
764       free(buf);
765 
766     } else { /* cur or unknown */
767       P->p_numMods = 1;
768       P->p_mods = (GModLayout**) ob_malloc(sizeof(GModLayout*),"GModLayout*");
769       assert(P->p_mods);
770       P->p_mods[0] = new_GModLayout(TkGate.circuit->es->env);
771     }
772   }
773 
774   P->p_numPages = P->p_numMods;
775 
776   return P;
777 }
778 
779 /*****************************************************************************
780  *
781  * Delete a print context.
782  *
783  * Parameters:
784  *     P		Print context to be deleted.
785  *
786  *****************************************************************************/
delete_GPrint(GPrint * P)787 void delete_GPrint(GPrint *P)
788 {
789   PHash_uninit(&P->p_genSymbols);
790 
791   if (P->p_f) {
792     if (P->p_isFile)
793       fclose(P->p_f);
794     else
795       pclose(P->p_f);
796   }
797 
798   if (P->p_mods) {
799     int i;
800     for (i = 0;i < P->p_numMods;i++) {
801       delete_GModLayout(P->p_mods[i]);
802     }
803     ob_free(P->p_mods);
804   }
805   ob_free(P);
806 }
807 
808 
GPrint_pageSetup(GPrint * P)809 static void GPrint_pageSetup(GPrint *P)
810 {
811 #if 0
812   const char *tray = P->p_size->ps_tray;
813 #endif
814   const char *dup_mode = P->p_isDuplex ? "true" : "false";
815 
816   /*
817    * Don't generate page setup for EPSF files.
818    */
819   if (P->p_isepsf) return;
820 
821   fprintf(P->p_f,"%%%%BeginSetup\n");
822   fprintf(P->p_f,"%%%%IncludeResource: font Hevetica\n");
823   fprintf(P->p_f,"%%%%IncludeResource: font Hevetica-Oblique\n");
824   fprintf(P->p_f,"%%%%IncludeResource: font Hevetica-Bold\n");
825   fprintf(P->p_f,"%%%%IncludeResource: font Hevetica-BoldOblique\n");
826   fprintf(P->p_f,"%%%%IncludeResource: font Symbol\n");
827 
828   /*
829    * This is causing problems for non-Letter size paper.
830    */
831 #if 0
832   fprintf(P->p_f,"%%%%BeginFeature: *PageSize %s\n",tray);
833   fprintf(P->p_f,"statusdict /%s known {\n",tray);
834   fprintf(P->p_f,"  statusdict begin\n");
835   fprintf(P->p_f,"    %s\n",tray);
836   fprintf(P->p_f,"  end\n");
837   fprintf(P->p_f,"} if\n");
838   fprintf(P->p_f,"%%%%EndFeature\n");
839 #endif
840 
841   fprintf(P->p_f,"%%%%BeginFeature: *DuplexMode %s\n",dup_mode);
842   fprintf(P->p_f,"statusdict /setduplexmode known {\n");
843   fprintf(P->p_f,"  statusdict begin\n");
844   fprintf(P->p_f,"    %s setduplexmode\n",dup_mode);
845   fprintf(P->p_f,"  end\n");
846   fprintf(P->p_f,"} if\n");
847   fprintf(P->p_f,"%%%%EndFeature\n");
848 
849   fprintf(P->p_f,"%%%%EndSetup\n");
850 }
851 
GPrint_createFonts(GPrint * P,Encoder * encoding)852 void GPrint_createFonts(GPrint *P,Encoder *encoding)
853 {
854   const char *encodingName = "-Latin1";
855   int i,j;
856 
857   for (i = 0;i < FF_NOKANJI_MAX;i++)
858     for (j = 0;j < FP_MAX;j++)
859       fprintf(P->p_f,"/%s-Latin1 /%s findfont defLatin1\n",
860 	      psFontNameTable[i][j],psFontNameTable[i][j]);
861 
862   /*
863    * Generate font commands for backward compatability.
864    */
865   fprintf(P->p_f,"/cfont { /%s%s findfont exch scalefont setfont } bind def\n",
866 	  psFontNameTable[FF_COURIER][FP_ROMAN],encodingName);
867   fprintf(P->p_f,"/rfont { /%s%s findfont exch scalefont setfont } bind def\n",
868 	  psFontNameTable[FF_HELVETICA][FP_ROMAN],encodingName);
869   fprintf(P->p_f,"/bfont { /%s%s findfont exch scalefont setfont } bind def\n",
870 	  psFontNameTable[FF_HELVETICA][FP_BOLD],encodingName);
871   fprintf(P->p_f,"/ifont { /%s%s findfont exch scalefont setfont } bind def\n",
872 	  psFontNameTable[FF_HELVETICA][FP_ITALIC],encodingName);
873   fprintf(P->p_f,"/bifont { /%s%s findfont exch scalefont setfont } bind def\n",
874 	  psFontNameTable[FF_HELVETICA][(FP_BOLD|FP_ITALIC)],encodingName);
875   fprintf(P->p_f,"/syfont { /%s findfont exch scalefont setfont } bind def\n",
876 	  psFontNameTable[FF_SYMBOL][FP_ROMAN]);
877 
878   /*
879    * Generate kanji font if needed
880    */
881   if (TkGate.japaneseMode) {
882     fprintf(P->p_f,"/kfont { /%s findfont exch scalefont setfont } bind def\n",
883 	    psFontNameTable[FF_KANJI][FP_ROMAN]);
884   }
885 
886 }
887 
888 /*****************************************************************************
889  *
890  * Generate the preamble of a postscript file.
891  *
892  * Parameters:
893  *     P		Print context to use.
894  *     do_gates		Non-zero if preamble code for drawing gates should be generated.
895  *
896  *****************************************************************************/
GPrint_outputPreamble(GPrint * P,int do_gates)897 void GPrint_outputPreamble(GPrint *P,int do_gates)
898 {
899   static char *month[] = {"January","February","March","April","May","June","July",
900 			  "August","September","October","November","December"};
901   struct passwd *pw;
902   struct tm *tm;
903   time_t clock[1];
904   int i,j;
905   HashElem *E;
906   int n;
907   char buf[STRMAX];
908   int recipe_pos = random() % 15;
909 
910   pw = getpwuid(getuid());
911 
912   time(clock);
913   tm = localtime(clock);
914 
915   fprintf(P->p_f,"%%!PS-Adobe-3.0%s\n",P->p_isepsf ? " EPSF-1.2" : "");
916   /*  fprintf(P->p_f,"%%%%Title: %s\n",P->p_opts.po_title);*/
917   fprintf(P->p_f,"%%%%Title: %s\n",TkGate.circuit->title);
918 
919 
920   fprintf(P->p_f,"%%%%DocumentNeededResources: font");
921   for (i = 0;i < FF_MAX;i++)
922     for (j = 0;j < FP_MAX;j++) {
923       if (TkGate.japaneseMode || i != FF_KANJI)
924 	fprintf(P->p_f," %s",psFontNameTable[i][j]);
925     }
926   fprintf(P->p_f,"\n");
927 
928   fprintf(P->p_f,"%%%%Creator: %s and TKGate %s\n",filterParen(buf,pw->pw_gecos),VERSIONS[0].vd_name);
929   fprintf(P->p_f,"%%%%CreationDate: %d %s %d\n",tm->tm_mday,month[tm->tm_mon],1900+tm->tm_year);
930   if (!P->p_isepsf) {
931     fprintf(P->p_f,"%%%%DocumentPaperSizes: %s\n",P->p_opts.po_paper);
932     fprintf(P->p_f,"%%%%Pages: %d\n",P->p_numPages);
933     fprintf(P->p_f,"%%%%Orientation: %s\n",P->p_orient ? "Landscape" : "Portrait");
934   } else {
935     if (P->p_mods && P->p_mods[0]) {
936       GModLayout *ML = P->p_mods[0];
937       fprintf(P->p_f,"%%%%BoundingBox: %d %d %d %d\n",
938 	      EPSF_MINX,EPSF_MINY,
939 	      EPSF_MINX+(ML->l_xmax-ML->l_xmin),EPSF_MINY+(ML->l_ymax-ML->l_ymin));
940     }
941   }
942 
943   fprintf(P->p_f,"%%%%EndComments\n");
944 
945   for (i = 0;gateps_copyright[i];i++)
946     fprintf(P->p_f,"%s\n",gateps_copyright[i]);
947 
948   if (TkGate.japaneseMode) {
949     for (i = 0;kanji_support_prolog[i];i++)
950       fprintf(P->p_f,"%s\n",kanji_support_prolog[i]);
951   }
952 
953   for (i = 0;gateprolog[i];i++)
954     fprintf(P->p_f,"%s\n",gateprolog[i]);
955 
956   if (do_gates) {
957     n = 0;
958     for (E = Hash_first(GateIdxHash);E;E = Hash_next(GateIdxHash,E)) {
959       GGateInfo *gi = (GGateInfo*) HashElem_obj(E);
960 
961       if (++n == recipe_pos) {
962 	int r_idx;
963 	const char *r;
964 
965 	fprintf(P->p_f,"%% ...and now for something completely different...\n");
966 	fprintf(P->p_f,"%%\n");
967 
968 	r_idx = random() % recipe_count;
969 	r = recipe_list[r_idx];
970 	fprintf(P->p_f,"%s",r);
971       }
972 
973       if (!gi->psdef) continue;
974       for (i = 0;gi->psdef[i];i++)
975 	fprintf(P->p_f,"%s\n",gi->psdef[i]);
976     }
977   }
978 
979   fprintf(P->p_f,"\n");
980   fprintf(P->p_f,"/Author (%s) def\n",filterParen(buf,pw->pw_gecos));
981   fprintf(P->p_f,"/Site (%s) def\n",filterParen(buf,TkGate.siteName));
982   fprintf(P->p_f,"/Date (%s %d, %d) def\n",month[tm->tm_mon],tm->tm_mday,1900+tm->tm_year);
983   fprintf(P->p_f,"/CircuitName (%s) def\n",filterParen(buf,TkGate.circuit->title));
984   fprintf(P->p_f,"/isepsf %s def\n",P->p_isepsf ? "true" : "false");
985   fprintf(P->p_f,"/NumPages ( of %d) def\n",P->p_numPages);
986   fprintf(P->p_f,"/GateVersion (TKGate %s) def\n",VERSIONS[0].vd_name);
987   fprintf(P->p_f,"/IsLandscape %s def\n",P->p_orient ? "true" : "false");
988   fprintf(P->p_f,"/PageWidth %0.2f def\n",P->p_width);
989   fprintf(P->p_f,"/PageHeight %0.2f def\n",P->p_height);
990   fprintf(P->p_f,"/LMargin %d def\n",PAGE_LMARGIN);
991   fprintf(P->p_f,"/RMargin %d def\n",PAGE_LMARGIN);
992   fprintf(P->p_f,"/TMargin %d def\n",PAGE_LMARGIN);
993   fprintf(P->p_f,"/BMargin %d def\n",PAGE_LMARGIN);
994   fprintf(P->p_f,"/LBlock %d def\n",PAGE_LBLOCK);
995 
996   if (TkGate.japaneseMode) {
997     fprintf(P->p_f,"/FCCToggleKanji (\\%03o) def\n",FCC_BEGINKANJI);
998   }
999 
1000   /*
1001    * If using Latin1 fonts, generate definitions for those fonts.
1002    */
1003   GPrint_createFonts(P, Circuit_getPSEncoder(TkGate.circuit));
1004 
1005   fprintf(P->p_f,"%%%%EndProlog\n");
1006   GPrint_pageSetup(P);
1007   fprintf(P->p_f,"\n");
1008 }
1009 
1010 /*****************************************************************************
1011  *
1012  * Generate the postscript trailer
1013  *
1014  * Parameters:
1015  *     P		Print context to use.
1016  *
1017  *****************************************************************************/
GPrint_outputTrailer(GPrint * P)1018 void GPrint_outputTrailer(GPrint *P)
1019 {
1020   fprintf(P->p_f,"%%%%Tailer\n");
1021 }
1022 
1023 /*****************************************************************************
1024  *
1025  * Print the currently selected critical path of a module
1026  *
1027  * Parameters:
1028  *     P		Print context to use.
1029  *     L		Module layout to be printed.
1030  *
1031  *****************************************************************************/
GPrint_printModuleCPath(GPrint * P,GModLayout * L)1032 static void GPrint_printModuleCPath(GPrint *P,GModLayout *L)
1033 {
1034   GModuleDef *M = L->l_mod;
1035   GWireList *wl;
1036 
1037   for (wl = M->m_wires;wl;wl = wl->wl_next) {
1038     GWire *w = wl->wl_wire;
1039     GWireNode *n = 0;
1040 
1041     /*
1042      * Draw critical path if set
1043      */
1044     if (w->cpath) {
1045       if (w->gate && w->gate->typeinfo->code == GC_JOINT) {
1046 	int x = w->gate->xpos;
1047 	int y = w->gate->ypos;
1048 
1049 	fprintf(P->p_f,"%d %d joint_gray\n",x,y);
1050       }
1051       if (w->nodes->out) {
1052 	fprintf(P->p_f,"gsave\n");
1053 	fprintf(P->p_f,"8 setlinewidth\n");
1054 	fprintf(P->p_f,".5 setgray\n");
1055 	fprintf(P->p_f,"newpath\n");
1056 
1057 	for (n = w->nodes;n;n = n->out) {
1058 	  int x,y;
1059 
1060 	  x = n->x;
1061 	  y = n->y;
1062 
1063 	  if (n == w->nodes) {
1064 	    fprintf(P->p_f,"%d %d moveto\n",x,y);
1065 	  } else {
1066 	    fprintf(P->p_f,"%d %d lineto\n",x,y);
1067 	  }
1068 	}
1069 	fprintf(P->p_f,"stroke\n");
1070 	fprintf(P->p_f,"grestore\n");
1071       }
1072     }
1073   }
1074 }
1075 
GPrint_printLabelsAndSizes(GPrint * P,GModLayout * L,GWire * w)1076 void GPrint_printLabelsAndSizes(GPrint *P,GModLayout *L,GWire *w)
1077 {
1078   GWireNode *n;
1079   int x,y,p;
1080   char label[STRMAX];
1081 
1082   GNet_getDisplayLabel(w->net, label, STRMAX, DLM_GET_ALWAYS);
1083 
1084   for (n = w->nodes;n && n->out;n = n->out) {
1085     if (n->showSize && w->net->n_nbits > 1) {
1086       x = (n->x + n->out->x)/2;
1087       y = (n->y + n->out->y)/2;
1088       fprintf(P->p_f,"%d %d sizesymbol\n",x,y);
1089       if (n->x == n->out->x)
1090 	fprintf(P->p_f,"(%d) %d %d %d wirelabel\n",w->net->n_nbits,BetweenTopAndBottom|AtLeft,x+8,y);
1091       else
1092 	fprintf(P->p_f,"(%d) %d %d %d wirelabel\n",w->net->n_nbits,BetweenLeftAndRight|AtBottom,x,y-3);
1093     }
1094     if (n->isLabeled) {
1095       GWireNode_getLabelPos(n,w->net,&x,&y,&p);
1096 
1097       fprintf(P->p_f,"(%s) %d %d %d wirelabel\n",label,p,x,y);
1098 
1099     }
1100   }
1101 }
1102 
1103 /*****************************************************************************
1104  *
1105  * Display all of the wires in a module.
1106  *
1107  * Parameters:
1108  *     P		Print context to use.
1109  *     L		Module for which wires are to be displayed.
1110  *
1111  *****************************************************************************/
GPrint_printModuleWires(GPrint * P,GModLayout * L)1112 static void GPrint_printModuleWires(GPrint *P,GModLayout *L)
1113 {
1114   GModuleDef *M = L->l_mod;
1115   GWireList *wl;
1116   int last_was_multi = 0;
1117 
1118   for (wl = M->m_wires;wl;wl = wl->wl_next) {
1119     GWire *w = wl->wl_wire;
1120     GWireNode *n = 0;
1121     int is_multi;
1122 
1123     if (!w->nodes->out) continue;	/* Print in one direction only */
1124 
1125     GPrint_printLabelsAndSizes(P,L,w);
1126 
1127     /*
1128      * Do the actual drawing of the wire.
1129      */
1130     is_multi = (w->net->n_nbits != 1);
1131     if (is_multi != last_was_multi) {
1132       if (is_multi)
1133 	fprintf(P->p_f,"2 setlinewidth\n");
1134       else
1135 	fprintf(P->p_f,"1 setlinewidth\n");
1136     }
1137     last_was_multi = is_multi;
1138     fprintf(P->p_f,"newpath\n");
1139     for (n = w->nodes;n;n = n->out) {
1140       int x,y;
1141 
1142       x = n->x;
1143       y = n->y;
1144       if (n->end && n->end->invert) {
1145 	int x2,y2,xi,yi;
1146 
1147 	xi = x;
1148 	yi = y;
1149 
1150 	if (n->out) {
1151 	  x2 = n->out->x;
1152 	  y2 = n->out->y;
1153 	} else {
1154 	  x2 = n->in->x;
1155 	  y2 = n->in->y;
1156 	}
1157 
1158 	if (y == y2) {
1159 	  if (x2 > x) {
1160 	    xi += 2;
1161 	    x += 4;
1162 	  } else {
1163 	    xi -= 2;
1164 	    x -= 4;
1165 	  }
1166 	} else {
1167 	  if (y2 > y) {
1168 	    yi += 2;
1169 	    y += 4;
1170 	  } else {
1171 	    yi -= 2;
1172 	    y -= 4;
1173 	  }
1174 	}
1175 
1176 	fprintf(P->p_f,"%d %d inverter\n",xi,yi);
1177       }
1178 
1179       if (n == w->nodes) {
1180 	fprintf(P->p_f,"%d %d moveto\n",x,y);
1181       } else {
1182 	fprintf(P->p_f,"%d %d lineto\n",x,y);
1183       }
1184     }
1185     fprintf(P->p_f,"stroke\n");
1186   }
1187 }
1188 
1189 /*****************************************************************************
1190  *
1191  * Print a single HDL module
1192  *
1193  * Parameters:
1194  *      P		Printer state variable
1195  *      L		Module with layout information
1196  *
1197  *
1198  *****************************************************************************/
GPrint_printHdlModule(GPrint * P,GModLayout * L,double xoff,double yoff)1199 static void GPrint_printHdlModule(GPrint *P,GModLayout *L,double xoff,double yoff)
1200 {
1201   int linesPerPage = (P->p_uHeight-2*PAGE_MODMARGIN)/(int)(1.2*hdl_font.points);
1202   int lineCount = 0;
1203   int startLine = 0;
1204   GModuleDef *M = L->l_mod;
1205   Encoder *encoder = Circuit_getPSEncoder(TkGate.circuit);
1206   char *c;
1207   int x,y;
1208 
1209   //  fprintf(P->p_f,"%f %f translate\n",xoff,yoff);
1210 
1211 #if 0
1212   fprintf(P->p_f,"gsave\n");
1213   fprintf(P->p_f,"  1 0 0 setrgbcolor\n");
1214   fprintf(P->p_f,"  newpath\n");
1215   fprintf(P->p_f,"  %d %d moveto\n",0,0);
1216   fprintf(P->p_f,"  %d %d lineto\n",L->l_width,0);
1217   fprintf(P->p_f,"  %d %d lineto\n",L->l_width,L->l_height);
1218   fprintf(P->p_f,"  %d %d lineto\n",0,L->l_height);
1219   fprintf(P->p_f,"  closepath stroke\n");
1220   fprintf(P->p_f,"grestore\n");
1221 #endif
1222 
1223   fprintf(P->p_f,"%d cfont\n",hdl_font.points);
1224   x = 0;
1225   y = L->l_height-0;
1226 
1227   startLine = linesPerPage*L->l_r;
1228 
1229   for (c = M->m_text;*c;) {
1230     char buf[STRMAX];		/* Buffer for parenthesis filtering */
1231     char line[STRMAX];		/* Raw line of text */
1232     char dline[STRMAX];		/* decode raw line of text */
1233     int l;
1234     char *e;
1235 
1236     for (e = c;*e && *e != '\n';e++);
1237 
1238     l = (e-c);
1239     if (l > STRMAX-1) l = STRMAX-1;
1240     strncpy(line,c,e-c);
1241     line[l] = 0;
1242 
1243     if (lineCount >= startLine) {
1244       y -= 1.2*hdl_font.points;
1245       fprintf(P->p_f,"%d %d moveto\n",x,y);
1246       recodeText(encoder,dline,STRMAX,line);
1247       fprintf(P->p_f,"(%s) show\n",filterParen(buf,dline));
1248     }
1249     lineCount++;
1250 
1251     if (lineCount >= (startLine + linesPerPage)) break;
1252 
1253     if (!*e) break;
1254     c = e+1;
1255   }
1256 }
1257 
1258 /*****************************************************************************
1259  *
1260  * Print a single netlist module
1261  *
1262  * Parameters:
1263  *      P		Printer state variable
1264  *      L		Module with layout information
1265  *
1266  *
1267  *****************************************************************************/
GPrint_printNetlistModule(GPrint * P,GModLayout * L,double scale,double xoff,double yoff)1268 static void GPrint_printNetlistModule(GPrint *P,GModLayout *L,double scale,double xoff,double yoff)
1269 {
1270   GModuleDef *M = L->l_mod;
1271   HashElem *E;
1272 
1273   fprintf(P->p_f,"0 %d translate\n",L->l_height);
1274   if (scale != 1.0)
1275     fprintf(P->p_f,"%f %f scale\n",scale,scale);
1276   fprintf(P->p_f,"1 -1 scale\n");
1277   fprintf(P->p_f,"%f %f translate\n",xoff,yoff);
1278 
1279   GPrint_printModuleCPath(P,L);
1280   GPrint_printModuleWires(P,L);
1281 
1282 
1283   for (E = Hash_first(M->m_gates);E;E = Hash_next(M->m_gates,E)) {
1284     GCElement *g = (GCElement*) HashElem_obj(E);
1285     (*g->typeinfo->PSWrite)(P,L,g);
1286   }
1287 }
1288 
1289 
1290 /*****************************************************************************
1291  *
1292  * Print a single module
1293  *
1294  * Parameters:
1295  *      P		Printer state variable
1296  *      L		Module with layout information
1297  *
1298  *
1299  *****************************************************************************/
GPrint_printModule(GPrint * P,GModLayout * L,double scale,double xoff,double yoff)1300 static void GPrint_printModule(GPrint *P,GModLayout *L,double scale,double xoff,double yoff)
1301 {
1302   GModuleDef *M = L->l_mod;
1303 
1304 
1305   fprintf(P->p_f,"gsave\n");
1306 
1307   if (GModuleDef_getType(M) == MT_TEXTHDL) {
1308     GPrint_printHdlModule(P,L,xoff,yoff);
1309   } else {
1310     GPrint_printNetlistModule(P,L,scale,xoff,yoff);
1311   }
1312 
1313   fprintf(P->p_f,"grestore\n");
1314 }
1315 
1316 
1317 /*****************************************************************************
1318  *
1319  * Print a layout of a module
1320  *
1321  * Parameters:
1322  *     P
1323  *     L
1324  *
1325  * When pages are partitioned, we include a little overlap on the edges to
1326  * compensate for any gates that might have been cut in two.
1327  *
1328  *         V
1329  * +-------+-+-------+
1330  * |       | |       |
1331  * |       | |       |
1332  * |       | |       |
1333  * +-------+-+-------+
1334  * |       | |       |
1335  * +-------+-+-------+<
1336  * |       | |       |
1337  * |       | |       |
1338  * |       | |       |
1339  * +-------+-+-------+
1340  *
1341  *****************************************************************************/
GPrint_printLayout(GPrint * P,GModLayout * L)1342 static void GPrint_printLayout(GPrint *P,GModLayout *L)
1343 {
1344   double xoff,yoff,scale;
1345 
1346   scale = 1.0;
1347 
1348   if (L->l_numRows <= 1 && L->l_numCols <= 1) {
1349     /*
1350      * The circuit is not paritioned.  Center it in the layout area by computing
1351      * the necessary offset.  If it is bigger than the layout area scale it
1352      * to make it fit.
1353      */
1354     int cwidth = (L->l_xmax-L->l_xmin);
1355     int cheight = (L->l_ymax-L->l_ymin);
1356     if (cwidth > L->l_width-PAGE_MODMARGIN*2 || cheight > L->l_height-PAGE_MODMARGIN*2) {
1357       double xscale = (double)(L->l_width-PAGE_MODMARGIN*2)/(double)cwidth;
1358       double yscale = (double)(L->l_height-PAGE_MODMARGIN*2)/(double)cheight;
1359       if (xscale < yscale)
1360 	scale = xscale;
1361       else
1362 	scale = yscale;
1363     }
1364     xoff = ((double)L->l_width/scale - (L->l_xmax+L->l_xmin))/2.0;
1365     yoff = ((double)L->l_height/scale - (L->l_ymax+L->l_ymin))/2.0;
1366   } else {
1367     /*
1368      * This is a piece of a partitioned circuit.
1369      */
1370 
1371     int xmin = L->l_xmin + L->l_c*L->l_width;
1372     int ymin = L->l_ymin + L->l_r*L->l_height;
1373     int xmax = xmin + L->l_width;
1374     int ymax = ymin + L->l_height;
1375 
1376     xoff = ((double)L->l_width/scale - (xmax+xmin))/2.0;
1377     yoff = ((double)L->l_height/scale - (ymax+ymin))/2.0;
1378   }
1379 
1380 #if 0
1381   fprintf(P->p_f,"newpath\n");
1382   fprintf(P->p_f,"%d %d 3 0 360 arc closepath fill\n",PAGE_MODMARGIN,PAGE_MODMARGIN);
1383   fprintf(P->p_f,"%d %d 3 0 360 arc closepath fill\n",L->l_width-PAGE_MODMARGIN,PAGE_MODMARGIN);
1384   fprintf(P->p_f,"%d %d 3 0 360 arc closepath fill\n",L->l_width-PAGE_MODMARGIN,L->l_height-PAGE_MODMARGIN);
1385   fprintf(P->p_f,"%d %d 3 0 360 arc closepath fill\n",PAGE_MODMARGIN,L->l_height-PAGE_MODMARGIN);
1386 
1387   fprintf(P->p_f,"%d %d moveto\n",PAGE_MODMARGIN,PAGE_MODMARGIN);
1388   fprintf(P->p_f,"%d %d lineto stroke\n",L->l_width-PAGE_MODMARGIN,L->l_height-PAGE_MODMARGIN);
1389   fprintf(P->p_f,"%d %d moveto\n",L->l_width-PAGE_MODMARGIN,PAGE_MODMARGIN);
1390   fprintf(P->p_f,"%d %d lineto stroke\n",PAGE_MODMARGIN,L->l_height-PAGE_MODMARGIN);
1391 #endif
1392 
1393   GPrint_printModule(P,L,scale,xoff,yoff);
1394 }
1395 
GPrint_printModPage(GPrint * P,GPage * PG)1396 static void GPrint_printModPage(GPrint *P,GPage *PG)
1397 {
1398   char buf[STRMAX];
1399   GModLayout *L = PG->pg_mods[0];
1400 
1401   if (L->l_numCols > 1 || L->l_numRows > 1) {
1402     fprintf(P->p_f,"%d %d %d %d (%d of %d) (%s) BP_P\n",
1403 	    L->l_r,L->l_c,L->l_numRows,L->l_numCols,PG->pg_num,P->p_numPages,
1404 	    filterParen(buf,L->l_mod->m_name));
1405     fprintf(P->p_f,"() %d %d %d %d BM\n",
1406 	    L->l_xbase,L->l_ybase,L->l_width,L->l_height);
1407   } else {
1408     fprintf(P->p_f,"(%d of %d) (%s) BP\n",PG->pg_num,P->p_numPages,
1409 	    filterParen(buf,L->l_mod->m_name));
1410 
1411     fprintf(P->p_f,"() %d %d %d %d BM\n",
1412 	    L->l_xbase,L->l_ybase,L->l_width,L->l_height);
1413   }
1414   GPrint_printLayout(P,L);
1415   fprintf(P->p_f,"EM\n");
1416   fprintf(P->p_f,"EP\n");
1417 }
1418 
GPrint_printMod4Page(GPrint * P,GPage * PG)1419 static void GPrint_printMod4Page(GPrint *P,GPage *PG)
1420 {
1421   char buf[STRMAX],*p;
1422   int i;
1423 
1424   /*
1425    * Set up list of module names.
1426    */
1427   *buf = 0;
1428   p = buf;
1429   for (i = 0;i < PG->pg_nmod;i++) {
1430     GModLayout *L = PG->pg_mods[i];
1431     if (i) {
1432       strcat(p,", ");
1433       p+=2;
1434     }
1435     filterParen(p,L->l_mod->m_name);
1436     p += strlen(p);
1437   }
1438 
1439   fprintf(P->p_f,"(%d of %d) (%s) BP\n",PG->pg_num,P->p_numPages,buf);
1440   for (i = 0;i < PG->pg_nmod;i++) {
1441     GModLayout *L = PG->pg_mods[i];
1442     fprintf(P->p_f,"(%s) %d %d %d %d BM_C\n",filterParen(buf,L->l_mod->m_name),
1443 	    L->l_xbase,L->l_ybase,L->l_width,L->l_height);
1444     GPrint_printLayout(P,L);
1445     fprintf(P->p_f,"EM\n");
1446   }
1447   fprintf(P->p_f,"EP\n");
1448 }
1449 
GPrint_printIndexPage(GPrint * P,GPage * PG)1450 static void GPrint_printIndexPage(GPrint *P,GPage *PG)
1451 {
1452   int x,y;
1453   char *mod_list[MODMAX];	/* Module names */
1454   int start_page[MODMAX];	/* Start page of module */
1455   int end_page[MODMAX];		/* End page of module */
1456   int num_modules = 0;
1457   int i,j;
1458 
1459   for (i = 0;i < P->p_numPages;i++) {
1460     GPage *G = P->p_pages[i];
1461     if (G->pg_type != PT_MODULE && G->pg_type != PT_MOD4) continue;
1462     for (j = 0;j < G->pg_nmod;j++) {
1463       GModLayout *L = G->pg_mods[j];
1464       GModuleDef *M = L->l_mod;
1465       if (L->l_r == 0 && L->l_c == 0) {		/* It is assumed (0,0) is printed first */
1466 	mod_list[num_modules] = M->m_name;
1467 	start_page[num_modules] = G->pg_num;
1468 	num_modules++;
1469       }
1470       end_page[num_modules-1] = G->pg_num;
1471     }
1472   }
1473 
1474 
1475   fprintf(P->p_f,"(%d of %d) (<index>) BP\n",PG->pg_num,P->p_numPages);
1476 
1477 
1478   /*
1479     Set position so that next entry will cause a new column to be generated
1480     at the desired place.
1481    */
1482   x = PIDX_LMARGIN-PIDX_COLSEP;
1483   y = 0;
1484 
1485   for (i = 0;i < num_modules;i++) {
1486     char buf[STRMAX];
1487 
1488     y -= PIDX_LINESEP;
1489     if (y < 0) {
1490       x += PIDX_COLSEP;
1491       y = P->p_uHeight - PIDX_TMARGIN;
1492       fprintf(P->p_f,"%d bfont\n",PIDX_FONT);
1493       fprintf(P->p_f,"%d %d moveto (Modules) show\n",x,y);
1494       fprintf(P->p_f,"%d %d moveto (Page) show\n",x+PIDX_PGCOLSEP,y);
1495       fprintf(P->p_f,"%d %d moveto %d %d lineto stroke\n",x,y-PIDX_HDRLINEPOS,x+PIDX_LINELEN,y-PIDX_HDRLINEPOS);
1496       fprintf(P->p_f,"%d rfont\n",PIDX_FONT);
1497       y -= PIDX_HDRSEP;
1498     }
1499 
1500     fprintf(P->p_f,"%d %d moveto (%s) show\n",x,y,filterParen(buf,mod_list[i]));
1501     if (start_page[i] == end_page[i])
1502       fprintf(P->p_f,"%d %d moveto (%d) show\n",x+PIDX_PGCOLSEP,y,start_page[i]);
1503     else
1504       fprintf(P->p_f,"%d %d moveto (%d-%d) show\n",x+PIDX_PGCOLSEP,y,start_page[i],end_page[i]);
1505 
1506   }
1507 
1508   fprintf(P->p_f,"EP\n");
1509 }
1510 
new_HGNode(GModuleDef * M)1511 static HGNode *new_HGNode(GModuleDef *M)
1512 {
1513   HGNode *G = (HGNode*) ob_malloc(sizeof(HGNode),"HGNode");
1514 
1515   G->hg_module = M;
1516   G->hg_maxDepth = 1;
1517   G->hg_expanded = 1;
1518   G->hg_nextSibling = 0;
1519   G->hg_children = 0;
1520 
1521   return G;
1522 }
1523 
HGNode_addChild(HGNode * G,HGNode * CG)1524 static void HGNode_addChild(HGNode *G,HGNode *CG)
1525 {
1526   if (CG->hg_maxDepth+1 > G->hg_maxDepth)
1527     G->hg_maxDepth = CG->hg_maxDepth+1;
1528   CG->hg_nextSibling = G->hg_children;
1529   G->hg_children = CG;
1530 }
1531 
build_HGNodeGraph(GModuleDef * M,PHash * H)1532 static HGNode *build_HGNodeGraph(GModuleDef *M,PHash *H)
1533 {
1534   HGNode *G;
1535   HashElem *E;
1536   PHash *LH;
1537 
1538   G = new_HGNode(M);
1539   LH = new_PHash();
1540 
1541   if (PHash_find(H,M)) {
1542     G->hg_expanded = 0;
1543   } else {
1544     G->hg_expanded = 1;
1545     PHash_insert(H,M,M);
1546     for (E = Hash_first(M->m_gates);E;E = Hash_next(M->m_gates,E)) {
1547       GCElement *g = (GCElement*) HashElem_obj(E);
1548       if (GCElement_isModule(g)) {
1549 	GModuleDef *CM = env_findModule(g->u.block.moduleName);
1550 	HGNode *CG;
1551 
1552 	if (CM && !PHash_find(LH,CM)) {
1553 	  PHash_insert(LH,CM,CM);
1554 	  CG = build_HGNodeGraph(CM,H);
1555 	  HGNode_addChild(G,CG);
1556 	}
1557       }
1558     }
1559   }
1560   /** @TODO check the necessity */
1561   delete_PHash(LH);
1562 
1563   return G;
1564 }
1565 
unbuild_HGNodeGraph(HGNode * G)1566 static void unbuild_HGNodeGraph(HGNode *G)
1567 {
1568   if (!G) return;
1569   unbuild_HGNodeGraph(G->hg_nextSibling);
1570   unbuild_HGNodeGraph(G->hg_children);
1571   ob_free(G);
1572 }
1573 
1574 /** @TODO to remove */
1575 /*
1576 static void HGNodeGraph_print(HGNode *G,int level)
1577 {
1578   int i;
1579 
1580   if (!G) return;
1581 
1582   for (i = 0;i < level;i++) printf(" ");
1583   printf("%s\n",G->hg_module->m_name);
1584   HGNodeGraph_print(G->hg_children,level+1);
1585   HGNodeGraph_print(G->hg_nextSibling,level);
1586 }
1587 */
1588 
HGNode_translatePoint(int * x,int * y)1589 static int HGNode_translatePoint(int *x,int *y)
1590 {
1591   int n = 0;
1592 
1593   while (*y < HG_BOTTOMY) {
1594     *y += HG_ROOTY-HG_BOTTOMY;
1595     *x += HG_NEXTCOLUMN;
1596     n++;
1597   }
1598 
1599   return n;
1600 }
1601 
HGNode_draw(HGNode * G,GPrint * P,int x,int y)1602 static void HGNode_draw(HGNode *G,GPrint *P,int x,int y)
1603 {
1604   char buf[STRMAX];
1605 
1606   HGNode_translatePoint(&x,&y);
1607   fprintf(P->p_f,"(%s) %s %d %d hgnode\n",filterParen(buf,G->hg_module->m_name),
1608 	  (G->hg_expanded ? "false" : "true"),x,y);
1609 }
1610 
HGNode_drawLine(GPrint * P,int x1,int y1,int x2,int y2)1611 static void HGNode_drawLine(GPrint *P,int x1,int y1,int x2,int y2)
1612 {
1613   int n1 = HGNode_translatePoint(&x1,&y1);
1614   int n2 = HGNode_translatePoint(&x2,&y2);
1615 
1616   if (n1 == n2)
1617     fprintf(P->p_f,"%d %d %d %d line\n",x1,y1,x2,y2);
1618   else if (n1 < n2) {
1619     fprintf(P->p_f,"%d %d %d %d line\n",x1,y1,x1,HG_BOTTOMY-HG_BOXHEIGHT/2);
1620     fprintf(P->p_f,"%d %d %d %d line\n",x2,HG_ROOTY,x2,y2);
1621   } else {
1622     fprintf(P->p_f,"%d %d %d %d line\n",x1,HG_ROOTY,x1,y2);
1623     fprintf(P->p_f,"%d %d %d %d line\n",x2,y1,x2,HG_BOTTOMY-HG_BOXHEIGHT/2);
1624   }
1625 }
1626 
HGNodeGraph_draw(HGNode * G,GPrint * P,int x,int y)1627 static int HGNodeGraph_draw(HGNode *G,GPrint *P,int x,int y)
1628 {
1629   int nc,ns;
1630 
1631   if (!G) return 0;
1632 
1633   HGNode_draw(G,P,x,y);
1634 
1635   if (G->hg_children) {
1636     HGNode_drawLine(P,x+HG_LINEINDENT,y-HG_BOXHEIGHT/2,x+HG_LINEINDENT,y-HG_LINE);
1637     HGNode_drawLine(P,x+HG_LINEINDENT,y-HG_LINE,x+HG_INDENT,y-HG_LINE);
1638     nc = HGNodeGraph_draw(G->hg_children,P,x+HG_INDENT,y-HG_LINE);
1639   } else
1640     nc = 0;
1641 
1642   if (G->hg_nextSibling) {
1643     HGNode_drawLine(P,x-HG_INDENT+HG_LINEINDENT,y,x-HG_INDENT+HG_LINEINDENT,y-HG_LINE*(nc+1));
1644     HGNode_drawLine(P,x-HG_INDENT+HG_LINEINDENT,y-HG_LINE*(nc+1),x,y-HG_LINE*(nc+1));
1645     ns = HGNodeGraph_draw(G->hg_nextSibling,P,x,y-HG_LINE*(nc+1));
1646   } else
1647     ns = 0;
1648 
1649   return nc + ns + 1;
1650 }
1651 
GPrint_printGraphPage(GPrint * P,GPage * PG)1652 static void GPrint_printGraphPage(GPrint *P,GPage *PG)
1653 {
1654   PHash *H;
1655   HGNode *G;
1656 
1657   H = new_PHash();
1658   G = build_HGNodeGraph(TkGate.circuit->root_mod,H);
1659 
1660   fprintf(P->p_f,"(%d of %d) (<hierarchy>) BP\n",PG->pg_num,P->p_numPages);
1661   fprintf(P->p_f,"%d bfont\n",HG_FONTSIZE);
1662   HGNodeGraph_draw(G,P,HG_ROOTX,HG_ROOTY);
1663   fprintf(P->p_f,"EP\n");
1664 
1665 #if 0
1666   for (E = Hash_first(H);E;E = Hash_next(H,E)) {
1667     NHashElem_key(E);
1668     HashElem_obj(E);
1669   }
1670 #endif
1671 
1672   unbuild_HGNodeGraph(G);
1673   delete_PHash(H);
1674 }
1675 
GPrint_outputPages(GPrint * P)1676 void GPrint_outputPages(GPrint *P)
1677 {
1678   int i;
1679 
1680   for (i = 0;i < P->p_numPages;i++) {
1681     GPage *PG = P->p_pages[i];
1682 
1683     fprintf(P->p_f,"\n%%%%Page: %d %d\n",i+1,i+1);
1684 
1685     switch (PG->pg_type) {
1686     case PT_MODULE :
1687       GPrint_printModPage(P,PG);
1688       break;
1689     case PT_MOD4 :
1690       GPrint_printMod4Page(P,PG);
1691       break;
1692     case PT_INDEX :
1693       GPrint_printIndexPage(P,PG);
1694       break;
1695     case PT_GRAPH :
1696       GPrint_printGraphPage(P,PG);
1697       break;
1698     case PT_TRACE :
1699       GPrint_printTracePage(P,PG);
1700       break;
1701     }
1702   }
1703 }
1704 
1705 /*
1706  * Do special case for EPSF setup
1707  */
GPrint_setupEPSFPage(GPrint * P)1708 void GPrint_setupEPSFPage(GPrint *P)
1709 {
1710   GModLayout *L = P->p_mods[0];
1711   /** @TODO to check necessity */
1712   /* int cwidth,cheight; */
1713   GPage *PG;
1714 
1715   GModuleDef_getBBX(L->l_mod, TD_PRINT, &L->l_xmin,&L->l_xmax,&L->l_ymin,&L->l_ymax);
1716   /** @TODO to check necessity */
1717   /*
1718   cwidth  = L->l_xmax-L->l_xmin + 2*PAGE_MODMARGIN;
1719   cheight = L->l_ymax-L->l_ymin + 2*PAGE_MODMARGIN;
1720   */
1721   L->l_isSmall = 0;
1722   L->l_numRows = 1;
1723   L->l_numCols = 1;
1724 
1725   P->p_pages = (GPage**) ob_malloc(sizeof(GPage*),"GPage*[]");
1726   assert(P->p_pages);
1727 
1728   L->l_xbase = EPSF_MINX;
1729   L->l_ybase = EPSF_MINY;
1730   L->l_width = L->l_xmax-L->l_xmin;
1731   L->l_height = L->l_ymax-L->l_ymin;
1732 
1733   PG = new_GPage(PT_MODULE,1);
1734   PG->pg_nmod = 1;
1735   PG->pg_mods[0] = L;
1736   P->p_pages[0] = PG;
1737   L->l_r = 0;
1738   L->l_c = 0;
1739 
1740   P->p_numPages = 1;
1741 }
1742 
1743 /*
1744  * Sort the modules in "hierarchy" order.
1745  */
GPrint_hsortPages(GPrint * P)1746 void GPrint_hsortPages(GPrint *P)
1747 {
1748   PHash *H;	/* Hash table for building hierarchy graph */
1749   PHash *Mhash;	/* Hash table for modules to be printed */
1750   HGNode *G = 0;
1751   List Q;		/* NOTE: lists do not have undo management.  We must clean up everything here. */
1752   GModLayout *L;
1753   int N = 0;
1754   int i;
1755 
1756   List_init(&Q);
1757   H = new_PHash();
1758   Mhash = new_PHash();
1759 
1760   for (i = 0;i < P->p_numMods;i++) {
1761     L = P->p_mods[i];
1762     PHash_insert(Mhash,L->l_mod,L);
1763   }
1764 
1765   //  P->p_numMods;
1766   G = build_HGNodeGraph(TkGate.circuit->root_mod,H);
1767   List_addToHead(&Q,G);
1768   while (List_numElems(&Q) > 0) {
1769     GModuleDef *M;
1770 
1771     G = (HGNode*) List_popHead(&Q);
1772     M = G->hg_module;
1773 
1774     for (G = G->hg_children;G;G = G->hg_nextSibling) {
1775       List_addToTail(&Q,G);
1776     }
1777 
1778     if ((L = (GModLayout*) PHash_find(Mhash,M))) {
1779       if (N < P->p_numMods)
1780 	P->p_mods[N++] = L;
1781       PHash_remove(Mhash,M);
1782     }
1783   }
1784 
1785   /*
1786    * If there were fewer sorted modules, then in the original list, this means
1787    * that we have unused modules.  In this case, we determine which modules are
1788    * unused and add them to the end of the list.
1789    */
1790   if (N != P->p_numMods) {
1791     HashElem *E;
1792 
1793     for (E = Hash_first(Mhash);E;E = Hash_next(Mhash,E)) {
1794       L = (GModLayout*) HashElem_obj(E);
1795       if (N < P->p_numMods)
1796 	P->p_mods[N++] = L;
1797     }
1798   }
1799 
1800   List_uninit(&Q);
1801   unbuild_HGNodeGraph(G);
1802   delete_PHash(Mhash);
1803   delete_PHash(H);
1804 }
1805 
1806 /*****************************************************************************
1807  *
1808  * Test a module to see if it is a "small" page.
1809  *
1810  *
1811  *
1812  *****************************************************************************/
GPrint_isSmallModule(GPrint * P,GModuleDef * M,int cwidth,int cheight)1813 static int GPrint_isSmallModule(GPrint *P,GModuleDef *M,int cwidth,int cheight)
1814 {
1815   if (GModuleDef_getType(M) == MT_TEXTHDL)
1816     return 0;
1817 
1818   return cwidth < P->p_uWidth/2		/* This module is less than half the page width */
1819     && cheight < P->p_uHeight/2		/* and less than half the page height */
1820     && !GModuleDef_isTop(M);		/* and it is not the root module... */
1821 }
1822 
1823 /*****************************************************************************
1824  *
1825  * Figure out what pages are going to be generated and what will be on them.
1826  *
1827  *****************************************************************************/
GPrint_setupPages(GPrint * P)1828 void GPrint_setupPages(GPrint *P)
1829 {
1830   int i,idx;
1831   int numSmall = 0;
1832   int numLarge = 0;
1833 
1834   /*
1835    * If this is an EPSF page, set things up a little different.
1836    */
1837   if (P->p_isepsf) {
1838     GPrint_setupEPSFPage(P);
1839     return;
1840   }
1841 
1842   GPrint_hsortPages(P);
1843 
1844   /*
1845     Compute page sizes and decide which ones are small
1846    */
1847   for (i = 0;i < P->p_numMods;i++) {
1848     GModLayout *L = P->p_mods[i];
1849     int cwidth,cheight;
1850 
1851     GModuleDef_getBBX(L->l_mod, TD_PRINT, &L->l_xmin,&L->l_xmax,&L->l_ymin,&L->l_ymax);
1852     cwidth  = L->l_xmax-L->l_xmin + 2*PAGE_MODMARGIN;
1853     cheight = L->l_ymax-L->l_ymin + 2*PAGE_MODMARGIN;
1854 
1855     /* If 4-up mode is enabled and module is small, mark it as a "small" module. */
1856     if (*P->p_opts.po_4up == '1' && GPrint_isSmallModule(P,L->l_mod,cwidth,cheight)) {
1857       L->l_isSmall = 1;
1858       numSmall++;
1859     }
1860 
1861     /*
1862      * If module is not a "small module" check to see how many pages we need for it.
1863      */
1864     if (!L->l_isSmall) {
1865       if (GModuleDef_getType(L->l_mod) == MT_NETLIST) {
1866 	/* Netlist Module */
1867 	if (P->p_style == PS_FIT || (cwidth < P->p_uWidth && cheight < P->p_uHeight)) {
1868 	  numLarge++;
1869 	  L->l_numRows = 1;
1870 	  L->l_numCols = 1;
1871 	} else {
1872 	  int j;
1873 	  /*
1874 	    Recompute size without margins added in
1875 	  */
1876 	  cwidth  = L->l_xmax-L->l_xmin;
1877 	  cheight = L->l_ymax-L->l_ymin;
1878 
1879 	  for (j = 1;cwidth+j*(2*PAGE_MODMARGIN)+(j-1)*PAGE_OVERLAP > j*P->p_uWidth;j++);
1880 	  L->l_numCols = j;
1881 
1882 	  for (j = 1;cheight+j*(2*PAGE_MODMARGIN)+(j-1)*PAGE_OVERLAP > j*P->p_uHeight;j++);
1883 	  L->l_numRows = j;
1884 
1885 	  numLarge += L->l_numRows*L->l_numCols;
1886 	}
1887       } else {
1888 	/* HDL Module */
1889 	int linesPerPage = (P->p_uHeight-2*PAGE_MODMARGIN)/(int)(1.2*hdl_font.points);
1890 	int numLines = GModuleDef_numHdlLines(L->l_mod);
1891 	int numPages = (numLines+linesPerPage-1)/linesPerPage;
1892 
1893 	L->l_numCols = 1;
1894 	L->l_numRows = numPages;
1895 	numLarge += numPages;
1896       }
1897     }
1898   }
1899 
1900   if (*P->p_opts.po_index == '1') numLarge++;
1901   if (*P->p_opts.po_graph == '1') numLarge++;
1902 
1903   P->p_numPages = numLarge + (numSmall+MODPGMAX-1)/MODPGMAX;
1904   P->p_pages = (GPage**) ob_malloc(P->p_numPages*sizeof(GPage*),"GPage*[]");
1905   assert(P->p_pages);
1906 
1907   idx = 0;
1908   if (*P->p_opts.po_index == '1') {
1909     P->p_pages[idx] = new_GPage(PT_INDEX,idx+1);
1910     idx++;
1911   }
1912   if (*P->p_opts.po_graph == '1') {
1913     P->p_pages[idx] = new_GPage(PT_GRAPH,idx+1);
1914     idx++;
1915   }
1916 
1917   /*
1918     Setup pages for large modules
1919     */
1920   if (numLarge) {
1921     for (i = 0;i < P->p_numMods;i++) {
1922       GModLayout *L = P->p_mods[i];
1923       if (L->l_isSmall) continue;
1924 
1925       L->l_xbase = PAGE_MODMARGIN;
1926       L->l_ybase = PAGE_MODMARGIN;
1927       L->l_width = P->p_uWidth - 2*PAGE_MODMARGIN;
1928       L->l_height = P->p_uHeight - 2*PAGE_MODMARGIN;
1929 
1930       if (L->l_numRows <= 1 && L->l_numCols <= 1) {
1931 	GPage *PG = new_GPage(PT_MODULE,idx+1);
1932 	PG->pg_nmod = 1;
1933 	PG->pg_mods[0] = L;
1934 	P->p_pages[idx++] = PG;
1935 	L->l_r = 0;
1936 	L->l_c = 0;
1937       } else {
1938 	int r,c;
1939 	for (r = 0;r < L->l_numRows;r++)
1940 	  for (c = 0;c < L->l_numCols;c++) {
1941 	    GPage *PG = new_GPage(PT_MODULE,idx+1);
1942 	    GModLayout *PL = copyNew_GModLayout(L);
1943 	    PL->l_r = r;
1944 	    PL->l_c = c;
1945 	    PG->pg_nmod = 1;
1946 	    PG->pg_mods[0] = PL;
1947 	    P->p_pages[idx++] = PG;
1948 	  }
1949       }
1950     }
1951   }
1952 
1953   if (numSmall) {
1954     GPage *PG = 0;
1955 
1956     for (i = 0;i < P->p_numMods;i++) {
1957       GModLayout *L = P->p_mods[i];
1958       if (!L->l_isSmall) continue;
1959 
1960       if (!PG) {
1961 	PG = new_GPage(PT_MOD4,idx+1);
1962 	P->p_pages[idx++] = PG;
1963       }
1964 
1965       L->l_xbase = (PG->pg_nmod & 0x1) ? (P->p_uWidth/2) : 0;
1966       L->l_ybase = (PG->pg_nmod & 0x2) ? 0 : (P->p_uHeight/2);
1967       L->l_width = P->p_uWidth/2;
1968       L->l_height = P->p_uHeight/2;
1969 
1970       L->l_xbase += PAGE_MODMARGIN;
1971       L->l_ybase += PAGE_MODMARGIN;
1972       L->l_width -= 3*PAGE_MODMARGIN/2;
1973       L->l_height -= 3*PAGE_MODMARGIN/2;
1974 
1975       L->l_r = 0;
1976       L->l_c = 0;
1977 
1978       if (!(PG->pg_nmod & 0x2)) {
1979 	L->l_ybase -= PAGE_MODMARGIN/2;
1980       }
1981 
1982       PG->pg_mods[PG->pg_nmod++] = L;
1983       if (PG->pg_nmod == MODPGMAX) PG = 0;
1984     }
1985   }
1986 
1987   P->p_numPages = idx;
1988 }
1989 
1990 /*
1991  * Print a circuit diagram document
1992  */
GPrintOpt_print(GPrintOpt * PO)1993 void GPrintOpt_print(GPrintOpt *PO)
1994 {
1995   GPrint *P = new_GPrint(PO);
1996 
1997   if (!P) return;
1998 
1999   GPrint_setupPages(P);
2000   GPrint_outputPreamble(P,1);
2001   GPrint_outputPages(P);
2002   GPrint_outputTrailer(P);
2003 
2004   delete_GPrint(P);
2005 }
2006