1 /*
2  * Copyright (c) 2004-2016 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 # define __STDC_LIMIT_MACROS
21 # include  "compile.h"
22 # include  "part.h"
23 # include  <cstdlib>
24 # include  <climits>
25 # include  <stdint.h>
26 # include  <iostream>
27 # include  <cassert>
28 
29 struct vvp_fun_part_state_s {
vvp_fun_part_state_svvp_fun_part_state_s30       vvp_fun_part_state_s() : bitsr(0.0) {}
31 
32       vvp_vector4_t bits;
33       double bitsr;
34 };
35 
vvp_fun_part(unsigned base,unsigned wid)36 vvp_fun_part::vvp_fun_part(unsigned base, unsigned wid)
37 : base_(base), wid_(wid)
38 {
39 }
40 
~vvp_fun_part()41 vvp_fun_part::~vvp_fun_part()
42 {
43 }
44 
vvp_fun_part_sa(unsigned base,unsigned wid)45 vvp_fun_part_sa::vvp_fun_part_sa(unsigned base, unsigned wid)
46 : vvp_fun_part(base, wid)
47 {
48       net_ = 0;
49 }
50 
~vvp_fun_part_sa()51 vvp_fun_part_sa::~vvp_fun_part_sa()
52 {
53 }
54 
recv_vec4(vvp_net_ptr_t port,const vvp_vector4_t & bit,vvp_context_t)55 void vvp_fun_part_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
56                                 vvp_context_t)
57 {
58       assert(port.port() == 0);
59 
60       vvp_vector4_t tmp (bit, base_, wid_);
61       if (val_ .eeq( tmp ))
62 	    return;
63 
64       val_ = tmp;
65 
66       if (net_ == 0) {
67 	    net_ = port.ptr();
68 	    schedule_functor(this);
69       }
70 }
71 
72 /*
73  * Handle the case that the part select node is actually fed by a part
74  * select assignment. It's not exactly clear what might make this
75  * happen, but is does seem to happen and this should have well
76  * defined behavior.
77  */
recv_vec4_pv(vvp_net_ptr_t port,const vvp_vector4_t & bit,unsigned base,unsigned wid,unsigned vwid,vvp_context_t)78 void vvp_fun_part_sa::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
79 				   unsigned base, unsigned wid, unsigned vwid,
80                                    vvp_context_t)
81 {
82       assert(bit.size() == wid);
83 
84       vvp_vector4_t tmp (vwid, BIT4_Z);
85       tmp.set_vec(base_, val_);
86       tmp.set_vec(base, bit);
87       recv_vec4(port, tmp, 0);
88 }
89 
run_run()90 void vvp_fun_part_sa::run_run()
91 {
92       vvp_net_t*ptr = net_;
93       net_ = 0;
94       ptr->send_vec4(val_, 0);
95 }
96 
vvp_fun_part_aa(unsigned base,unsigned wid)97 vvp_fun_part_aa::vvp_fun_part_aa(unsigned base, unsigned wid)
98 : vvp_fun_part(base, wid)
99 {
100       context_scope_ = vpip_peek_context_scope();
101       context_idx_ = vpip_add_item_to_context(this, context_scope_);
102 }
103 
~vvp_fun_part_aa()104 vvp_fun_part_aa::~vvp_fun_part_aa()
105 {
106 }
107 
alloc_instance(vvp_context_t context)108 void vvp_fun_part_aa::alloc_instance(vvp_context_t context)
109 {
110       vvp_set_context_item(context, context_idx_, new vvp_vector4_t);
111 }
112 
reset_instance(vvp_context_t context)113 void vvp_fun_part_aa::reset_instance(vvp_context_t context)
114 {
115       vvp_vector4_t*val = static_cast<vvp_vector4_t*>
116             (vvp_get_context_item(context, context_idx_));
117 
118       val->set_to_x();
119 }
120 
121 #ifdef CHECK_WITH_VALGRIND
free_instance(vvp_context_t context)122 void vvp_fun_part_aa::free_instance(vvp_context_t context)
123 {
124       vvp_vector4_t*val = static_cast<vvp_vector4_t*>
125             (vvp_get_context_item(context, context_idx_));
126       delete val;
127 }
128 #endif
129 
recv_vec4(vvp_net_ptr_t port,const vvp_vector4_t & bit,vvp_context_t context)130 void vvp_fun_part_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
131                                 vvp_context_t context)
132 {
133       if (context) {
134             assert(port.port() == 0);
135 
136             vvp_vector4_t*val = static_cast<vvp_vector4_t*>
137                   (vvp_get_context_item(context, context_idx_));
138 
139             vvp_vector4_t tmp (wid_, BIT4_X);
140             for (unsigned idx = 0 ;  idx < wid_ ;  idx += 1) {
141                   if (idx + base_ < bit.size())
142                         tmp.set_bit(idx, bit.value(base_+idx));
143             }
144             if (!val->eeq( tmp )) {
145                   *val = tmp;
146                   port.ptr()->send_vec4(tmp, context);
147             }
148       } else {
149             context = context_scope_->live_contexts;
150             while (context) {
151                   recv_vec4(port, bit, context);
152                   context = vvp_get_next_context(context);
153             }
154       }
155 }
156 
157 /*
158  * Handle the case that the part select node is actually fed by a part
159  * select assignment. It's not exactly clear what might make this
160  * happen, but is does seem to happen and this should have well
161  * defined behavior.
162  */
recv_vec4_pv(vvp_net_ptr_t port,const vvp_vector4_t & bit,unsigned base,unsigned wid,unsigned vwid,vvp_context_t context)163 void vvp_fun_part_aa::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
164 				   unsigned base, unsigned wid, unsigned vwid,
165                                    vvp_context_t context)
166 {
167       if (context) {
168             assert(bit.size() == wid);
169 
170             vvp_vector4_t*val = static_cast<vvp_vector4_t*>
171                   (vvp_get_context_item(context, context_idx_));
172 
173             vvp_vector4_t tmp (vwid, BIT4_Z);
174             tmp.set_vec(base_, *val);
175             tmp.set_vec(base, bit);
176             recv_vec4(port, tmp, context);
177       } else {
178             context = context_scope_->live_contexts;
179             while (context) {
180                   recv_vec4_pv(port, bit, base, wid, vwid, context);
181                   context = vvp_get_next_context(context);
182             }
183       }
184 }
185 
vvp_fun_part_pv(unsigned b,unsigned w,unsigned v)186 vvp_fun_part_pv::vvp_fun_part_pv(unsigned b, unsigned w, unsigned v)
187 : base_(b), wid_(w), vwid_(v)
188 {
189 }
190 
~vvp_fun_part_pv()191 vvp_fun_part_pv::~vvp_fun_part_pv()
192 {
193 }
194 
recv_vec4(vvp_net_ptr_t port,const vvp_vector4_t & bit,vvp_context_t context)195 void vvp_fun_part_pv::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
196                                 vvp_context_t context)
197 {
198       assert(port.port() == 0);
199 
200       if (bit.size() != wid_) {
201 	    cerr << "internal error: part_pv data mismatch. "
202 		 << "base_=" << base_ << ", wid_=" << wid_
203 		 << ", vwid_=" << vwid_ << ", bit=" << bit
204 		 << endl;
205       }
206       assert(bit.size() == wid_);
207 
208       port.ptr()->send_vec4_pv(bit, base_, wid_, vwid_, context);
209 }
210 
recv_vec4_pv(vvp_net_ptr_t port,const vvp_vector4_t & bit,unsigned base,unsigned wid,unsigned vwid,vvp_context_t ctx)211 void vvp_fun_part_pv::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
212                                  unsigned base, unsigned wid, unsigned vwid,
213                                  vvp_context_t ctx)
214 {
215       assert(port.port() == 0);
216       assert(bit.size() == wid);
217       assert(base + wid <= vwid);
218       assert(vwid == wid_);
219 
220       vvp_vector4_t tmp(wid_, BIT4_Z);
221       tmp.set_vec(base, bit);
222 
223       port.ptr()->send_vec4_pv(tmp, base_, wid_, vwid_, ctx);
224 }
225 
recv_vec8(vvp_net_ptr_t port,const vvp_vector8_t & bit)226 void vvp_fun_part_pv::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit)
227 {
228       assert(port.port() == 0);
229 
230       if (bit.size() != wid_) {
231 	    cerr << "internal error: part_pv (strength-aware) data mismatch. "
232 		 << "base_=" << base_ << ", wid_=" << wid_
233 		 << ", vwid_=" << vwid_ << ", bit=" << bit
234 		 << endl;
235       }
236       assert(bit.size() == wid_);
237 
238       port.ptr()->send_vec8_pv(bit, base_, wid_, vwid_);
239 }
240 
vvp_fun_part_var(unsigned w,bool is_signed)241 vvp_fun_part_var::vvp_fun_part_var(unsigned w, bool is_signed)
242 : wid_(w), is_signed_(is_signed)
243 {
244 }
245 
~vvp_fun_part_var()246 vvp_fun_part_var::~vvp_fun_part_var()
247 {
248 }
249 
recv_vec4_(vvp_net_ptr_t port,const vvp_vector4_t & bit,int & base,vvp_vector4_t & source,vvp_vector4_t & ref)250 bool vvp_fun_part_var::recv_vec4_(vvp_net_ptr_t port, const vvp_vector4_t&bit,
251                                   int&base, vvp_vector4_t&source,
252                                   vvp_vector4_t&ref)
253 {
254       int32_t tmp;
255       switch (port.port()) {
256 	  case 0:
257 	    source = bit;
258 	    break;
259 	  case 1:
260 	      // INT_MIN is before the vector and is used to
261 	      // represent a 'bx value on the select input.
262 	    tmp = INT32_MIN;
263 	    vector4_to_value(bit, tmp, is_signed_);
264 	    if (static_cast<int>(tmp) == base) return false;
265 	    base = tmp;
266 	    break;
267 	  default:
268 	    fprintf(stderr, "Unsupported port type %u.\n", port.port());
269 	    assert(0);
270 	    break;
271       }
272 
273       vvp_vector4_t res (wid_);
274 
275       for (unsigned idx = 0 ;  idx < wid_ ;  idx += 1) {
276 	    int adr = base+idx;
277 	    if (adr < 0) continue;
278 	    if ((unsigned)adr >= source.size()) break;
279 
280 	    res.set_bit(idx, source.value((unsigned)adr));
281       }
282 
283       if (! ref.eeq(res)) {
284 	    ref = res;
285             return true;
286       }
287       return false;
288 }
289 
vvp_fun_part_var_sa(unsigned w,bool is_signed)290 vvp_fun_part_var_sa::vvp_fun_part_var_sa(unsigned w, bool is_signed)
291 : vvp_fun_part_var(w, is_signed), base_(0)
292 {
293 }
294 
~vvp_fun_part_var_sa()295 vvp_fun_part_var_sa::~vvp_fun_part_var_sa()
296 {
297 }
298 
recv_vec4(vvp_net_ptr_t port,const vvp_vector4_t & bit,vvp_context_t)299 void vvp_fun_part_var_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
300                                     vvp_context_t)
301 {
302       if (recv_vec4_(port, bit, base_, source_, ref_)) {
303 	    port.ptr()->send_vec4(ref_, 0);
304       }
305 }
306 
recv_vec4_pv(vvp_net_ptr_t port,const vvp_vector4_t & bit,unsigned base,unsigned wid,unsigned vwid,vvp_context_t)307 void vvp_fun_part_var_sa::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
308 				       unsigned base, unsigned wid, unsigned vwid,
309                                        vvp_context_t)
310 {
311       assert(bit.size() == wid);
312 
313       vvp_vector4_t tmp = source_;
314       if (tmp.size() == 0)
315 	    tmp = vvp_vector4_t(vwid);
316 
317       assert(tmp.size() == vwid);
318       tmp.set_vec(base, bit);
319       recv_vec4(port, tmp, 0);
320 }
321 
322 struct vvp_fun_part_var_state_s {
vvp_fun_part_var_state_svvp_fun_part_var_state_s323       vvp_fun_part_var_state_s() : base(0) { }
324 
325       int base;
326       vvp_vector4_t source;
327       vvp_vector4_t ref;
328 };
329 
vvp_fun_part_var_aa(unsigned w,bool is_signed)330 vvp_fun_part_var_aa::vvp_fun_part_var_aa(unsigned w, bool is_signed)
331 : vvp_fun_part_var(w, is_signed)
332 {
333       context_scope_ = vpip_peek_context_scope();
334       context_idx_ = vpip_add_item_to_context(this, context_scope_);
335 }
336 
~vvp_fun_part_var_aa()337 vvp_fun_part_var_aa::~vvp_fun_part_var_aa()
338 {
339 }
340 
alloc_instance(vvp_context_t context)341 void vvp_fun_part_var_aa::alloc_instance(vvp_context_t context)
342 {
343       vvp_set_context_item(context, context_idx_, new vvp_fun_part_var_state_s);
344 }
345 
reset_instance(vvp_context_t context)346 void vvp_fun_part_var_aa::reset_instance(vvp_context_t context)
347 {
348       vvp_fun_part_var_state_s*state = static_cast<vvp_fun_part_var_state_s*>
349             (vvp_get_context_item(context, context_idx_));
350 
351       state->base = 0;
352       state->source.set_to_x();
353       state->ref.set_to_x();
354 }
355 
356 #ifdef CHECK_WITH_VALGRIND
free_instance(vvp_context_t context)357 void vvp_fun_part_var_aa::free_instance(vvp_context_t context)
358 {
359       vvp_fun_part_var_state_s*state = static_cast<vvp_fun_part_var_state_s*>
360             (vvp_get_context_item(context, context_idx_));
361       delete state;
362 }
363 #endif
364 
recv_vec4(vvp_net_ptr_t port,const vvp_vector4_t & bit,vvp_context_t context)365 void vvp_fun_part_var_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
366                                     vvp_context_t context)
367 {
368       if (context) {
369             vvp_fun_part_var_state_s*state = static_cast<vvp_fun_part_var_state_s*>
370                   (vvp_get_context_item(context, context_idx_));
371 
372             if (recv_vec4_(port, bit, state->base, state->source, state->ref)) {
373                   port.ptr()->send_vec4(state->ref, context);
374             }
375       } else {
376             context = context_scope_->live_contexts;
377             while (context) {
378                   recv_vec4(port, bit, context);
379                   context = vvp_get_next_context(context);
380             }
381       }
382 }
383 
recv_vec4_pv(vvp_net_ptr_t port,const vvp_vector4_t & bit,unsigned base,unsigned wid,unsigned vwid,vvp_context_t context)384 void vvp_fun_part_var_aa::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
385 				       unsigned base, unsigned wid, unsigned vwid,
386                                        vvp_context_t context)
387 {
388       if (context) {
389             vvp_fun_part_var_state_s*state = static_cast<vvp_fun_part_var_state_s*>
390                   (vvp_get_context_item(context, context_idx_));
391 
392             assert(bit.size() == wid);
393 
394             vvp_vector4_t tmp = state->source;
395             if (tmp.size() == 0)
396                   tmp = vvp_vector4_t(vwid);
397 
398             assert(tmp.size() == vwid);
399             tmp.set_vec(base, bit);
400             recv_vec4(port, tmp, context);
401       } else {
402             context = context_scope_->live_contexts;
403             while (context) {
404                   recv_vec4(port, bit, context);
405                   context = vvp_get_next_context(context);
406             }
407       }
408 }
409 
410 /*
411  * Given a node functor, create a network node and link it into the
412  * netlist. This form assumes nodes with a single input.
413  */
link_node_1(char * label,char * source,vvp_net_fun_t * fun)414 void link_node_1(char*label, char*source, vvp_net_fun_t*fun)
415 {
416       vvp_net_t*net = new vvp_net_t;
417       net->fun = fun;
418 
419       define_functor_symbol(label, net);
420       free(label);
421 
422       input_connect(net, 0, source);
423 }
424 
compile_part_select(char * label,char * source,unsigned base,unsigned wid)425 void compile_part_select(char*label, char*source,
426 			 unsigned base, unsigned wid)
427 {
428       vvp_fun_part*fun = 0;
429       if (vpip_peek_current_scope()->is_automatic()) {
430             fun = new vvp_fun_part_aa(base, wid);
431       } else {
432             fun = new vvp_fun_part_sa(base, wid);
433       }
434       link_node_1(label, source, fun);
435 }
436 
compile_part_select_pv(char * label,char * source,unsigned base,unsigned wid,unsigned vector_wid)437 void compile_part_select_pv(char*label, char*source,
438 			    unsigned base, unsigned wid,
439 			    unsigned vector_wid)
440 {
441       vvp_fun_part_pv*fun = new vvp_fun_part_pv(base, wid, vector_wid);
442       link_node_1(label, source, fun);
443 }
444 
compile_part_select_var(char * label,char * source,char * var,unsigned wid,bool is_signed)445 void compile_part_select_var(char*label, char*source, char*var,
446 			     unsigned wid, bool is_signed)
447 {
448       vvp_fun_part_var*fun = 0;
449       if (vpip_peek_current_scope()->is_automatic()) {
450             fun = new vvp_fun_part_var_aa(wid, is_signed);
451       } else {
452             fun = new vvp_fun_part_var_sa(wid, is_signed);
453       }
454       vvp_net_t*net = new vvp_net_t;
455       net->fun = fun;
456 
457       define_functor_symbol(label, net);
458       free(label);
459 
460       input_connect(net, 0, source);
461       input_connect(net, 1, var);
462 }
463