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