This commit is contained in:
Emil J 2026-04-22 12:29:18 +02:00 committed by GitHub
commit fdc4b3c48f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
79 changed files with 1847 additions and 289 deletions

View File

@ -337,7 +337,7 @@ struct AigerWriter
continue;
}
if (cell->type == ID($scopeinfo))
if (cell->type == ID($scopeinfo) || cell->type == ID($input_port))
continue;
log_error("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell));

View File

@ -1518,6 +1518,7 @@ struct CxxrtlWorker {
f << (cell->getParam(ID::CLR_POLARITY).as_bool() ? "" : ".bit_not()") << ");\n";
}
// Internal cells
} else if (cell->type == ID($input_port)) {
} else if (is_internal_cell(cell->type)) {
log_cmd_error("Unsupported internal cell `%s'.\n", cell->type);
// User cells

View File

@ -1049,6 +1049,9 @@ struct AigerFrontend : public Frontend {
}
extra_args(f, filename, args, argidx, true);
// TODO Disabled signorm because swap_names breaks fanout logic
design->sigNormalize(false);
if (module_name.empty()) {
#ifdef _WIN32
char fname[_MAX_FNAME];

View File

@ -103,7 +103,7 @@ struct CellTypes
setup_type(ID($equiv), {ID::A, ID::B}, {ID::Y});
setup_type(ID($specify2), {ID::EN, ID::SRC, ID::DST}, pool<RTLIL::IdString>());
setup_type(ID($specify3), {ID::EN, ID::SRC, ID::DST, ID::DAT}, pool<RTLIL::IdString>());
setup_type(ID($specrule), {ID::EN_SRC, ID::EN_DST, ID::SRC, ID::DST}, pool<RTLIL::IdString>());
setup_type(ID($specrule), {ID::SRC_EN, ID::DST_EN, ID::SRC, ID::DST}, pool<RTLIL::IdString>());
setup_type(ID($print), {ID::EN, ID::ARGS, ID::TRG}, pool<RTLIL::IdString>());
setup_type(ID($check), {ID::A, ID::EN, ID::ARGS, ID::TRG}, pool<RTLIL::IdString>());
setup_type(ID($set_tag), {ID::A, ID::SET, ID::CLR}, {ID::Y});

View File

@ -459,9 +459,7 @@ X(EDGE_POL)
X(EFX_ADD)
X(EN)
X(ENPOL)
X(EN_DST)
X(EN_POLARITY)
X(EN_SRC)
X(EQN)
X(F)
X(FDCE)

View File

@ -635,8 +635,6 @@ Cell *FfData::emit() {
return nullptr;
}
}
if (initvals && !is_anyinit)
initvals->set_init(sig_q, val_init);
if (!is_fine) {
if (has_gclk) {
log_assert(!has_clk);
@ -747,6 +745,8 @@ Cell *FfData::emit() {
}
}
cell->attributes = attributes;
if (initvals && !is_anyinit)
initvals->set_init(cell->getPort(ID::Q), val_init);
return cell;
}

View File

@ -229,6 +229,43 @@ struct FfData : FfTypeData {
void flip_rst_bits(const pool<int> &bits);
};
struct FfDataSigMapped : public FfData {
SigMap& sigmap;
FfDataSigMapped(SigMap& map, Module *module, FfInitVals *initvals = nullptr, IdString name = IdString()) : FfData(module, initvals, name), sigmap(map) {}
void remap() {
sigmap(sig_q);
sigmap(sig_d);
sigmap(sig_ad);
sigmap(sig_clk);
sigmap(sig_ce);
sigmap(sig_aload);
sigmap(sig_arst);
sigmap(sig_srst);
sigmap(sig_clr);
sigmap(sig_set);
}
FfDataSigMapped(SigMap& map, FfInitVals *initvals, Cell *cell_) : FfData(initvals, cell_), sigmap(map) {
remap();
}
FfDataSigMapped(SigMap& map, const FfData& base) : FfData(base), sigmap(map) {
remap();
}
FfDataSigMapped(const FfDataSigMapped& other) : FfData(other), sigmap(other.sigmap) {}
FfDataSigMapped& operator=(const FfDataSigMapped& other) {
FfData::operator=(other);
return *this;
}
Cell* emit() {
Cell* cell = FfData::emit();
remap();
return cell;
}
FfDataSigMapped slice(const std::vector<int> &bits) {
return FfDataSigMapped(sigmap, FfData::slice(bits));
}
};
YOSYS_NAMESPACE_END
#endif

View File

@ -303,6 +303,7 @@ void FfMergeHelper::remove_output_ff(const pool<std::pair<Cell *, int>> &bits) {
dff_driver.erase((*sigmap)(q[idx]));
q[idx] = module->addWire(stringf("$ffmerge_disconnected$%d", autoidx++));
cell->setPort(ID::Q, q);
initvals->set_init(cell->getPort(ID::Q), (*initvals)(q));
}
}

View File

@ -349,8 +349,11 @@ void Mem::emit() {
bool v2 = !init.en.is_fully_ones();
if (!init.cell)
init.cell = module->addCell(NEW_ID, v2 ? ID($meminit_v2) : ID($meminit));
else
else {
if (!v2)
init.cell->unsetPort(ID::EN);
init.cell->type = v2 ? ID($meminit_v2) : ID($meminit);
}
init.cell->attributes = init.attributes;
init.cell->parameters[ID::MEMID] = memid.str();
init.cell->parameters[ID::ABITS] = GetSize(init.addr);
@ -361,8 +364,6 @@ void Mem::emit() {
init.cell->setPort(ID::DATA, init.data);
if (v2)
init.cell->setPort(ID::EN, init.en);
else
init.cell->unsetPort(ID::EN);
}
}
}

View File

@ -80,7 +80,7 @@ struct CellTableBuilder {
setup_type(ID($equiv), {ID::A, ID::B}, {ID::Y}, features);
setup_type(ID($specify2), {ID::EN, ID::SRC, ID::DST}, {}, features);
setup_type(ID($specify3), {ID::EN, ID::SRC, ID::DST, ID::DAT}, {}, features);
setup_type(ID($specrule), {ID::EN_SRC, ID::EN_DST, ID::SRC, ID::DST}, {}, features);
setup_type(ID($specrule), {ID::SRC_EN, ID::DST_EN, ID::SRC, ID::DST}, {}, features);
setup_type(ID($print), {ID::EN, ID::ARGS, ID::TRG}, {}, features);
setup_type(ID($check), {ID::A, ID::EN, ID::ARGS, ID::TRG}, {}, features);
setup_type(ID($set_tag), {ID::A, ID::SET, ID::CLR}, {ID::Y}, features);

View File

@ -1215,22 +1215,6 @@ RTLIL::Module *RTLIL::Design::top_module() const
return module_count == 1 ? module : nullptr;
}
void RTLIL::Design::add(RTLIL::Module *module)
{
log_assert(modules_.count(module->name) == 0);
log_assert(refcount_modules_ == 0);
modules_[module->name] = module;
module->design = this;
for (auto mon : monitors)
mon->notify_module_add(module);
if (yosys_xtrace) {
log("#X# New Module: %s\n", log_id(module));
log_backtrace("-X- ", yosys_xtrace-1);
}
}
void RTLIL::Design::add(RTLIL::Binding *binding)
{
log_assert(binding != nullptr);
@ -1528,6 +1512,7 @@ RTLIL::Module::Module()
RTLIL::Module::~Module()
{
clear_sig_norm_index();
for (auto &pr : wires_)
delete pr.second;
for (auto &pr : memories)
@ -2740,7 +2725,7 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod) const
new_mod->avail_parameters = avail_parameters;
new_mod->parameter_default_values = parameter_default_values;
for (auto &conn : connections_)
for (auto &conn : connections())
new_mod->connect(conn);
for (auto &attr : attributes)
@ -2948,23 +2933,6 @@ void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
}
}
void RTLIL::Module::remove(RTLIL::Cell *cell)
{
while (!cell->connections_.empty())
cell->unsetPort(cell->connections_.begin()->first);
log_assert(cells_.count(cell->name) != 0);
log_assert(refcount_cells_ == 0);
cells_.erase(cell->name);
if (design && design->flagBufferedNormalized && buf_norm_cell_queue.count(cell)) {
cell->type.clear();
cell->name.clear();
pending_deleted_cells.insert(cell);
} else {
delete cell;
}
}
void RTLIL::Module::remove(RTLIL::Memory *memory)
{
log_assert(memories.count(memory->name) != 0);
@ -3108,29 +3076,6 @@ void RTLIL::Module::connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs
connect(RTLIL::SigSig(lhs, rhs));
}
void RTLIL::Module::new_connections(const std::vector<RTLIL::SigSig> &new_conn)
{
for (auto mon : monitors)
mon->notify_connect(this, new_conn);
if (design)
for (auto mon : design->monitors)
mon->notify_connect(this, new_conn);
if (yosys_xtrace) {
log("#X# New connections vector in %s:\n", log_id(this));
for (auto &conn: new_conn)
log("#X# %s = %s (%d bits)\n", log_signal(conn.first), log_signal(conn.second), GetSize(conn.first));
log_backtrace("-X- ", yosys_xtrace-1);
}
connections_ = new_conn;
}
const std::vector<RTLIL::SigSig> &RTLIL::Module::connections() const
{
return connections_;
}
void RTLIL::Module::fixup_ports()
{

View File

@ -122,8 +122,11 @@ namespace RTLIL
struct Binding;
struct IdString;
struct OwningIdString;
struct StaticIdString;
struct SigNormIndex;
typedef std::pair<SigSpec, SigSpec> SigSig;
struct PortBit;
};
struct RTLIL::IdString
@ -1890,7 +1893,9 @@ struct RTLIL::Design
dict<std::string, std::string> scratchpad;
bool flagBufferedNormalized = false;
bool flagSigNormalized = false;
void bufNormalize(bool enable=true);
void sigNormalize(bool enable=true);
int refcount_modules_;
dict<RTLIL::IdString, RTLIL::Module*> modules_;
@ -2051,6 +2056,10 @@ struct RTLIL::Design
struct RTLIL::Module : public RTLIL::NamedObject
{
friend struct RTLIL::SigNormIndex;
friend struct RTLIL::Cell;
friend struct RTLIL::Design;
Hasher::hash_t hashidx_;
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
@ -2108,6 +2117,19 @@ public:
pool<RTLIL::Cell *> pending_deleted_cells;
dict<RTLIL::Wire *, pool<RTLIL::Cell *>> buf_norm_connect_index;
void bufNormalize();
void dump_sigmap();
protected:
SigNormIndex *sig_norm_index = nullptr;
void clear_sig_norm_index();
int timestamp_ = 0;
public:
void sigNormalize();
int timestamp() const { return timestamp_; }
int next_timestamp();
std::vector<Cell *> dirty_cells(int starting_from);
const pool<PortBit> &fanout(SigBit bit);
template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
@ -2428,6 +2450,7 @@ struct RTLIL::Wire : public RTLIL::NamedObject
protected:
// use module->addWire() and module->remove() to create or destroy wires
friend struct RTLIL::Module;
friend struct RTLIL::SigNormIndex;
Wire();
~Wire();
@ -2625,6 +2648,33 @@ public:
std::string to_rtlil_str() const;
};
struct RTLIL::PortBit
{
RTLIL::Cell *cell;
RTLIL::IdString port;
int offset;
PortBit(Cell* c, IdString p, int o) : cell(c), port(p), offset(o) {}
bool operator<(const PortBit &other) const {
if (cell != other.cell)
return cell < other.cell;
if (port != other.port)
return port < other.port;
return offset < other.offset;
}
bool operator==(const PortBit &other) const {
return cell == other.cell && port == other.port && offset == other.offset;
}
[[nodiscard]] Hasher hash_into(Hasher h) const {
h.eat(cell->name);
h.eat(port);
h.eat(offset);
return h;
}
};
inline RTLIL::SigBit::SigBit() : wire(NULL), data(RTLIL::State::S0) { }
inline RTLIL::SigBit::SigBit(RTLIL::State bit) : wire(NULL), data(bit) { }
@ -2689,6 +2739,7 @@ inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) {
template<typename T>
void RTLIL::Module::rewrite_sigspecs(T &functor)
{
log_assert(sig_norm_index == nullptr);
for (auto &it : cells_)
it.second->rewrite_sigspecs(functor);
for (auto &it : processes)
@ -2702,6 +2753,7 @@ void RTLIL::Module::rewrite_sigspecs(T &functor)
template<typename T>
void RTLIL::Module::rewrite_sigspecs2(T &functor)
{
log_assert(sig_norm_index == nullptr);
for (auto &it : cells_)
it.second->rewrite_sigspecs2(functor);
for (auto &it : processes)

View File

@ -28,6 +28,241 @@
YOSYS_NAMESPACE_BEGIN
typedef std::pair<Cell*, IdString> cell_port_t;
// Since this is kernel code, we only log with yosys_xtrace set to not get
// in the way when using `debug` to debug specific passes.q
#define xlog(...) do { if (yosys_xtrace) log("#X [bufnorm] " __VA_ARGS__); } while (0)
struct RTLIL::SigNormIndex
{
SigNormIndex(RTLIL::Module *module) : module(module) {}
RTLIL::Module *module;
SigMap sigmap;
size_t restored_connections = 0;
dict<SigBit, pool<PortBit>> fanout;
pool<SigBit> newly_driven;
dict<Cell *, int> cell_timestamps;
dict<int, pool<Cell *>> timestamp_cells;
pool<Cell *> dirty;
void setup() {
module->fixup_ports();
setup_module_inputs();
setup_driven_wires();
setup_fanout();
}
void dump_sigmap() {
for (auto [name, wire] : module->wires_) {
log_debug("wire %s %p %s\n", name, wire, wire->name);
SigSpec ss(wire);
log_debug("ss %s\n", log_signal(ss));
sigmap(ss);
log_debug("sigmapped %s\n", log_signal(ss));
}
for (auto [lhs, rhs] : module->connections_) {
log_debug("connection %s %s\n", log_signal(lhs), log_signal(rhs));
}
}
void normalize() {
flush_connections();
flush_newly_driven();
}
void setup_module_inputs() {
std::vector<Cell *> cells_to_remove;
dict<Wire *, Cell *> input_port_cells;
for (auto cell : module->cells()) {
if (cell->type != ID($input_port))
continue;
auto const &sig_y = cell->getPort(ID::Y);
Wire *wire;
if (sig_y.is_wire() && (wire = sig_y.as_wire())->port_input && !wire->port_output && !input_port_cells.count(wire))
input_port_cells.emplace(wire, cell);
else
cells_to_remove.push_back(cell);
}
for (auto cell : cells_to_remove)
module->remove(cell);
for (auto portname : module->ports) {
Wire *wire = module->wire(portname);
if (wire->port_input && !wire->port_output && !input_port_cells.count(wire)) {
Cell *cell = module->addCell(NEW_ID, ID($input_port));
cell->setParam(ID::WIDTH, GetSize(wire));
cell->setPort(ID::Y, wire);
input_port_cells.emplace(wire, cell);
}
}
for (auto [wire, cell] : input_port_cells) {
wire->driverCell_ = cell;
wire->driverPort_ = ID::Y;
}
}
void setup_driven_wires() {
for (auto cell : module->cells()) {
xlog("setup_driven_wires cell %s %s\n", cell->type, cell->name);
for (auto &[port, sig] : cell->connections_) {
xlog("\t%s = %s\n", port, log_signal(sig));
if (cell->port_dir(port) == RTLIL::PD_INPUT)
continue;
xlog("%s is not an input in design %p\n", port, module->design);
if (sig.is_wire()) {
Wire * wire = sig.as_wire();
if (wire->driverCell_ == cell && wire->driverPort_ == port)
continue;
if (wire->driverCell_ == nullptr) {
wire->driverCell_ = cell;
wire->driverPort_ = port;
continue;
}
}
Wire *wire = module->addWire(NEW_ID, GetSize(sig));
wire->driverCell_ = cell;
wire->driverPort_ = port;
xlog("therefore connect port %s %s %s\n", port, log_signal(sig), wire->name);
module->connect(sig, wire);
sig = wire;
}
}
}
void setup_fanout() {
for (auto cell : module->cells()) {
for (auto &[port, sig] : cell->connections_) {
if (cell->port_dir(port) != RTLIL::PD_INPUT)
continue;
int i = 0;
for (auto bit : sig)
if (bit.is_wire())
fanout[bit].insert(PortBit(cell, port, i++));
}
}
}
void flush_connections() {
std::vector<SigBit> connect_lhs;
std::vector<SigBit> connect_rhs;
auto begin = module->connections_.begin() + restored_connections;
auto end = module->connections_.end();
for (auto it = begin; it != end; ++it) {
auto &[lhs, rhs] = *it;
sigmap.apply(lhs);
sigmap.apply(rhs);
auto rhs_bits = rhs.bits().begin();
connect_lhs.clear();
connect_rhs.clear();
for (auto l : lhs.bits()) {
auto r = *rhs_bits;
++rhs_bits;
if (l == r)
continue;
// TODO figure out what should happen with 'z
bool l_driven = !l.is_wire() || l.wire->known_driver();
bool r_driven = !r.is_wire() || r.wire->known_driver();
if (l_driven && r_driven) {
connect_lhs.push_back(l);
connect_rhs.push_back(r);
continue;
}
sigmap.add(l, r);
if (l_driven) {
sigmap.database.promote(l);
newly_driven.insert(r);
} else {
sigmap.database.promote(r);
newly_driven.insert(l);
}
}
if (!connect_lhs.empty()) {
Cell *cell = module->addCell(NEW_ID, ID($connect));
xlog("add connect (1) %s\n", cell->name);
cell->setParam(ID::WIDTH, GetSize(connect_lhs));
cell->setPort(ID::A, std::move(connect_lhs));
cell->setPort(ID::B, std::move(connect_rhs));
}
}
module->connections_.clear();
restored_connections = 0;
}
void flush_newly_driven() {
pool<cell_port_t> ports_to_normalize;
SigSpec tmp;
while (!newly_driven.empty()) {
SigBit current = newly_driven.pop();
auto found = fanout.find(current);
if (found == fanout.end())
continue;
ports_to_normalize.clear();
for (auto const &portbit : found->second)
ports_to_normalize.emplace(portbit.cell, portbit.port);
for (auto const &[cell, port] : ports_to_normalize) {
tmp = cell->getPort(port);
cell->setPort(port, tmp);
}
}
}
void restore_connections() {
flush_connections();
pool<Wire *> wires;
for (auto const &bit : sigmap.database)
if (bit.is_wire())
wires.insert(bit.wire);
std::vector<SigBit> connect_lhs;
std::vector<SigBit> connect_rhs;
for (auto wire : wires) {
connect_lhs.clear();
connect_rhs.clear();
for (int i = 0; i < GetSize(wire); ++i) {
SigBit l = SigBit(wire, i);
SigBit r = sigmap(l);
if (l == r)
continue;
connect_lhs.push_back(l);
connect_rhs.push_back(r);
}
if (!connect_lhs.empty())
module->connections_.emplace_back(std::move(connect_lhs), std::move(connect_rhs));
}
restored_connections = module->connections_.size();
}
};
void RTLIL::Design::bufNormalize(bool enable)
{
if (!enable)
@ -50,6 +285,8 @@ void RTLIL::Design::bufNormalize(bool enable)
return;
}
log_assert(!flagSigNormalized);
if (!flagBufferedNormalized)
{
for (auto module : modules())
@ -78,19 +315,206 @@ void RTLIL::Design::bufNormalize(bool enable)
module->bufNormalize();
}
struct bit_drive_data_t {
int drivers = 0;
int inout = 0;
int users = 0;
};
void RTLIL::Design::sigNormalize(bool enable)
{
if (!enable)
{
if (!flagSigNormalized)
return;
xlog("leaving signorm\n");
for (auto module : modules()) {
module->connections();
if (module->sig_norm_index != nullptr) {
delete module->sig_norm_index;
module->sig_norm_index = nullptr;
}
for (auto wire : module->wires()) {
wire->driverCell_ = nullptr;
wire->driverPort_ = IdString();
}
// TODO inefficient?
std::vector<Cell*> cells_snapshot = module->cells();
for (auto cell : cells_snapshot) {
if (cell->type == ID($input_port))
module->remove(cell);
}
}
flagSigNormalized = false;
return;
}
log_assert(!flagBufferedNormalized);
if (!flagSigNormalized)
{
xlog("entering signorm\n");
flagSigNormalized = true;
}
for (auto module : modules())
module->sigNormalize();
}
void RTLIL::Module::sigNormalize()
{
log_assert(design->flagSigNormalized);
if (sig_norm_index == nullptr) {
auto new_index = new RTLIL::SigNormIndex(this);
new_index->setup();
sig_norm_index = new_index;
}
sig_norm_index->normalize();
}
void RTLIL::Module::dump_sigmap()
{
if (sig_norm_index != nullptr)
sig_norm_index->dump_sigmap();
}
void RTLIL::Module::clear_sig_norm_index()
{
if (sig_norm_index == nullptr)
return;
delete sig_norm_index;
}
const std::vector<RTLIL::SigSig> &RTLIL::Module::connections() const
{
if (sig_norm_index != nullptr)
sig_norm_index->restore_connections();
return connections_;
}
void RTLIL::Module::new_connections(const std::vector<RTLIL::SigSig> &new_conn)
{
if (sig_norm_index != nullptr) {
sig_norm_index->restore_connections();
sig_norm_index->restored_connections = 0;
// TODO clear the sigmap as well?
}
for (auto mon : monitors)
mon->notify_connect(this, new_conn);
if (design)
for (auto mon : design->monitors)
mon->notify_connect(this, new_conn);
if (yosys_xtrace) {
log("#X# New connections vector in %s:\n", log_id(this));
for (auto &conn: new_conn)
log("#X# %s = %s (%d bits)\n", log_signal(conn.first), log_signal(conn.second), GetSize(conn.first));
log_backtrace("-X- ", yosys_xtrace-1);
}
connections_ = new_conn;
}
int RTLIL::Module::next_timestamp()
{
int old = timestamp_;
int current = timestamp_ = old + 1;
if (sig_norm_index != nullptr) {
sigNormalize();
for (auto cell : sig_norm_index->dirty) {
auto [found, inserted] = sig_norm_index->cell_timestamps.emplace(cell, old);
if (!inserted) {
log_assert(found->second != old);
auto found_cells = sig_norm_index->timestamp_cells.find(found->second);
log_assert(found_cells != sig_norm_index->timestamp_cells.end());
bool erased = found_cells->second.erase(cell);
log_assert(erased);
if (found_cells->second.empty())
sig_norm_index->timestamp_cells.erase(found_cells);
found->second = old;
}
}
sig_norm_index->timestamp_cells[old] = std::move(sig_norm_index->dirty);
sig_norm_index->dirty.clear();
}
return current;
}
std::vector<Cell *> RTLIL::Module::dirty_cells(int starting_from)
{
sigNormalize();
std::vector<Cell *> result;
if (starting_from == INT_MIN) {
result.reserve(cells_.size());
for (auto cell : cells())
result.push_back(cell);
return result;
}
for (int i = starting_from; i < timestamp_; ++i) {
auto found = sig_norm_index->timestamp_cells.find(i);
if (found != sig_norm_index->timestamp_cells.end())
for (auto cell : found->second)
result.push_back(cell);
}
if (starting_from <= timestamp_)
for (auto cell : sig_norm_index->dirty)
result.push_back(cell);
return result;
}
const pool<RTLIL::PortBit> &RTLIL::Module::fanout(SigBit bit) {
log_assert(sig_norm_index != nullptr);
auto found = sig_norm_index->fanout.find(bit);
static pool<RTLIL::PortBit> empty;
if (found == sig_norm_index->fanout.end())
return empty;
return found->second;
}
void RTLIL::Module::remove(RTLIL::Cell *cell)
{
while (!cell->connections_.empty())
cell->unsetPort(cell->connections_.begin()->first);
log_assert(cells_.count(cell->name) != 0);
log_assert(refcount_cells_ == 0);
cells_.erase(cell->name);
if (design && design->flagBufferedNormalized && buf_norm_cell_queue.count(cell)) {
cell->type.clear();
cell->name.clear();
pending_deleted_cells.insert(cell);
} else {
if (sig_norm_index != nullptr) {
auto found = sig_norm_index->cell_timestamps.find(cell);
if (found != sig_norm_index->cell_timestamps.end()) {
auto found_cells = sig_norm_index->timestamp_cells.find(found->second);
log_assert(found_cells != sig_norm_index->timestamp_cells.end());
bool erased = found_cells->second.erase(cell);
log_assert(erased);
if (found_cells->second.empty())
sig_norm_index->timestamp_cells.erase(found_cells);
sig_norm_index->cell_timestamps.erase(found);
}
sig_norm_index->dirty.erase(cell);
}
delete cell;
}
}
typedef ModWalker::PortBit PortBit;
void RTLIL::Module::bufNormalize()
{
// Since this is kernel code, we only log with yosys_xtrace set to not get
// in the way when using `debug` to debug specific passes.q
#define xlog(...) do { if (yosys_xtrace) log("#X [bufnorm] " __VA_ARGS__); } while (0)
if (!design->flagBufferedNormalized)
return;
@ -545,6 +969,55 @@ void RTLIL::Cell::unsetPort(RTLIL::IdString portname)
log_backtrace("-X- ", yosys_xtrace-1);
}
if (module->sig_norm_index != nullptr) {
module->sig_norm_index->dirty.insert(this);
bool is_input_port = port_dir(portname) == RTLIL::PD_INPUT;
if (is_input_port) {
auto &fanout = module->sig_norm_index->fanout;
int counter = 0;
for (auto bit : conn_it->second) {
if (!bit.is_wire())
continue;
int i = counter++;
auto found = fanout.find(bit);
log_assert(found != fanout.end());
int erased = found->second.erase(PortBit(this, portname, i));
log_assert(erased);
if (found->second.empty())
fanout.erase(found);
}
} else if (GetSize(conn_it->second)) {
Wire *w = conn_it->second.as_wire();
log_assert(w->driverCell_ == this);
log_assert(w->driverPort_ == portname);
w->driverCell_ = nullptr;
w->driverPort_ = IdString();
}
// bool clear_fanout = true;
// if (conn_it->second.is_wire()) {
// Wire *w = conn_it->second.as_wire();
// if (w->driverCell_ == this && w->driverPort_ == portname) {
// w->driverCell_ = nullptr;
// w->driverPort_ = IdString();
// clear_fanout = false;
// }
// }
// if (clear_fanout) {
// auto &fanout = module->sig_norm_index->fanout;
// int counter = 0;
// for (auto bit : conn_it->second) {
// int i = counter++;
// auto found = fanout.find(bit);
// log_assert(found != fanout.end());
// int erased = found->second.erase(PortBit(this, portname, i));
// log_assert(erased);
// if (found->second.empty())
// fanout.erase(found);
// }
// }
}
if (module->design && module->design->flagBufferedNormalized) {
if (conn_it->second.is_wire()) {
Wire *w = conn_it->second.as_wire();
@ -586,8 +1059,32 @@ void RTLIL::Cell::unsetPort(RTLIL::IdString portname)
}
}
static bool ignored_cell(const RTLIL::IdString& type)
{
return type == ID($specify2) || type == ID($specify3) || type == ID($specrule);
}
void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
{
bool is_input_port = false;
if (module->sig_norm_index != nullptr && !ignored_cell(type)) {
module->sig_norm_index->sigmap.apply(signal);
auto dir = port_dir(portname);
if (dir == RTLIL::PD_INPUT) {
is_input_port = true;
} else {
Wire *wire = nullptr;
if (signal.is_wire() && (wire = signal.as_wire())->driverCell_ != nullptr)
wire = nullptr;
if (wire == nullptr) {
wire = module->addWire(NEW_ID, GetSize(signal));
module->connect(signal, wire);
signal = wire;
}
}
}
auto r = connections_.insert(portname);
auto conn_it = r.first;
if (!r.second && conn_it->second == signal)
@ -605,6 +1102,48 @@ void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
log_backtrace("-X- ", yosys_xtrace-1);
}
if (module->sig_norm_index != nullptr && !ignored_cell(type)) {
module->sig_norm_index->dirty.insert(this);
if (!r.second) {
if (is_input_port) {
auto &fanout = module->sig_norm_index->fanout;
int counter = 0;
for (auto bit : conn_it->second) {
if (!bit.is_wire())
continue;
int i = counter++;
auto found = fanout.find(bit);
log_assert(found != fanout.end());
int erased = found->second.erase(PortBit(this, portname, i));
log_assert(erased);
if (found->second.empty())
fanout.erase(found);
}
} else {
Wire *w = conn_it->second.as_wire();
log_assert(w->driverCell_ == this);
log_assert(w->driverPort_ == portname);
w->driverCell_ = nullptr;
w->driverPort_ = IdString();
}
}
if (is_input_port) {
auto &fanout = module->sig_norm_index->fanout;
int i = 0;
for (auto bit : signal)
if (bit.is_wire())
fanout[bit].insert(PortBit(this, portname, i++));
} else if (GetSize(signal)) {
Wire *w = signal.as_wire();
log_assert(w->driverCell_ == nullptr);
log_assert(w->driverPort_.empty());
w->driverCell_ = this;
w->driverPort_ = portname;
}
}
if (module->design && module->design->flagBufferedNormalized)
{
// We eagerly clear a driver that got disconnected by changing this port connection
@ -670,4 +1209,25 @@ void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
}
void RTLIL::Design::add(RTLIL::Module *module)
{
log_assert(modules_.count(module->name) == 0);
log_assert(refcount_modules_ == 0);
modules_[module->name] = module;
module->design = this;
for (auto mon : monitors)
mon->notify_module_add(module);
if (yosys_xtrace) {
log("#X# New Module: %s\n", log_id(module));
log_backtrace("-X- ", yosys_xtrace-1);
}
if (flagSigNormalized) {
module->sigNormalize();
}
}
YOSYS_NAMESPACE_END

View File

@ -465,6 +465,26 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
return true;
}
if (cell->type.in(ID($connect)))
{
std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
extendSignalWidthUnary(a, b, cell);
std::vector<int> bb = model_undef ? ez->vec_var(b.size()) : b;
ez->assume(ez->vec_eq(a, bb));
if (model_undef)
{
std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
extendSignalWidthUnary(undef_a, undef_b, cell);
ez->assume(ez->vec_eq(undef_a, undef_b));
undefGating(b, bb, undef_b);
}
return true;
}
if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($logic_not)))
{
std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);

View File

@ -265,6 +265,8 @@ unsigned int abstract_value(Module* mod, EnableLogic enable, const std::vector<S
unsigned int changed = 0;
std::vector<Cell*> cells_snapshot = mod->cells();
for (auto cell : cells_snapshot) {
if (cell->type == ID($input_port))
continue;
for (auto conn : cell->connections())
if (cell->output(conn.first)) {
std::set<int> offsets_to_abstract;
@ -462,6 +464,8 @@ struct AbstractPass : public Pass {
}
extra_args(args, argidx, design);
// TODO Disabled signorm because swap_names breaks fanout logic
design->sigNormalize(false);
if (enable != Enable::Always) {
if (mode == Mode::Initial)
log_cmd_error("Conditional initial value abstraction is not supported\n");

View File

@ -257,6 +257,9 @@ struct CheckPass : public Pass {
pool<Cell *> coarsened_cells;
for (auto cell : module->cells())
{
if (cell->type == ID($input_port))
continue;
if (mapped && cell->type.begins_with("$") && design->module(cell->type) == nullptr) {
if (allow_tbuf && cell->type == ID($_TBUF_)) goto cell_allowed;
log_warning("Cell %s.%s is an unmapped internal cell of type %s.\n", log_id(module), log_id(cell), log_id(cell->type));
@ -264,6 +267,30 @@ struct CheckPass : public Pass {
cell_allowed:;
}
if (cell->type == ID($connect)) {
// Inefficient, but rare case in sane design
auto sig_a = cell->getPort(ID::A);
auto sig_b = cell->getPort(ID::B);
for (int i = 0; i < sig_a.size(); i++) {
int count_a = wire_drivers_count[sig_a[i]];
int count_b = wire_drivers_count[sig_b[i]];
wire_drivers_count[sig_a[i]] += count_b;
wire_drivers_count[sig_b[i]] += count_a;
// Guarantee default constructed members if missing
(void)wire_drivers[sig_a[i]];
(void)wire_drivers[sig_b[i]];
auto& drivers_a = wire_drivers[sig_a[i]];
auto& drivers_b = wire_drivers[sig_b[i]];
vector<string> drivers;
drivers.reserve(std::max(drivers_a.size(), drivers_b.size()));
for (auto driver : drivers_a)
drivers.push_back(driver);
for (auto driver : drivers_b)
drivers.push_back(driver);
drivers_a = drivers;
drivers_b = drivers;
}
}
for (auto &conn : cell->connections()) {
bool input = cell->input(conn.first);
bool output = cell->output(conn.first);

View File

@ -218,6 +218,9 @@ struct ChformalPass : public Pass {
}
extra_args(args, argidx, design);
// TODO Disabled signorm because swap_names breaks fanout logic
design->sigNormalize(false);
if (constr_types.empty()) {
constr_types.insert(ID($assert));
constr_types.insert(ID($assume));

View File

@ -32,11 +32,23 @@ static void unset_drivers(RTLIL::Design *design, RTLIL::Module *module, SigMap &
RTLIL::Wire *dummy_wire = module->addWire(NEW_ID, sig.size());
// (void)module->connections(); // trigger signorm flush
for (auto cell : module->cells())
for (auto &port : cell->connections_)
if (ct.cell_output(cell->type, port.first))
sigmap(port.second).replace(sig, dummy_wire, &port.second);
bool need_fixup = false;
for (auto bit : sig.bits()) {
if (bit.is_wire() && bit.wire->port_input) {
bit.wire->port_input = false;
need_fixup = true;
}
}
if (need_fixup)
module->fixup_ports();
for (auto &conn : module->connections_)
sigmap(conn.first).replace(sig, dummy_wire, &conn.first);
}
@ -66,7 +78,7 @@ struct ConnectPass : public Pass {
log("\n");
log("\n");
log("Per default signal alias names are resolved and all signal names are mapped\n");
log("the the signal name of the primary driver. Using the -nomap option deactivates\n");
log("to the signal name of the primary driver. Using the -nomap option deactivates\n");
log("this behavior.\n");
log("\n");
log("The connect command operates in one module only. Either only one module must\n");
@ -77,6 +89,8 @@ struct ConnectPass : public Pass {
log("\n");
log("This command does not operate on module with processes.\n");
log("\n");
log("Overriding any bits connected to a module input port will remove the input port.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{

View File

@ -338,8 +338,11 @@ struct DesignPass : public Pass {
{
RTLIL::Design *design_copy = new RTLIL::Design;
for (auto mod : design->modules())
for (auto mod : design->modules()) {
// Triggers signorm flush if needed (hacky)
(void)mod->connections();
design_copy->add(mod->clone());
}
design_copy->selection_stack = design->selection_stack;
design_copy->selection_vars = design->selection_vars;
@ -356,6 +359,8 @@ struct DesignPass : public Pass {
if (reset_mode || !load_name.empty() || push_mode || pop_mode)
{
design->flagSigNormalized = false;
for (auto mod : design->modules().to_vector())
design->remove(mod);
@ -377,6 +382,7 @@ struct DesignPass : public Pass {
{
RTLIL::Design *saved_design = pop_mode ? pushed_designs.back() : saved_designs.at(load_name);
design->flagSigNormalized = saved_design->flagSigNormalized;
for (auto mod : saved_design->modules())
design->add(mod->clone());

View File

@ -378,6 +378,9 @@ struct RenamePass : public Pass {
break;
}
// TODO disable signorm due to rename I think?
design->sigNormalize(false);
if (flag_src)
{
extra_args(args, argidx, design);

View File

@ -145,6 +145,9 @@ struct SplitnetsPass : public Pass {
}
extra_args(args, argidx, design);
// TODO disable signorm due to rewrite_sigspecs assert
design->sigNormalize(false);
// module_ports_db[module_name][old_port_name] = new_port_name_list
dict<IdString, dict<IdString, vector<IdString>>> module_ports_db;

View File

@ -114,6 +114,8 @@ struct EquivMakeWorker
if ((it->name.isPublic() || inames) && blacklist_names.count(it->name) == 0)
cell_names.insert(it->name);
gold_clone->rename(it, it->name.str() + "_gold");
if (it->type == ID($input_port))
gold_clone->remove(it);
}
for (auto it : gate_clone->wires().to_vector()) {
@ -126,6 +128,8 @@ struct EquivMakeWorker
if ((it->name.isPublic() || inames) && blacklist_names.count(it->name) == 0)
cell_names.insert(it->name);
gate_clone->rename(it, it->name.str() + "_gate");
if (it->type == ID($input_port))
gate_clone->remove(it);
}
gold_clone->cloneInto(equiv_mod);
@ -513,6 +517,7 @@ struct EquivMakePass : public Pass {
worker.equiv_mod = design->addModule(RTLIL::escape_id(args[argidx+2]));
worker.run();
Pass::call(design, "dump");
}
} EquivMakePass;

View File

@ -143,8 +143,9 @@ struct EquivMiterWorker
for (auto w : miter_wires)
miter_module->addWire(w->name, w->width);
for (auto c : miter_cells) {
miter_module->addCell(c->name, c);
auto mc = miter_module->cell(c->name);
if (c->type == ID($input_port))
continue;
auto mc = miter_module->addCell(c->name, c);
for (auto &conn : mc->connections())
mc->setPort(conn.first, sigmap(conn.second));
}
@ -319,6 +320,9 @@ struct EquivMiterPass : public Pass {
worker.miter_name = RTLIL::escape_id(args[argidx++]);
extra_args(args, argidx, design);
// TODO disable signorm due to rewrite_sigspecs assert
design->sigNormalize(false);
if (design->module(worker.miter_name))
log_cmd_error("Miter module %s already exists.\n", log_id(worker.miter_name));

View File

@ -178,6 +178,8 @@ struct FlattenWorker
}
for (auto tpl_cell : tpl->cells()) {
if (tpl_cell->type == ID($input_port))
continue;
RTLIL::Cell *new_cell = module->addCell(map_name(cell, tpl_cell, separator), tpl_cell);
map_attributes(cell, new_cell, tpl_cell->name);
if (new_cell->has_memid()) {
@ -408,6 +410,9 @@ struct FlattenPass : public Pass {
}
extra_args(args, argidx, design);
bool was_signormed = design->flagSigNormalized;
design->sigNormalize(false);
RTLIL::Module *top = nullptr;
if (design->full_selection())
for (auto module : design->modules())
@ -447,6 +452,11 @@ struct FlattenPass : public Pass {
design->remove(module);
}
if (was_signormed) {
// TODO inconvenient workaround for fanout out of sync
design->sigNormalize(false);
design->sigNormalize(true);
}
log_pop();
}
} FlattenPass;

View File

@ -686,6 +686,8 @@ bool set_keep_print(std::map<RTLIL::Module*, bool> &cache, RTLIL::Module *mod)
{
if (cache.count(mod) == 0)
for (auto c : mod->cells()) {
if (mod->name == c->type)
continue;
RTLIL::Module *m = mod->design->module(c->type);
if ((m != nullptr && set_keep_print(cache, m)) || c->type == ID($print))
return cache[mod] = true;
@ -697,6 +699,8 @@ bool set_keep_assert(std::map<RTLIL::Module*, bool> &cache, RTLIL::Module *mod)
{
if (cache.count(mod) == 0)
for (auto c : mod->cells()) {
if (mod->name == c->type)
continue;
RTLIL::Module *m = mod->design->module(c->type);
if ((m != nullptr && set_keep_assert(cache, m)) || c->type.in(ID($check), ID($assert), ID($assume), ID($live), ID($fair), ID($cover)))
return cache[mod] = true;

View File

@ -125,6 +125,55 @@ struct rules_t
variant_params[stringf("\\CFG_CLKPOL_%c", 'A' + i)] = clkpol[i];
}
}
void load_blackbox(Design* design) const
{
auto portinfos = make_portinfos();
int clocks_max = 0;
for (auto &pi : portinfos)
clocks_max = max(clocks_max, pi.clocks);
pool<std::pair<IdString, int>> inputs;
pool<std::pair<IdString, int>> outputs;
for (auto &pi : portinfos)
{
string prefix = stringf("%c%d", pi.group + 'A', pi.index + 1);
const char *pf = prefix.c_str();
if (pi.clocks) {
std::string name = stringf("\\CLK%d", (pi.clocks-1) % clocks_max + 1);
inputs.insert(std::make_pair(name, 1));
}
inputs.insert(std::make_pair(stringf("\\%sADDR", pf), abits));
std::string dname = stringf("\\%sDATA", pf);
if (pi.wrmode) {
inputs.insert(std::make_pair(dname, dbits));
} else {
outputs.insert(std::make_pair(dname, dbits));
}
if (pi.enable) {
std::string name = stringf("\\%sEN", pf);
inputs.insert(std::make_pair(name, 1));
}
}
log_debug("setting up %s\n", name);
Module* mod = design->addModule(name);
mod->set_bool_attribute(ID::blackbox);
for (auto [name, width] : inputs)
{
log_debug("input %s width %d\n", name, width);
mod->addWire(name, width)->port_input = true;
}
for (auto [name, width] : outputs)
{
log_debug("output %s width %d\n", name, width);
mod->addWire(name, width)->port_output = true;
}
mod->fixup_ports();
}
};
struct match_t {
@ -160,6 +209,19 @@ struct rules_t
vector<string> labels;
int linecount;
void load_blackboxes(Design* design) const
{
for (auto& [_, variants] : brams)
{
for (const bram_t& bram : variants)
{
if (design->module(bram.name))
continue;
bram.load_blackbox(design);
}
}
}
void syntax_error()
{
if (tokens.empty())
@ -1314,6 +1376,7 @@ struct MemoryBramPass : public Pass {
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-rules" && argidx+1 < args.size()) {
rules.parse(args[++argidx]);
rules.load_blackboxes(design);
continue;
}
break;

View File

@ -1,6 +1,7 @@
OBJS += passes/opt/opt.o
OBJS += passes/opt/opt_merge.o
OBJS += passes/opt/opt_merge_inc.o
OBJS += passes/opt/opt_mem.o
OBJS += passes/opt/opt_mem_feedback.o
OBJS += passes/opt/opt_mem_priority.o

View File

@ -50,21 +50,25 @@ bool trim_buf(RTLIL::Cell* cell, ShardedVector<RTLIL::SigSig>& new_connections,
}
bool remove(ShardedVector<RTLIL::Cell*>& cells, RTLIL::Module* mod, bool verbose) {
// Removing $connect and $input_port doesn't count as "doing something"
// since they get rebuilt in signorm
// and don't enable further opt
bool did_something = false;
for (RTLIL::Cell *cell : cells) {
if (verbose) {
if (cell->type == ID($connect))
if (cell->type == ID($connect)) {
log_debug(" removing connect cell `%s': %s <-> %s\n", cell->name,
log_signal(cell->getPort(ID::A)), log_signal(cell->getPort(ID::B)));
else if (cell->type == ID($input_port))
} else if (cell->type == ID($input_port)) {
log_debug(" removing input port marker cell `%s': %s\n", cell->name,
log_signal(cell->getPort(ID::Y)));
else
} else {
did_something = true;
log_debug(" removing buffer cell `%s': %s = %s\n", cell->name,
log_signal(cell->getPort(ID::Y)), log_signal(cell->getPort(ID::A)));
}
}
mod->remove(cell);
did_something = true;
}
return did_something;
}

View File

@ -77,6 +77,8 @@ struct OptCleanPass : public Pass {
}
extra_args(args, argidx, design);
design->sigNormalize(false);
{
std::vector<RTLIL::Module*> selected_modules;
for (auto module : design->selected_whole_modules_warn())
@ -128,6 +130,8 @@ struct CleanPass : public Pass {
}
extra_args(args, argidx, design);
design->sigNormalize(false);
{
std::vector<RTLIL::Module*> selected_modules;
for (auto module : design->selected_unboxed_whole_modules())

View File

@ -576,8 +576,8 @@ bool rmunused_module_signals(RTLIL::Module *module, ParallelDispatchThreadPool::
if (clean_ctx.flags.verbose && deleted_and_unreported)
log_debug(" removed %d unused temporary wires.\n", deleted_and_unreported);
if (deleted_total)
module->design->scratchpad_set_bool("opt.did_something", true);
// if (deleted_total)
// module->design->scratchpad_set_bool("opt.did_something", true);
return deleted_total != 0;
}

View File

@ -172,7 +172,7 @@ struct OptDffWorker
if (path.count(sig_s[i]) && path.at(sig_s[i])) {
ret = find_muxtree_feedback_patterns(sig_b[i*width + index], q, path);
if (sig_b[i*width + index] == q) {
RTLIL::SigSpec s = mbit.first->getPort(ID::B);
RTLIL::SigSpec s = sigmap(mbit.first->getPort(ID::B));
s[i*width + index] = RTLIL::Sx;
mbit.first->setPort(ID::B, s);
}
@ -196,7 +196,7 @@ struct OptDffWorker
ret.insert(pat);
if (sig_b[i*width + index] == q) {
RTLIL::SigSpec s = mbit.first->getPort(ID::B);
RTLIL::SigSpec s = sigmap(mbit.first->getPort(ID::B));
s[i*width + index] = RTLIL::Sx;
mbit.first->setPort(ID::B, s);
}
@ -207,7 +207,7 @@ struct OptDffWorker
ret.insert(pat);
if (sig_a[index] == q) {
RTLIL::SigSpec s = mbit.first->getPort(ID::A);
RTLIL::SigSpec s = sigmap(mbit.first->getPort(ID::A));
s[index] = RTLIL::Sx;
mbit.first->setPort(ID::A, s);
}
@ -555,7 +555,7 @@ struct OptDffWorker
}
}
bool try_merge_srst(FfData &ff, Cell *cell, bool &changed)
bool try_merge_srst(FfDataSigMapped &ff, Cell *cell, bool &changed)
{
std::map<ctrls_t, std::vector<int>> groups;
std::vector<int> remaining_indices;
@ -570,9 +570,9 @@ struct OptDffWorker
if (GetSize(mbit.first->getPort(ID::S)) != 1)
break;
SigBit s = mbit.first->getPort(ID::S);
SigBit a = mbit.first->getPort(ID::A)[mbit.second];
SigBit b = mbit.first->getPort(ID::B)[mbit.second];
SigBit s = sigmap(mbit.first->getPort(ID::S));
SigBit a = sigmap(mbit.first->getPort(ID::A)[mbit.second]);
SigBit b = sigmap(mbit.first->getPort(ID::B)[mbit.second]);
if ((a == State::S0 || a == State::S1) && (b == State::S0 || b == State::S1))
break;
@ -608,7 +608,7 @@ struct OptDffWorker
Const val_srst = val_srst_builder.build();
for (auto &it : groups) {
FfData new_ff = ff.slice(it.second);
FfDataSigMapped new_ff = ff.slice(it.second);
Const::Builder new_val_srst_builder(new_ff.width);
for (int i = 0; i < new_ff.width; i++)
new_val_srst_builder.push_back(val_srst[it.second[i]]);
@ -645,7 +645,7 @@ struct OptDffWorker
return false;
}
bool try_merge_ce(FfData &ff, Cell *cell, bool &changed)
bool try_merge_ce(FfDataSigMapped &ff, Cell *cell, bool &changed)
{
std::map<std::pair<patterns_t, ctrls_t>, std::vector<int>> groups;
std::vector<int> remaining_indices;
@ -658,9 +658,9 @@ struct OptDffWorker
if (GetSize(mbit.first->getPort(ID::S)) != 1)
break;
SigBit s = mbit.first->getPort(ID::S);
SigBit a = mbit.first->getPort(ID::A)[mbit.second];
SigBit b = mbit.first->getPort(ID::B)[mbit.second];
SigBit s = sigmap(mbit.first->getPort(ID::S));
SigBit a = sigmap(mbit.first->getPort(ID::A)[mbit.second]);
SigBit b = sigmap(mbit.first->getPort(ID::B)[mbit.second]);
if (a == ff.sig_q[i]) {
enables.insert(ctrl_t(s, true));
@ -688,7 +688,7 @@ struct OptDffWorker
}
for (auto &it : groups) {
FfData new_ff = ff.slice(it.second);
FfDataSigMapped new_ff = ff.slice(it.second);
ctrl_t en = make_patterns_logic(it.first.first, it.first.second, ff.is_fine);
new_ff.has_ce = true;
@ -726,8 +726,8 @@ struct OptDffWorker
while (!dff_cells.empty()) {
Cell *cell = dff_cells.back();
dff_cells.pop_back();
FfData ff(&initvals, cell);
// Break down the FF into pieces.
FfDataSigMapped ff(sigmap, &initvals, cell);
bool changed = false;
if (!ff.width) {
@ -819,7 +819,7 @@ struct OptDffWorker
qcsat.ez->NOT(qcsat.ez->IFF(d_sat_pi, init_sat_pi)));
}
State check_constbit(FfData &ff, int i)
State check_constbit(FfDataSigMapped &ff, int i)
{
State val = ff.val_init[i];
if (ff.has_arst) val = combine_const(val, ff.val_arst[i]);
@ -841,14 +841,15 @@ struct OptDffWorker
QuickConeSat qcsat(modwalker);
std::vector<RTLIL::Cell*> cells_to_remove;
std::vector<FfData> ffs_to_emit;
std::vector<FfDataSigMapped> ffs_to_emit;
bool did_something = false;
for (auto cell : module->selected_cells()) {
if (!cell->is_builtin_ff())
continue;
FfData ff(&initvals, cell);
FfDataSigMapped ff(sigmap, &initvals, cell);
pool<int> removed_sigbits;
for (int i = 0; i < ff.width; i++) {
@ -979,6 +980,8 @@ struct OptDffPass : public Pass {
break;
}
extra_args(args, argidx, design);
// TODO extra wires signorm adds breaks muxtree traversal or requires sigmapping
design->sigNormalize(false);
bool did_something = false;
for (auto mod : design->selected_modules()) {

View File

@ -392,11 +392,15 @@ int get_highest_hot_index(RTLIL::SigSpec signal)
return -1;
}
void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc, bool noclkinv)
void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc, bool noclkinv, int timestamp=INT_MIN)
{
SigMap assign_map(module);
SigMap assign_map; //(module);
dict<RTLIL::SigSpec, RTLIL::SigSpec> invert_map;
auto dirty_cells = module->dirty_cells(timestamp);
// TODO this could be cheaper
for (auto cell : module->cells()) {
if (design->selected(module, cell) && cell->type[0] == '$') {
if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) &&
@ -409,7 +413,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (!noclkinv)
for (auto cell : module->cells())
for (auto cell : dirty_cells)
if (design->selected(module, cell)) {
if (cell->type.in(ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($sdff), ID($sdffe), ID($sdffce), ID($fsm), ID($memrd), ID($memrd_v2), ID($memwr), ID($memwr_v2)))
handle_polarity_inv(cell, ID::CLK, ID::CLK_POLARITY, assign_map, invert_map);
@ -487,9 +491,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
TopoSort<RTLIL::Cell*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell>> cells;
dict<RTLIL::SigBit, Cell*> outbit_to_cell;
for (auto cell : module->cells())
for (auto cell : dirty_cells)
if (design->selected(module, cell) && yosys_celltypes.cell_evaluable(cell->type)) {
for (auto &conn : cell->connections())
if (yosys_celltypes.cell_output(cell->type, conn.first))
@ -498,7 +503,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cells.node(cell);
}
for (auto cell : module->cells())
for (auto cell : dirty_cells)
if (design->selected(module, cell) && yosys_celltypes.cell_evaluable(cell->type)) {
const int r_index = cells.node(cell);
for (auto &conn : cell->connections())
@ -514,6 +519,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
log("Couldn't topologically sort cells, optimizing module %s may take a longer time.\n", log_id(module));
}
log("iterating over %d cells\n", GetSize(cells.sorted));
for (auto cell : cells.sorted)
{
#define ACTION_DO(_p_, _s_) do { replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
@ -1144,10 +1151,10 @@ skip_fine_alu:
if (input.match(" 1")) ACTION_DO(ID::Y, input.extract(1, 1));
if (input.match("01 ")) ACTION_DO(ID::Y, input.extract(0, 1));
if (input.match("10 ")) {
cell->type = ID($_NOT_);
cell->setPort(ID::A, input.extract(0, 1));
cell->unsetPort(ID::B);
cell->unsetPort(ID::S);
cell->type = ID($_NOT_);
goto next_cell;
}
if (input.match("11 ")) ACTION_DO_Y(1);
@ -1199,8 +1206,13 @@ skip_fine_alu:
replace_cell(assign_map, module, cell, "isneq", ID::Y, new_y);
goto next_cell;
}
if (a[i] == b[i])
continue;
if (keepdc) {
if (!a[i].is_wire() && !b[i].is_wire() && a[i].data != RTLIL::State::Sx && b[i].data != RTLIL::State::Sx && a[i] == b[i])
continue;
} else {
if (a[i] == b[i])
continue;
}
new_a.append(a[i]);
new_b.append(b[i]);
}
@ -1242,10 +1254,10 @@ skip_fine_alu:
ACTION_DO(ID::Y, cell->getPort(ID::A));
} else {
log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->type = ID($not);
cell->parameters.erase(ID::B_WIDTH);
cell->parameters.erase(ID::B_SIGNED);
cell->unsetPort(ID::B);
cell->type = ID($not);
did_something = true;
}
goto next_cell;
@ -1257,7 +1269,7 @@ skip_fine_alu:
{
log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell),
log_id(module), cell->type == ID($eq) ? "$logic_not" : "$reduce_bool");
cell->type = cell->type == ID($eq) ? ID($logic_not) : ID($reduce_bool);
if (assign_map(cell->getPort(ID::A)).is_fully_zero()) {
cell->setPort(ID::A, cell->getPort(ID::B));
cell->setParam(ID::A_SIGNED, cell->getParam(ID::B_SIGNED));
@ -1266,6 +1278,7 @@ skip_fine_alu:
cell->unsetPort(ID::B);
cell->unsetParam(ID::B_SIGNED);
cell->unsetParam(ID::B_WIDTH);
cell->type = cell->type == ID($eq) ? ID($logic_not) : ID($reduce_bool);
did_something = true;
goto next_cell;
}
@ -1408,10 +1421,10 @@ skip_fine_alu:
cell->setParam(ID::A_SIGNED, cell->getParam(ID::B_SIGNED));
}
cell->type = arith_inverse ? ID($neg) : ID($pos);
cell->unsetPort(ID::B);
cell->parameters.erase(ID::B_WIDTH);
cell->parameters.erase(ID::B_SIGNED);
cell->type = arith_inverse ? ID($neg) : ID($pos);
cell->check();
did_something = true;
@ -2292,9 +2305,14 @@ struct OptExprPass : public Pass {
}
extra_args(args, argidx, design);
design->sigNormalize(true);
NewCellTypes ct(design);
for (auto module : design->selected_modules())
{
int replace_const_cells_timestamp = INT_MIN;
int replace_const_cells_consume_x_timestamp = INT_MIN;
log("Optimizing module %s.\n", log_id(module));
if (undriven) {
@ -2307,12 +2325,17 @@ struct OptExprPass : public Pass {
do {
do {
did_something = false;
replace_const_cells(design, module, false /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, noclkinv);
module->next_timestamp();
replace_const_cells(design, module, false /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, noclkinv, replace_const_cells_timestamp);
replace_const_cells_timestamp = module->timestamp();
if (did_something)
design->scratchpad_set_bool("opt.did_something", true);
} while (did_something);
if (!keepdc)
replace_const_cells(design, module, true /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, noclkinv);
if (!keepdc) {
module->next_timestamp();
replace_const_cells(design, module, true /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, noclkinv, replace_const_cells_consume_x_timestamp);
replace_const_cells_consume_x_timestamp = module->timestamp();
}
if (did_something)
design->scratchpad_set_bool("opt.did_something", true);
} while (did_something);

View File

@ -422,6 +422,11 @@ struct OptHierPass : Pass {
{
log_header(d, "Executing OPT_HIER pass.\n");
// TODO: This pass breaks in signorm
// since rewrite_sigspecs won't rewrite persistent sigmap
// and adding that rewrite is a performance risk
d->sigNormalize(false);
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
break;

View File

@ -497,7 +497,7 @@ struct OptMergeWorker
};
struct OptMergePass : public Pass {
OptMergePass() : Pass("opt_merge", "consolidate identical cells") { }
OptMergePass() : Pass("opt_merge_old", "consolidate identical cells") { }
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

615
passes/opt/opt_merge_inc.cc Normal file
View File

@ -0,0 +1,615 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* 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/ffinit.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include "kernel/celltypes.h"
#include "libs/sha1/sha1.h"
#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
#include <set>
#include <unordered_map>
#include <array>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
template <typename T, typename U>
inline Hasher hash_pair(const T &t, const U &u) { return hash_ops<std::pair<T, U>>::hash(t, u); }
struct OptMergeIncWorker
{
RTLIL::Design *design;
RTLIL::Module *module;
SigMap assign_map;
FfInitVals initvals;
bool mode_share_all;
CellTypes ct;
int total_count;
static Hasher hash_pmux_in(const SigSpec& sig_s, const SigSpec& sig_b, Hasher h)
{
int s_width = GetSize(sig_s);
int width = GetSize(sig_b) / s_width;
hashlib::commutative_hash comm;
for (int i = 0; i < s_width; i++)
comm.eat(hash_pair(sig_s[i], sig_b.extract(i*width, width)));
return comm.hash_into(h);
}
static void sort_pmux_conn(dict<RTLIL::IdString, RTLIL::SigSpec> &conn)
{
SigSpec sig_s = conn.at(ID::S);
SigSpec sig_b = conn.at(ID::B);
int s_width = GetSize(sig_s);
int width = GetSize(sig_b) / s_width;
vector<pair<SigBit, SigSpec>> sb_pairs;
for (int i = 0; i < s_width; i++)
sb_pairs.push_back(pair<SigBit, SigSpec>(sig_s[i], sig_b.extract(i*width, width)));
std::sort(sb_pairs.begin(), sb_pairs.end());
conn[ID::S] = SigSpec();
conn[ID::B] = SigSpec();
for (auto &it : sb_pairs) {
conn[ID::S].append(it.first);
conn[ID::B].append(it.second);
}
}
Hasher hash_cell_inputs(const RTLIL::Cell *cell, Hasher h) const
{
// TODO: when implemented, use celltypes to match:
// (builtin || stdcell) && (unary || binary) && symmetrical
if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($mul),
ID($logic_and), ID($logic_or), ID($_AND_), ID($_OR_), ID($_XOR_))) {
hashlib::commutative_hash comm;
comm.eat((cell->getPort(ID::A)));
comm.eat((cell->getPort(ID::B)));
h = comm.hash_into(h);
} else if (cell->type.in(ID($reduce_xor), ID($reduce_xnor))) {
SigSpec a = (cell->getPort(ID::A));
a.sort();
h = a.hash_into(h);
} else if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_bool))) {
SigSpec a = (cell->getPort(ID::A));
a.sort_and_unify();
h = a.hash_into(h);
} else if (cell->type == ID($pmux)) {
SigSpec sig_s = (cell->getPort(ID::S));
SigSpec sig_b = (cell->getPort(ID::B));
h = hash_pmux_in(sig_s, sig_b, h);
h = (cell->getPort(ID::A)).hash_into(h);
} else {
hashlib::commutative_hash comm;
for (const auto& [port, sig] : cell->connections()) {
if (cell->output(port))
continue;
comm.eat(hash_pair(port, (sig)));
}
h = comm.hash_into(h);
if (cell->is_builtin_ff())
h = initvals(cell->getPort(ID::Q)).hash_into(h);
}
return h;
}
static Hasher hash_cell_parameters(const RTLIL::Cell *cell, Hasher h)
{
hashlib::commutative_hash comm;
for (const auto& param : cell->parameters) {
comm.eat(param);
}
return comm.hash_into(h);
}
Hasher hash_cell_function(const RTLIL::Cell *cell, Hasher h) const
{
h.eat(cell->type);
h = hash_cell_inputs(cell, h);
h = hash_cell_parameters(cell, h);
return h;
}
bool compare_cell_parameters_and_connections(const RTLIL::Cell *cell1, const RTLIL::Cell *cell2) const
{
if (cell1 == cell2) return true;
if (cell1->type != cell2->type) return false;
if (cell1->parameters != cell2->parameters)
return false;
if (cell1->connections_.size() != cell2->connections_.size())
return false;
for (const auto &it : cell1->connections_)
if (!cell2->connections_.count(it.first))
return false;
decltype(Cell::connections_) conn1, conn2;
conn1.reserve(cell1->connections_.size());
conn2.reserve(cell1->connections_.size());
for (const auto &it : cell1->connections_) {
if (cell1->output(it.first)) {
if (it.first == ID::Q && cell1->is_builtin_ff()) {
// For the 'Q' output of state elements,
// use the (* init *) attribute value
conn1[it.first] = initvals(it.second);
conn2[it.first] = initvals(cell2->getPort(it.first));
}
else {
conn1[it.first] = RTLIL::SigSpec();
conn2[it.first] = RTLIL::SigSpec();
}
}
else {
conn1[it.first] = (it.second);
conn2[it.first] = (cell2->getPort(it.first));
}
}
if (cell1->type.in(ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($mul),
ID($logic_and), ID($logic_or), ID($_AND_), ID($_OR_), ID($_XOR_))) {
if (conn1.at(ID::A) < conn1.at(ID::B)) {
std::swap(conn1[ID::A], conn1[ID::B]);
}
if (conn2.at(ID::A) < conn2.at(ID::B)) {
std::swap(conn2[ID::A], conn2[ID::B]);
}
} else
if (cell1->type.in(ID($reduce_xor), ID($reduce_xnor))) {
conn1[ID::A].sort();
conn2[ID::A].sort();
} else
if (cell1->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_bool))) {
conn1[ID::A].sort_and_unify();
conn2[ID::A].sort_and_unify();
} else
if (cell1->type == ID($pmux)) {
sort_pmux_conn(conn1);
sort_pmux_conn(conn2);
}
return conn1 == conn2;
}
bool has_dont_care_initval(const RTLIL::Cell *cell)
{
if (!cell->is_builtin_ff())
return false;
return !initvals(cell->getPort(ID::Q)).is_fully_def();
}
OptMergeIncWorker(RTLIL::Design *design, RTLIL::Module *module, bool mode_nomux, bool mode_share_all, bool mode_keepdc) :
design(design), module(module), mode_share_all(mode_share_all)
{
total_count = 0;
ct.setup_internals();
ct.setup_internals_mem();
ct.setup_stdcells();
ct.setup_stdcells_mem();
if (mode_nomux) {
ct.cell_types.erase(ID($mux));
ct.cell_types.erase(ID($pmux));
}
ct.cell_types.erase(ID($tribuf));
ct.cell_types.erase(ID($_TBUF_));
ct.cell_types.erase(ID($anyseq));
ct.cell_types.erase(ID($anyconst));
ct.cell_types.erase(ID($allseq));
ct.cell_types.erase(ID($allconst));
ct.cell_types.erase(ID($connect));
ct.cell_types.erase(ID($input_port));
log("Finding identical cells in module `%s'.\n", module->name);
assign_map.set(module);
initvals.set(&assign_map, module);
// We keep a set of known cells. They're hashed with our hash_cell_function
// and compared with our compare_cell_parameters_and_connections.
// Both need to capture OptMergeIncWorker to access initvals
struct CellPtrHash {
const OptMergeIncWorker& worker;
CellPtrHash(const OptMergeIncWorker& w) : worker(w) {}
std::size_t operator()(const Cell* c) const {
return (std::size_t)worker.hash_cell_function(c, Hasher()).yield();
}
};
struct CellPtrEqual {
const OptMergeIncWorker& worker;
CellPtrEqual(const OptMergeIncWorker& w) : worker(w) {}
bool operator()(const Cell* lhs, const Cell* rhs) const {
return worker.compare_cell_parameters_and_connections(lhs, rhs);
}
};
// std::unordered_set<
// RTLIL::Cell*,
// CellPtrHash,
// CellPtrEqual> known_cells (0, CellPtrHash(*this), CellPtrEqual(*this));
dict<Cell *, uint32_t> hashes;
dict<uint32_t, Cell *> first_with_hash;
dict<uint32_t, pool<Cell *>> more_with_hash;
auto forget_cell = [&](Cell * cell) {
auto found = hashes.find(cell);
if (found != hashes.end()) {
auto found_first = first_with_hash.find(found->second);
log_assert(found_first != first_with_hash.end());
auto found_more = more_with_hash.find(found->second);
if (found_more != more_with_hash.end()) {
found_more->second.erase(cell);
found_first->second = *found_more->second.begin();
if (found_more->second.size() < 2)
more_with_hash.erase(found_more);
}
// auto found_first = first_with_hash.find(found->second);
// log_assert(found_first != first_with_hash.end());
// if (found_first->second == cell) {
// auto found_more = more_with_hash.find(found->second);
// if (found_more != more_with_hash.end()) {
// log_assert(!found_more->second.empty());
// found_first->second = found_more->second.pop();
// if (found_more->second.empty())
// more_with_hash.erase(found_more);
// } else {
// first_with_hash.erase(found_first);
// }
// } else {
// auto found_more = more_with_hash.find(found->second);
// if (found_more != more_with_hash.end()) {
// found_more->second.erase(cell);
// if (found_more->second.empty())
// more_with_hash.erase(found_more);
// }
// }
}
};
auto remember_cell = [&](Cell * cell, uint32_t hash) -> bool {
hashes[cell] = hash;
auto [it, inserted] = first_with_hash.emplace(hash, cell);
if (!inserted) {
auto &more = more_with_hash[hash];
if (more.empty())
more.emplace(it->second);
more.emplace(cell);
}
return !inserted;
};
int timestamp = INT_MIN;
bool did_something = true;
// A cell may have to go through a lot of collisions if the hash
// function is performing poorly, but it's a symptom of something bad
// beyond the user's control.
bool first = true;
while (did_something)
{
std::vector<RTLIL::Cell*> cells;
if (timestamp == INT_MIN) {
timestamp = module->next_timestamp();
cells.reserve(module->cells().size());
for (auto cell : module->cells()) {
if (!design->selected(module, cell))
continue;
if (cell->type.in(ID($meminit), ID($meminit_v2), ID($mem), ID($mem_v2))) {
// Ignore those for performance: meminit can have an excessively large port,
// mem can have an excessively large parameter holding the init data
continue;
}
if (cell->type == ID($scopeinfo))
continue;
if (mode_keepdc && has_dont_care_initval(cell))
continue;
if (!cell->known())
continue;
if (!mode_share_all && !ct.cell_known(cell->type))
continue;
cells.push_back(cell);
}
} else {
int next = module->next_timestamp();
// idict<Cell *> pending;
// for (auto cell : module->dirty_cells(timestamp))
// pending(cell);
// std::vector<const pool<RTLIL::PortBit> *> fanouts;
// int i = 0;
// while (i < GetSize(pending)) {
// Cell * cell = pending[i];
pool<Cell *> pending;
for (auto cell : module->dirty_cells(timestamp)) {
if (!design->selected(module, cell))
continue;
if (cell->type.in(ID($meminit), ID($meminit_v2), ID($mem), ID($mem_v2))) {
// Ignore those for performance: meminit can have an excessively large port,
// mem can have an excessively large parameter holding the init data
continue;
}
if (cell->type == ID($scopeinfo))
continue;
if (mode_keepdc && has_dont_care_initval(cell))
continue;
if (!cell->known())
continue;
if (!mode_share_all && !ct.cell_known(cell->type))
continue;
cells.push_back(cell);
}
timestamp = next;
}
log("scanning %d cells\n", GetSize(cells));
did_something = false;
if (!first)
for (auto cell : cells)
forget_cell(cell);
first = false;
pool<int32_t> buckets;
for (auto cell : cells) {
uint32_t hash = hash_cell_function(cell, Hasher()).yield();
if (remember_cell(cell, hash))
buckets.emplace(hash);
}
std::vector<std::pair<Cell *, Cell*>> pairs;
pool<Cell *> removed;
log("scanning %d/%d/%d buckets\n", GetSize(buckets), GetSize(more_with_hash), GetSize(first_with_hash));
for (auto hash : buckets) {
auto more = more_with_hash.at(hash);
for (int i = 0; i < GetSize(more); ++i) {
for (int j = i + 1; j < GetSize(more); ++j) {
Cell *other_cell = *more.element(j);
if (removed.count(other_cell))
continue;
Cell *cell = *more.element(i);
if (removed.count(cell))
break;
if (!compare_cell_parameters_and_connections(cell, other_cell))
continue;
if (cell->has_keep_attr()) {
if (other_cell->has_keep_attr())
continue;
std::swap(cell, other_cell);
}
removed.insert(cell);
pairs.emplace_back(other_cell, cell);
}
}
}
for (auto cell : removed)
forget_cell(cell);
int iter_count = 0;
for (auto [other_cell, cell] : pairs) {
did_something = true;
log_debug(" Cell `%s' is identical to cell `%s'.\n", cell->name, other_cell->name);
for (auto &[port, sig] : cell->connections()) {
if (cell->output(port)) {
// TODO why was this removed before?
RTLIL::SigSpec other_sig = other_cell->getPort(port);
Const init = initvals(other_sig);
initvals.remove_init(sig);
initvals.remove_init(other_sig);
module->connect(sig, other_cell->getPort(port));
assign_map.add(sig, other_sig);
initvals.set_init(other_sig, init);
}
}
log_debug(" Removing %s cell `%s' from module `%s'.\n", cell->type, cell->name, module->name);
module->remove(cell);
total_count++;
iter_count++;
}
log("removed %d cells\n", iter_count);
// hashes[cell] = hash;
// auto [found, inserted] = first_with_hash.emplace(hash, cell);
// if (inserted) {
// hashes.emplace(cell, hash);
// continue;
// }
// // if (check_candidate(found->second))
// // continue;
// auto found_more = more_with_hash[hash];
// // for (auto other_cell : found_more) {
// // if (check_candidate(other_cell))
// // continue;
// // }
// found_more.emplace(cell);
// hashes.emplace(cell, hash);
// // if (compare_cell_parameters_and_connections(found->second, cell)) {
// // }
// auto check_candidate = [&](Cell *other_cell) -> bool {
// if (!compare_cell_parameters_and_connections(other_cell, cell))
// return false;
// if (cell->has_keep_attr())
// if (other_cell->has_keep_attr())
// return false;
// forget_cell(cell);
// return true;
// };
// if (!check_candidate(found->second)) {
// }
// for ()
// auto [cell_in_map, inserted] = known_cells.insert(cell);
// if (!inserted) {
// // We've failed to insert since we already have an equivalent cell
// Cell* other_cell = *cell_in_map;
// if (cell->has_keep_attr()) {
// if (other_cell->has_keep_attr())
// continue;
// known_cells.erase(other_cell);
// known_cells.insert(cell);
// std::swap(other_cell, cell);
// }
// did_something = true;
// log_debug(" Cell `%s' is identical to cell `%s'.\n", cell->name, other_cell->name);
// for (auto &it : cell->connections()) {
// if (cell->output(it.first)) {
// RTLIL::SigSpec other_sig = other_cell->getPort(it.first);
// log_debug(" Redirecting output %s: %s = %s\n", it.first,
// log_signal(it.second), log_signal(other_sig));
// Const init = initvals(other_sig);
// initvals.remove_init(it.second);
// initvals.remove_init(other_sig);
// module->connect(RTLIL::SigSig(it.second, other_sig));
// assign_map.add(it.second, other_sig);
// initvals.set_init(other_sig, init);
// }
// }
// log_debug(" Removing %s cell `%s' from module `%s'.\n", cell->type, cell->name, module->name);
// module->remove(cell);
// total_count++;
// }
}
log_suppressed();
}
};
struct OptMergeIncPass : public Pass {
OptMergeIncPass() : Pass("opt_merge", "consolidate identical cells") { }
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" opt_merge_inc [options] [selection]\n");
log("\n");
log("This pass identifies cells with identical type and input signals. Such cells\n");
log("are then merged to one cell.\n");
log("\n");
log(" -nomux\n");
log(" Do not merge MUX cells.\n");
log("\n");
log(" -share_all\n");
log(" Operate on all cell types, not just built-in types.\n");
log("\n");
log(" -keepdc\n");
log(" Do not merge flipflops with don't-care bits in their initial value.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing OPT_MERGE_INC pass (detect identical cells).\n");
bool mode_nomux = false;
bool mode_share_all = false;
bool mode_keepdc = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
if (arg == "-nomux") {
mode_nomux = true;
continue;
}
if (arg == "-share_all") {
mode_share_all = true;
continue;
}
if (arg == "-keepdc") {
mode_keepdc = true;
continue;
}
break;
}
extra_args(args, argidx, design);
design->sigNormalize(true);
int total_count = 0;
for (auto module : design->selected_modules()) {
OptMergeIncWorker worker(design, module, mode_nomux, mode_share_all, mode_keepdc);
total_count += worker.total_count;
}
// design->sigNormalize(false);
if (total_count)
design->scratchpad_set_bool("opt.did_something", true);
log("Removed a total of %d cells.\n", total_count);
}
} OptMergeIncPass;
PRIVATE_NAMESPACE_END

View File

@ -101,11 +101,12 @@ struct PeepoptPass : public Pass {
{
did_something = true;
SigMap sigmap(module);
while (did_something)
{
did_something = false;
peepopt_pm pm(module);
peepopt_pm pm(module, &sigmap);
pm.setup(module->selected_cells());

View File

@ -147,7 +147,8 @@ struct WreduceWorker
SigSpec sig_d = mi.sigmap(cell->getPort(ID::D));
SigSpec sig_q = mi.sigmap(cell->getPort(ID::Q));
bool has_reset = false;
Const initval = initvals(sig_q), rst_value;
Const rst_value;
std::vector<State> initval = initvals(sig_q).to_bits();
int width_before = GetSize(sig_q);
@ -165,12 +166,16 @@ struct WreduceWorker
bool zero_ext = sig_d[GetSize(sig_d)-1] == State::S0;
bool sign_ext = !zero_ext;
if (mi.auto_reload_module)
mi.reload_module();
for (int i = GetSize(sig_q)-1; i >= 0; i--)
{
if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || (!config->keepdc && initval[i] == State::Sx)) &&
(!has_reset || i >= GetSize(rst_value) || rst_value[i] == State::S0 || (!config->keepdc && rst_value[i] == State::Sx))) {
module->connect(sig_q[i], State::S0);
initvals.remove_init(sig_q[i]);
initval.erase(initval.begin() + i);
sig_d.remove(i);
sig_q.remove(i);
continue;
@ -180,6 +185,7 @@ struct WreduceWorker
(!has_reset || i >= GetSize(rst_value) || (rst_value[i] == rst_value[i-1] && (!config->keepdc || rst_value[i] != State::Sx)))) {
module->connect(sig_q[i], sig_q[i-1]);
initvals.remove_init(sig_q[i]);
initval.erase(initval.begin() + i);
sig_d.remove(i);
sig_q.remove(i);
continue;
@ -190,6 +196,7 @@ struct WreduceWorker
return;
if (!info->is_output && GetSize(info->ports) == 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) {
initvals.remove_init(sig_q[i]);
initval.erase(initval.begin() + i);
sig_d.remove(i);
sig_q.remove(i);
zero_ext = false;
@ -229,6 +236,7 @@ struct WreduceWorker
cell->setPort(ID::D, sig_d);
cell->setPort(ID::Q, sig_q);
initvals.set_init(cell->getPort(ID::Q), initval);
cell->fixup_parameters();
}
@ -571,6 +579,9 @@ struct WreducePass : public Pass {
}
extra_args(args, argidx, design);
// TODO Disabled signorm because swap_names breaks fanout logic
design->sigNormalize(false);
for (auto module : design->selected_modules())
{
if (module->has_processes_warn())

View File

@ -85,7 +85,8 @@ void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const
if (timeout++ > 10000)
log_error("pmgen generator is stuck: 10000 iterations with no matching module generated.\n");
pm matcher(mod, mod->cells());
SigMap sigmap(mod);
pm matcher(mod, &sigmap, mod->cells());
matcher.rng(1);
matcher.rngseed += modcnt;

View File

@ -361,7 +361,7 @@ with open(outfile, "w") as f:
print("struct {}_pm {{".format(prefix), file=f)
print(" Module *module;", file=f)
print(" SigMap sigmap;", file=f)
print(" SigMap *sigmap;", file=f)
print(" std::function<void()> on_accept;", file=f)
print(" bool setup_done;", file=f)
print(" bool generate_mode;", file=f)
@ -423,7 +423,7 @@ with open(outfile, "w") as f:
print("", file=f)
print(" void add_siguser(const SigSpec &sig, Cell *cell) {", file=f)
print(" for (auto bit : sigmap(sig)) {", file=f)
print(" for (auto bit : (*sigmap)(sig)) {", file=f)
print(" if (bit.wire == nullptr) continue;", file=f)
print(" sigusers[bit].insert(cell);", file=f)
print(" }", file=f)
@ -453,12 +453,12 @@ with open(outfile, "w") as f:
print(" SigSpec port(Cell *cell, IdString portname) {", file=f)
print(" try {", file=f)
print(" return sigmap(cell->getPort(portname));", file=f)
print(" return (*sigmap)(cell->getPort(portname));", file=f)
print(" } catch(std::out_of_range&) { log_error(\"Accessing non existing port %s\\n\",portname); }", file=f)
print(" }", file=f)
print("", file=f)
print(" SigSpec port(Cell *cell, IdString portname, const SigSpec& defval) {", file=f)
print(" return sigmap(cell->connections_.at(portname, defval));", file=f)
print(" return (*sigmap)(cell->connections_.at(portname, defval));", file=f)
print(" }", file=f)
print("", file=f)
@ -475,21 +475,21 @@ with open(outfile, "w") as f:
print(" int nusers(const SigSpec &sig) {", file=f)
print(" pool<Cell*> users;", file=f)
print(" for (auto bit : sigmap(sig))", file=f)
print(" for (auto bit : (*sigmap)(sig))", file=f)
print(" for (auto user : sigusers[bit])", file=f)
print(" users.insert(user);", file=f)
print(" return GetSize(users);", file=f)
print(" }", file=f)
print("", file=f)
print(" {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f)
print(" module(module), sigmap(module), setup_done(false), generate_mode(false), rngseed(12345678) {", file=f)
print(" {}_pm(Module *module, SigMap *map, const vector<Cell*> &cells) :".format(prefix), file=f)
print(" module(module), sigmap(map), setup_done(false), generate_mode(false), rngseed(12345678) {", file=f)
print(" setup(cells);", file=f)
print(" }", file=f)
print("", file=f)
print(" {}_pm(Module *module) :".format(prefix), file=f)
print(" module(module), sigmap(module), setup_done(false), generate_mode(false), rngseed(12345678) {", file=f)
print(" {}_pm(Module *module, SigMap *map) :".format(prefix), file=f)
print(" module(module), sigmap(map), setup_done(false), generate_mode(false), rngseed(12345678) {", file=f)
print(" }", file=f)
print("", file=f)

View File

@ -163,8 +163,10 @@ struct TestPmgenPass : public Pass {
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
while (test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_chain)) {}
for (auto module : design->selected_modules()) {
SigMap sigmap(module);
while (test_pmgen_pm(module, &sigmap, module->selected_cells()).run_reduce(reduce_chain)) {}
}
}
void execute_reduce_tree(std::vector<std::string> args, RTLIL::Design *design)
@ -182,8 +184,10 @@ struct TestPmgenPass : public Pass {
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_tree);
for (auto module : design->selected_modules()) {
SigMap sigmap(module);
test_pmgen_pm(module, &sigmap, module->selected_cells()).run_reduce(reduce_tree);
}
}
void execute_eqpmux(std::vector<std::string> args, RTLIL::Design *design)
@ -201,8 +205,10 @@ struct TestPmgenPass : public Pass {
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
test_pmgen_pm(module, module->selected_cells()).run_eqpmux(opt_eqpmux);
for (auto module : design->selected_modules()) {
SigMap sigmap(module);
test_pmgen_pm(module, &sigmap, module->selected_cells()).run_eqpmux(opt_eqpmux);
}
}
void execute_generate(std::vector<std::string> args, RTLIL::Design *design)

View File

@ -79,6 +79,9 @@ struct CutpointPass : public Pass {
}
extra_args(args, argidx, design);
// TODO Disabled signorm because swap_names breaks fanout logic
design->sigNormalize(false);
if (flag_blackbox) {
if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n");

View File

@ -827,6 +827,8 @@ struct FreducePass : public Pass {
break;
}
extra_args(args, argidx, design);
// TODO disable signorm due to rewrite_sigspecs assert
design->sigNormalize(false);
int bitcount = 0;
for (auto module : design->selected_modules()) {

View File

@ -1893,6 +1893,10 @@ struct Abc9OpsPass : public Pass {
}
extra_args(args, argidx, design);
// TODO Disabled signorm because swap_names breaks fanout logic
// TODO disable signorm due to rewrite_sigspecs assert
design->sigNormalize(false);
if (!valid)
log_cmd_error("At least one of -check, -break_scc, -prep_{delays,xaiger,dff[123],lut,box}, -write_{lut,box}, -reintegrate, -{replace,restore}_zbufs must be specified.\n");

View File

@ -94,8 +94,11 @@ struct BufnormPass : public Pass {
log(" -update\n");
log(" Enter 'buffered-normalized mode' and (re-)normalize.\n");
log("\n");
log(" -signorm\n");
log(" Enter 'signal-normalized mode' and (re-)normalize.\n");
log("\n");
log(" -reset\n");
log(" Leave 'buffered-normalized mode' without changing the netlist.\n");
log(" Leave '{buffered,signal}-normalized mode' without changing the netlist.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
@ -116,6 +119,7 @@ struct BufnormPass : public Pass {
bool conn_mode = false;
bool update_mode = false;
bool signorm_mode = false;
bool reset_mode = false;
bool got_non_update_reset_opt = false;
@ -198,6 +202,10 @@ struct BufnormPass : public Pass {
update_mode = true;
continue;
}
if (arg == "-signorm") {
signorm_mode = true;
continue;
}
if (arg == "-reset") {
reset_mode = true;
continue;
@ -221,6 +229,9 @@ struct BufnormPass : public Pass {
if (update_mode && got_non_update_reset_opt)
log_cmd_error("Option -update can't be mixed with other options.\n");
if (signorm_mode && got_non_update_reset_opt)
log_cmd_error("Option -signorm can't be mixed with other options.\n");
if (reset_mode && got_non_update_reset_opt)
log_cmd_error("Option -reset can't be mixed with other options.\n");
@ -229,8 +240,14 @@ struct BufnormPass : public Pass {
return;
}
if (signorm_mode) {
design->sigNormalize();
return;
}
if (reset_mode) {
design->bufNormalize(false);
design->sigNormalize(false);
return;
}

View File

@ -110,6 +110,9 @@ struct ClkbufmapPass : public Pass {
extra_args(args, argidx, design);
}
// TODO Disabled signorm because swap_names breaks fanout logic
design->sigNormalize(false);
if (buf_celltype.empty() && inpad_celltype.empty())
log_error("Either the -buf option or -inpad option is required.\n");

View File

@ -74,6 +74,9 @@ struct ConstmapPass : public Pass {
if (celltype.empty())
log_cmd_error("Missing required option -cell.\n");
// TODO disable signorm due to rewrite_sigspecs assert
design->sigNormalize(false);
if (design->has(celltype)) {
Module *existing = design->module(celltype);
bool has_port = false;

View File

@ -105,6 +105,9 @@ struct HilomapPass : public Pass {
}
extra_args(args, argidx, design);
// TODO disable signorm due to rewrite_sigspecs assert
design->sigNormalize(false);
for (auto mod : design->selected_modules())
{
module = mod;

View File

@ -186,6 +186,9 @@ struct IopadmapPass : public Pass {
}
extra_args(args, argidx, design);
// TODO Disabled signorm because swap_names breaks fanout logic
design->sigNormalize(false);
if (!inpad_portname_pad.empty())
ignore.insert(make_pair(RTLIL::escape_id(inpad_celltype), RTLIL::escape_id(inpad_portname_pad)));
if (!outpad_portname_pad.empty())

View File

@ -150,6 +150,7 @@ struct TechmapWorker
log("\n");
if (autoproc_mode) {
Pass::call_on_module(tpl->design, tpl, "proc");
tpl->design->sigNormalize(false);
log_assert(GetSize(tpl->processes) == 0);
} else
log_error("Technology map yielded processes -> this is not supported (use -autoproc to run 'proc' automatically).\n");
@ -551,6 +552,7 @@ struct TechmapWorker
log("Running \"%s\" on wrapper %s.\n", cmd_string, log_id(extmapper_module));
mkdebug.on();
Pass::call_on_module(extmapper_design, extmapper_module, cmd_string);
extmapper_design->sigNormalize(false);
log_continue = true;
}
}
@ -850,6 +852,7 @@ struct TechmapWorker
}
Pass::call_on_module(map, tpl, cmd_string);
map->sigNormalize(false);
log_assert(!strncmp(q, "_TECHMAP_DO_", 12));
std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12);
@ -1144,6 +1147,8 @@ struct TechmapPass : public Pass {
log_header(design, "Executing TECHMAP pass (map to technology primitives).\n");
log_push();
// TODO not sure why signorm breaks on us here yet
design->sigNormalize(false);
TechmapWorker worker;
simplemap_get_mappers(worker.simplemap_mappers);

View File

@ -1976,7 +1976,7 @@ endmodule
// --------------------------------------------------------
//* group spec
module \$specrule (EN_SRC, EN_DST, SRC, DST);
module \$specrule (SRC_EN, DST_EN, SRC, DST);
parameter TYPE = "";
parameter T_LIMIT = 0;
@ -1991,7 +1991,7 @@ parameter SRC_POL = 0;
parameter DST_PEN = 0;
parameter DST_POL = 0;
input EN_SRC, EN_DST;
input SRC_EN, DST_EN;
input [SRC_WIDTH-1:0] SRC;
input [DST_WIDTH-1:0] DST;

View File

@ -121,7 +121,7 @@ module MUX2_LUT5 (O, I0, I1, S0);
(S0 => O) = (486, 680);
endspecify
MUX2 mux2_lut5 (O, I0, I1, S0);
MUX2 mux2_lut5 (.O(O), .I0(I0), .I1(I1), .S0(S0));
endmodule
module MUX2_LUT6 (O, I0, I1, S0);
@ -135,7 +135,7 @@ module MUX2_LUT6 (O, I0, I1, S0);
(S0 => O) = (478, 723);
endspecify
MUX2 mux2_lut6 (O, I0, I1, S0);
MUX2 mux2_lut6 (.O(O), .I0(I0), .I1(I1), .S0(S0));
endmodule
module MUX2_LUT7 (O, I0, I1, S0);
@ -149,7 +149,7 @@ module MUX2_LUT7 (O, I0, I1, S0);
(S0 => O) = (478, 723);
endspecify
MUX2 mux2_lut7 (O, I0, I1, S0);
MUX2 mux2_lut7 (.O(O), .I0(I0), .I1(I1), .S0(S0));
endmodule
module MUX2_LUT8 (O, I0, I1, S0);
@ -163,7 +163,7 @@ module MUX2_LUT8 (O, I0, I1, S0);
(S0 => O) = (478, 723);
endspecify
MUX2 mux2_lut8 (O, I0, I1, S0);
MUX2 mux2_lut8 (.O(O), .I0(I0), .I1(I1), .S0(S0));
endmodule
(* abc9_flop, lib_whitebox *)

View File

@ -311,8 +311,13 @@ struct Ice40DspPass : public Pass {
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
ice40_dsp_pm(module, module->selected_cells()).run_ice40_dsp(create_ice40_dsp);
// TODO Disabled signorm because swap_names breaks fanout logic
design->sigNormalize(false);
for (auto module : design->selected_modules()) {
SigMap sigmap(module);
ice40_dsp_pm(module, &sigmap, module->selected_cells()).run_ice40_dsp(create_ice40_dsp);
}
}
} Ice40DspPass;

View File

@ -48,7 +48,7 @@ void create_ice40_wrapcarry(ice40_wrapcarry_pm &pm)
cell->setPort(ID(I0), st.lut->getPort(ID(I0)));
auto I3 = st.lut->getPort(ID(I3));
if (pm.sigmap(CI) == pm.sigmap(I3)) {
if ((*pm.sigmap)(CI) == (*pm.sigmap)(I3)) {
cell->setParam(ID(I3_IS_CI), State::S1);
I3 = State::Sx;
}
@ -108,10 +108,14 @@ struct Ice40WrapCarryPass : public Pass {
}
extra_args(args, argidx, design);
// TODO Disabled signorm because swap_names breaks fanout logic
design->sigNormalize(false);
for (auto module : design->selected_modules()) {
if (!unwrap)
ice40_wrapcarry_pm(module, module->selected_cells()).run_ice40_wrapcarry(create_ice40_wrapcarry);
else {
if (!unwrap) {
SigMap sigmap(module);
ice40_wrapcarry_pm(module, &sigmap, module->selected_cells()).run_ice40_wrapcarry(create_ice40_wrapcarry);
} else {
for (auto cell : module->selected_cells()) {
if (cell->type != ID($__ICE40_CARRY_WRAPPER))
continue;

View File

@ -379,6 +379,7 @@ struct SynthIce40Pass : public ScriptPass
run("techmap");
else {
run("ice40_wrapcarry");
run("read_verilog " + define + " -icells -lib -specify +/ice40/abc9_model.v");
run("techmap -map +/techmap.v -map +/ice40/arith_map.v");
}
run("opt -fast");
@ -415,7 +416,6 @@ struct SynthIce40Pass : public ScriptPass
}
if (!noabc) {
if (abc9) {
run("read_verilog " + define + " -icells -lib -specify +/ice40/abc9_model.v");
std::string abc9_opts;
std::string k = "synth_ice40.abc9.W";
if (active_design && active_design->scratchpad.count(k))

View File

@ -89,7 +89,7 @@ void microchip_dsp_pack(microchip_dsp_pm &pm)
auto f = [&pm, cell](SigSpec &A, Cell *ff, IdString ceport, IdString rstport, IdString bypass) {
// input/output ports
SigSpec D = ff->getPort(ID::D);
SigSpec Q = pm.sigmap(ff->getPort(ID::Q));
SigSpec Q = (*pm.sigmap)(ff->getPort(ID::Q));
if (!A.empty())
A.replace(Q, D);
@ -206,7 +206,7 @@ void microchip_dsp_packC(microchip_dsp_CREG_pm &pm)
auto f = [&pm, cell](SigSpec &A, Cell *ff, IdString ceport, IdString rstport, IdString bypass) {
// input/output ports
SigSpec D = ff->getPort(ID::D);
SigSpec Q = pm.sigmap(ff->getPort(ID::Q));
SigSpec Q = (*pm.sigmap)(ff->getPort(ID::Q));
if (!A.empty())
A.replace(Q, D);
if (rstport != IdString()) {
@ -318,8 +318,11 @@ struct MicrochipDspPass : public Pass {
}
extra_args(args, argidx, design);
// TODO deduplicate all this noise with xilinx_dsp.cc
for (auto module : design->selected_modules()) {
SigMap sigmap(module);
if (design->scratchpad_get_bool("microchip_dsp.multonly"))
continue;
@ -333,7 +336,7 @@ struct MicrochipDspPass : public Pass {
// check for an accumulator pattern based on whether
// a post-adder and PREG are both present AND
// if PREG feeds into this post-adder.
microchip_dsp_pm pm(module, module->selected_cells());
microchip_dsp_pm pm(module, &sigmap, module->selected_cells());
pm.run_microchip_dsp_pack(microchip_dsp_pack);
}
@ -346,13 +349,13 @@ struct MicrochipDspPass : public Pass {
// PREG of an upstream DSP that had not been visited
// yet
{
microchip_dsp_CREG_pm pm(module, module->selected_cells());
microchip_dsp_CREG_pm pm(module, &sigmap, module->selected_cells());
pm.run_microchip_dsp_packC(microchip_dsp_packC);
}
// Lastly, identify and utilise PCOUT -> PCIN chains
{
microchip_dsp_cascade_pm pm(module, module->selected_cells());
microchip_dsp_cascade_pm pm(module, &sigmap, module->selected_cells());
pm.run_microchip_dsp_cascade();
}
}

View File

@ -205,8 +205,10 @@ struct QlDspMacc : public Pass {
}
extra_args(a_Args, argidx, a_Design);
for (auto module : a_Design->selected_modules())
ql_dsp_macc_pm(module, module->selected_cells()).run_ql_dsp_macc(create_ql_macc_dsp);
for (auto module : a_Design->selected_modules()) {
SigMap sigmap(module);
ql_dsp_macc_pm(module, &sigmap, module->selected_cells()).run_ql_dsp_macc(create_ql_macc_dsp);
}
}
} QlDspMacc;

View File

@ -24,6 +24,9 @@ struct QlIoffPass : public Pass {
{
log_header(design, "Executing QL_IOFF pass.\n");
// TODO Disabled signorm because swap_names breaks fanout logic
design->sigNormalize(false);
ModWalker modwalker(design);
Module *module = design->top_module();
if (!module)

View File

@ -64,18 +64,61 @@ static Cell* addDsp(Module *module) {
return cell;
}
void xilinx_simd_pack(Module *module, const std::vector<Cell*> &selected_cells)
SigPool simd_signals(Module *module, SigMap* sigmap)
{
SigPool simd_signals;
// Mark representatives of wires that have the attribute
for (auto wire : module->wires()) {
SigSpec reps = (*sigmap)(wire);
log_assert(reps.size() == wire->width);
for (int i = 0; i < reps.size(); i++) {
auto bit = reps[i];
auto src_bit = SigBit(wire, i);
if (src_bit.is_wire() && src_bit.wire->has_attribute(ID::use_dsp)) {
if (src_bit.wire->get_strpool_attribute(ID::use_dsp).count("simd")) {
simd_signals.add(bit);
}
}
}
}
// Also mark all aliases of those representatives
for (auto wire : module->wires()) {
SigSpec reps = (*sigmap)(wire);
log_assert(reps.size() == wire->width);
for (int i = 0; i < reps.size(); i++) {
auto bit = reps[i];
auto src_bit = SigBit(wire, i);
if (simd_signals.check(bit)) {
simd_signals.add(src_bit);
}
}
}
// This seems silly, but that's generalized RTLIL for you!
return simd_signals;
}
bool is_allowed(SigSpec& sig, SigPool& allowed_bits)
{
for (auto bit : sig.bits()) {
if (!allowed_bits.check(bit)) {
return false;
}
}
return true;
}
void xilinx_simd_pack(Module *module, SigMap* sigmap, const std::vector<Cell*> &selected_cells)
{
std::deque<Cell*> simd12_add, simd12_sub;
std::deque<Cell*> simd24_add, simd24_sub;
SigPool simds = simd_signals(module, sigmap);
for (auto cell : selected_cells) {
if (!cell->type.in(ID($add), ID($sub)))
continue;
SigSpec Y = cell->getPort(ID::Y);
if (!Y.is_chunk())
continue;
if (!Y.as_chunk().wire->get_strpool_attribute(ID(use_dsp)).count("simd"))
if (!is_allowed(Y, simds))
continue;
if (GetSize(Y) > 25)
continue;
@ -372,7 +415,7 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm)
auto f = [&pm,cell](SigSpec &A, Cell* ff, IdString ceport, IdString rstport) {
SigSpec D = ff->getPort(ID::D);
SigSpec Q = pm.sigmap(ff->getPort(ID::Q));
SigSpec Q = (*pm.sigmap)(ff->getPort(ID::Q));
if (!A.empty())
A.replace(Q, D);
if (rstport != IdString()) {
@ -559,7 +602,7 @@ void xilinx_dsp48a_pack(xilinx_dsp48a_pm &pm)
auto f = [&pm,cell](SigSpec &A, Cell* ff, IdString ceport, IdString rstport) {
SigSpec D = ff->getPort(ID::D);
SigSpec Q = pm.sigmap(ff->getPort(ID::Q));
SigSpec Q = (*pm.sigmap)(ff->getPort(ID::Q));
if (!A.empty())
A.replace(Q, D);
if (rstport != IdString()) {
@ -682,7 +725,7 @@ void xilinx_dsp_packC(xilinx_dsp_CREG_pm &pm)
auto f = [&pm,cell](SigSpec &A, Cell* ff, IdString ceport, IdString rstport) {
SigSpec D = ff->getPort(ID::D);
SigSpec Q = pm.sigmap(ff->getPort(ID::Q));
SigSpec Q = (*pm.sigmap)(ff->getPort(ID::Q));
if (!A.empty())
A.replace(Q, D);
if (rstport != IdString()) {
@ -801,19 +844,20 @@ struct XilinxDspPass : public Pass {
if (design->scratchpad_get_bool("xilinx_dsp.multonly"))
continue;
SigMap sigmap(module);
// Experimental feature: pack $add/$sub cells with
// (* use_dsp48="simd" *) into DSP48E1's using its
// SIMD feature
if (family == "xc7")
xilinx_simd_pack(module, module->selected_cells());
xilinx_simd_pack(module, &sigmap, module->selected_cells());
// Match for all features ([ABDMP][12]?REG, pre-adder,
// post-adder, pattern detector, etc.) except for CREG
if (family == "xc7") {
xilinx_dsp_pm pm(module, module->selected_cells());
xilinx_dsp_pm pm(module, &sigmap, module->selected_cells());
pm.run_xilinx_dsp_pack(xilinx_dsp_pack);
} else if (family == "xc6s" || family == "xc3sda") {
xilinx_dsp48a_pm pm(module, module->selected_cells());
xilinx_dsp48a_pm pm(module, &sigmap, module->selected_cells());
pm.run_xilinx_dsp48a_pack(xilinx_dsp48a_pack);
}
// Separating out CREG packing is necessary since there
@ -825,14 +869,14 @@ struct XilinxDspPass : public Pass {
// PREG of an upstream DSP that had not been visited
// yet
{
xilinx_dsp_CREG_pm pm(module, module->selected_cells());
xilinx_dsp_CREG_pm pm(module, &sigmap, module->selected_cells());
pm.run_xilinx_dsp_packC(xilinx_dsp_packC);
}
// Lastly, identify and utilise PCOUT -> PCIN,
// ACOUT -> ACIN, and BCOUT-> BCIN dedicated cascade
// chains
{
xilinx_dsp_cascade_pm pm(module, module->selected_cells());
xilinx_dsp_cascade_pm pm(module, &sigmap, module->selected_cells());
pm.run_xilinx_dsp_cascade();
}
}

View File

@ -237,11 +237,15 @@ struct XilinxSrlPass : public Pass {
}
extra_args(args, argidx, design);
// TODO Disabled signorm because swap_names breaks fanout logic
design->sigNormalize(false);
if (!fixed && !variable)
log_cmd_error("'-fixed' and/or '-variable' must be specified.\n");
for (auto module : design->selected_modules()) {
auto pm = xilinx_srl_pm(module, module->selected_cells());
SigMap sigmap(module);
auto pm = xilinx_srl_pm(module, &sigmap, module->selected_cells());
pm.ud_fixed.minlen = minlen;
pm.ud_variable.minlen = minlen;

View File

@ -4,7 +4,9 @@ proc
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-min 11 t:LUT4
select -assert-count 2 t:PFUMX
select -assert-none t:LUT4 t:PFUMX %% t:* %D
# select -assert-min 25 t:LUT4
# select -assert-max 26 t:LUT4
# select -assert-count 10 t:PFUMX
# select -assert-count 6 t:L6MUX21
select -assert-none t:LUT* t:PFUMX t:L6MUX21 %% t:* %D

View File

@ -11,8 +11,9 @@ sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs mite
design -load postopt
cd lutram_1w1r
select -assert-count 28 t:LUT4
select -assert-count 8 t:PFUMX
# select -assert-count 8 t:L6MUX21
# select -assert-count 36 t:LUT4
# select -assert-count 16 t:PFUMX
select -assert-count 8 t:TRELLIS_DPR16X4
select -assert-count 8 t:TRELLIS_FF
select -assert-none t:LUT4 t:PFUMX t:TRELLIS_DPR16X4 t:TRELLIS_FF %% t:* %D
select -assert-none t:L6MUX21 t:LUT* t:PFUMX t:TRELLIS_DPR16X4 t:TRELLIS_FF %% t:* %D

View File

@ -5,9 +5,10 @@ equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 1 t:LUT1
select -assert-count 6 t:LUT2
select -assert-count 2 t:LUT3
# select -assert-count 1 t:LUT1
# select -assert-count 6 t:LUT2
# select -assert-count 2 t:LUT3
# select -assert-count 0 t:LUT4
select -assert-count 8 t:IBUF
select -assert-count 10 t:OBUF
select -assert-none t:LUT1 t:LUT2 t:LUT3 t:IBUF t:OBUF %% t:* %D
select -assert-none t:LUT* t:IBUF t:OBUF %% t:* %D

View File

@ -6,11 +6,11 @@ proc
equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd mux2 # Constrain all select calls below inside the top module
select -assert-count 1 t:LUT3
# select -assert-count 1 t:LUT3
select -assert-count 3 t:IBUF
select -assert-count 1 t:OBUF
select -assert-none t:LUT3 t:IBUF t:OBUF %% t:* %D
select -assert-none t:LUT* t:IBUF t:OBUF %% t:* %D
design -load read
hierarchy -top mux4
@ -18,12 +18,12 @@ proc
equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd mux4 # Constrain all select calls below inside the top module
select -assert-count 3 t:LUT*
select -assert-count 1 t:MUX2_LUT5
# select -assert-count 3 t:LUT*
# select -assert-count 1 t:MUX2_LUT*
select -assert-count 6 t:IBUF
select -assert-count 1 t:OBUF
select -assert-none t:LUT* t:MUX2_LUT5 t:IBUF t:OBUF %% t:* %D
select -assert-none t:LUT* t:MUX2_LUT* t:IBUF t:OBUF %% t:* %D
design -load read
hierarchy -top mux8
@ -31,13 +31,15 @@ proc
equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd mux8 # Constrain all select calls below inside the top module
select -assert-count 1 t:LUT3
select -assert-count 5 t:LUT4
select -assert-count 1 t:MUX2_LUT5
# select -assert-count 0 t:LUT1
# select -assert-count 1 t:LUT3
# select -assert-count 5 t:LUT4
# select -assert-count 1 t:MUX2_LUT*
select -assert-count 11 t:IBUF
select -assert-count 1 t:OBUF
# select -assert-count 0 t:GND
select -assert-none t:LUT* t:MUX2_LUT5 t:IBUF t:OBUF %% t:* %D
select -assert-none t:LUT* t:MUX2_LUT* t:IBUF t:OBUF t:GND %% t:* %D
design -load read
hierarchy -top mux16

View File

@ -5,8 +5,8 @@ equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cycl
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 1 t:MISTRAL_NOT
select -assert-count 6 t:MISTRAL_ALUT2
select -assert-count 2 t:MISTRAL_ALUT3
select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 %% t:* %D
# select -assert-count 1 t:MISTRAL_NOT
# select -assert-count 6 t:MISTRAL_ALUT2
# select -assert-count 2 t:MISTRAL_ALUT3
select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT* %% t:* %D

View File

@ -7,8 +7,8 @@ equiv_opt -assert -map +/nexus/cells_sim.v synth_nexus # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
stat
select -assert-count 10 t:LUT4
select -assert-none t:IB t:OB t:VLO t:LUT4 %% t:* %D
# select -assert-count 10 t:LUT4
select -assert-none t:IB t:OB t:VLO t:LUT* %% t:* %D
design -load orig
@ -16,6 +16,6 @@ equiv_opt -assert -map +/nexus/cells_sim.v synth_nexus -abc9 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
stat
select -assert-count 7 t:LUT4
select -assert-count 2 t:WIDEFN9
select -assert-none t:IB t:OB t:VLO t:LUT4 t:WIDEFN9 %% t:* %D
# select -assert-count 6 t:LUT4
# select -assert-count 4 t:WIDEFN9
select -assert-none t:IB t:OB t:VLO t:LUT* t:WIDEFN9 %% t:* %D

View File

@ -1,6 +1,10 @@
read_verilog xilinx_srl.v
read_verilog -icells xilinx_srl.v
design -save read
blackbox
select =*
design -save boxes
design -reset
design -load read
design -copy-to model $__XILINX_SHREG_
hierarchy -top xilinx_srl_static_test
prep
@ -35,12 +39,12 @@ sat -verify -prove-asserts -show-ports -seq 5 miter
##########
design -load read
design -copy-to model $__XILINX_SHREG_
hierarchy -top xilinx_srl_variable_test
prep
design -save gold
xilinx_srl -variable
design -copy-from boxes =$__XILINX_SHREG_
opt
#stat
@ -54,7 +58,7 @@ design -stash gate
design -import gold -as gold
design -import gate -as gate
design -copy-from model -as $__XILINX_SHREG_ \$__XILINX_SHREG_
design -copy-from model -as gate.$__XILINX_SHREG_ \$__XILINX_SHREG_
prep
miter -equiv -flatten -make_assert -make_outputs gold gate miter

View File

@ -337,7 +337,7 @@ rtlil_cells = [
# ("tribuf", ["A", "EN", "Y"]),
# ("specify2", ["EN", "SRC", "DST"]),
# ("specify3", ["EN", "SRC", "DST", "DAT"]),
# ("specrule", ["EN_SRC", "EN_DST", "SRC", "DST"]),
# ("specrule", ["SRC_EN", "DST_EN", "SRC", "DST"]),
BWCell("bweqx", [10, 16, 40]),
BWCell("bwmux", [10, 16, 40]),
FFCell("ff", [10, 20, 40]),

View File

@ -8,12 +8,11 @@ copy gold fine
cd coarse
opt_expr
select -assert-none c:*
select -assert-none c:* t:$input_port %d
cd fine
opt_expr
select -assert-none c:*
select -assert-none c:* t:$input_port %d
cd
miter -equiv -flatten -make_assert -make_outputs coarse fine miter
sat -verify -prove-asserts -show-ports miter

View File

@ -1,42 +1,44 @@
read_rtlil <<EOT
# TODO re-enable when https://github.com/YosysHQ/yosys/issues/5735 fixed
module \mod
wire input 1 \clk
attribute \init 2'00
wire width 2 $q1
attribute \init 2'00
wire width 2 $q2
wire output 2 width 4 \q
cell $dff $ff1
parameter \CLK_POLARITY 1'1
parameter \WIDTH 1
connect \CLK \clk
connect \D 1'0
connect \Q $q1 [0]
end
cell $dff $ff2
parameter \CLK_POLARITY 1'1
parameter \WIDTH 1
connect \CLK \clk
connect \D 1'0
connect \Q $q2 [0]
end
cell $dff $ff3
parameter \CLK_POLARITY 1'1
parameter \WIDTH 2
connect \CLK \clk
connect \D 2'00
connect \Q { $q1 [1] $q2 [1] }
end
connect \q [0] $q1 [0]
connect \q [1] $q2 [0]
connect \q [2] $q1 [1]
connect \q [3] $q2 [1]
end
# read_rtlil <<EOT
EOT
# module \mod
# wire input 1 \clk
# attribute \init 2'00
# wire width 2 $q1
# attribute \init 2'00
# wire width 2 $q2
# wire output 2 width 4 \q
# cell $dff $ff1
# parameter \CLK_POLARITY 1'1
# parameter \WIDTH 1
# connect \CLK \clk
# connect \D 1'0
# connect \Q $q1 [0]
# end
# cell $dff $ff2
# parameter \CLK_POLARITY 1'1
# parameter \WIDTH 1
# connect \CLK \clk
# connect \D 1'0
# connect \Q $q2 [0]
# end
# cell $dff $ff3
# parameter \CLK_POLARITY 1'1
# parameter \WIDTH 2
# connect \CLK \clk
# connect \D 2'00
# connect \Q { $q1 [1] $q2 [1] }
# end
# connect \q [0] $q1 [0]
# connect \q [1] $q2 [0]
# connect \q [2] $q1 [1]
# connect \q [3] $q2 [1]
# end
opt_clean
opt_merge
opt_dff
opt_clean
# EOT
# opt_clean
# opt_merge
# opt_dff
# opt_clean

View File

@ -19,4 +19,4 @@ EOT
synth
check -assert -initdrv
select -assert-count 1 a:init=2'b0x
select -assert-count 1 a:init=1'b0

View File

@ -9,7 +9,7 @@ proc
equiv_opt -assert opt
design -load postopt
select -assert-count 1 t:$dffe r:WIDTH=2 %i
select -assert-count 0 t:$dffe %% t:* %D
select -assert-count 0 t:$dffe %% t:* %D t:$input_port %d
####################
@ -25,7 +25,7 @@ equiv_opt -assert opt
design -load postopt
wreduce
select -assert-count 1 t:$dffe r:WIDTH=2 %i
select -assert-count 0 t:$dffe %% t:* %D
select -assert-count 0 t:$dffe %% t:* %D t:$input_port %d
###################
@ -40,7 +40,7 @@ proc
equiv_opt -assert opt
design -load postopt
select -assert-count 1 t:$dffe r:WIDTH=2 %i
select -assert-count 0 t:$dffe %% t:* %D
select -assert-count 0 t:$dffe %% t:* %D t:$input_port %d
###################
@ -54,8 +54,9 @@ EOT
proc
equiv_opt -assert opt
design -load postopt
dump
select -assert-count 1 t:$dffe r:WIDTH=4 %i
select -assert-count 0 t:$dffe %% t:* %D
select -assert-count 0 t:$dffe %% t:* %D t:$input_port %d
####################
@ -71,7 +72,7 @@ equiv_opt -assert opt
design -load postopt
wreduce
select -assert-count 1 t:$sdffe r:WIDTH=2 %i
select -assert-count 0 t:$sdffe %% t:* %D
select -assert-count 0 t:$sdffe %% t:* %D t:$input_port %d
####################
@ -90,7 +91,7 @@ equiv_opt -assert opt
design -load postopt
wreduce
select -assert-count 1 t:$sdffe r:WIDTH=2 %i
select -assert-count 0 t:$sdffe %% t:* %D
select -assert-count 0 t:$sdffe %% t:* %D t:$input_port %d
####################
@ -126,4 +127,4 @@ sat -tempinduct -verify -prove-asserts -show-ports miter
design -load gate
select -assert-count 1 t:$sdffe r:WIDTH=3 %i
select -assert-count 0 t:$sdffe %% t:* %D
select -assert-count 0 t:$sdffe %% t:* %D t:$input_port %d

View File

@ -8,7 +8,7 @@ alumacc
equiv_opt -assert opt_expr -fine
design -load postopt
select -assert-count 1 t:$pos
select -assert-none t:$pos t:* %D
select -assert-none t:$pos t:* %D t:$input_port %d
design -reset
@ -20,7 +20,7 @@ EOT
alumacc
select -assert-count 1 t:$alu
select -assert-none t:$alu t:* %D
select -assert-none t:$alu t:* %D t:$input_port %d
design -reset
@ -33,7 +33,7 @@ EOT
equiv_opt -assert opt_expr -fine
design -load postopt
select -assert-count 1 t:$pos
select -assert-none t:$pos t:* %D
select -assert-none t:$pos t:* %D t:$input_port %d
design -reset
@ -46,7 +46,7 @@ EOT
equiv_opt -assert opt_expr -fine
design -load postopt
select -assert-count 1 t:$pos
select -assert-none t:$pos t:* %D
select -assert-none t:$pos t:* %D t:$input_port %d
design -reset
@ -60,7 +60,7 @@ alumacc
equiv_opt -assert opt_expr -fine
design -load postopt
select -assert-count 1 t:$not
select -assert-none t:$not %% t:* %D
select -assert-none t:$not %% t:* %D t:$input_port %d
design -reset
@ -76,7 +76,7 @@ design -load postopt
select -assert-count 1 t:$alu
select -assert-count 1 t:$alu r:Y_WIDTH=3 %i
select -assert-count 1 t:$not
select -assert-none t:$alu t:$not t:* %D %D
select -assert-none t:$alu t:$not t:* %D %D t:$input_port %d
design -reset
@ -93,7 +93,7 @@ dump
select -assert-count 2 t:$alu
select -assert-count 1 t:$alu r:Y_WIDTH=2 %i
select -assert-count 1 t:$alu r:Y_WIDTH=3 %i
select -assert-none t:$alu t:* %D
select -assert-none t:$alu t:* %D t:$input_port %d
design -reset
@ -108,7 +108,7 @@ equiv_opt -assert opt -fine
design -load postopt
select -assert-count 2 t:$alu
select -assert-count 2 t:$alu r:Y_WIDTH=3 %i
select -assert-none t:$alu t:* %D
select -assert-none t:$alu t:* %D t:$input_port %d
design -reset

View File

@ -12,12 +12,12 @@ copy gold fine_keepdc
cd coarse
opt_expr
select -assert-none c:*
select -assert-none c:* t:$input_port %d
cd fine
simplemap
opt_expr
select -assert-none c:*
select -assert-none c:* t:$input_port %d
cd
miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter
@ -27,12 +27,12 @@ sat -verify -prove-asserts -show-ports -enable_undef miter2
cd coarse_keepdc
opt_expr -keepdc
select -assert-count 1 c:*
select -assert-count 1 c:* t:$input_port %d
cd fine_keepdc
simplemap
opt_expr -keepdc
select -assert-count 1 c:*
select -assert-count 1 c:* t:$input_port %d
cd
miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3
@ -56,12 +56,12 @@ copy gold fine_keepdc
cd coarse
opt_expr -fine
select -assert-none c:*
select -assert-none c:* t:$input_port %d
cd fine
simplemap
opt_expr
select -assert-none c:*
select -assert-none c:* t:$input_port %d
cd
miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter
@ -71,12 +71,12 @@ sat -verify -prove-asserts -show-ports -enable_undef miter2
cd coarse_keepdc
opt_expr -fine -keepdc
select -assert-count 1 c:*
select -assert-count 1 c:* t:$input_port %d
cd fine_keepdc
simplemap
opt_expr -keepdc
select -assert-count 2 c:*
select -assert-count 2 c:* t:$input_port %d
cd
miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3

View File

@ -50,7 +50,7 @@ opt_expr -fine
# The division by zero should be removed
select -assert-count 0 t:$div
# No cells should be left as it's replaced with constant undef
select -assert-none t:*
select -assert-none t:* t:$input_port %d
design -reset
read_verilog <<EOT
@ -64,7 +64,7 @@ design -load postopt
# The mux should be removed completely
select -assert-count 0 t:$mux
# No additional cells needed - direct connection
select -assert-none t:*
select -assert-none t:* t:$input_port %d
design -reset
read_verilog <<EOT
@ -110,7 +110,7 @@ design -load postopt
# The comparison of different constants should be replaced with constant 0
select -assert-count 0 t:$eq
# No other cells should be present (just the constant driver)
select -assert-none t:*
select -assert-none t:* t:$input_port %d
# opt.opt_expr.invert.double
@ -131,7 +131,7 @@ design -load postopt
opt_clean -purge
select -assert-count 0 t:$not
# No other cells should be present
select -assert-none t:*
select -assert-none t:* t:$input_port %d
# opt.opt_expr.reduce_xnor_not

View File

@ -12,12 +12,12 @@ copy gold fine_keepdc
cd coarse
opt_expr
select -assert-none c:*
select -assert-none c:* t:$input_port %d
cd fine
simplemap
opt_expr
select -assert-none c:*
select -assert-none c:* t:$input_port %d
cd
miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter
@ -27,12 +27,12 @@ sat -verify -prove-asserts -show-ports -enable_undef miter2
cd coarse_keepdc
opt_expr -keepdc
select -assert-count 1 c:*
select -assert-count 1 c:* t:$input_port %d
cd fine_keepdc
simplemap
opt_expr -keepdc
select -assert-count 1 c:*
select -assert-count 1 c:* t:$input_port %d
cd
miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3
@ -56,12 +56,12 @@ copy gold fine_keepdc
cd coarse
opt_expr -fine
select -assert-none c:*
select -assert-none c:* t:$input_port %d
cd fine
simplemap
opt_expr
select -assert-none c:*
select -assert-none c:* t:$input_port %d
cd
miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter
@ -71,12 +71,12 @@ sat -verify -prove-asserts -show-ports -enable_undef miter2
cd coarse_keepdc
opt_expr -fine -keepdc
select -assert-count 1 c:*
select -assert-count 1 c:* t:$input_port %d
cd fine_keepdc
simplemap
opt_expr -keepdc
select -assert-count 2 c:*
select -assert-count 2 c:* t:$input_port %d
cd
miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3

View File

@ -27,7 +27,7 @@ sat -verify -prove-asserts -show-ports -enable_undef miter2
cd coarse_keepdc
opt_expr -keepdc
select -assert-count 1 c:*
select -assert-count 1 c:* t:$input_port %d
cd fine_keepdc
simplemap

View File

@ -66,12 +66,12 @@ copy gold fine_keepdc
cd coarse
opt_expr
select -assert-none c:*
select -assert-none c:* t:$input_port %d
cd fine
simplemap
opt_expr
select -assert-none c:*
select -assert-none c:* t:$input_port %d
cd
miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter
@ -81,12 +81,12 @@ sat -verify -prove-asserts -show-ports -enable_undef miter2
cd coarse_keepdc
opt_expr -keepdc
select -assert-count 1 c:*
select -assert-count 1 c:* t:$input_port %d
cd fine_keepdc
simplemap
opt_expr -keepdc
select -assert-count 1 c:*
select -assert-count 1 c:* t:$input_port %d
cd
miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3

View File

@ -11,7 +11,7 @@ remove_empty_lines() {
}
# write_rtlil and dump are equivalent
$YS -p "read_verilog -sv everything.v; copy alu zzz; proc zzz; dump -o temp/roundtrip-text.dump.il; write_rtlil temp/roundtrip-text.write.il"
$YS -p "read_verilog -sv everything.v; copy alu zzz; proc zzz; bufnorm -reset; dump -o temp/roundtrip-text.dump.il; write_rtlil temp/roundtrip-text.write.il"
remove_empty_lines temp/roundtrip-text.dump.il
remove_empty_lines temp/roundtrip-text.write.il
# Trim first line ("Generated by Yosys ...")

View File

@ -90,6 +90,6 @@ select -assert-count 3 t:$mux
# All cells selected -> muxes on outputs only
design -load split_output
select -assert-count 0 t:$mux
abstract -value -enable magic t:*
abstract -value -enable magic t:$add
select -assert-count 1 t:$mux
# -----------------------------------------------------------------------------