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