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 Tue Mar 17 06:49:35 2009
19 ****************************************************************************/
20 
21 #include <stdlib.h>
22 
23 #include "tkgate.h"
24 
25 static const char *unitCodes[] = {"s", "ms", "us", "ns", "ps", "fs"};
26 static int numUnitCodes  = sizeof(unitCodes)/sizeof(unitCodes[0]);
27 
28 /*
29  * 1ns/1ns
30  */
31 static Timescale defaultTimescale = {1000000,1000000};
32 
Timescale_decode(simtime_t n,int * num,char * units)33 void Timescale_decode(simtime_t n, int *num,char *units)
34 {
35   int index = 0;
36 
37   while (n >= 1000) {
38     n /= 1000;
39     index++;
40   }
41 
42   if (index >= numUnitCodes || (n != 1 && n != 10 && n != 100)) {
43     /* Invalid code, so just default to 1ns */
44     if (num) *num = 1;
45     if (units) strcpy(units,"ns");
46     return;
47   }
48 
49 
50   if (units) strcpy(units,unitCodes[numUnitCodes-1-index]);
51   if (num) *num = n;
52 }
53 
Timescale_codeToUnits(int code)54 const char *Timescale_codeToUnits(int code)
55 {
56   if (code >= 0 && code < numUnitCodes)
57     return unitCodes[code];
58   else
59     return 0;
60 }
61 
Timescale_unitsToCode(const char * units)62 int Timescale_unitsToCode(const char *units)
63 {
64   int i;
65 
66   for (i = 0;i < numUnitCodes;i++) {
67     if (strcmp(units, unitCodes[i]) == 0) return i;
68   }
69   return -1;
70 }
71 
Timescale_parse(int num,const char * units)72 simtime_t Timescale_parse(int num,const char *units)
73 {
74   simtime_t U = 1;
75   int i;
76 
77   for (i = numUnitCodes-1;i >= 0;i--) {
78     if (strcmp(units, unitCodes[i]) == 0) break;
79     U *= 1000;
80   }
81 
82   if (i < 0) {
83     return 0;
84   }
85 
86   if (num != 1 && num != 10 && num != 100) {
87     return 0;
88   }
89 
90   U *= num;
91 
92   return U;
93 }
94 
Timescale_save(Timescale * ts,FILE * f)95 void Timescale_save(Timescale *ts, FILE *f)
96 {
97   int n1,n2;
98   char u1[STRMAX],u2[STRMAX];
99 
100   Timescale_decode(ts->ts_units, &n1, u1);
101   Timescale_decode(ts->ts_precision, &n2, u2);
102 
103   fprintf(f,"`timescale %d%s/%d%s\n",n1,u1,n2,u2);
104 }
105 
new_Circuit()106 Circuit *new_Circuit()
107 {
108   Circuit *c = OM_MALLOC(Circuit);
109   extern Timescale defaultTimescale;
110 
111   c->currentFile = new_CurrentFile();
112   c->fileVersion = ob_strdup("");
113   c->title = 0;
114   c->c_encoding = 0;
115   c->c_locale = 0;
116   c->c_timescale = defaultTimescale;
117   c->mid_mod = new_GModuleDef("<interfaces>");		/* Buffer for all interfaces */
118   c->mid_display = new_GModuleDef("<display>");		/* Temporary buffer for editing an interface */
119   c->mid_altMod = new_GModuleDef("<alternate>");	/* Buffer for all alternate interfaces */
120   c->c_breakpoints = new_NHash();
121   c->c_scripts = new_NHash();
122   c->c_probes = new_List();
123   c->cut_buffer = 0;
124   c->mg_selection = 0;
125   c->numInitScripts = 0;
126   c->initScripts = 0;
127   c->zoom_factor = 1;
128   c->modified_flags = 0;
129   c->search = new_GSearchContext();
130   c->es = new_EditState();
131   c->moduleTable = new_SHash();
132   c->c_gatePrefix = TKGATE_DEFAULT_PREFIX;
133   c->labelsel = new_GrabbedLabel();
134   c->rot = 0;
135   c->mode = MODE_MOVE;
136   c->c_isNewFile = 0;
137   c->no_set_modify = 0;
138   c->org_x = 0;
139   c->org_y = 0;
140 
141   Circuit_initOptions(c);
142   Circuit_setLocale(c,TkGate.locale);
143   Circuit_setFileEncoding(c,TkGate.locale->l_encVerilog);
144 
145   return c;
146 }
147 
Circuit_initOptions(Circuit * c)148 void Circuit_initOptions(Circuit *c)
149 {
150   c->fileVersion = ob_strdup(VERSIONS[0].vd_name);
151 
152   c->c_tvMode = TV_ALL;
153   c->c_startup = 0;
154   c->c_startupUnits = UC_NANOSEC;
155 
156   c->discardChanges = 0;
157   c->useExtBars = TkGate.extendBars;
158   c->showSwitchNets = TkGate.showSwitchNets;
159   c->simAutoStart = 0;
160 
161   c->simClockMode = 0;
162   c->simClockName = 0;
163 }
164 
Circuit_setCurrentFile(const char * name)165 void Circuit_setCurrentFile(const char *name)
166 {
167   CurrentFile_set(TkGate.circuit->currentFile,name);
168 }
169 
Circuit_setCurrentFileVersion(const char * ver)170 void Circuit_setCurrentFileVersion(const char *ver)
171 {
172   ob_touch(TkGate.circuit);
173   if (TkGate.circuit->fileVersion)
174     ob_free(TkGate.circuit->fileVersion);
175   TkGate.circuit->fileVersion = ob_strdup(ver);
176 }
177 
Circuit_setTitle(const char * title)178 void Circuit_setTitle(const char *title)
179 {
180   ob_touch(TkGate.circuit);
181   if (TkGate.circuit->title) ob_free(TkGate.circuit->title);
182   TkGate.circuit->title = title ? ob_strdup(title) : 0;
183 }
184 
Circuit_setLocale(Circuit * c,Locale * locale)185 void Circuit_setLocale(Circuit *c,Locale *locale)
186 {
187   ob_touch(c);
188   c->c_locale = locale;
189   c->c_displayEncoder = getEncoder(locale->l_encDisplay,CE_UTF8);
190   c->c_psEncoder = getEncoder(locale->l_encPostscript,CE_UTF8);
191 #if LOCALE_DEBUG
192   printf("Circuit_setLocale(%s)\n",locale->l_code);
193 #endif
194 }
195 
Circuit_setFileEncoding(Circuit * c,const char * encoding)196 void Circuit_setFileEncoding(Circuit *c,const char *encoding)
197 {
198   ob_touch(c);
199   if (c->c_encoding) ob_free(c->c_encoding);
200   c->c_encoding = ob_strdup(encoding);
201 
202   TkGate.japaneseMode = (strcmp(encoding,CE_EUC_JP) == 0);
203 
204 #if LOCALE_DEBUG
205   printf("Circuit_setFileEncoding(%s)\n",encoding);
206 #endif
207 
208   if (TkGate.japaneseMode)
209     initJapanese();
210   c->c_loadEncoder = getEncoder(CE_UTF8,c->c_encoding);
211   c->c_saveEncoder = getEncoder(c->c_encoding,CE_UTF8);
212 }
213 
Circuit_setScripts(int nScripts,const char ** scripts)214 void Circuit_setScripts(int nScripts,const char **scripts)
215 {
216   int i;
217 
218   ob_touch(TkGate.circuit);
219   if (TkGate.circuit->initScripts)
220     ob_free(TkGate.circuit->initScripts);
221 
222   TkGate.circuit->numInitScripts = nScripts;
223   if (nScripts == 0) {
224     TkGate.circuit->initScripts = 0;
225     return;
226   }
227   TkGate.circuit->initScripts = (char**) ob_malloc(sizeof(char**)*nScripts,"char**");
228   for (i = 0;i < nScripts;i++)
229     TkGate.circuit->initScripts[i] = ob_strdup(scripts[i]);
230 }
231 
232 #if 0
233 void Circuit_setLibraries(int nLibraries,const char **libraries)
234 {
235   int i;
236 
237   ob_touch(TkGate.circuit);
238   if (TkGate.circuit->libraries)
239     ob_free(TkGate.circuit->libraries);
240 
241   TkGate.circuit->numLibraries = nLibraries;
242   if (nLibraries == 0) {
243     TkGate.circuit->libraries = 0;
244     return;
245   }
246   TkGate.circuit->libraries = (char**) ob_malloc(sizeof(char**)*nLibraries,"char**");
247   for (i = 0;i < nLibraries;i++)
248     TkGate.circuit->libraries[i] = ob_strdup(libraries[i]);
249 }
250 #endif
251 
Circuit_setClockName(const char * name)252 void Circuit_setClockName(const char *name)
253 {
254   Circuit *C = TkGate.circuit;
255   char *p;
256 
257   ob_touch(C);
258   if (C->simClockName) ob_free(C->simClockName);
259   C->simClockName = 0;
260 
261   if (!name || !*name) return;
262 
263   C->simClockName = ob_strdup(name);
264 
265   for (p = C->simClockName;*p;p++) {
266     if (!isalpha(*p) && !isdigit(*p) && !strchr("_.",*p))
267       memmove(p,p+1,strlen(p));
268   }
269 
270   if (!*C->simClockName) {
271     ob_free(C->simClockName);
272     C->simClockName = 0;
273   }
274 }
275 
276 /*****************************************************************************
277  *
278  * Change the root/top module.
279  *
280  *****************************************************************************/
Circuit_changeRoot(GModuleDef * newR)281 void Circuit_changeRoot(GModuleDef *newR)
282 {
283   GModuleDef *oldR = TkGate.circuit->root_mod;
284 
285   /*
286    * No change in root.
287    */
288   if (newR == oldR)
289     return;
290 
291   ob_touch(TkGate.circuit);
292   TkGate.circuit->root_mod = newR;
293 
294   /*
295    * The current root shouldn't have an interface, but if it does, delete it.
296    */
297   if (oldR->m_interface) {
298     gate_delete(oldR->m_interface, TkGate.circuit->mid_mod,0);
299     ob_touch(oldR);
300     oldR->m_interface = 0;
301     oldR->m_altInterface = 0;
302   }
303 
304   /*
305    * If the current root module has an alternate interface, move it to be the primary interface.
306    */
307   if (oldR->m_altInterface) {
308     GCElement *g;
309 
310     ob_touch(oldR);
311     g = (*oldR->m_altInterface->typeinfo->CopyGate)(TkGate.circuit->mid_mod,oldR->m_altInterface,0,0,0);
312     gate_delete(oldR->m_altInterface, TkGate.circuit->mid_altMod,0);
313     oldR->m_interface = g;
314   } else
315     modint_setInterface(oldR,0);
316 
317   /*
318    * If the new root has an alternate interface, delete it.
319    */
320   if (newR->m_altInterface) {
321     gate_delete(newR->m_altInterface, TkGate.circuit->mid_altMod,0);
322     ob_touch(newR);
323     newR->m_interface = 0;
324   }
325 
326   /*
327    * If the new root module has an interface, move it to be the alternate interface.
328    */
329   if (newR->m_interface) {
330     GCElement *g;
331 
332     ob_touch(newR);
333     g = (*newR->m_interface->typeinfo->CopyGate)(TkGate.circuit->mid_altMod,newR->m_interface,0,0,0);
334     gate_delete(newR->m_interface, TkGate.circuit->mid_mod,0);
335     newR->m_altInterface = g;
336   }
337 
338   if (TkGate.circuit->es->isInterface) {
339     modint_arrange(TkGate.circuit->es);
340   }
341 
342   SetModified(MF_MODULE);
343 }
344 
Circuit_clearSavedProbes(Circuit * c)345 void Circuit_clearSavedProbes(Circuit *c)
346 {
347   ListElem *le;
348 
349   /*
350    * Saved probe names do not use ob_malloc system.
351    */
352   for (le = List_first(c->c_probes);le;le = List_next(c->c_probes,le)) {
353     free(ListElem_obj(le));
354   }
355   List_flush(c->c_probes);
356 }
357 
Circuit_addProbeName(Circuit * c,const char * name,GNet * net)358 void Circuit_addProbeName(Circuit *c,const char *name,GNet *net)
359 {
360   /*
361    * Saved probe names do not use ob_malloc system.
362    */
363   List_addToTail(c->c_probes,strdup(name));
364 }
365 
Circuit_clear()366 void Circuit_clear()
367 {
368   Circuit *c = TkGate.circuit;
369   extern Timescale defaultTimescale;
370 
371   BrkPtTable_flush(c->c_breakpoints);
372   c->c_timescale = defaultTimescale;
373 
374   Circuit_clearSavedProbes(c);
375 
376   Circuit_setTitle(0);
377   Circuit_setFileEncoding(c, TkGate.locale->l_encVerilog);
378   Circuit_setLocale(c, TkGate.locale);
379 }
380 
381 /*****************************************************************************
382  *
383  * Test to see if there is anything selected in a circuit.
384  *
385  *****************************************************************************/
Circuit_isSelection(Circuit * c)386 int Circuit_isSelection(Circuit *c)
387 {
388   if (TkGate.circuit->select || TkGate.circuit->mg_selection || TkGate.circuit->wnsel)
389     return 1;
390   else
391     return 0;
392 }
393 
Circuit_loadLibrary(Circuit * c,const char * name)394 void Circuit_loadLibrary(Circuit *c,const char *name)
395 {
396   if (tkgate_currentMode() != MM_EDIT)
397     tkgate_setMajorMode(MM_EDIT);
398 
399   if (VerilogOpenLibrary(name) < 0) {
400     message(1,msgLookup("err.badlibopen"),name);	/* Unable to open library file '%s'. */
401     return;
402   }
403 
404   if (c->es->isInterface)
405     modint_arrange(c->es);
406 
407   FlagRedraw();
408 }
409 
Circuit_unloadLibrary(Circuit * c,const char * name)410 void Circuit_unloadLibrary(Circuit *c,const char *name)
411 {
412   HashElem *he;
413   PHash *dhash;
414 
415   /*
416    * Make sure "name" is a loaded library.
417    */
418   if (!SHash_find(TkGate.libraries, name))
419     return;
420 
421   dhash = new_PHash_noob();
422 
423   /*
424    * Get list of modules to be deleted.
425    */
426   for (he = Hash_first(TkGate.circuit->moduleTable);he;he = Hash_next(TkGate.circuit->moduleTable,he)) {
427     GModuleDef *M = (GModuleDef*) HashElem_obj(he);
428     if (M->m_isLib && strcmp(M->m_libName,name) == 0) {
429       PHash_insert(dhash,M,M);
430     }
431   }
432 
433   /*
434    * Delete modules found in library
435    */
436   for (he = Hash_first(dhash);he;he = Hash_next(dhash,he)) {
437     GModuleDef *M = (GModuleDef*) HashElem_obj(he);
438     ob_touch(M);
439     M->m_isLib = 0;
440     M->m_protIntf = 0;
441     M->m_protEdit = 0;
442     env_delete(TkGate.circuit->es,M->m_name);
443   }
444   delete_PHash(dhash);
445   SHash_remove(TkGate.libraries, name);
446 }
447 
Circuit_unloadAllLibraries(Circuit * c)448 void Circuit_unloadAllLibraries(Circuit *c)
449 {
450   HashElem *he;
451   const char *names[Hash_numElems(TkGate.libraries)+1];
452   int n,i;
453 
454   for (he = Hash_first(TkGate.libraries), n = 0;he;he = Hash_next(TkGate.libraries,he))
455     names[n++] = SHashElem_key(he);
456 
457   for (i = 0;i < n;i++)
458     Circuit_unloadLibrary(c, names[i]);
459 }
460 
new_GrabbedLabel()461 GrabbedLabel *new_GrabbedLabel()
462 {
463   GrabbedLabel *gl = OM_MALLOC(GrabbedLabel);
464 
465   gl->net = 0;
466   gl->label = 0;
467 
468   return gl;
469 }
470 
GrabbedLabel_draw(int x,int y)471 void GrabbedLabel_draw(int x,int y)
472 {
473   GrabbedLabel *gl = TkGate.circuit->labelsel;
474   GC gc;
475 
476   if (gl->net->n_nbits > 1)
477     gc = TkGate.selBusGC;
478   else
479     gc = TkGate.selWireGC;
480 
481   if (gl->net)
482     dce_DrawString(gc,x + gl->ox,y + gl->oy,gl->position,gl->label);
483 }
484 
GrabbedLabel_unset()485 void GrabbedLabel_unset()
486 {
487   GrabbedLabel *gl = TkGate.circuit->labelsel;
488   gl->net = 0;
489   if (gl->label) ob_free(gl->label);
490   gl->label = 0;
491 }
492 
GrabbedLabel_set(GNet * net,int ox,int oy,int p)493 void GrabbedLabel_set(GNet *net,int ox,int oy,int p)
494 {
495   GrabbedLabel *gl = TkGate.circuit->labelsel;
496   char label[STRMAX];
497 
498   GNet_getDisplayLabel(net,label,STRMAX, DLM_GET_ALWAYS);
499   gl->net = net;
500   gl->label = ob_strdup(label);
501   gl->ox = ox;
502   gl->oy = oy;
503   gl->position = p;
504 }
505