1 /*
2  * Copyright (c) 2001-2013 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  "resolv.h"
21 # include  "schedule.h"
22 # include  "compile.h"
23 # include  "statistics.h"
24 # include  <iostream>
25 # include  <algorithm>
26 # include  <cassert>
27 
28 
29 /*
30  * The core functor for a resolver node stores all the input values
31  * received by that node. This provides the necessary information
32  * for implementing the $countdrivers system call. For efficiency,
33  * the resolver is implemented using a balanced quaternary tree, so
34  * the core functor also stores the current value for each branch
35  * of the tree, to eliminate the need to re-evaluate branches whose
36  * inputs haven't changed. The tree values are flattened into a linear
37  * array, with the input values stored at the start of the array, then
38  * the next level of branch values, and so on, down to the final array
39  * array element which stores the current output value.
40  */
41 
42 
resolv_core(unsigned nports,vvp_net_t * net)43 resolv_core::resolv_core(unsigned nports, vvp_net_t*net)
44 : nports_(nports), net_(net)
45 {
46       count_functors_resolv += 1;
47 }
48 
~resolv_core()49 resolv_core::~resolv_core()
50 {
51 }
52 
recv_vec4_pv_(unsigned port,const vvp_vector4_t & bit,unsigned base,unsigned wid,unsigned vwid)53 void resolv_core::recv_vec4_pv_(unsigned port, const vvp_vector4_t&bit,
54 				unsigned base, unsigned wid, unsigned vwid)
55 {
56       assert(bit.size() == wid);
57       vvp_vector4_t res (vwid);
58 
59       for (unsigned idx = 0 ;  idx < base ;  idx += 1)
60 	    res.set_bit(idx, BIT4_Z);
61 
62       for (unsigned idx = 0 ;  idx < wid && idx+base < vwid;  idx += 1)
63 	    res.set_bit(idx+base, bit.value(idx));
64 
65       for (unsigned idx = base+wid ;  idx < vwid ;  idx += 1)
66 	    res.set_bit(idx, BIT4_Z);
67 
68       recv_vec4_(port, res);
69 }
70 
recv_vec8_pv_(unsigned port,const vvp_vector8_t & bit,unsigned base,unsigned wid,unsigned vwid)71 void resolv_core::recv_vec8_pv_(unsigned port, const vvp_vector8_t&bit,
72 				unsigned base, unsigned wid, unsigned vwid)
73 {
74       assert(bit.size() == wid);
75       vvp_vector8_t res (vwid);
76 
77       for (unsigned idx = 0 ;  idx < base ;  idx += 1)
78 	    res.set_bit(idx, vvp_scalar_t());
79 
80       for (unsigned idx = 0 ;  idx < wid && idx+base < vwid;  idx += 1)
81 	    res.set_bit(idx+base, bit.value(idx));
82 
83       for (unsigned idx = base+wid ;  idx < vwid ;  idx += 1)
84 	    res.set_bit(idx, vvp_scalar_t());
85 
86       recv_vec8_(port, res);
87 }
88 
89 
resolv_extend(resolv_core * core,unsigned port_base)90 resolv_extend::resolv_extend(resolv_core*core, unsigned port_base)
91 : core_(core), port_base_(port_base)
92 {
93 }
94 
~resolv_extend()95 resolv_extend::~resolv_extend()
96 {
97 }
98 
99 
resolv_tri(unsigned nports,vvp_net_t * net,vvp_scalar_t hiz_value)100 resolv_tri::resolv_tri(unsigned nports, vvp_net_t*net, vvp_scalar_t hiz_value)
101 : resolv_core(nports, net), hiz_value_(hiz_value)
102 {
103         // count the input (leaf) nodes
104       unsigned nnodes = nports;
105 
106         // add in the intermediate branch nodes
107       while (nports > 4) {
108             nports = (nports + 3) / 4;
109             nnodes += nports;
110       }
111         // add one more node for storing the output value
112         // (not needed if there is only one input)
113       if (nnodes > 1)
114             nnodes += 1;
115 
116       val_ = new vvp_vector8_t [nnodes];
117 }
118 
~resolv_tri()119 resolv_tri::~resolv_tri()
120 {
121       delete[] val_;
122 }
123 
recv_vec4_(unsigned port,const vvp_vector4_t & bit)124 void resolv_tri::recv_vec4_(unsigned port, const vvp_vector4_t&bit)
125 {
126       recv_vec8_(port, vvp_vector8_t(bit, 6,6 /* STRONG */));
127 }
128 
recv_vec8_(unsigned port,const vvp_vector8_t & bit)129 void resolv_tri::recv_vec8_(unsigned port, const vvp_vector8_t&bit)
130 {
131       assert(port < nports_);
132 
133       if (val_[port].eeq(bit))
134 	    return;
135 
136       val_[port] = bit;
137 
138         // Starting at the leaf level, work down the tree, resolving
139         // the changed values. base is the first node in the current
140         // level and span is the number of nodes at that level. ip
141         // is the first node in the group of four nodes at that level
142         // that include the node that has changed, and op is the node
143         // at the next level that stores the resolved value from that
144         // group.
145       unsigned base = 0;
146       unsigned span = nports_;
147       while (span > 1) {
148             unsigned next_base = base + span;
149             unsigned ip = base + (port & ~0x3);
150             unsigned op = next_base + (port / 4);
151             unsigned ll = min(ip + 4, next_base);
152 
153             vvp_vector8_t out = val_[ip];
154             for (ip = ip + 1; ip < ll; ip += 1) {
155                   if (val_[ip].size() == 0)
156                         continue;
157                   if (out.size() == 0)
158                         out = val_[ip];
159                   else
160                         out = resolve(out, val_[ip]);
161             }
162             if (val_[op].eeq(out))
163                   return;
164             val_[op] = out;
165 
166             base = next_base;
167             span = (span + 3) / 4;
168             port = port / 4;
169       }
170 
171       if (! hiz_value_.is_hiz()) {
172 	    for (unsigned idx = 0 ;  idx < val_[base].size() ;  idx += 1) {
173 		  val_[base].set_bit(idx, resolve(val_[base].value(idx),
174 						  hiz_value_));
175 	    }
176       }
177 
178       net_->send_vec8(val_[base]);
179 }
180 
count_drivers(unsigned bit_idx,unsigned counts[3])181 void resolv_tri::count_drivers(unsigned bit_idx, unsigned counts[3])
182 {
183       for (unsigned idx = 0 ; idx < nports_ ; idx += 1) {
184 	    if (val_[idx].size() == 0)
185 	          continue;
186 
187             update_driver_counts(val_[idx].value(bit_idx).value(), counts);
188       }
189 }
190 
191 
resolv_wired_logic(unsigned nports,vvp_net_t * net)192 resolv_wired_logic::resolv_wired_logic(unsigned nports, vvp_net_t*net)
193 : resolv_core(nports, net)
194 {
195         // count the input (leaf) nodes
196       unsigned nnodes = nports;
197 
198         // add in the intermediate branch nodes
199       while (nports > 4) {
200             nports = (nports + 3) / 4;
201             nnodes += nports;
202       }
203         // add one more node for storing the output value
204         // (not needed if there is only one input)
205       if (nnodes > 1)
206             nnodes += 1;
207 
208       val_ = new vvp_vector4_t [nnodes];
209 }
210 
~resolv_wired_logic()211 resolv_wired_logic::~resolv_wired_logic()
212 {
213       delete[] val_;
214 }
215 
recv_vec4_(unsigned port,const vvp_vector4_t & bit)216 void resolv_wired_logic::recv_vec4_(unsigned port, const vvp_vector4_t&bit)
217 {
218       assert(port < nports_);
219 
220       if (val_[port].eeq(bit))
221 	    return;
222 
223       val_[port] = bit;
224 
225         // Starting at the leaf level, work down the tree, resolving
226         // the changed values. base is the first node in the current
227         // level and span is the number of nodes at that level. ip
228         // is the first node in the group of four nodes at that level
229         // that include the node that has changed, and op is the node
230         // at the next level that stores the resolved value from that
231         // group.
232       unsigned base = 0;
233       unsigned span = nports_;
234       while (span > 1) {
235             unsigned next_base = base + span;
236             unsigned ip = base + (port & ~0x3);
237             unsigned op = next_base + (port / 4);
238             unsigned ll = min(ip + 4, next_base);
239 
240             vvp_vector4_t out = val_[ip];
241             for (ip = ip + 1; ip < ll; ip += 1) {
242                   if (val_[ip].size() == 0)
243                         continue;
244                   if (out.size() == 0)
245                         out = val_[ip];
246                   else
247                         out = wired_logic_math_(out, val_[ip]);
248             }
249             if (val_[op].eeq(out))
250                   return;
251             val_[op] = out;
252 
253             base = next_base;
254             span = (span + 3) / 4;
255             port = port / 4;
256       }
257 
258       net_->send_vec4(val_[base], 0);
259 }
260 
recv_vec8_(unsigned port,const vvp_vector8_t & bit)261 void resolv_wired_logic::recv_vec8_(unsigned port, const vvp_vector8_t&bit)
262 {
263       recv_vec4_(port, reduce4(bit));
264 }
265 
count_drivers(unsigned bit_idx,unsigned counts[3])266 void resolv_wired_logic::count_drivers(unsigned bit_idx, unsigned counts[3])
267 {
268       for (unsigned idx = 0 ; idx < nports_ ; idx += 1) {
269 	    if (val_[idx].size() == 0)
270 	          continue;
271 
272             update_driver_counts(val_[idx].value(bit_idx), counts);
273       }
274 }
275 
276 
resolv_triand(unsigned nports,vvp_net_t * net)277 resolv_triand::resolv_triand(unsigned nports, vvp_net_t*net)
278 : resolv_wired_logic(nports, net)
279 {
280 }
281 
~resolv_triand()282 resolv_triand::~resolv_triand()
283 {
284 }
285 
wired_logic_math_(vvp_vector4_t & a,vvp_vector4_t & b)286 vvp_vector4_t resolv_triand::wired_logic_math_(vvp_vector4_t&a, vvp_vector4_t&b)
287 {
288       assert(a.size() == b.size());
289 
290       vvp_vector4_t out (a.size());
291 
292       for (unsigned idx = 0 ; idx < out.size() ; idx += 1) {
293 	    vvp_bit4_t abit = a.value(idx);
294 	    vvp_bit4_t bbit = b.value(idx);
295 	    if (abit == BIT4_Z) {
296 		  out.set_bit(idx, bbit);
297 	    } else if (bbit == BIT4_Z) {
298 		  out.set_bit(idx, abit);
299 	    } else if (abit == BIT4_0 || bbit == BIT4_0) {
300 		  out.set_bit(idx, BIT4_0);
301 	    } else if (abit == BIT4_X || bbit == BIT4_X) {
302 		  out.set_bit(idx, BIT4_X);
303 	    } else {
304 		  out.set_bit(idx, BIT4_1);
305 	    }
306       }
307 
308       return out;
309 }
310 
311 
resolv_trior(unsigned nports,vvp_net_t * net)312 resolv_trior::resolv_trior(unsigned nports, vvp_net_t*net)
313 : resolv_wired_logic(nports, net)
314 {
315 }
316 
~resolv_trior()317 resolv_trior::~resolv_trior()
318 {
319 }
320 
wired_logic_math_(vvp_vector4_t & a,vvp_vector4_t & b)321 vvp_vector4_t resolv_trior::wired_logic_math_(vvp_vector4_t&a, vvp_vector4_t&b)
322 {
323       assert(a.size() == b.size());
324 
325       vvp_vector4_t out (a.size());
326 
327       for (unsigned idx = 0 ; idx < out.size() ; idx += 1) {
328 	    vvp_bit4_t abit = a.value(idx);
329 	    vvp_bit4_t bbit = b.value(idx);
330 	    if (abit == BIT4_Z) {
331 		  out.set_bit(idx, bbit);
332 	    } else if (bbit == BIT4_Z) {
333 		  out.set_bit(idx, abit);
334 	    } else if (abit == BIT4_1 || bbit == BIT4_1) {
335 		  out.set_bit(idx, BIT4_1);
336 	    } else if (abit == BIT4_X || bbit == BIT4_X) {
337 		  out.set_bit(idx, BIT4_X);
338 	    } else {
339 		  out.set_bit(idx, BIT4_0);
340 	    }
341       }
342 
343       return out;
344 }
345