1 /*
2  * Copyright (c) 2002-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  "compile.h"
21 # include  "vpi_priv.h"
22 # include  <cstdio>
23 # include  <cstdlib>
24 # include  <cstring>
25 # include  <cassert>
26 # include  "ivl_alloc.h"
27 
__vpiNamedEvent(__vpiScope * sc,const char * nam)28 inline __vpiNamedEvent::__vpiNamedEvent(__vpiScope*sc, const char*nam)
29 {
30       scope_ = sc;
31       name_ = vpip_name_string(nam);
32       callbacks_ = 0;
33 }
34 
~__vpiNamedEvent()35 __vpiNamedEvent::~__vpiNamedEvent()
36 {
37       while (callbacks_) {
38 	    struct __vpiCallback *tmp = callbacks_->next;
39 	    delete callbacks_;
40 	    callbacks_ = tmp;
41       }
42 }
43 
get_type_code(void) const44 int __vpiNamedEvent::get_type_code(void) const
45 { return vpiNamedEvent; }
46 
vpi_get(int code)47 int __vpiNamedEvent::vpi_get(int code)
48 {
49       switch (code) {
50 
51 	  case vpiAutomatic:
52 	    return scope_->is_automatic()? 1 : 0;
53       }
54 
55       return 0;
56 }
57 
vpi_get_str(int code)58 char* __vpiNamedEvent::vpi_get_str(int code)
59 {
60       if (code == vpiFile) {  // Not implemented for now!
61 	    return simple_set_rbuf_str(file_names[0]);
62       }
63       return generic_get_str(code, scope_, name_, NULL);
64 }
65 
vpi_put_value(p_vpi_value,int)66 vpiHandle __vpiNamedEvent::vpi_put_value(p_vpi_value, int)
67 {
68 	// p_vpi_value may be NULL, and an event doesn't care
69 	// what the value is
70       vvp_vector4_t val;
71       vvp_net_ptr_t dest(funct, 0);
72       vvp_send_vec4(dest, val, vthread_get_wt_context());
73 
74       return this;
75 }
76 
vpi_handle(int code)77 vpiHandle __vpiNamedEvent::vpi_handle(int code)
78 {
79       switch (code) {
80 	  case vpiScope:
81 	    return scope_;
82 
83 	  case vpiModule:
84 	    return vpip_module(scope_);
85       }
86 
87       return 0;
88 }
89 
90 
vpip_make_named_event(const char * name,vvp_net_t * funct)91 vpiHandle vpip_make_named_event(const char*name, vvp_net_t*funct)
92 {
93       __vpiNamedEvent*obj = new __vpiNamedEvent(vpip_peek_current_scope(), name);
94 
95       obj->funct = funct;
96 
97       return obj;
98 }
99 
100 /*
101  * This function runs the callbacks for a named event. All the
102  * callbacks are listed in the callback member of the event handle,
103  * this function scans that list.
104  *
105  * This also handles the case where the callback has been removed. The
106  * vpi_remove_cb doesn't actually remove any callbacks, it marks them
107  * as canceled by clearing the cb_rtn function. This function reaps
108  * those marked handles when it scans the list.
109  *
110  * We can not use vpi_free_object() here since it does not really
111  * delete the callback.
112  */
run_vpi_callbacks()113 void __vpiNamedEvent::run_vpi_callbacks()
114 {
115       struct __vpiCallback*next = callbacks_;
116       struct __vpiCallback*prev = 0;
117       while (next) {
118 	    struct __vpiCallback*cur = next;
119 	    next = cur->next;
120 
121 	    if (cur->cb_data.cb_rtn != 0) {
122 		  callback_execute(cur);
123 		  prev = cur;
124 
125 	    } else if (prev == 0) {
126 		  callbacks_ = next;
127 		  cur->next = 0;
128 		  delete cur;
129 
130 	    } else {
131 		  assert(prev->next == cur);
132 		  prev->next = next;
133 		  cur->next = 0;
134 		  delete cur;
135 	    }
136       }
137 }
138