/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/utils.h"
#include "kernel/log.h"
#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
bool did_something;
void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
{
CellTypes ct(design);
SigMap sigmap(module);
SigPool driven_signals;
SigPool used_signals;
SigPool all_signals;
dict<SigBit, pair<Wire*, State>> initbits;
pool<Wire*> revisit_initwires;
for (auto cell : module->cells())
for (auto &conn : cell->connections()) {
if (!ct.cell_known(cell->type) || ct.cell_output(cell->type, conn.first))
driven_signals.add(sigmap(conn.second));
if (!ct.cell_known(cell->type) || ct.cell_input(cell->type, conn.first))
used_signals.add(sigmap(conn.second));
}
for (auto wire : module->wires()) {
if (wire->attributes.count(ID(init))) {
SigSpec sig = sigmap(wire);
Const initval = wire->attributes.at(ID(init));
for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) {
if (initval[i] == State::S0 || initval[i] == State::S1)
initbits[sig[i]] = make_pair(wire, initval[i]);
}
}
if (wire->port_input)
driven_signals.add(sigmap(wire));
if (wire->port_output || wire->get_bool_attribute(ID::keep))
used_signals.add(sigmap(wire));
all_signals.add(sigmap(wire));
}
all_signals.del(driven_signals);
RTLIL::SigSpec undriven_signals = all_signals.export_all();
for (auto &c : undriven_signals.chunks())
{
RTLIL::SigSpec sig = c;
if (c.wire->name[0] == '$')
sig = used_signals.extract(sig);
if (sig.size() == 0)
continue;
Const val(RTLIL::State::Sx, GetSize(sig));
for (int i = 0; i < GetSize(sig); i++) {
SigBit bit = sigmap(sig[i]);
auto cursor = initbits.find(bit);
if (cursor != initbits.end()) {
revisit_initwires.insert(cursor->second.first);
val[i] = cursor->second.second;
}
}
log_debug("Setting undriven signal in %s to constant: %s = %s\n", log_id(module), log_signal(sig), log_signal(val));
module->connect(sig, val);
did_something = true;
}
if (!revisit_initwires.empty())
{
SigMap sm2(module);
for (auto wire : revisit_initwires) {
SigSpec sig = sm2(wire);
Const initval = wire->attributes.at(ID(init));
for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) {
if (SigBit(initval[i]) == sig[i])
initval[i] = State::Sx;
}
if (initval.is_fully_undef()) {
log_debug("Removing init attribute from %s/%s.\n", log_id(module), log_id(wire));
wire->attributes.erase(ID(init));
did_something = true;
} else if (initval != wire->attributes.at(ID(init))) {
log_debug("Updating init attribute on %s/%s: %s\n", log_id(module), log_id(wire), log_signal(initval));
wire->attributes[ID(init)] = initval;