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