1 /*
2 * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com)
3 *
4 * This source code is free software; you can redistribute it
5 * and/or modify it in source code form under the terms of the GNU
6 * General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 # include "config.h"
21 # include "compiler.h"
22 # include "netlist.h"
23 # include "ivl_assert.h"
24
25 /*
26 * NOTE: The name_ is perm-allocated by the caller.
27 */
NetEvent(perm_string n)28 NetEvent::NetEvent(perm_string n)
29 : name_(n)
30 {
31 local_flag_ = false;
32 scope_ = 0;
33 snext_ = 0;
34 probes_ = 0;
35 trig_ = 0;
36 waitref_ = 0;
37 exprref_ = 0;
38 wlist_ = 0;
39 }
40
~NetEvent()41 NetEvent::~NetEvent()
42 {
43 assert(waitref_ == 0);
44 if (scope_) scope_->rem_event(this);
45 while (probes_) {
46 NetEvProbe*tmp = probes_->enext_;
47 delete probes_;
48 probes_ = tmp;
49 }
50 /* name_ is lex_strings. */
51 }
52
name() const53 perm_string NetEvent::name() const
54 {
55 return name_;
56 }
57
scope()58 NetScope* NetEvent::scope()
59 {
60 assert(scope_);
61 return scope_;
62 }
63
scope() const64 const NetScope* NetEvent::scope() const
65 {
66 assert(scope_);
67 return scope_;
68 }
69
nprobe() const70 unsigned NetEvent::nprobe() const
71 {
72 unsigned cnt = 0;
73 NetEvProbe*cur = probes_;
74 while (cur) {
75 cnt += 1;
76 cur = cur->enext_;
77 }
78
79 return cnt;
80 }
81
probe(unsigned idx)82 NetEvProbe* NetEvent::probe(unsigned idx)
83 {
84 NetEvProbe*cur = probes_;
85 while (cur && idx) {
86 cur = cur->enext_;
87 idx -= 1;
88 }
89 return cur;
90 }
91
probe(unsigned idx) const92 const NetEvProbe* NetEvent::probe(unsigned idx) const
93 {
94 NetEvProbe*cur = probes_;
95 while (cur && idx) {
96 cur = cur->enext_;
97 idx -= 1;
98 }
99 return cur;
100 }
101
ntrig() const102 unsigned NetEvent::ntrig() const
103 {
104 unsigned cnt = 0;
105 NetEvTrig*cur = trig_;
106 while (cur) {
107 cnt += 1;
108 cur = cur->enext_;
109 }
110
111 return cnt;
112 }
113
nwait() const114 unsigned NetEvent::nwait() const
115 {
116 return waitref_;
117 }
118
nexpr() const119 unsigned NetEvent::nexpr() const
120 {
121 return exprref_;
122 }
123
124 /*
125 * A "similar" event is one that has an identical non-nil set of
126 * probes.
127 */
find_similar_event(list<NetEvent * > & event_list)128 void NetEvent::find_similar_event(list<NetEvent*>&event_list)
129 {
130 if (probes_ == 0)
131 return;
132
133 set<NetEvent*> candidate_events;
134
135 /* First, get a list of all the NetEvProbes that are connected
136 to my first probe. Then use that to create a set of
137 candidate events. These candidate events are a superset of
138 the similar events, so I will be culling this list later. */
139 list<NetEvProbe*>first_probes;
140 probes_->find_similar_probes(first_probes);
141
142 for (list<NetEvProbe*>::iterator idx = first_probes.begin()
143 ; idx != first_probes.end() ; ++ idx ) {
144
145 candidate_events.insert( (*idx)->event() );
146 }
147
148 if (candidate_events.empty())
149 return;
150
151 /* Now scan the remaining probes, in each case checking that
152 the probe event is a candidate event. After each iteration,
153 events that don't have a similar probe will be removed from
154 the candidate_events set. If the candidate_events set
155 becomes empty, then give up. */
156 unsigned probe_count = 1;
157 for (NetEvProbe*cur = probes_->enext_ ; cur; cur = cur->enext_) {
158 list<NetEvProbe*>similar_probes;
159 cur->find_similar_probes(similar_probes);
160
161 set<NetEvent*> candidate_tmp;
162 for (list<NetEvProbe*>::iterator idx = similar_probes.begin()
163 ; idx != similar_probes.end() ; ++ idx ) {
164
165 NetEvent*tmp = (*idx)->event();
166 if (candidate_events.find(tmp) != candidate_events.end())
167 candidate_tmp .insert(tmp);
168 }
169
170 // None of the candidate events match this probe? Give up!
171 if (candidate_tmp.empty())
172 return;
173
174 candidate_events = candidate_tmp;
175 probe_count += 1;
176 }
177
178 /* Scan the surviving candidate events. We know that they all
179 have probes that match the current event's probes. Check
180 for remaining compatibility details and save the survivors
181 in the event_list that the caller passed. */
182 for (set<NetEvent*>::iterator idx = candidate_events.begin()
183 ; idx != candidate_events.end() ; ++ idx ) {
184
185 NetEvent*tmp = *idx;
186
187 // This shouldn't be possible?
188 if (tmp == this)
189 continue;
190
191 /* For automatic tasks, the VVP runtime holds state for events
192 in the automatically allocated context. This means we can't
193 merge similar events in different automatic tasks. */
194 if (scope()->is_auto() && (tmp->scope() != scope()))
195 continue;
196
197 unsigned tcnt = 0;
198 for (NetEvProbe*cur = tmp->probes_ ; cur ; cur = cur->enext_)
199 tcnt += 1;
200
201 if (tcnt == probe_count)
202 event_list .push_back(tmp);
203 }
204
205 }
206
207
replace_event(NetEvent * that)208 void NetEvent::replace_event(NetEvent*that)
209 {
210 while (wlist_) {
211 wlist_->obj->replace_event(this, that);
212 }
213 }
214
nex_async_()215 NexusSet* NetEvent::nex_async_()
216 {
217 /* If there are behavioral trigger statements attached to me,
218 then this is not an asynchronous event. */
219 if (trig_ != 0)
220 return 0;
221
222
223 NexusSet*tmp = new NexusSet;
224 for (NetEvProbe*cur = probes_ ; cur != 0 ; cur = cur->enext_) {
225 if (cur->edge() != NetEvProbe::ANYEDGE) {
226 delete tmp;
227 return 0;
228 }
229
230 for (unsigned idx = 0 ; idx < cur->pin_count() ; idx += 1) {
231 Nexus*nex = cur->pin(idx).nexus();
232 tmp->add(nex, 0, nex->vector_width());
233 }
234 }
235
236 return tmp;
237 }
238
NetEvTrig(NetEvent * ev)239 NetEvTrig::NetEvTrig(NetEvent*ev)
240 : event_(ev)
241 {
242 enext_ = event_->trig_;
243 event_->trig_ = this;
244 }
245
~NetEvTrig()246 NetEvTrig::~NetEvTrig()
247 {
248 if (event_->trig_ == this) {
249 event_->trig_ = enext_;
250
251 } else {
252 NetEvTrig*cur = event_->trig_;
253 while (cur->enext_ != this) {
254 assert(cur->enext_);
255 cur = cur->enext_;
256 }
257
258 cur->enext_ = this->enext_;
259 }
260 }
261
event() const262 const NetEvent* NetEvTrig::event() const
263 {
264 return event_;
265 }
266
NetEvProbe(NetScope * s,perm_string n,NetEvent * tgt,edge_t t,unsigned p)267 NetEvProbe::NetEvProbe(NetScope*s, perm_string n, NetEvent*tgt,
268 edge_t t, unsigned p)
269 : NetNode(s, n, p), event_(tgt), edge_(t)
270 {
271 for (unsigned idx = 0 ; idx < p ; idx += 1) {
272 pin(idx).set_dir(Link::INPUT);
273 }
274
275 enext_ = event_->probes_;
276 event_->probes_ = this;
277 }
278
~NetEvProbe()279 NetEvProbe::~NetEvProbe()
280 {
281 if (event_->probes_ == this) {
282 event_->probes_ = enext_;
283
284 } else {
285 NetEvProbe*cur = event_->probes_;
286 while (cur->enext_ != this) {
287 assert(cur->enext_);
288 cur = cur->enext_;
289 }
290
291 cur->enext_ = this->enext_;
292 }
293 }
294
edge() const295 NetEvProbe::edge_t NetEvProbe::edge() const
296 {
297 return edge_;
298 }
299
event()300 NetEvent* NetEvProbe::event()
301 {
302 return event_;
303 }
304
event() const305 const NetEvent* NetEvProbe::event() const
306 {
307 return event_;
308 }
309
310 /*
311 * A similar NetEvProbe is one that is connected to all the same nexa
312 * that this probe is connected to, and also is the same edge
313 * type. Don't count myself as a similar probe.
314 */
find_similar_probes(list<NetEvProbe * > & plist)315 void NetEvProbe::find_similar_probes(list<NetEvProbe*>&plist)
316 {
317 Nexus*nex = pin(0).nexus();
318
319 for (Link*lcur = nex->first_nlink(); lcur; lcur = lcur->next_nlink()) {
320 NetPins*obj = lcur->get_obj();
321 // Skip NexusSet objects
322 if (obj == 0)
323 continue;
324
325 if (obj->pin_count() != pin_count())
326 continue;
327
328 NetEvProbe*tmp = dynamic_cast<NetEvProbe*>(obj);
329 if (tmp == 0)
330 continue;
331
332 if (tmp == this)
333 continue;
334
335 if (edge() != tmp->edge())
336 continue;
337
338 bool ok_flag = true;
339 for (unsigned idx = 1 ; ok_flag && idx < pin_count() ; idx += 1)
340 if (! pin(idx).is_linked(tmp->pin(idx)))
341 ok_flag = false;
342
343 if (ok_flag == true)
344 plist .push_back(tmp);
345 }
346 }
347
NetEvWait(NetProc * pr)348 NetEvWait::NetEvWait(NetProc*pr)
349 : statement_(pr), has_t0_trigger_(false)
350 {
351 }
352
~NetEvWait()353 NetEvWait::~NetEvWait()
354 {
355 if (! events_.empty()) {
356 for (unsigned idx = 0 ; idx < events_.size() ; idx += 1) {
357 NetEvent*tgt = events_[idx];
358 tgt->waitref_ -= 1;
359
360 struct NetEvent::wcell_*tmp = tgt->wlist_;
361 if (tmp->obj == this) {
362 tgt->wlist_ = tmp->next;
363 delete tmp;
364 } else {
365 assert(tmp->next);
366 while (tmp->next->obj != this) {
367 tmp = tmp->next;
368 assert(tmp->next);
369 }
370 tmp->next = tmp->next->next;
371 delete tmp;
372 }
373 delete tgt;
374 }
375 events_.clear();
376 }
377 delete statement_;
378 }
379
add_event(NetEvent * tgt)380 void NetEvWait::add_event(NetEvent*tgt)
381 {
382 /* A wait fork is an empty event. */
383 if (! tgt) {
384 assert(events_.empty());
385 events_.push_back(0);
386 return;
387 }
388
389 events_.push_back(tgt);
390
391 // Remember to tell the NetEvent that there is someone
392 // pointing to it.
393 tgt->waitref_ += 1;
394
395 struct NetEvent::wcell_*tmp = new NetEvent::wcell_;
396 tmp->obj = this;
397 tmp->next = tgt->wlist_;
398 tgt->wlist_ = tmp;
399 }
400
replace_event(NetEvent * src,NetEvent * repl)401 void NetEvWait::replace_event(NetEvent*src, NetEvent*repl)
402 {
403 unsigned idx;
404 for (idx = 0 ; idx < events_.size() ; idx += 1) {
405 if (events_[idx] == src)
406 break;
407 }
408
409 assert(idx < events_.size());
410
411 // First, remove me from the list held by the src NetEvent.
412 assert(src->waitref_ > 0);
413 src->waitref_ -= 1;
414 struct NetEvent::wcell_*tmp = src->wlist_;
415 if (tmp->obj == this) {
416 src->wlist_ = tmp->next;
417 delete tmp;
418 } else {
419 assert(tmp->next);
420 while (tmp->next->obj != this) {
421 tmp = tmp->next;
422 assert(tmp->next);
423 }
424 tmp->next = tmp->next->next;
425 delete tmp;
426 }
427
428 // Replace the src pointer with the repl pointer.
429 events_[idx] = repl;
430
431 // Remember to tell the replacement NetEvent that there is
432 // someone pointing to it.
433 repl->waitref_ += 1;
434
435 tmp = new NetEvent::wcell_;
436 tmp->obj = this;
437 tmp->next = repl->wlist_;
438 repl->wlist_ = tmp;
439
440 }
441
statement()442 NetProc* NetEvWait::statement()
443 {
444 return statement_;
445 }
446
statement() const447 const NetProc* NetEvWait::statement() const
448 {
449 return statement_;
450 }
451