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