1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
|
/*
* Copyright (c) 2000-2015 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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "config.h"
# include "netlist.h"
# include "netmisc.h"
# include "ivl_assert.h"
/*
* Scan the link for drivers. If there are only constant drivers, then
* the nexus has a known constant value.
*/
bool Nexus::drivers_constant() const
{
if (driven_ == VAR)
return false;
if (driven_ != NO_GUESS)
return true;
unsigned constant_drivers = 0;
for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
/* A target of a procedural assign or force statement
can't be treated as constant. */
const NetNet*sig = dynamic_cast<const NetNet*>(cur->get_obj());
if (sig && (sig->peek_lref() > 0)) {
driven_ = VAR;
return false;
}
/* If we are connected to a tran, there may be a driver
on the other side of the tran. We could try checking
for this, but for now, be pessimistic. */
if (dynamic_cast<const NetTran*>(cur->get_obj())) {
driven_ = VAR;
return false;
}
Link::DIR cur_dir = cur->get_dir();
if (cur_dir == Link::INPUT)
continue;
/* If this is an input or inout port of a root module,
then this is probably not a constant value. I
certainly don't know what the value is, anyhow. This
can happen in cases like this:
module main(sig);
input sig;
endmodule
If main is a root module (it has no parent) then sig
is not constant because it connects to an unspecified
outside world. */
if (cur_dir == Link::PASSIVE) {
if (sig == 0 || sig->scope()->parent() != 0)
continue;
if (sig->port_type() == NetNet::NOT_A_PORT)
continue;
if (sig->port_type() == NetNet::POUTPUT)
continue;
driven_ = VAR;
return false;
}
/* If there is an implicit pullup/pulldown on a net,
count it as a constant driver. */
if (sig)
switch (sig->type()) {
case NetNet::SUPPLY0:
case NetNet::TRI0:
constant_drivers += 1;
driven_ = V0;
continue;
case NetNet::SUPPLY1:
case NetNet::TRI1:
constant_drivers += 1;
driven_ = V1;
continue;
default:
break;
}
if (! dynamic_cast<const NetConst*>(cur->get_obj())) {
driven_ = VAR;
return false;
}
constant_drivers += 1;
}
/* If there is more than one constant driver for this nexus, we
would need to resolve the constant value, taking into account
the drive strengths. This is a lot of work for something that
will rarely occur, so for now leave the resolution to be done
at run time. */
if (constant_drivers > 1) {
driven_ = VAR;
return false;
}
return true;
}
verinum::V Nexus::driven_value() const
{
switch (driven_) {
case V0:
return verinum::V0;
case V1:
return verinum::V1;
case Vx:
return verinum::Vx;
case Vz:
return verinum::Vz;
case VAR:
assert(0);
break;
case NO_GUESS:
break;
}
const Link*cur = list_;
verinum::V val = verinum::Vz;
for (cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
const NetConst*obj;
const NetNet*sig;
if ((obj = dynamic_cast<const NetConst*>(cur->get_obj()))) {
// Multiple drivers are not currently supported.
ivl_assert(*obj, val == verinum::Vz);
val = obj->value(cur->get_pin());
} else if ((sig = dynamic_cast<const NetNet*>(cur->get_obj()))) {
// If we find an implicit pullup or pulldown on a
// net, this is a good guess for the driven value,
// but keep looking for other drivers.
if ((sig->type() == NetNet::SUPPLY0) ||
(sig->type() == NetNet::TRI0)) {
// Multiple drivers are not currently supported.
ivl_assert(*obj, val == verinum::Vz);
val = verinum::V0;
}
if ((sig->type() == NetNet::SUPPLY1) ||
(sig->type() == NetNet::TRI1)) {
// Multiple drivers are not currently supported.
ivl_assert(*obj, val == verinum::Vz);
val = verinum::V1;
}
}
}
/* Cache the result. */
switch (val) {
case verinum::V0:
driven_ = V0;
break;
case verinum::V1:
driven_ = V1;
break;
case verinum::Vx:
driven_ = Vx;
break;
case verinum::Vz:
driven_ = Vz;
break;
}
return val;
}
verinum Nexus::driven_vector() const
{
const Link*cur = list_;
verinum val;
unsigned width = 0;
for (cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
const NetConst*obj;
const NetNet*sig;
if ((obj = dynamic_cast<const NetConst*>(cur->get_obj()))) {
// Multiple drivers are not currently supported.
ivl_assert(*obj, val.len() == 0);
ivl_assert(*obj, cur->get_pin() == 0);
val = obj->value();
width = val.len();
} else if ((sig = dynamic_cast<const NetNet*>(cur->get_obj()))) {
width = sig->vector_width();
// If we find an implicit pullup or pulldown on a
// net, this is a good guess for the driven value,
// but keep looking for other drivers.
if ((sig->type() == NetNet::SUPPLY0) ||
(sig->type() == NetNet::TRI0)) {
// Multiple drivers are not currently supported.
ivl_assert(*obj, val.len() == 0);
val = verinum(verinum::V0, width);
}
if ((sig->type() == NetNet::SUPPLY1) ||
(sig->type() == NetNet::TRI1)) {
// Multiple drivers are not currently supported.
ivl_assert(*obj, val.len() == 0);
val = verinum(verinum::V1, width);
}
}
}
// If we have a width but not a value, this must be an undriven net.
if (val.len() != width)
val = verinum(verinum::Vz, width);
return val;
}
/*
* Calculate a vector that represent all the bits of the vector, with
* each driven bit set to true, otherwise false.
*/
vector<bool> Nexus::driven_mask(void) const
{
vector<bool> mask (vector_width());
for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
Link::DIR link_dir = cur->get_dir();
if (link_dir==Link::PASSIVE)
continue;
if (link_dir==Link::INPUT)
continue;
const NetPins*obj = cur->get_obj();
// If the link is to a variable (REG or INTEGER) then
// the variable is driving all the bits. We have our
// complete answer, mark all the bits as driven and
// finish. Otherwise, we are not going to get new
// information from this node, move on.
if (const NetNet*sig = dynamic_cast<const NetNet*> (obj)) {
NetNet::Type sig_type = sig->type();
if (sig_type==NetNet::INTEGER || sig_type==NetNet::REG) {
for (size_t idx = 0 ; idx < mask.size() ; idx += 1)
mask[idx] = true;
return mask;
}
continue;
}
const NetPartSelect*obj_ps = dynamic_cast<const NetPartSelect*>(obj);
if(obj_ps) {
if (obj_ps->dir()==NetPartSelect::VP) {
if(cur->get_pin() != 0)
continue;
for (size_t idx = 0 ; idx < mask.size() ; idx += 1)
mask[idx] = true;
return mask;
} else {
if (cur->get_pin() != 1)
continue;
}
for (unsigned idx = 0 ; idx < obj_ps->width() ; idx += 1) {
size_t bit = idx + obj_ps->base();
ivl_assert(*obj, bit < mask.size());
mask[bit] = true;
}
continue;
}
for (size_t idx = 0 ; idx < mask.size() ; idx += 1)
mask[idx] = true;
return mask;
}
return mask;
}
|