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 /*****************************************************************************
21  *
22  * Comparison function for elements in list of nets
23  *
24  * Parameters:
25  *     vA,vB		Pointer to the pointers to the elements.
26  *
27  * Returns:		<0, 0 or >0 depending on comparison results.
28  *
29  * This function is used to ensure that lists of nets in triggers are in a
30  * canonical order.  We don't really care what that order is as long as it
31  * is the same for any list of nets.  For this reason we just sort on the
32  * addresses of the Nets in memory.
33  *
34  *
35  *****************************************************************************/
addrCmp(const void * vA,const void * vB)36 static int addrCmp(const void *vA,const void *vB)
37 {
38   void *A = *(void**)vA;
39   void *B = *(void**)vB;
40 
41   if (A < B)
42     return -1;
43   else if (A > B)
44     return 1;
45   else
46     return 0;
47 }
48 
49 /*****************************************************************************
50  *
51  * Create a new trigger object.
52  *
53  * Parameters:
54  *     posedges		Sorted list of Net* which invoke this trigger on a posedge
55  *     negedges		Sorted list of Net* which invoke this trigger on a negedge
56  *     next		Next trigger in hash bucket
57  *
58  * Returns:		Newly created Trigger object.
59  *
60  * Single bit signals that do not have a qualifier will be placed in both
61  * the posedges and negedges lists.  Multi-bit signals will be placed in
62  * only the posedges list and be triggered on any change.
63  *
64  *****************************************************************************/
new_Trigger(List * posedges,List * negedges,Trigger * next)65 Trigger *new_Trigger(List *posedges,List *negedges,Trigger *next)
66 {
67   Trigger *t = (Trigger*) malloc(sizeof(Trigger));
68 
69   t->t_posedges = posedges ? copy_List(posedges) : new_List();
70   t->t_negedges = negedges ? copy_List(negedges) : new_List();
71   t->t_events = 0;
72   t->t_next = 0;
73 
74   return t;
75 }
76 
77 /*****************************************************************************
78  *
79  * Get the hash code for a pair of lists.
80  *
81  * Parameters:
82  *     posedges		Sorted list of posedge Net*
83  *     negedges		Sorted list of negedge Net*
84  *
85  * Returns:		Hash code representing lists.
86  *
87  * The value returned is a hash value representing the pair of lists.  For any
88  * identical pairs of lists, the same hash code will always be returned.  For
89  * unmatching pairs of lists, the value returned should "usually" be different.
90  *
91  *****************************************************************************/
Trigger_getHashCode(List * posedges,List * negedges)92 uintptr_t Trigger_getHashCode(List *posedges,List *negedges)
93 {
94   ListElem *le;
95   uintptr_t HC = 0;
96 
97   for (le = List_first(posedges);le;le = List_next(posedges,le)) {
98     uintptr_t X = (uintptr_t) ListElem_obj(le);
99     HC = ((HC+X) << 8) + X*X + (HC>>8);
100   }
101   for (le = List_first(negedges);le;le = List_next(negedges,le)) {
102     uintptr_t X = (uintptr_t) ListElem_obj(le);
103     HC = ((HC+X) << 8) + X*X + (HC>>8);
104   }
105 
106   return HC;
107 }
108 
109 /*****************************************************************************
110  *
111  * Sort both lists and get the hash code using Trigger_getHashCode
112  *
113  * Parameters:
114  *     posedges		Unsorted list of posedge Net*
115  *     negedges		Unsorted list of negedge Net*
116  *
117  * Returns:		Hash code representing lists.
118  *
119  *****************************************************************************/
Trigger_sortAndGetHashCode(List * posedges,List * negedges)120 uintptr_t Trigger_sortAndGetHashCode(List *posedges,List *negedges)
121 {
122   List_sort(posedges,addrCmp);
123   List_sort(negedges,addrCmp);
124   return Trigger_getHashCode(posedges,negedges);
125 }
126 
127 
128 /*****************************************************************************
129  *
130  * Test a trigger to see if it exactly matches the posesges and negedges list.
131  * it is assumed that the lists are sorted.
132  *
133  * Parameters:
134  *     t		Trigger to compare
135  *     posedges		Sorted list of posedge sensitive nets
136  *     negedges		Sorted list of negedge sensitive nets
137  *
138  *****************************************************************************/
Trigger_match(Trigger * t,List * posedges,List * negedges)139 int Trigger_match(Trigger *t,List *posedges,List *negedges)
140 {
141   ListElem *le1, *le2;
142 
143   if (List_numElems(t->t_posedges) != List_numElems(posedges)) return 0;
144   if (List_numElems(t->t_negedges) != List_numElems(negedges)) return 0;
145 
146   le1 = List_first(t->t_posedges);
147   le2 = List_first(posedges);
148   while (le1 && le2) {
149     if (ListElem_obj(le1) != ListElem_obj(le2))
150       return 0;
151     le1 = List_next(t->t_posedges,le1);
152     le2 = List_next(posedges,le2);
153   }
154 
155   le1 = List_first(t->t_negedges);
156   le2 = List_first(negedges);
157   while (le1 && le2) {
158     if (ListElem_obj(le1) != ListElem_obj(le2))
159       return 0;
160     le1 = List_next(t->t_negedges,le1);
161     le2 = List_next(negedges,le2);
162   }
163 
164   return 1;
165 }
166 
167 
168 /*****************************************************************************
169  *
170  * Find/create a the specified trigger.
171  *
172  * Parameters:
173  *     tlist		Pointer to head of list of triggers with matching hashcodes
174  *     posedges		Sorted list of posedge sensitive Net*
175  *     negedges		Sorted list of negedge sensitive Net*
176  *
177  * Looks through the list *tlist of triggers for a trigger with the same
178  * posedges/negedges as those passed.  If the trigger is found it is returned
179  * and if it is not found a new trigger is created and it is inserted into
180  * *tlist.  Assuming Trigger_getHashCode() returns good values, the *tlist
181  * should almost always have either 0 or 1 elements, and when it has 1 element
182  * the lookup should almost always succeed.
183  *
184  *****************************************************************************/
Trigger_getTrigger(Trigger ** tlist,List * posedges,List * negedges)185 Trigger *Trigger_getTrigger(Trigger **tlist,List *posedges,List *negedges)
186 {
187   Trigger *t;
188   ListElem *le;
189 
190   for (t = *tlist;t;t = t->t_next)
191     if (Trigger_match(t,posedges,negedges))
192       return t;
193 
194   *tlist = t = new_Trigger(posedges,negedges,*tlist);
195 
196   for (le = List_first(posedges);le;le = List_next(posedges,le)) {
197     Net_posedgeListen((Net*) ListElem_obj(le),t);
198   }
199 
200   for (le = List_first(negedges);le;le = List_next(negedges,le)) {
201     Net_negedgeListen((Net*) ListElem_obj(le),t);
202   }
203 
204   return t;
205 }
206 
207 /*****************************************************************************
208  *
209  * Print representation of a trigger.
210  *
211  * Parameters:
212  *     t		Trigger to print.
213  *     f		File on which to print representation.
214  *
215  *****************************************************************************/
Trigger_print(Trigger * t,FILE * f)216 void Trigger_print(Trigger *t,FILE *f)
217 {
218   ListElem *le;
219 
220   fprintf(f,"@id<%p> (",t);
221   for (le = List_first(t->t_posedges);le;le = List_next(t->t_posedges,le)) {
222     Net *n = (Net*)ListElem_obj(le);
223 
224     if (Net_nbits(n) > 1)
225       fprintf(f," %s",Net_getName(n));
226     else
227       fprintf(f," posedge %s",Net_getName(n));
228   }
229   for (le = List_first(t->t_negedges);le;le = List_next(t->t_negedges,le)) {
230     Net *n = (Net*)ListElem_obj(le);
231 
232     fprintf(f," negedge %s",Net_getName(n));
233   }
234   fprintf(f,")");
235 }
236 
237 /*****************************************************************************
238  *
239  * Fire a trigger and move all its queued events to the global time queue.
240  *
241  * Parameters:
242  *     t		Trigger to fire.
243  *
244  * When this function is called, any events that are stored in the trigger
245  * are moved to the main simulator time queue at the current time.
246  *
247  *****************************************************************************/
Trigger_fire(Trigger * t)248 void Trigger_fire(Trigger *t)
249 {
250   EvQueue *Q = Circuit_getQueue(&vgsim.vg_circuit);
251 
252   while (t->t_events) {
253     Event *e = t->t_events;
254     t->t_events = e->ev_base.eb_next;
255 
256     EvQueue_enqueueAfter(Q,e,0);
257   }
258 }
259 
260 /*****************************************************************************
261  *
262  * Queue an event to be invoked when the trigger is fired.
263  *
264  * Parameters:
265  *     t		Trigger in which to place event
266  *     e		Event to be invoked when trigger fires.
267  *
268  *****************************************************************************/
Trigger_enqueue(Trigger * t,Event * e)269 void Trigger_enqueue(Trigger *t, Event *e)
270 {
271   e->ev_base.eb_next = t->t_events;
272   t->t_events = e;
273 }
274 
275