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 "thyme.h"
19
20 #define NET_DEBUG 0
21
new_Net_memory(const char * name,unsigned msb,unsigned lsb,unsigned beginAddr,unsigned endAddr)22 Net *new_Net_memory(const char *name,unsigned msb,unsigned lsb,
23 unsigned beginAddr,unsigned endAddr)
24 {
25 Net *n = (Net*) malloc(sizeof(Net));
26
27 n->n_name = strdup(name);
28 n->n_msb = msb;
29 n->n_lsb = lsb;
30 n->n_nbits = iabs(msb-lsb) + 1;
31 n->n_drivers = 0;
32 n->n_type = NT_MEMORY;
33 n->n_flags = NA_NONE;
34 n->n_numDrivers = 0;
35 n->n_numMonitors = 0;
36 n->n_wfunc = Value_wire;
37 List_init(&n->n_posedgeNotify);
38 List_init(&n->n_negedgeNotify);
39
40 Memory_init(&n->n_data.memory,beginAddr, endAddr, n->n_nbits,n);
41
42 return n;
43 }
44
delete_Net(Net * n)45 void delete_Net(Net *n)
46 {
47 Value_uninit(Net_getValue(n));
48 free(n->n_name);
49 free(n);
50 }
51
52 /*****************************************************************************
53 *
54 * Create a new Net
55 *
56 * Parameter:
57 * name Name of net
58 * ntype Type code of net
59 * msb MSB of net
60 * lsb LSB of net
61 *
62 *****************************************************************************/
new_Net(const char * name,nettype_t ntype,unsigned msb,unsigned lsb)63 Net *new_Net(const char *name,nettype_t ntype,unsigned msb,unsigned lsb)
64 {
65 Net *n = (Net*) malloc(sizeof(Net));
66 Value *value = Net_getValue(n);
67
68 n->n_name = strdup(name);
69 n->n_msb = msb;
70 n->n_lsb = lsb;
71 n->n_nbits = iabs(msb-lsb) + 1;
72 n->n_drivers = 0;
73 n->n_type = ntype;
74 n->n_flags = NA_NONE;
75 n->n_numMonitors = 0;
76 n->n_numDrivers = 0;
77 List_init(&n->n_posedgeNotify);
78 List_init(&n->n_negedgeNotify);
79 Value_init(Net_getValue(n),n->n_nbits);
80
81 if ((n->n_type & NT_P_AND))
82 n->n_wfunc = Value_wand;
83 else if ((n->n_type & NT_P_OR))
84 n->n_wfunc = Value_wor;
85 else if ((n->n_type & NT_P_PULL0))
86 n->n_wfunc = Value_tri0;
87 else if ((n->n_type & NT_P_PULL1))
88 n->n_wfunc = Value_tri1;
89 else
90 n->n_wfunc = Value_wire;
91
92 switch ((n->n_type & NT_P_REGTYPE_MASK)) {
93 case NT_P_REAL :
94 value->flags = SF_REAL;
95 break;
96 case NT_P_INTEGER :
97 case NT_P_TIME :
98 value->flags = SF_INT;
99 break;
100 }
101
102 if (NT_GET_0STR(ntype) && !NT_GET_1STR(ntype)) {
103 Value_zero(value);
104 if (NT_GET_0STR(ntype) == NT_P_SUPPLY0) n->n_flags = NA_FIXED;
105 } else if (NT_GET_1STR(ntype) && !NT_GET_0STR(ntype)) {
106 Value_one(value);
107 if (NT_GET_1STR(ntype) == NT_P_SUPPLY1) n->n_flags = NA_FIXED;
108 } else if ((ntype & NT_P_WIRE)) {
109 Value_float(value);
110 } else {
111 Value_unknown(value);
112 }
113
114 value->permFlags = SF_NETVAL | value->flags;
115
116 return n;
117 }
118
119 /*****************************************************************************
120 *
121 * Return the local name of a net by trimming of leading '.' components
122 *
123 * Parameters
124 * n Net
125 *
126 * Returns: Local name of net
127 *
128 *****************************************************************************/
Net_getLocalName(Net * n)129 const char *Net_getLocalName(Net *n)
130 {
131 char *p = strrchr(n->n_name,'.');
132 if (!p) return n->n_name;
133 return p+1;
134 }
135
136 /*****************************************************************************
137 *
138 * Register a trigger as being a posedge listener of a net
139 *
140 * Parameters
141 * n Net on which to look for posedge transitions
142 * t Trigger to be registered.
143 *
144 *****************************************************************************/
Net_posedgeListen(Net * n,Trigger * t)145 void Net_posedgeListen(Net*n,Trigger*t)
146 {
147 List_addToTail(&n->n_posedgeNotify,t);
148 }
149
150 /*****************************************************************************
151 *
152 * Register a trigger as being a negedge listener of a net
153 *
154 * Parameters
155 * n Net on which to look for negedge transitions
156 * t Trigger to be registered.
157 *
158 *****************************************************************************/
Net_negedgeListen(Net * n,Trigger * t)159 void Net_negedgeListen(Net*n,Trigger*t)
160 {
161 List_addToTail(&n->n_negedgeNotify,t);
162 }
163
164 /*****************************************************************************
165 *
166 * This function is called every time there is a posedge transition on n
167 *
168 * Parameters
169 * n Net on which a posedge transition was observed.
170 *
171 *****************************************************************************/
Net_posedgeNotify(Net * n)172 void Net_posedgeNotify(Net *n)
173 {
174 ListElem *le;
175
176 if ((n->n_flags & NA_CLOCK))
177 EvQueue_clockNotify(Circuit_getQueue(&vgsim.vg_circuit), n, TT_POSEDGE);
178
179 for (le = List_first(&n->n_posedgeNotify);le;le = List_next(&n->n_posedgeNotify,le)) {
180 Trigger_fire((Trigger*)ListElem_obj(le));
181 }
182 }
183
184 /*****************************************************************************
185 *
186 * This function is called every time there is a negedge transition on n
187 *
188 * Parameters
189 * n Net on which a negedge transition was observed.
190 *
191 *****************************************************************************/
Net_negedgeNotify(Net * n)192 void Net_negedgeNotify(Net *n)
193 {
194 ListElem *le;
195
196 if ((n->n_flags & NA_CLOCK))
197 EvQueue_clockNotify(Circuit_getQueue(&vgsim.vg_circuit), n, TT_NEGEDGE);
198
199 for (le = List_first(&n->n_negedgeNotify);le;le = List_next(&n->n_negedgeNotify,le)) {
200 Trigger_fire((Trigger*)ListElem_obj(le));
201 }
202 }
203
204 /*****************************************************************************
205 *
206 * Chage the value of a net and notify anything that is triggering on this net.
207 *
208 * Parameters:
209 * n Net to be set.
210 * s New value for net (or NULL if this is an "event" node).
211 *
212 * Determines the transition edge type based on the current and new values for
213 * the net and sets the new value. If the new value is the same as the current
214 * value, nothing is done. Otherwise, the EDGE, POSEDGE or NEGEDGE listeners
215 * as appropriate are notified.
216 *
217 *****************************************************************************/
Net_set(Net * n,Value * s)218 void Net_set(Net*n,Value*s)
219 {
220 EvQueue *Q;
221 Value *temp_s = 0;
222
223 if (!s) {
224 Net_posedgeNotify(n);
225 return;
226 }
227
228 if ((n->n_type & NT_P_REGTYPE_MASK) == NT_P_REAL) {
229 real_t dst, src;
230 int src_ok,dst_ok;
231
232 src_ok = Value_toReal(s,&src);
233 dst_ok = Value_toReal(Net_getValue(n), &dst);
234
235 if (src_ok == dst_ok && src == dst)
236 return; /* Value not changed */
237
238 if (n->n_numMonitors > 0) {
239 Q = Circuit_getQueue(&vgsim.vg_circuit);
240 EvQueue_monitoredChangeNotify(Q);
241 }
242
243 if (src_ok)
244 Value_convertNaN(Net_getValue(n));
245 else
246 Value_convertR(Net_getValue(n), src);
247
248 Net_posedgeNotify(n);
249 return;
250 }
251
252 if ((n->n_flags & NA_FIXED)) return;
253
254 if ((s->flags & SF_REAL)) {
255 real_t v_f;
256 unsigned v_u;
257 if (Value_toReal(s,&v_f) != 0)
258 v_f = 0;
259 v_u = (unsigned) v_f;
260 temp_s = new_Value(Value_nbits(s));
261 s = temp_s;
262 Value_convertI(s, v_u);
263 }
264
265 switch (Value_transitionType(Net_getValue(n), s)) {
266 case TT_NONE :
267 break;
268 case TT_EDGE :
269 case TT_POSEDGE :
270 if (n->n_numMonitors > 0) {
271 Q = Circuit_getQueue(&vgsim.vg_circuit);
272 EvQueue_monitoredChangeNotify(Q);
273 }
274 Value_copy(Net_getValue(n), s);
275 Net_posedgeNotify(n);
276 break;
277 case TT_NEGEDGE :
278 if (n->n_numMonitors > 0) {
279 Q = Circuit_getQueue(&vgsim.vg_circuit);
280 EvQueue_monitoredChangeNotify(Q);
281 }
282 Value_copy(Net_getValue(n), s);
283 Net_negedgeNotify(n);
284 break;
285 }
286
287 switch ((n->n_type & NT_P_REGTYPE_MASK)) {
288 case NT_P_INTEGER :
289 case NT_P_TIME :
290 Net_getValue(n)->flags = SF_INT;
291 break;
292 default :
293 Net_getValue(n)->flags = SF_NONE;
294 break;
295 }
296
297 if (temp_s)
298 delete_Value(temp_s);
299
300 }
301
302 /*****************************************************************************
303 *
304 * Change the value of a subrange of net and notify anything that is triggering on this net.
305 *
306 * Parameters:
307 * n Net to be set.
308 * s New value for net
309 *
310 * Determines the transition edge type based on the current and new values for
311 * the net and sets the new value. If the new value is the same as the current
312 * value, nothing is done. Otherwise, the EDGE, POSEDGE or NEGEDGE listeners
313 * as appropriate are notified.
314 *
315 *****************************************************************************/
Net_setRange(Net * n,int nlsb,Value * s,int smsb,int slsb)316 void Net_setRange(Net*n,int nlsb,Value*s,int smsb,int slsb)
317 {
318 EvQueue *Q;
319
320 if ((n->n_type & NT_P_REGTYPE_MASK) == NT_P_REAL) {
321 Value_convertNaN(Net_getValue(n));
322 return;
323 }
324
325 if ((n->n_flags & NA_FIXED)) return;
326
327 switch (Value_copyRange(Net_getValue(n), nlsb, s, smsb, slsb)) {
328 case TT_EDGE :
329 case TT_POSEDGE :
330 if (n->n_numMonitors > 0) {
331 Q = Circuit_getQueue(&vgsim.vg_circuit);
332 EvQueue_monitoredChangeNotify(Q);
333 }
334 Net_posedgeNotify(n);
335 break;
336 case TT_NEGEDGE :
337 if (n->n_numMonitors > 0) {
338 Q = Circuit_getQueue(&vgsim.vg_circuit);
339 EvQueue_monitoredChangeNotify(Q);
340 }
341 Net_negedgeNotify(n);
342 break;
343 case TT_NONE :
344 break;
345 }
346 }
347
348 /*****************************************************************************
349 *
350 * Set a net to the unknown state and notify triggers.
351 *
352 * Parameters:
353 * n Net that is transitioning to the unknown state.
354 *
355 *****************************************************************************/
Net_makeUnknown(Net * n)356 void Net_makeUnknown(Net *n)
357 {
358 Value_unknown(Net_getValue(n));
359 Net_posedgeNotify(n);
360 }
361
362
363 /*****************************************************************************
364 *
365 * Print a human-readable string for a net
366 *
367 * Parameters:
368 * n Net to be printed
369 * f File on which to print
370 *
371 *****************************************************************************/
Net_print(Net * n,FILE * f)372 void Net_print(Net *n,FILE *f)
373 {
374
375 if (n->n_type != MEMORY) {
376 char buf[STRMAX];
377
378 NT_getStr(n->n_type,buf);
379 fprintf(f,"%s [%d:%d] %s",buf,n->n_msb,n->n_lsb,n->n_name);
380 } else
381 fprintf(f,"reg [%d:%d] %s[]",n->n_msb,n->n_lsb,n->n_name);
382 }
383
384 /*****************************************************************************
385 *
386 * Create a new driver on a net and return the Value object for it.
387 *
388 * Parameters:
389 * n Net on which to create driver
390 *
391 * Returns: Driver ID of newly created driver.
392 *
393 *****************************************************************************/
Net_addDriver(Net * n)394 int Net_addDriver(Net*n)
395 {
396 int id = n->n_numDrivers++;
397
398 if (id == 0)
399 n->n_drivers = (Value**) malloc(sizeof(Value*)*n->n_numDrivers);
400 else
401 n->n_drivers = (Value**) realloc(n->n_drivers, sizeof(Value*)*n->n_numDrivers);
402
403 n->n_drivers[id] = new_Value(Net_nbits(n));
404 Value_float(n->n_drivers[id]);
405
406 return id;
407 }
408
409 /*****************************************************************************
410 *
411 * Notify net that driver with id 'id' has changed.
412 *
413 * Parameters:
414 * n Net on which a driver change has occured
415 * id ID of driver thange changed (currently unused)
416 *
417 *****************************************************************************/
Net_driverChangeNotify(Net * n,int id)418 void Net_driverChangeNotify(Net *n,int id)
419 {
420 Value *s, *floatValue;
421 int i;
422
423 #if NET_DEBUG
424 printf(" Net_driverChange %s<%d> was ",n->n_name,n->n_numDrivers);
425 Value_print(Net_getValue(n),stdout);
426 printf("\n");
427 #endif
428
429 switch (n->n_numDrivers) {
430 case 0 :
431 s = new_Value(Net_nbits(n));
432 Value_float(s);
433 if ((n->n_type & NT_P_TRIREG))
434 Value_trireg(s,s,&n->n_data.value);
435 Net_set(n,s);
436 delete_Value(s);
437 break;
438 case 1 :
439 s = n->n_drivers[0];
440 floatValue = new_Value(Net_nbits(n));
441 Value_float(floatValue);
442 (*n->n_wfunc)(s,s,floatValue);
443 delete_Value(floatValue);
444 if (n->n_type & NT_P_TRIREG)
445 Value_trireg(s,s,Net_getValue(n));
446 Net_set(n,s);
447 break;
448 case 2:
449 s = new_Value(Net_nbits(n));
450 (*n->n_wfunc)(s,n->n_drivers[0],n->n_drivers[1]);
451 if ((n->n_type & NT_P_TRIREG))
452 Value_trireg(s,s,Net_getValue(n));
453 Net_set(n,s);
454 delete_Value(s);
455 break;
456 default :
457 s = new_Value(Net_nbits(n));
458 (*n->n_wfunc)(s,n->n_drivers[0],n->n_drivers[1]);
459 for (i = 2;i < n->n_numDrivers;i++)
460 (*n->n_wfunc)(s,s,n->n_drivers[i]);
461 if ((n->n_type & NT_P_TRIREG))
462 Value_trireg(s,s,&n->n_data.value);
463 Net_set(n,s);
464 delete_Value(s);
465 break;
466 }
467 }
468 #if 0
469 #if NET_DEBUG|1
470 printf(" Net_driverChange %s<%d> (%s) was ",n->n_name,n->n_numDrivers,
471 (n->n_type & NT_P_TRIREG) ? "trireg" : "non-trireg");
472 Value_print(Net_getValue(n),stdout);
473 printf("\n");
474 #endif
475
476 if (n->n_numDrivers == 1) {
477 Value *s = n->n_drivers[0];
478
479 Net_set(n,s);
480 } else {
481 Value *s = new_Value(Net_nbits(n));
482 int i;
483
484 Value_float(s);
485
486 for (i = 0;i < n->n_numDrivers;i++)
487 (*n->n_wfunc)(s,s,n->n_drivers[i]);
488
489 /*
490 * If this is a trireg net, merge driver result with the current net value.
491 */
492 if ((n->n_type & NT_P_TRIREG))
493 Value_trireg(s,s,&n->n_data.value);
494
495 Net_set(n,s);
496 delete_Value(s);
497 }
498 #endif
499
Net_reportValue(Net * n,const char * who,const char * name,Circuit * c)500 void Net_reportValue(Net *n,const char *who,const char *name,Circuit *c)
501 {
502 EvQueue *Q = c->c_evQueue;
503 char buf[STRMAX];
504
505 if (!name) name = n->n_name;
506
507
508 Value_getvstr(Net_getValue(n),buf);
509 if (who)
510 vgio_printf("tell %s %s %s @ %llu\n",who,name,buf,EvQueue_getCurTime(Q));
511 else
512 vgio_printf("valueof %s %s @ %llu\n",name,buf,EvQueue_getCurTime(Q));
513 }
514
Net_memSet(Net * n,unsigned addr,Value * data)515 void Net_memSet(Net *n, unsigned addr, Value *data)
516 {
517 Memory_put(&n->n_data.memory, addr, data);
518 Memory_accessNotify(&n->n_data.memory, addr, 1);
519 Net_posedgeNotify(n);
520 }
521
Net_memSetRange(Net * n,unsigned addr,int nLsb,Value * data,int vMsb,int vLsb)522 void Net_memSetRange(Net *n, unsigned addr,int nLsb,Value *data,int vMsb,int vLsb)
523 {
524 Memory_putRange(&n->n_data.memory, addr, nLsb, data, vMsb, vLsb);
525 Memory_accessNotify(&n->n_data.memory, addr, 1);
526 Net_posedgeNotify(n);
527 }
528
new_SNetMap(Net * net,int netLsb,int snLsb,int width)529 SNetMap *new_SNetMap(Net *net,int netLsb,int snLsb,int width)
530 {
531 abort();
532 return 0;
533 }
534