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 <stdarg.h>
21 #include <string.h>
22 #include <assert.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <pwd.h>
26 #include "tkgate.h"
27 
28 
29 static SHash *primitiveTable = 0;
30 
31 static void Primitive_generator(FILE *f,const char *vsStart,const char *vsEnd,PrimParm *primParm);
32 
33 
34 /*****************************************************************************
35  *
36  * Load the definition for primitive "name" from the appropriate file.
37  *
38  * Parameters:
39  *    name		Name of the primitive to load
40  *
41  * Returns:		Object with Primitive.
42  *
43  * Looks in the file "${TKGATE_HOME}/primitives/name.v" for the primitive
44  * cell definition.
45  *
46  *****************************************************************************/
Primitive_load(const char * name)47 static Primitive *Primitive_load(const char *name)
48 {
49   Primitive *p = (Primitive*)malloc(sizeof(Primitive));
50   char path[STRMAX];
51   char *body,*s;
52   FILE *f;
53   struct stat sb;
54   int nread;
55 
56   p->p_name = strdup(name);
57   p->p_body = 0;
58   p->p_end = 0;
59 
60   sprintf(path,"%s/primitives/%s.v",TkGate.homedir,name);
61 
62   if (stat(path,&sb) != 0 || !(f = fopen(path,"r"))) {
63     message(1,msgLookup("primitive.err.missing"),name);
64     return p;
65   }
66   body = (char*)malloc(sb.st_size+1);
67 
68   nread = fread(body, 1, sb.st_size, f);
69   fclose(f);
70   assert(nread == sb.st_size);
71   body[sb.st_size] = 0;
72 
73   //
74   // Skip to "module" keyword.
75   //
76   body = strstr(body,"module");
77   if (!body) {
78     message(1,msgLookup("primitive.err.nomodule"),name);
79     return p;
80   }
81 
82   s = body + 6;				// Skip over "module"
83   while (isspace(*s))s++;		//    and whitespace
84   p->p_nameStart = s;			// this is the start of the module name
85   while (*s && !isspace(*s))s++;	//    Skip to end of the module name
86   p->p_nameEnd = s;
87 
88   if (p->p_nameStart == p->p_nameEnd || !isalpha(*p->p_nameStart)) {
89     message(1,msgLookup("primitive.err.nomodname"),name);
90     return p;
91   }
92   if (strncmp(name,p->p_nameStart,p->p_nameEnd-p->p_nameStart) != 0) {
93     message(1,msgLookup("primitive.err.wrongname"),name);
94     return p;
95   }
96 
97   p->p_parmStart = 0;
98   p->p_parmEnd = 0;
99 
100   while (isspace(*s)) s++;
101   if (*s == '#') {
102     char *start = s;
103     char *end = 0;
104     s++;
105     while (isspace(*s)) s++;
106     if (*s == '(') {
107       int c = 1;
108       for (s++;*s && c > 0;s++) {
109 	if (*s == '(') c++;
110 	if (*s == ')') c--;
111       }
112       if (*s)
113 	end = s;
114     }
115 
116     if (start && end) {
117       char buf[STRMAX];
118       memmove(buf,start,end-start);
119       buf[end-start] = 0;
120 
121       p->p_parmStart = start;
122       p->p_parmEnd = end;
123     }
124   }
125 
126   p->p_body = body;
127   p->p_end = body + strlen(body);
128 
129   return p;
130 }
131 
132 /*****************************************************************************
133  *
134  * Lookup the definition for primitive "name", loading if necessary
135  *
136  * Parameters:
137  *    name		Name of the primitive to load
138  *
139  * Returns:		Object with Primitive.
140  *
141  *****************************************************************************/
Primitive_lookup(const char * name)142 static Primitive *Primitive_lookup(const char *name)
143 {
144   Primitive *p;
145 
146   if (!primitiveTable) primitiveTable = new_SHash_noob();
147 
148   p = (Primitive*)SHash_find(primitiveTable,name);
149   if (!p) {
150     p = Primitive_load(name);
151     SHash_insert(primitiveTable,name,p);
152   }
153 
154   return p;
155 }
156 
157 /*****************************************************************************
158  *
159  * Find the next variable call sequence in a string.
160  *
161  * Parameters:
162  *    begin		Beginning of string to search
163  *    end		End of string to search
164  *    vsStart		Beginning of string to search for
165  *    vsEnd		End of string to search for
166  *
167  * Returns:		Non-zero if a variable call was found
168  *
169  *****************************************************************************/
Primitive_nextVariable(const char * begin,const char * end,const char ** vsStart,const char ** vsEnd)170 static int Primitive_nextVariable(const char *begin,const char *end,
171 				  const char **vsStart,const char **vsEnd)
172 {
173   const char *s = begin;
174 
175   for (;;) {
176     //
177     // Advance to the next $ or % character
178     //
179     s = s+strcspn(s, "$%\\");
180     if (!*s) return 0;
181     if (s >= end) return 0;
182 
183 
184     if (strncmp(s,"${",2) == 0 || strncmp(s,"$${",3) == 0) {
185       int count = 1;
186 
187       *vsStart = s;
188       while (*s != '{')s++;
189       while (count > 0 && *++s) {
190 	if (*s == '{') count++;
191 	if (*s == '}') count--;
192       }
193       *vsEnd = s+1;
194       return 1;
195     } else if (*s == '%') {
196       *vsStart = s;
197       *vsEnd = s+1;
198       return 1;
199     } else if (*s == '\\') {
200       *vsStart = s;
201       if (s[1])
202 	*vsEnd = s+2;
203       else
204 	*vsEnd = s+1;
205       return 1;
206     }
207 
208     //
209     // This wasn't a special sequence, skip a character and keep looking.
210     //
211     s++;
212   }
213 
214   return 0;
215 }
216 
Primitive_substitute(FILE * f,int id,const char * vsStart,const char * vsEnd,PrimParm * primParm)217 void Primitive_substitute(FILE *f,int id,const char *vsStart,const char *vsEnd,PrimParm *primParm)
218 {
219   //
220   // We are assuming the variable call begins with this sequence
221   //
222   if (strncmp(vsStart,"${",2) != 0)
223     return;
224   vsStart += 2;
225 
226 
227   //
228   // We are assuming the variable call ends with this sequence
229   //
230   if (vsEnd[-1] != '}')
231     return;
232   vsEnd--;
233 
234   fprintf(f,"%s",PrimParm_nget(primParm,vsStart,vsEnd-vsStart));
235 }
236 
Primitive_writeText(FILE * f,const char * begin,const char * end,int id,PrimParm * primParm)237 static void Primitive_writeText(FILE *f,const char *begin,const char *end,
238 				int id,PrimParm *primParm)
239 {
240   const char *vsStart,*vsEnd, *s;
241 
242   s = begin;
243 
244   while (Primitive_nextVariable(s,end,&vsStart,&vsEnd)) {
245     //
246     // Make sure variable isn't after end of target area
247     //
248     if (vsEnd > end) break;
249 
250     //
251     // Write everything up to the start of the variable
252     //
253     fwrite(s,1,vsStart-s,f);
254 
255     //
256     // Write the special text
257     //
258     if (strncmp(vsStart,"${",2) == 0)
259       Primitive_substitute(f,id,vsStart,vsEnd,primParm);
260     else if (strncmp(vsStart,"$${",3) == 0)
261       Primitive_generator(f,vsStart,vsEnd,primParm);
262     else if (*vsStart == '%' && id >= 0 ) {
263       fprintf(f,"%d",id);
264     } else if (*vsStart == '\\' && id >= 0) {
265       if (vsStart[1] == 'n')
266 	fprintf(f,"\n");
267     } else {
268       fwrite(vsStart,1,vsEnd-vsStart,f);
269     }
270 
271     //
272     // Move us after the variable
273     //
274     s = vsEnd;
275   }
276 
277   //
278   // If there is anything left after the last variable, print it.
279   //
280   if (s < end)
281     fwrite(s,1,end-s,f);
282 }
283 
Primitive_generator(FILE * f,const char * vsStart,const char * vsEnd,PrimParm * primParm)284 static void Primitive_generator(FILE *f,const char *vsStart,const char *vsEnd,PrimParm *primParm)
285 {
286   char *k1,*k2;
287   const char *strcount;
288   int count = 0;
289   int i;
290 
291   //
292   // We are assuming the variable call begins with this sequence
293   //
294   if (strncmp(vsStart,"$${",3) != 0)
295     return;
296   vsStart += 3;
297 
298 
299   //
300   // We are assuming the variable call ends with this sequence
301   //
302   if (vsEnd[-1] != '}')
303     return;
304   vsEnd--;
305 
306   //
307   // Find first mandatory colon
308   //
309   k1 = strchr(vsStart,':');
310   if (!k1) return;
311 
312   //
313   // Find second optional colon
314   //
315   if (k1 != vsEnd) {
316     k2 = strchr(k1+1,':');
317     if (k2 >= vsEnd) k2 = 0;
318   } else
319     k2 = 0;
320 
321   strcount = PrimParm_nget(primParm,vsStart,k1-vsStart);
322   if (strcount)
323     sscanf(strcount,"%d",&count);
324 
325 #if 0
326   fprintf(f,"GENERATE [");
327   fwrite(vsStart,1,k1-vsStart,f);
328   fprintf(f,"] [");
329   if (k2) {
330     fwrite(k1+1,1,k2-k1-1,f);
331     fprintf(f,"] [");
332     fwrite(k2+1,1,vsEnd-1-k2,f);
333   } else {
334     fwrite(k1+1,1,vsEnd-k1-1,f);
335   }
336 
337   fprintf(f,"]");
338 #endif
339 
340 #if 1
341   if (k2) {
342     for (i = 0;i < count;i++) {
343       if (i != 0) {
344 	Primitive_writeText(f,k1+1,k2,i,primParm);
345       }
346       Primitive_writeText(f,k2+1,vsEnd,i,primParm);
347     }
348   } else {
349     for (i = 0;i < count;i++) {
350       //fwrite(k1+1,1,vsEnd-k1-1,f);
351       Primitive_writeText(f,k1+1,vsEnd,i,primParm);
352     }
353   }
354 #endif
355 }
356 
Primitive_write(FILE * f,const char * name,GCellSpec * gcs,PrimParm * primParm)357 void Primitive_write(FILE *f,const char *name,GCellSpec *gcs,PrimParm *primParm)
358 {
359   Primitive *p = Primitive_lookup(name);
360 
361   if (!p || !p->p_body) return;
362 
363   fprintf(f,"//: /builtinBegin\n");
364   fprintf(f,"module %s",gcs->gc_name);
365 
366   Primitive_writeText(f,p->p_nameEnd,p->p_end,-1,primParm);
367 
368   fprintf(f,"//: /builtinEnd\n\n");
369 }
370 
PrimParm_init(PrimParm * primParm)371 void PrimParm_init(PrimParm *primParm)
372 {
373   primParm->pp_size = 0;
374 }
375 
PrimParm_get(PrimParm * primParm,const char * name)376 char *PrimParm_get(PrimParm *primParm,const char *name)
377 {
378   int i;
379 
380   for (i = 0;i < primParm->pp_size;i++) {
381     if (strcmp(primParm->pp_specs[i].pps_name,name) == 0)
382       return primParm->pp_specs[i].pps_value;
383   }
384 
385   if (primParm->pp_size > (PARMSPEC_MAXPARMS-2)) {
386     *primParm->pp_specs[primParm->pp_size].pps_value = 0;
387     return primParm->pp_specs[primParm->pp_size].pps_value;
388   }
389 
390   strcpy(primParm->pp_specs[primParm->pp_size].pps_name,name);
391   *primParm->pp_specs[primParm->pp_size].pps_value = 0;
392   return primParm->pp_specs[primParm->pp_size++].pps_value;
393 }
394 
PrimParm_nget(PrimParm * primParm,const char * name,int n)395 const char *PrimParm_nget(PrimParm *primParm,const char *name,int n)
396 {
397   int i;
398 
399   for (i = 0;i < primParm->pp_size;i++) {
400     if (strncmp(primParm->pp_specs[i].pps_name,name,n) == 0)
401       return primParm->pp_specs[i].pps_value;
402   }
403 
404   return "";
405 }
406 
PrimParm_set(PrimParm * primParm,const char * name,const char * fmt,...)407 void PrimParm_set(PrimParm *primParm,const char *name,const char *fmt,...)
408 {
409   va_list ap;
410 
411   va_start(ap,fmt);
412   vsprintf(PrimParm_get(primParm,name),fmt,ap);
413   va_end(ap);
414 }
415 
PrimParm_invSet(PrimParm * primParm,const char * name,int isInv)416 void PrimParm_invSet(PrimParm *primParm,const char *name,int isInv)
417 {
418   strcpy(PrimParm_get(primParm,name),isInv ? "~" : "");
419 }
420 
PrimParm_rangeSet(PrimParm * primParm,const char * name,int rangeMax)421 void PrimParm_rangeSet(PrimParm *primParm,const char *name,int rangeMax)
422 {
423   strcpy(PrimParm_get(primParm,name),bitrangeSpec(rangeMax));
424 }
425 
PrimParm_intSet(PrimParm * primParm,const char * name,int n)426 void PrimParm_intSet(PrimParm *primParm,const char *name,int n)
427 {
428   PrimParm_set(primParm, name, "%d", n);
429 }
430 
431