mirror of https://github.com/YosysHQ/yosys.git
Merge 282d38f9fd into 70ee009dd9
This commit is contained in:
commit
fdc4b3c48f
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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});
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
37
kernel/ff.h
37
kernel/ff.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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---|
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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());
|
||||
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 *)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ...")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
# -----------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Reference in New Issue