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