1 /*
2  * Copyright (c) 2008-2018 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  <list>
25 
26 # include  <iostream>
27 
28 using namespace std;
29 
30 class vvp_island_tran : public vvp_island {
31 
32     public:
33       void run_island();
34       void count_drivers(vvp_island_port*port, unsigned bit_idx,
35                          unsigned counts[3]);
36 };
37 
38 enum tran_state_t {
39       tran_disabled,
40       tran_enabled,
41       tran_unknown
42 };
43 
44 struct vvp_island_branch_tran : public vvp_island_branch {
45 
46       vvp_island_branch_tran(vvp_net_t*en__, bool active_high__,
47                              unsigned width__, unsigned part__,
48                              unsigned offset__, bool resistive__);
49       bool run_test_enabled();
50       void run_resolution();
51       void run_output();
52 
53       vvp_net_t*en;
54       unsigned width, part, offset;
55       bool active_high, resistive;
56       tran_state_t state;
57 };
58 
vvp_island_branch_tran(vvp_net_t * en__,bool active_high__,unsigned width__,unsigned part__,unsigned offset__,bool resistive__)59 vvp_island_branch_tran::vvp_island_branch_tran(vvp_net_t*en__,
60                                                bool active_high__,
61                                                unsigned width__,
62                                                unsigned part__,
63                                                unsigned offset__,
64                                                bool resistive__)
65 : en(en__), width(width__), part(part__), offset(offset__),
66   active_high(active_high__), resistive(resistive__)
67 {
68       state = en__ ? tran_disabled : tran_enabled;
69 }
70 
BRANCH_TRAN(vvp_island_branch * tmp)71 static inline vvp_island_branch_tran* BRANCH_TRAN(vvp_island_branch*tmp)
72 {
73       vvp_island_branch_tran*res = dynamic_cast<vvp_island_branch_tran*>(tmp);
74       assert(res);
75       return res;
76 }
77 
78 /*
79  * The run_island() method is called by the scheduler to run the
80  * entire island. We run the island by calling run_resolution() for
81  * all the branches in the island.
82 */
run_island()83 void vvp_island_tran::run_island()
84 {
85 	// Test to see if any of the branches are enabled. This loop
86 	// tests the enabled inputs for all the branches and caches
87 	// the results in the state for each branch.
88       bool runnable = false;
89       for (vvp_island_branch*cur = branches_ ; cur ; cur = cur->next_branch) {
90 	    vvp_island_branch_tran*tmp = dynamic_cast<vvp_island_branch_tran*>(cur);
91 	    assert(tmp);
92 	    runnable |= tmp->run_test_enabled();
93       }
94 
95 	// Now resolve all the branches in the island.
96       for (vvp_island_branch*cur = branches_ ; cur ; cur = cur->next_branch) {
97 	    vvp_island_branch_tran*tmp = dynamic_cast<vvp_island_branch_tran*>(cur);
98 	    assert(tmp);
99 	    tmp->run_resolution();
100       }
101 
102 	// Now output the resolved values.
103       for (vvp_island_branch*cur = branches_ ; cur ; cur = cur->next_branch) {
104 	    vvp_island_branch_tran*tmp = dynamic_cast<vvp_island_branch_tran*>(cur);
105 	    assert(tmp);
106 	    tmp->run_output();
107       }
108 }
109 
count_drivers_(vvp_branch_ptr_t cur,bool other_side_visited,unsigned bit_idx,unsigned counts[3])110 static void count_drivers_(vvp_branch_ptr_t cur, bool other_side_visited,
111                            unsigned bit_idx, unsigned counts[3])
112 {
113         // First count any value driven into the port associated with
114         // the current endpoint.
115       vvp_net_t*net = cur.port() ? cur.ptr()->b : cur.ptr()->a;
116       vvp_scalar_t bit = island_get_value(net).value(bit_idx);
117       update_driver_counts(bit.value(), counts);
118 
119         // Now handle all the branches attached to that port.
120       vvp_branch_ptr_t idx = cur;
121       do {
122             vvp_island_branch_tran*tmp = BRANCH_TRAN(idx.ptr());
123 
124               // If this branch represents a tran gate, we count the
125               // value on the other side of the tran (providing it is
126               // enabled) as a single driver.
127             if (tmp->width == 0) {
128                   if (tmp->state == tran_enabled) {
129                         net = idx.port() ? idx.ptr()->a : idx.ptr()->b;
130                         bit = island_get_sent_value(net).value(bit_idx);
131                         update_driver_counts(bit.value(), counts);
132                   }
133                   continue;
134             }
135 
136               // If we get here, this branch is a part select. If we've
137               // just come from the other end of the branch, we're done.
138             if ((idx == cur) && other_side_visited)
139                   continue;
140 
141               // If this is the narrow end of the part select, the other
142               // end must include the bit we are interested in. Follow
143               // the branch to collect any drivers on the other side.
144             if (idx.port() == 1) {
145                   vvp_branch_ptr_t a_side(tmp, 0);
146                   count_drivers_(a_side, true, tmp->offset + bit_idx, counts);
147                   continue;
148             }
149 
150               // If we get here, this branch is the wide end of a part
151               // select. If the bit we are interested in is within the
152               // selected part, follow the branch to collect any drivers
153               // on the other side.
154             if ((bit_idx >= tmp->offset) && (bit_idx < tmp->offset+tmp->part)) {
155                   vvp_branch_ptr_t b_side(tmp, 1);
156                   count_drivers_(b_side, true, bit_idx - tmp->offset, counts);
157                   continue;
158             }
159       } while ((idx = next(idx)) != cur);
160 }
161 
count_drivers(vvp_island_port * port,unsigned bit_idx,unsigned counts[3])162 void vvp_island_tran::count_drivers(vvp_island_port*port, unsigned bit_idx,
163                                     unsigned counts[3])
164 {
165         // First we need to find a branch that is attached to the specified
166         // port. Unfortunately there's no quick way to do this.
167       vvp_island_branch*branch = branches_;
168       unsigned side = 0;
169       while (branch) {
170             if (branch->a->fun == port) {
171                   side = 0;
172                   break;
173             }
174             if (branch->b->fun == port) {
175                   side = 1;
176                   break;
177             }
178             branch = branch->next_branch;
179       }
180       assert(branch);
181 
182         // Now count the drivers, pushing through the network as necessary.
183       vvp_branch_ptr_t endpoint(branch, side);
184       count_drivers_(endpoint, false, bit_idx, counts);
185 }
186 
run_test_enabled()187 bool vvp_island_branch_tran::run_test_enabled()
188 {
189       vvp_island_port*ep = en? dynamic_cast<vvp_island_port*> (en->fun) : 0;
190 
191 	// If there is no ep port (no "enabled" input) then this is a
192 	// tran branch. Assume it is always enabled.
193       if (ep == 0) {
194 	    state = tran_enabled;
195 	    return true;
196       }
197 
198 	// Get the input that is driving this enable.
199 	// SPECIAL NOTE: Try to get the input value from the
200 	// *outvalue* of the port. If the enable is connected to a
201 	// .port (instead of a .import) then there may be feedback
202 	// going on, and we need to be looking at the resolved input,
203 	// not the event input. For example:
204 	//
205 	//   tranif1 (pin, X, pin);
206 	//
207 	// In this case, when we test the value for "pin", we need to
208 	// look at the value that is resolved from this
209 	// island. Reading the outvalue will do the trick.
210 	//
211 	// If the outvalue is nil, then we know that this port is a
212 	// .import after all, so just read the invalue.
213       vvp_bit4_t enable_val;
214       if (ep->outvalue.size() != 0)
215 	    enable_val = ep->outvalue.value(0).value();
216       else if (ep->invalue.size() == 0)
217 	    enable_val = BIT4_Z;
218       else
219 	    enable_val = ep->invalue.value(0).value();
220 
221       switch (enable_val) {
222 	  case BIT4_0:
223 	    state = active_high ? tran_disabled : tran_enabled;
224 	    break;
225 	  case BIT4_1:
226 	    state = active_high ? tran_enabled : tran_disabled;
227 	    break;
228 	  default:
229 	    state = tran_unknown;
230 	    break;
231       }
232       return (state != tran_disabled);
233 }
234 
235 // The IEEE standard does not specify the behaviour when a tranif control
236 // input is 'x' or 'z'. We use the rules that are given for MOS switches.
resolve_ambiguous(const vvp_vector8_t & a,const vvp_vector8_t & b,tran_state_t state,unsigned str_map[8])237 inline vvp_vector8_t resolve_ambiguous(const vvp_vector8_t&a,
238                                        const vvp_vector8_t&b,
239                                        tran_state_t state,
240                                        unsigned str_map[8])
241 {
242       assert(a.size() == b.size());
243       vvp_vector8_t out (a.size());
244 
245       for (unsigned idx = 0 ;  idx < out.size() ;  idx += 1) {
246 	    vvp_scalar_t a_bit = a.value(idx);
247 	    vvp_scalar_t b_bit = b.value(idx);
248             b_bit = vvp_scalar_t(b_bit.value(),
249                                  str_map[b_bit.strength0()],
250                                  str_map[b_bit.strength1()]);
251 	    if (state == tran_unknown) {
252 		  switch (b_bit.value()) {
253 		      case BIT4_0:
254 			b_bit = vvp_scalar_t(BIT4_X, b_bit.strength0(), 0);
255 			break;
256 		      case BIT4_1:
257 			b_bit = vvp_scalar_t(BIT4_X, 0, b_bit.strength1());
258 			break;
259 		      default:
260 			break;
261 		  }
262 	    }
263 	    out.set_bit(idx, resolve(a_bit, b_bit));
264       }
265       return out;
266 }
267 
268 static void push_value_through_branches(const vvp_vector8_t&val,
269 					list<vvp_branch_ptr_t>&connections);
270 
push_value_through_branch(const vvp_vector8_t & val,vvp_branch_ptr_t cur)271 static void push_value_through_branch(const vvp_vector8_t&val,
272                                       vvp_branch_ptr_t cur)
273 {
274       vvp_island_branch_tran*branch = BRANCH_TRAN(cur.ptr());
275 
276         // If the branch is disabled, skip.
277       if (branch->state == tran_disabled)
278             return;
279 
280       unsigned src_ab = cur.port();
281       unsigned dst_ab = src_ab^1;
282 
283       vvp_net_t*dst_net = dst_ab? branch->b : branch->a;
284       vvp_island_port*dst_port = dynamic_cast<vvp_island_port*>(dst_net->fun);
285 
286       vvp_vector8_t old_val = dst_port->value;
287 
288         // If the port on the other side has not yet been visited,
289         // get its input value.
290       if (dst_port->value.size() == 0)
291             dst_port->value = island_get_value(dst_net);
292 
293         // If we don't yet have an initial value for the port, skip.
294       if (dst_port->value.size() == 0)
295             return;
296 
297         // Now resolve the pushed value with whatever values we have
298         // previously collected (and resolved) for the port.
299       if (branch->width == 0) {
300               // There are no part selects.
301             dst_port->value = resolve_ambiguous(dst_port->value, val, branch->state,
302                                                 vvp_switch_strength_map[branch->resistive]);
303 
304       } else if (dst_ab == 1) {
305               // The other side is a strict subset (part select)
306               // of this side.
307             vvp_vector8_t tmp = val.subvalue(branch->offset, branch->part);
308             dst_port->value = resolve(dst_port->value, tmp);
309 
310       } else {
311               // The other side is a superset of this side.
312             vvp_vector8_t tmp = part_expand(val, branch->width, branch->offset);
313             dst_port->value = resolve(dst_port->value, tmp);
314       }
315 
316         // If the resolved value for the port has changed, push the new
317         // value back into the network.
318       if (! dst_port->value.eeq(old_val)) {
319             list<vvp_branch_ptr_t> connections;
320 
321 	    vvp_branch_ptr_t dst_side(branch, dst_ab);
322 	    island_collect_node(connections, dst_side);
323 
324 	    push_value_through_branches(dst_port->value, connections);
325       }
326 }
327 
push_value_through_branches(const vvp_vector8_t & val,list<vvp_branch_ptr_t> & connections)328 static void push_value_through_branches(const vvp_vector8_t&val,
329 					list<vvp_branch_ptr_t>&connections)
330 {
331       for (list<vvp_branch_ptr_t>::iterator idx = connections.begin()
332 		 ; idx != connections.end() ; ++ idx ) {
333 
334             push_value_through_branch(val, *idx);
335       }
336 }
337 
338 /*
339  * This method resolves the value for a branch recursively. It uses
340  * recursive descent to span the graph of branches, pushing values
341  * through the network until a stable state is reached.
342  */
run_resolution()343 void vvp_island_branch_tran::run_resolution()
344 {
345       list<vvp_branch_ptr_t> connections;
346       vvp_island_port*port;
347 
348 	// If the A side port hasn't already been visited, then push
349         // its input value through all the branches connected to it.
350       port = dynamic_cast<vvp_island_port*>(a->fun);
351       if (port->value.size() == 0) {
352 	    vvp_branch_ptr_t a_side(this, 0);
353 	    island_collect_node(connections, a_side);
354 
355 	    port->value = island_get_value(a);
356             if (port->value.size() != 0)
357 	          push_value_through_branches(port->value, connections);
358 
359             connections.clear();
360       }
361 
362 	// Do the same for the B side port. Note that if the branch
363         // is enabled, the B side port will have already been visited
364         // when we resolved the A side port.
365       port = dynamic_cast<vvp_island_port*>(b->fun);
366       if (port->value.size() == 0) {
367 	    vvp_branch_ptr_t b_side(this, 1);
368 	    island_collect_node(connections, b_side);
369 
370 	    port->value = island_get_value(b);
371 	    if (port->value.size() != 0)
372 	          push_value_through_branches(port->value, connections);
373 
374             connections.clear();
375       }
376 }
377 
run_output()378 void vvp_island_branch_tran::run_output()
379 {
380       vvp_island_port*port;
381 
382 	// If the A side port hasn't already been updated, send the
383         // resolved value to the output.
384       port = dynamic_cast<vvp_island_port*>(a->fun);
385       if (port->value.size() != 0) {
386 	    island_send_value(a, port->value);
387 	    port->value = vvp_vector8_t::nil;
388       }
389 
390 	// Do the same for the B side port.
391       port = dynamic_cast<vvp_island_port*>(b->fun);
392       if (port->value.size() != 0) {
393 	    island_send_value(b, port->value);
394 	    port->value = vvp_vector8_t::nil;
395       }
396 }
397 
compile_island_tran(char * label)398 void compile_island_tran(char*label)
399 {
400       vvp_island*use_island = new vvp_island_tran;
401       compile_island_base(label, use_island);
402 }
403 
compile_island_tranif(int sense,char * island,char * pa,char * pb,char * pe,bool resistive)404 void compile_island_tranif(int sense, char*island, char*pa, char*pb, char*pe,
405                            bool resistive)
406 {
407       vvp_island*use_island = compile_find_island(island);
408       assert(use_island);
409       free(island);
410 
411       vvp_net_t*en = NULL;
412 
413       if (pe) {
414 	    en = use_island->find_port(pe);
415 	    assert(en);
416 	    free(pe);
417       }
418 
419       vvp_island_branch_tran*br = new vvp_island_branch_tran(en,
420                                                              sense ? true :
421                                                                      false,
422                                                              0, 0, 0, resistive);
423 
424       use_island->add_branch(br, pa, pb);
425 
426       free(pa);
427       free(pb);
428 }
429 
430 
compile_island_tranvp(char * island,char * pa,char * pb,unsigned wid,unsigned par,unsigned off)431 void compile_island_tranvp(char*island, char*pa, char*pb,
432 			   unsigned wid, unsigned par, unsigned off)
433 {
434       vvp_island*use_island = compile_find_island(island);
435       assert(use_island);
436       free(island);
437 
438       vvp_island_branch_tran*br = new vvp_island_branch_tran(NULL, false,
439                                                              wid, par, off, false);
440 
441       use_island->add_branch(br, pa, pb);
442 
443       free(pa);
444       free(pb);
445 }
446