From dd284ee582503377c3025c14ca892652e60cf5cd Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 13 Jul 2012 19:28:16 +0100 Subject: [PATCH] Additional support for $countdrivers. This patch extends the implementation of $countdrivers to handle wires connected to islands. --- vvp/island_tran.cc | 75 ++++++++++++++++++++++++++++++++++++++++++---- vvp/vvp_island.cc | 7 ----- vvp/vvp_island.h | 15 +++++++++- 3 files changed, 84 insertions(+), 13 deletions(-) diff --git a/vvp/island_tran.cc b/vvp/island_tran.cc index a3dee08ea..ac9a96604 100644 --- a/vvp/island_tran.cc +++ b/vvp/island_tran.cc @@ -106,16 +106,81 @@ void vvp_island_tran::run_island() } } -static bool warn_count_drivers = true; +static void count_drivers_(vvp_branch_ptr_t cur, bool other_side_visited, + unsigned bit_idx, unsigned counts[3]) +{ + // First count any value driven into the port associated with + // the current endpoint. + vvp_net_t*net = cur.port() ? cur.ptr()->b : cur.ptr()->a; + vvp_scalar_t bit = island_get_value(net).value(bit_idx); + update_driver_counts(bit.value(), counts); + + // Now handle all the branches attached to that port. + vvp_branch_ptr_t idx = cur; + do { + vvp_island_branch_tran*tmp = BRANCH_TRAN(idx.ptr()); + + // If this branch represents a tran gate, we count the + // value on the other side of the tran (providing it is + // enabled) as a single driver. + if (tmp->width == 0) { + if (tmp->state == tran_enabled) { + net = idx.port() ? idx.ptr()->a : idx.ptr()->b; + bit = island_get_sent_value(net).value(bit_idx); + update_driver_counts(bit.value(), counts); + } + continue; + } + + // If we get here, this branch is a part select. If we've + // just come from the other end of the branch, we're done. + if ((idx == cur) && other_side_visited) + continue; + + // If this is the narrow end of the part select, the other + // end must include the bit we are interested in. Follow + // the branch to collect any drivers on the other side. + if (idx.port() == 1) { + vvp_branch_ptr_t a_side(tmp, 0); + count_drivers_(a_side, true, tmp->offset + bit_idx, counts); + continue; + } + + // If we get here, this branch is the wide end of a part + // select. If the bit we are interested in is within the + // selected part, follow the branch to collect any drivers + // on the other side. + if ((bit_idx >= tmp->offset) && (bit_idx < tmp->offset+tmp->part)) { + vvp_branch_ptr_t b_side(tmp, 1); + count_drivers_(b_side, true, bit_idx - tmp->offset, counts); + continue; + } + } while ((idx = next(idx)) != cur); +} void vvp_island_tran::count_drivers(vvp_island_port*port, unsigned bit_idx, unsigned counts[3]) { - if (warn_count_drivers) { - cerr << "sorry: $countdrivers is not yet fully implemented." << endl; - cerr << " Some driver counts will not be correct." << endl; - warn_count_drivers = false; + // First we need to find a branch that is attached to the specified + // port. Unfortunately there's no quick way to do this. + vvp_island_branch*branch = branches_; + unsigned side = 0; + while (branch) { + if (branch->a->fun == port) { + side = 0; + break; + } + if (branch->b->fun == port) { + side = 1; + break; + } + branch = branch->next_branch; } + assert(branch); + + // Now count the drivers, pushing through the network as necessary. + vvp_branch_ptr_t endpoint(branch, side); + count_drivers_(endpoint, false, bit_idx, counts); } bool vvp_island_branch_tran::run_test_enabled() diff --git a/vvp/vvp_island.cc b/vvp/vvp_island.cc index f799d9809..78358e8e2 100644 --- a/vvp/vvp_island.cc +++ b/vvp/vvp_island.cc @@ -226,13 +226,6 @@ vvp_island_branch::~vvp_island_branch() { } -static vvp_branch_ptr_t next(vvp_branch_ptr_t cur) -{ - vvp_island_branch*ptr = cur.ptr(); - unsigned ab = cur.port(); - return ptr->link[ab]; -} - void island_collect_node(list&conn, vvp_branch_ptr_t cur) { conn .push_back(cur); diff --git a/vvp/vvp_island.h b/vvp/vvp_island.h index 0e20f2c2f..9b7226872 100644 --- a/vvp/vvp_island.h +++ b/vvp/vvp_island.h @@ -1,7 +1,7 @@ #ifndef __vvp_island_H #define __vvp_island_H /* - * Copyright (c) 2008-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2012 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -182,6 +182,12 @@ inline vvp_vector8_t island_get_value(vvp_net_t*net) } } +inline vvp_vector8_t island_get_sent_value(vvp_net_t*net) +{ + vvp_island_port*fun = dynamic_cast(net->fun); + return fun->outvalue; +} + extern void island_send_value(vvp_net_t*net, const vvp_vector8_t&val); /* @@ -206,6 +212,13 @@ struct vvp_island_branch { vvp_net_t*b; }; +static inline vvp_branch_ptr_t next(vvp_branch_ptr_t cur) +{ + vvp_island_branch*ptr = cur.ptr(); + unsigned ab = cur.port(); + return ptr->link[ab]; +} + /* * This function collects into the conn list all the branch ends * that are connected together with the reference branch endpoint