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