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