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