1 /*
2  * Copyright (c) 2008-2015 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  "vvp_island.h"
21 # include  "compile.h"
22 # include  "symbols.h"
23 # include  "schedule.h"
24 # include  "config.h"
25 #ifdef CHECK_WITH_VALGRIND
26 # include  "vvp_cleanup.h"
27 #endif
28 # include  <iostream>
29 # include  <list>
30 # include  <cassert>
31 # include  <cstdlib>
32 # include  <cstring>
33 # include "ivl_alloc.h"
34 
35 static bool at_EOS = false;
36 
island_send_value(vvp_net_t * net,const vvp_vector8_t & val)37 void island_send_value(vvp_net_t*net, const vvp_vector8_t&val)
38 {
39       vvp_island_port*fun = dynamic_cast<vvp_island_port*>(net->fun);
40       if (fun->outvalue .eeq(val))
41 	    return;
42 
43       fun->outvalue = val;
44       net->send_vec8(fun->outvalue);
45 }
46 
47 /*
48  * Implementations...
49  */
vvp_island()50 vvp_island::vvp_island()
51 {
52       flagged_ = false;
53       branches_ = 0;
54       ports_ = 0;
55       anodes_ = 0;
56       bnodes_ = 0;
57 }
58 
~vvp_island()59 vvp_island::~vvp_island()
60 {
61 	// We can only delete islands at the end of simulation.
62       if (!at_EOS) assert(0);
63 
64       while (branches_) {
65 	    vvp_island_branch *next = branches_->next_branch;
66 	    delete branches_;
67 	    branches_ = next;
68       }
69 }
70 
flag_island()71 void vvp_island::flag_island()
72 {
73       if (flagged_ == true)
74 	    return;
75 
76       schedule_generic(this, 0, false, false);
77       flagged_ = true;
78 }
79 
80 /*
81 * This method handles the callback from the scheduler. It does basic
82 * housecleaning and calls the run_island() method implemented by the
83 * derived class.
84 */
run_run()85 void vvp_island::run_run()
86 {
87       flagged_ = false;
88       run_island();
89 }
90 
91 
add_port(const char * key,vvp_net_t * net)92 void vvp_island::add_port(const char*key, vvp_net_t*net)
93 {
94       if (ports_ == 0)
95 	    ports_ = new symbol_map_s<vvp_net_t>;
96 
97 	// each port should have a unique label
98       assert(ports_->sym_get_value(key) == 0);
99 
100       ports_->sym_set_value(key, net);
101 }
102 
add_branch(vvp_island_branch * branch,const char * pa,const char * pb)103 void vvp_island::add_branch(vvp_island_branch*branch, const char*pa, const char*pb)
104 {
105       vvp_island_branch*cur;
106       assert(ports_);
107       branch->a = ports_->sym_get_value(pa);
108       branch->b = ports_->sym_get_value(pb);
109       assert(branch->a && branch->b);
110 
111       vvp_branch_ptr_t ptra (branch, 0);
112       vvp_branch_ptr_t ptrb (branch, 1);
113       if (anodes_ == 0)
114 	    anodes_ = new symbol_map_s<vvp_island_branch>;
115       if (bnodes_ == 0)
116 	    bnodes_ = new symbol_map_s<vvp_island_branch>;
117 
118       if ((cur = anodes_->sym_get_value(pa))) {
119 	    branch->link[0] = cur->link[0];
120 	    cur->link[0] = ptra;
121       } else if ((cur = bnodes_->sym_get_value(pa))) {
122 	    branch->link[0] = cur->link[1];
123 	    cur->link[1] = ptra;
124       } else {
125 	    branch->link[0] = ptra;
126 	    anodes_->sym_set_value(pa, branch);
127       }
128 
129       if ((cur = anodes_->sym_get_value(pb))) {
130 	    branch->link[1] = cur->link[0];
131 	    cur->link[0] = ptrb;
132       } else if ((cur = bnodes_->sym_get_value(pb))) {
133 	    branch->link[1] = cur->link[1];
134 	    cur->link[1] = ptrb;
135       } else {
136 	    branch->link[1] = ptrb;
137 	    bnodes_->sym_set_value(pb, branch);
138       }
139 
140       branch->next_branch = branches_;
141       branches_ = branch;
142 }
143 
find_port(const char * key)144 vvp_net_t* vvp_island::find_port(const char*key)
145 {
146       if (ports_ == 0)
147 	    return 0;
148       else
149 	    return ports_->sym_get_value(key);
150 }
151 
compile_cleanup()152 void vvp_island::compile_cleanup()
153 {
154       delete ports_;
155       ports_ = 0;
156 
157       delete anodes_;
158       anodes_ = 0;
159 
160       delete bnodes_;
161       bnodes_ = 0;
162 }
163 
vvp_island_port(vvp_island * ip)164 vvp_island_port::vvp_island_port(vvp_island*ip)
165 : island_(ip)
166 {
167 }
168 
~vvp_island_port()169 vvp_island_port::~vvp_island_port()
170 {
171 }
172 
recv_vec4(vvp_net_ptr_t,const vvp_vector4_t & bit,vvp_context_t)173 void vvp_island_port::recv_vec4(vvp_net_ptr_t, const vvp_vector4_t&bit,
174                                 vvp_context_t)
175 {
176       vvp_vector8_t tmp (bit, 6, 6);
177       if (invalue .eeq(tmp))
178 	    return;
179 
180       invalue = tmp;
181       island_->flag_island();
182 }
183 
recv_vec4_pv(vvp_net_ptr_t port,const vvp_vector4_t & bit,unsigned base,unsigned wid,unsigned vwid,vvp_context_t)184 void vvp_island_port::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
185 				   unsigned base, unsigned wid, unsigned vwid,
186                                    vvp_context_t)
187 {
188       vvp_vector8_t tmp(bit, 6, 6);
189       recv_vec8_pv(port, tmp, base, wid, vwid);
190 }
191 
192 
recv_vec8(vvp_net_ptr_t,const vvp_vector8_t & bit)193 void vvp_island_port::recv_vec8(vvp_net_ptr_t, const vvp_vector8_t&bit)
194 {
195       if (invalue .eeq(bit))
196 	    return;
197 
198       invalue = bit;
199       island_->flag_island();
200 }
201 
recv_vec8_pv(vvp_net_ptr_t,const vvp_vector8_t & bit,unsigned base,unsigned wid,unsigned vwid)202 void vvp_island_port::recv_vec8_pv(vvp_net_ptr_t, const vvp_vector8_t&bit,
203                                    unsigned base, unsigned wid, unsigned vwid)
204 {
205       if (invalue.size() == 0) {
206 	    assert(bit.size() == wid);
207 	    invalue = part_expand(bit, vwid, base);
208       } else {
209 	    assert(invalue.size() == vwid);
210 	    for (unsigned idx = 0; idx < wid ; idx += 1) {
211 		  if ((base+idx) >= vwid)
212 			break;
213 		  invalue.set_bit(base+idx, bit.value(idx));
214 	    }
215       }
216 
217       island_->flag_island();
218 }
219 
force_flag(bool run_now)220 void vvp_island_port::force_flag(bool run_now)
221 {
222       if (run_now)
223 	    island_->run_island();
224       else
225 	    island_->flag_island();
226 }
227 
~vvp_island_branch()228 vvp_island_branch::~vvp_island_branch()
229 {
230 }
231 
island_collect_node(list<vvp_branch_ptr_t> & conn,vvp_branch_ptr_t cur)232 void island_collect_node(list<vvp_branch_ptr_t>&conn, vvp_branch_ptr_t cur)
233 {
234       conn .push_back(cur);
235       for (vvp_branch_ptr_t idx = next(cur) ; idx != cur ; idx = next(idx))
236 	    conn.push_back(idx);
237 }
238 
239 /* **** COMPILE/LINK SUPPORT **** */
240 
241 /*
242 * We need to keep an island symbol table to make island labels to
243 * islands, and we need a list of the islands that we can run through
244 * during cleanup. After linking is done, the compile_island_cleanup() is
245 * called to erase the symbol table, we still need the list to cleanup the
246 * island memory at EOS.
247 */
248 static symbol_map_s<vvp_island>* island_table = 0;
249 static vvp_island** island_list = 0;
250 static unsigned island_count = 0;
251 
252 #ifdef CHECK_WITH_VALGRIND
island_delete()253 void island_delete()
254 {
255       at_EOS = true;
256       for (unsigned idx = 0; idx < island_count; idx += 1) {
257 	    delete island_list[idx];
258       }
259       free(island_list);
260       island_list = 0;
261       island_count = 0;
262 }
263 #endif
264 
compile_island_base(char * label,vvp_island * use_island)265 void compile_island_base(char*label, vvp_island*use_island)
266 {
267       if (island_table == 0)
268 	    island_table = new symbol_map_s<vvp_island>;
269 
270       island_table->sym_set_value(label, use_island);
271       island_count += 1;
272       island_list = (vvp_island **)realloc(island_list,
273                                            island_count*sizeof(vvp_island **));
274       island_list[island_count-1] = use_island;
275       free(label);
276 }
277 
compile_find_island(const char * island)278 vvp_island* compile_find_island(const char*island)
279 {
280       assert(island_table);
281       vvp_island*use_island = island_table->sym_get_value(island);
282       assert(use_island);
283       return use_island;
284 }
285 
286 /*
287  * This handles the compile of a .port record. A .port is a 2-way port
288  * between the island and the outside. For example,
289  *
290  *   <label> .port <island> <src> ;
291  *
292  * The <src> is a label in the domain outside the island, and the
293  * <label> is in the domain inside the island. Since this port is
294  * bi-directional, the <label> is also available in the domain outside
295  * the island. The outside should use the <label> to access the nexus
296  * that this port represents, because the island will resolve internal
297  * drivers with the external driver and make the output available on
298  * <label>.
299  */
compile_island_port(char * label,char * island,char * src)300 void compile_island_port(char*label, char*island, char*src)
301 {
302       assert(island_table);
303       vvp_island*use_island = island_table->sym_get_value(island);
304       assert(use_island);
305       free(island);
306 
307       vvp_net_t*net = new vvp_net_t;
308       vvp_island_port*fun = new vvp_island_port(use_island);
309       net->fun = fun;
310 
311 	// Get the source from outside the island
312       input_connect(net, 0, src);
313 
314 	// Define the functor outside the island.
315       define_functor_symbol(label, net);
316 
317 	// Also define it inside the island.
318       use_island->add_port(label, net);
319 
320       free(label);
321 }
322 
compile_island_export(char * label,char * island)323 void compile_island_export(char*label, char*island)
324 {
325       fprintf(stderr, "XXXX %s .export %s;\n", label, island);
326       free(label);
327       free(island);
328 }
329 
330 /*
331  * This handles the compile of a .import record. A .import is an input
332  * port into the island from the outside domain. For example,
333  *
334  *   <label> .import <island> <src> ;
335  *
336  * The <src> is a label in the domain outside the island, and the
337  * <label> is in the domain inside the island. Branches within the
338  * island use the <label>.
339  */
compile_island_import(char * label,char * island,char * src)340 void compile_island_import(char*label, char*island, char*src)
341 {
342       assert(island_table);
343       vvp_island*use_island = island_table->sym_get_value(island);
344       assert(use_island);
345       free(island);
346 
347       vvp_net_t*net = new vvp_net_t;
348       vvp_island_port*fun = new vvp_island_port(use_island);
349       net->fun = fun;
350 
351 	// Get the source from outside the island
352       input_connect(net, 0, src);
353 
354 	// Define the functor only inside the island.
355       use_island->add_port(label, net);
356 
357       free(label);
358 }
359 
compile_island_cleanup(void)360 void compile_island_cleanup(void)
361 {
362 	// Call the per-island cleanup to get rid of local symbol tables.
363       for (unsigned idx = 0; idx < island_count; idx += 1) {
364 	    island_list[idx]->compile_cleanup();
365       }
366 
367 	// If we are not doing valgrind checking then free the list.
368 #ifndef CHECK_WITH_VALGRIND
369       free(island_list);
370       island_list = 0;
371       island_count = 0;
372 #endif
373 
374 	// Remove the island symbol table itself.
375       delete island_table;
376       island_table = 0;
377 }
378