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 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include "tkgate.h"
22 #include "yybasic.h"
23 
24 void BeginDD();
25 
26 #if !TKGATE_NOYYRESTART
27 void yyrestart(FILE*);
28 #endif
29 
30 static int delay_def_is_init = 0;
31 static SHash *delay_def_table = 0;
32 static char **the_tech_list = 0;
33 static int tech_list_len = 0;
34 
35 static GDelayDef *cur_dd = 0;
36 
37 /*
38   Add 'tech' to the list of defined technlogies.  If it is already defined,
39   then do nothing.
40  */
add_tech(const char * tech)41 static void add_tech(const char *tech)
42 {
43   if (!the_tech_list) {
44     the_tech_list = (char**) malloc(16*sizeof(char*));
45     the_tech_list[0] = strdup(tech);
46     the_tech_list[1] = 0;
47     tech_list_len = 1;
48   } else {
49     int i;
50     for (i = 0;i < tech_list_len;i++)
51       if (strcmp(tech,the_tech_list[i]) == 0) return;
52 
53     if ((tech_list_len+1) % 16) {
54       the_tech_list = (char**)realloc(the_tech_list,(tech_list_len+17)*sizeof(char**));
55     }
56 
57     the_tech_list[tech_list_len++] = strdup(tech);
58     the_tech_list[tech_list_len] = 0;
59   }
60 }
61 
new_GDelayDef(const char * tech,const char * prim)62 GDelayDef *new_GDelayDef(const char *tech,const char *prim)
63 {
64   GDelayDef *dd = (GDelayDef *) malloc(sizeof(GDelayDef));
65 
66   dd->dd_tech = strdup(tech);
67   dd->dd_prim = strdup(prim);
68   dd->dd_area = 0;
69   dd->dd_power = 0;
70   dd->dd_area = 0;
71   dd->dd_numDelays = 0;
72   dd->dd_next = 0;
73 
74   return dd;
75 }
76 
delete_GDelayDef(GDelayDef * dd)77 void delete_GDelayDef(GDelayDef *dd)
78 {
79   int i;
80 
81   free(dd->dd_tech);
82   free(dd->dd_prim);
83   delete_Expr(dd->dd_area);
84   delete_Expr(dd->dd_power);
85 
86   for (i = 0;i < dd->dd_numDelays;i++) {
87     delete_Expr(dd->dd_delay[i]);
88   }
89 
90   if (dd->dd_next) delete_GDelayDef(dd->dd_next);
91 }
92 
GDelayDef_flush()93 void GDelayDef_flush()
94 {
95   HashElem *E;
96 
97   if (!delay_def_is_init) return;
98 
99   for (E = Hash_first(delay_def_table);E;E = Hash_next(delay_def_table,E)) {
100     GDelayDef *dd = (GDelayDef*) HashElem_obj(E);
101     delete_GDelayDef(dd);
102   }
103   SHash_flush(delay_def_table);
104 
105   free(the_tech_list);
106   tech_list_len = 0;
107   the_tech_list = 0;
108 }
109 
GDelayDef_readFile(const char * file_name)110 int GDelayDef_readFile(const char *file_name)
111 {
112   extern const char *ycFileName;
113   extern int ycLineNumber;
114   FILE *f;
115 
116   if (!delay_def_is_init) {
117     delay_def_is_init = 1;
118     delay_def_table = new_SHash();
119   }
120 
121   if (!(f = fopen(file_name,"r"))) {
122     return -1;
123   }
124 
125   ycFileName = (char*)file_name;
126   ycLineNumber = 1;
127   yc_setup();
128   BeginDD();
129 #if TKGATE_NOYYRESTART
130   yyin = f;
131 #else
132   yyrestart(f);
133 #endif
134   yc_pushpool();
135   yyparse();
136   yc_poppool();
137   fclose(f);
138 
139   return 0;
140 }
141 
GDelayDef_findList(const char * prim)142 GDelayDef *GDelayDef_findList(const char *prim)
143 {
144   return (GDelayDef*)SHash_find(delay_def_table,(char*)prim);
145 }
146 
GDelayDef_findTech(GDelayDef * dd,const char * tech)147 GDelayDef *GDelayDef_findTech(GDelayDef *dd,const char *tech)
148 {
149  GDelayDef *l;
150 
151   /*
152     Try to find matching technology first.
153    */
154   if (tech) {
155     for (l = dd;l;l = l->dd_next)
156       if (l->dd_tech && strcmp(l->dd_tech,tech) == 0)
157 	return l;
158   }
159 
160   /*
161     Look for default next
162    */
163   for (l = dd;l;l = l->dd_next)
164     if (strcmp(l->dd_tech,"default") == 0)
165       return l;
166 
167   return dd;			/* Return anything as a last resort */
168 }
169 
170 
GDelayDef_find(const char * tech,const char * prim)171 GDelayDef *GDelayDef_find(const char *tech,const char *prim)
172 {
173   GDelayDef *dd = GDelayDef_findList(prim);
174 
175   return GDelayDef_findTech(dd,tech);
176 }
177 
GDelayDef_begin(const char * tech,const char * prim)178 void GDelayDef_begin(const char *tech,const char *prim)
179 {
180   GDelayDef *old_dd = (GDelayDef*)SHash_find(delay_def_table,(char*)prim);
181   GDelayDef *new_dd,*l;
182 
183   add_tech(tech);
184 
185   for (l = old_dd;l;l = l->dd_next) {
186     if (strcmp(l->dd_tech,tech) == 0)
187       break;
188   }
189   if (l) {
190     int i;
191 
192     delete_Expr(l->dd_area);
193     delete_Expr(l->dd_power);
194 
195     l->dd_area = 0;
196     l->dd_power = 0;
197     for (i = 0;i < l->dd_numDelays;i++) {
198       delete_Expr(l->dd_delay[i]);
199       l->dd_names[i] = 0;
200       l->dd_delay[i] = 0;
201     }
202 
203     l->dd_numDelays = 0;
204     new_dd = l;
205   } else {
206     new_dd = new_GDelayDef(tech,prim);
207     new_dd->dd_next = old_dd;
208     if (old_dd)
209       SHash_remove(delay_def_table,(char*)prim);
210     SHash_insert(delay_def_table,(char*)prim,new_dd);
211   }
212 
213   cur_dd = new_dd;
214 }
215 
GDelayDef_end()216 void GDelayDef_end()
217 {
218   cur_dd = 0;
219 }
220 
PrimSet(const char * code,const char * parm,Expr * e)221 void PrimSet(const char *code,const char *parm,Expr *e)
222 {
223   if (strcmp(code,"delay") == 0) {
224     int i;
225 
226     i = cur_dd->dd_numDelays++;
227     cur_dd->dd_names[i] = strdup(parm);
228     cur_dd->dd_delay[i] = e;
229   } else if (strcmp(code,"area") == 0) {
230     cur_dd->dd_area = e;
231   } else if (strcmp(code,"power") == 0) {
232     cur_dd->dd_power = e;
233   }
234 }
235 
GDelayDef_getTechList()236 char **GDelayDef_getTechList()
237 {
238   return the_tech_list;
239 }
240 
241 /*****************************************************************************
242  *
243  * Gate-delay lookup function based on a gate instantce
244  *
245  * Parameters:
246  *     func		Function that is being invoked
247  *     name		Name of pad
248  *     data		Data for lookup (gate)
249  *     rval		Returned value of function
250  *
251  * Returns:		Non-zero on error.
252  *
253  *****************************************************************************/
gate_properties_lookup(const char * func,const char * name,void * data,int * rval)254 static int gate_properties_lookup(const char *func,const char *name,void *data,int *rval)
255 {
256   GCElement *g = (GCElement*) data;
257   int N = GCElement_numPads(g);
258   int b = 0, n = 0, c = 0;
259   int i;
260 
261   if (!func) return EE_BADFUNC;
262   if (!name) return EE_NOTDEF;
263 
264   for (i = 0;i < N;i++) {
265     if (strcmp(GCElement_getPadName(g,i),name) == 0) {
266       GWire *w;
267       for (w = g->wires[i];w;w = w->next) {
268 	GNet *net = w->net;
269 	if (net->n_nbits > b) b = net->n_nbits;
270 	if (w->invert) c++;
271 	n++;
272       }
273     }
274   }
275 
276   if (n == 0) {
277     expr_errsym = name;
278     return EE_NOTDEF;
279   }
280 
281   if (strcmp(func,"bits") == 0) {
282     *rval = b;
283     return 0;
284   } else if (strcmp(func,"inv") == 0) {
285     *rval = c;
286     return 0;
287   } else if (strcmp(func,"num") == 0) {
288     *rval = n;
289     return 0;
290   } else {
291     expr_errsym = func;
292     return EE_BADFUNC;
293   }
294 
295   return 0;
296 }
297 
GDelayDef_getDelays(GDelayDef * dd,GCElement * g,int * delays)298 int GDelayDef_getDelays(GDelayDef *dd, GCElement *g, int *delays)
299 {
300   GGateInfo *gi = g->typeinfo;
301   int i, j, n, rr;
302 
303   for (i = 0;gi->delayNames[i];i++) {
304     delays[i] = 1;
305     for (j = 0;j < gi->num_delays;j++)
306       if (*dd->dd_names[j] == '*' || strcmp(dd->dd_names[j],gi->delayNames[i]) == 0) {
307 	rr = Expr_eval(dd->dd_delay[j],&n,gate_properties_lookup,g);
308 	if (rr != EE_OK) return -1;
309 	delays[i] = n;
310 	break;
311       }
312 
313     if (j == gi->num_delays) {
314       message(MC_MSGLOG|MC_URGENT,"Failed to find delay <%s> value for %s<%s>.",gi->delayNames[i],g->ename,gi->name);
315     }
316 
317   }
318 
319   return gi->num_delays;
320 }
321 
322