mirror of https://github.com/YosysHQ/yosys.git
Merge pull request #3967 from YosysHQ/claire/bufnorm
Add "buffered-normalized mode", add $buf cell type, and add "bufnorm" command
This commit is contained in:
commit
a553b7c0c7
|
@ -125,6 +125,10 @@ void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::
|
||||||
dump_const(f, it.second);
|
dump_const(f, it.second);
|
||||||
f << stringf("\n");
|
f << stringf("\n");
|
||||||
}
|
}
|
||||||
|
if (wire->driverCell_) {
|
||||||
|
f << stringf("%s" "# driver %s %s\n", indent.c_str(),
|
||||||
|
wire->driverCell()->name.c_str(), wire->driverPort().c_str());
|
||||||
|
}
|
||||||
f << stringf("%s" "wire ", indent.c_str());
|
f << stringf("%s" "wire ", indent.c_str());
|
||||||
if (wire->width != 1)
|
if (wire->width != 1)
|
||||||
f << stringf("width %d ", wire->width);
|
f << stringf("width %d ", wire->width);
|
||||||
|
|
|
@ -601,6 +601,14 @@ RTLIL::Const RTLIL::const_pos(const RTLIL::Const &arg1, const RTLIL::Const&, boo
|
||||||
return arg1_ext;
|
return arg1_ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RTLIL::Const RTLIL::const_buf(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
|
||||||
|
{
|
||||||
|
RTLIL::Const arg1_ext = arg1;
|
||||||
|
extend_u0(arg1_ext, result_len, signed1);
|
||||||
|
|
||||||
|
return arg1_ext;
|
||||||
|
}
|
||||||
|
|
||||||
RTLIL::Const RTLIL::const_neg(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
|
RTLIL::Const RTLIL::const_neg(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
|
||||||
{
|
{
|
||||||
RTLIL::Const arg1_ext = arg1;
|
RTLIL::Const arg1_ext = arg1;
|
||||||
|
|
|
@ -290,7 +290,7 @@ Aig::Aig(Cell *cell)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cell->type.in(ID($not), ID($_NOT_), ID($pos), ID($_BUF_)))
|
if (cell->type.in(ID($not), ID($_NOT_), ID($pos), ID($buf), ID($_BUF_)))
|
||||||
{
|
{
|
||||||
for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) {
|
for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) {
|
||||||
int A = mk.inport(ID::A, i);
|
int A = mk.inport(ID::A, i);
|
||||||
|
|
|
@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
void bitwise_unary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
|
void bitwise_unary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
|
||||||
{
|
{
|
||||||
bool is_signed = cell->getParam(ID::A_SIGNED).as_bool();
|
bool is_signed = (cell->type != ID($buf)) && cell->getParam(ID::A_SIGNED).as_bool();
|
||||||
int a_width = GetSize(cell->getPort(ID::A));
|
int a_width = GetSize(cell->getPort(ID::A));
|
||||||
int y_width = GetSize(cell->getPort(ID::Y));
|
int y_width = GetSize(cell->getPort(ID::Y));
|
||||||
|
|
||||||
|
@ -392,7 +392,7 @@ PRIVATE_NAMESPACE_END
|
||||||
|
|
||||||
bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell)
|
bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell)
|
||||||
{
|
{
|
||||||
if (cell->type.in(ID($not), ID($pos))) {
|
if (cell->type.in(ID($not), ID($pos), ID($buf))) {
|
||||||
bitwise_unary_op(this, cell);
|
bitwise_unary_op(this, cell);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ struct CellTypes
|
||||||
void setup_internals_eval()
|
void setup_internals_eval()
|
||||||
{
|
{
|
||||||
std::vector<RTLIL::IdString> unary_ops = {
|
std::vector<RTLIL::IdString> unary_ops = {
|
||||||
ID($not), ID($pos), ID($neg),
|
ID($not), ID($pos), ID($buf), ID($neg),
|
||||||
ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool),
|
ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool),
|
||||||
ID($logic_not), ID($slice), ID($lut), ID($sop)
|
ID($logic_not), ID($slice), ID($lut), ID($sop)
|
||||||
};
|
};
|
||||||
|
@ -339,7 +339,7 @@ struct CellTypes
|
||||||
type = ID($shl);
|
type = ID($shl);
|
||||||
|
|
||||||
if (type != ID($sshr) && type != ID($sshl) && type != ID($shr) && type != ID($shl) && type != ID($shift) && type != ID($shiftx) &&
|
if (type != ID($sshr) && type != ID($sshl) && type != ID($shr) && type != ID($shl) && type != ID($shift) && type != ID($shiftx) &&
|
||||||
type != ID($pos) && type != ID($neg) && type != ID($not)) {
|
type != ID($pos) && type != ID($buf) && type != ID($neg) && type != ID($not)) {
|
||||||
if (!signed1 || !signed2)
|
if (!signed1 || !signed2)
|
||||||
signed1 = false, signed2 = false;
|
signed1 = false, signed2 = false;
|
||||||
}
|
}
|
||||||
|
@ -381,6 +381,7 @@ struct CellTypes
|
||||||
HANDLE_CELL_TYPE(modfloor)
|
HANDLE_CELL_TYPE(modfloor)
|
||||||
HANDLE_CELL_TYPE(pow)
|
HANDLE_CELL_TYPE(pow)
|
||||||
HANDLE_CELL_TYPE(pos)
|
HANDLE_CELL_TYPE(pos)
|
||||||
|
HANDLE_CELL_TYPE(buf)
|
||||||
HANDLE_CELL_TYPE(neg)
|
HANDLE_CELL_TYPE(neg)
|
||||||
#undef HANDLE_CELL_TYPE
|
#undef HANDLE_CELL_TYPE
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ X(CE_OVER_SRST)
|
||||||
X(CFG_ABITS)
|
X(CFG_ABITS)
|
||||||
X(CFG_DBITS)
|
X(CFG_DBITS)
|
||||||
X(CFG_INIT)
|
X(CFG_INIT)
|
||||||
|
X(chain)
|
||||||
X(CI)
|
X(CI)
|
||||||
X(CLK)
|
X(CLK)
|
||||||
X(clkbuf_driver)
|
X(clkbuf_driver)
|
||||||
|
|
|
@ -77,7 +77,7 @@ void QuickConeSat::prepare()
|
||||||
|
|
||||||
int QuickConeSat::cell_complexity(RTLIL::Cell *cell)
|
int QuickConeSat::cell_complexity(RTLIL::Cell *cell)
|
||||||
{
|
{
|
||||||
if (cell->type.in(ID($concat), ID($slice), ID($pos), ID($_BUF_)))
|
if (cell->type.in(ID($concat), ID($slice), ID($pos), ID($buf), ID($_BUF_)))
|
||||||
return 0;
|
return 0;
|
||||||
if (cell->type.in(ID($not), ID($and), ID($or), ID($xor), ID($xnor),
|
if (cell->type.in(ID($not), ID($and), ID($or), ID($xor), ID($xnor),
|
||||||
ID($reduce_and), ID($reduce_or), ID($reduce_xor),
|
ID($reduce_and), ID($reduce_or), ID($reduce_xor),
|
||||||
|
|
167
kernel/rtlil.cc
167
kernel/rtlil.cc
|
@ -21,6 +21,7 @@
|
||||||
#include "kernel/macc.h"
|
#include "kernel/macc.h"
|
||||||
#include "kernel/celltypes.h"
|
#include "kernel/celltypes.h"
|
||||||
#include "kernel/binding.h"
|
#include "kernel/binding.h"
|
||||||
|
#include "kernel/sigtools.h"
|
||||||
#include "frontends/verilog/verilog_frontend.h"
|
#include "frontends/verilog/verilog_frontend.h"
|
||||||
#include "frontends/verilog/preproc.h"
|
#include "frontends/verilog/preproc.h"
|
||||||
#include "backends/rtlil/rtlil_backend.h"
|
#include "backends/rtlil/rtlil_backend.h"
|
||||||
|
@ -1108,6 +1109,13 @@ namespace {
|
||||||
cell->type.begins_with("$verific$") || cell->type.begins_with("$array:") || cell->type.begins_with("$extern:"))
|
cell->type.begins_with("$verific$") || cell->type.begins_with("$array:") || cell->type.begins_with("$extern:"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (cell->type == ID($buf)) {
|
||||||
|
port(ID::A, param(ID::WIDTH));
|
||||||
|
port(ID::Y, param(ID::WIDTH));
|
||||||
|
check_expected();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (cell->type.in(ID($not), ID($pos), ID($neg))) {
|
if (cell->type.in(ID($not), ID($pos), ID($neg))) {
|
||||||
param_bool(ID::A_SIGNED);
|
param_bool(ID::A_SIGNED);
|
||||||
port(ID::A, param(ID::A_WIDTH));
|
port(ID::A, param(ID::A_WIDTH));
|
||||||
|
@ -2493,6 +2501,23 @@ DEF_METHOD(ReduceBool, 1, ID($reduce_bool))
|
||||||
DEF_METHOD(LogicNot, 1, ID($logic_not))
|
DEF_METHOD(LogicNot, 1, ID($logic_not))
|
||||||
#undef DEF_METHOD
|
#undef DEF_METHOD
|
||||||
|
|
||||||
|
#define DEF_METHOD(_func, _y_size, _type) \
|
||||||
|
RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool /* is_signed */, const std::string &src) { \
|
||||||
|
RTLIL::Cell *cell = addCell(name, _type); \
|
||||||
|
cell->parameters[ID::WIDTH] = sig_a.size(); \
|
||||||
|
cell->setPort(ID::A, sig_a); \
|
||||||
|
cell->setPort(ID::Y, sig_y); \
|
||||||
|
cell->set_src_attribute(src); \
|
||||||
|
return cell; \
|
||||||
|
} \
|
||||||
|
RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed, const std::string &src) { \
|
||||||
|
RTLIL::SigSpec sig_y = addWire(NEW_ID, _y_size); \
|
||||||
|
add ## _func(name, sig_a, sig_y, is_signed, src); \
|
||||||
|
return sig_y; \
|
||||||
|
}
|
||||||
|
DEF_METHOD(Buf, sig_a.size(), ID($buf))
|
||||||
|
#undef DEF_METHOD
|
||||||
|
|
||||||
#define DEF_METHOD(_func, _y_size, _type) \
|
#define DEF_METHOD(_func, _y_size, _type) \
|
||||||
RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed, const std::string &src) { \
|
RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed, const std::string &src) { \
|
||||||
RTLIL::Cell *cell = addCell(name, _type); \
|
RTLIL::Cell *cell = addCell(name, _type); \
|
||||||
|
@ -3540,6 +3565,110 @@ void RTLIL::Cell::unsetPort(const RTLIL::IdString& portname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RTLIL::Design::bufNormalize(bool enable)
|
||||||
|
{
|
||||||
|
if (!enable)
|
||||||
|
{
|
||||||
|
if (!flagBufferedNormalized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto module : modules()) {
|
||||||
|
module->bufNormQueue.clear();
|
||||||
|
for (auto wire : module->wires()) {
|
||||||
|
wire->driverCell_ = nullptr;
|
||||||
|
wire->driverPort_ = IdString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flagBufferedNormalized = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!flagBufferedNormalized)
|
||||||
|
{
|
||||||
|
for (auto module : modules())
|
||||||
|
{
|
||||||
|
for (auto cell : module->cells())
|
||||||
|
for (auto &conn : cell->connections()) {
|
||||||
|
if (!cell->output(conn.first) || GetSize(conn.second) == 0)
|
||||||
|
continue;
|
||||||
|
if (conn.second.is_wire()) {
|
||||||
|
Wire *wire = conn.second.as_wire();
|
||||||
|
log_assert(wire->driverCell_ == nullptr);
|
||||||
|
wire->driverCell_ = cell;
|
||||||
|
wire->driverPort_ = conn.first;
|
||||||
|
} else {
|
||||||
|
pair<RTLIL::Cell*, RTLIL::IdString> key(cell, conn.first);
|
||||||
|
module->bufNormQueue.insert(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flagBufferedNormalized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto module : modules())
|
||||||
|
module->bufNormalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RTLIL::Module::bufNormalize()
|
||||||
|
{
|
||||||
|
if (!design->flagBufferedNormalized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (GetSize(bufNormQueue) || !connections_.empty())
|
||||||
|
{
|
||||||
|
pool<pair<RTLIL::Cell*, RTLIL::IdString>> queue;
|
||||||
|
bufNormQueue.swap(queue);
|
||||||
|
|
||||||
|
pool<Wire*> outWires;
|
||||||
|
for (auto &conn : connections())
|
||||||
|
for (auto &chunk : conn.first.chunks())
|
||||||
|
if (chunk.wire) outWires.insert(chunk.wire);
|
||||||
|
|
||||||
|
SigMap sigmap(this);
|
||||||
|
new_connections({});
|
||||||
|
|
||||||
|
for (auto &key : queue)
|
||||||
|
{
|
||||||
|
Cell *cell = key.first;
|
||||||
|
const IdString &portname = key.second;
|
||||||
|
const SigSpec &sig = cell->getPort(portname);
|
||||||
|
if (GetSize(sig) == 0) continue;
|
||||||
|
|
||||||
|
if (sig.is_wire()) {
|
||||||
|
Wire *wire = sig.as_wire();
|
||||||
|
if (wire->driverCell_) {
|
||||||
|
log_error("Conflict between %s %s in module %s\n",
|
||||||
|
log_id(cell), log_id(wire->driverCell_), log_id(this));
|
||||||
|
}
|
||||||
|
log_assert(wire->driverCell_ == nullptr);
|
||||||
|
wire->driverCell_ = cell;
|
||||||
|
wire->driverPort_ = portname;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &chunk : sig.chunks())
|
||||||
|
if (chunk.wire) outWires.insert(chunk.wire);
|
||||||
|
|
||||||
|
Wire *wire = addWire(NEW_ID, GetSize(sig));
|
||||||
|
sigmap.add(sig, wire);
|
||||||
|
cell->setPort(portname, wire);
|
||||||
|
|
||||||
|
// FIXME: Move init attributes from old 'sig' to new 'wire'
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto wire : outWires)
|
||||||
|
{
|
||||||
|
SigSpec outsig = wire, insig = sigmap(wire);
|
||||||
|
for (int i = 0; i < GetSize(wire); i++)
|
||||||
|
if (insig[i] == outsig[i])
|
||||||
|
insig[i] = State::Sx;
|
||||||
|
addBuf(NEW_ID, insig, outsig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal)
|
void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal)
|
||||||
{
|
{
|
||||||
auto r = connections_.insert(portname);
|
auto r = connections_.insert(portname);
|
||||||
|
@ -3559,6 +3688,40 @@ void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal
|
||||||
log_backtrace("-X- ", yosys_xtrace-1);
|
log_backtrace("-X- ", yosys_xtrace-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (module->design && module->design->flagBufferedNormalized && output(portname))
|
||||||
|
{
|
||||||
|
pair<RTLIL::Cell*, RTLIL::IdString> key(this, portname);
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetSize(signal) == 0) {
|
||||||
|
module->bufNormQueue.erase(key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!signal.is_wire()) {
|
||||||
|
module->bufNormQueue.insert(key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Wire *w = signal.as_wire();
|
||||||
|
if (w->driverCell_ != nullptr) {
|
||||||
|
pair<RTLIL::Cell*, RTLIL::IdString> other_key(w->driverCell_, w->driverPort_);
|
||||||
|
module->bufNormQueue.insert(other_key);
|
||||||
|
}
|
||||||
|
w->driverCell_ = this;
|
||||||
|
w->driverPort_ = portname;
|
||||||
|
|
||||||
|
module->bufNormQueue.erase(key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
conn_it->second = std::move(signal);
|
conn_it->second = std::move(signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3654,9 +3817,9 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
|
||||||
type.begins_with("$verific$") || type.begins_with("$array:") || type.begins_with("$extern:"))
|
type.begins_with("$verific$") || type.begins_with("$array:") || type.begins_with("$extern:"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (type == ID($mux) || type == ID($pmux) || type == ID($bmux)) {
|
if (type == ID($buf) || type == ID($mux) || type == ID($pmux) || type == ID($bmux)) {
|
||||||
parameters[ID::WIDTH] = GetSize(connections_[ID::Y]);
|
parameters[ID::WIDTH] = GetSize(connections_[ID::Y]);
|
||||||
if (type != ID($mux))
|
if (type != ID($buf) && type != ID($mux))
|
||||||
parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]);
|
parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]);
|
||||||
check();
|
check();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -503,6 +503,7 @@ namespace RTLIL
|
||||||
RTLIL::Const const_pow (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
RTLIL::Const const_pow (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||||
|
|
||||||
RTLIL::Const const_pos (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
RTLIL::Const const_pos (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||||
|
RTLIL::Const const_buf (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||||
RTLIL::Const const_neg (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
RTLIL::Const const_neg (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
|
||||||
|
|
||||||
RTLIL::Const const_mux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3);
|
RTLIL::Const const_mux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3);
|
||||||
|
@ -1065,6 +1066,9 @@ struct RTLIL::Design
|
||||||
pool<RTLIL::Monitor*> monitors;
|
pool<RTLIL::Monitor*> monitors;
|
||||||
dict<std::string, std::string> scratchpad;
|
dict<std::string, std::string> scratchpad;
|
||||||
|
|
||||||
|
bool flagBufferedNormalized = false;
|
||||||
|
void bufNormalize(bool enable=true);
|
||||||
|
|
||||||
int refcount_modules_;
|
int refcount_modules_;
|
||||||
dict<RTLIL::IdString, RTLIL::Module*> modules_;
|
dict<RTLIL::IdString, RTLIL::Module*> modules_;
|
||||||
std::vector<RTLIL::Binding*> bindings_;
|
std::vector<RTLIL::Binding*> bindings_;
|
||||||
|
@ -1209,6 +1213,9 @@ public:
|
||||||
std::vector<RTLIL::IdString> ports;
|
std::vector<RTLIL::IdString> ports;
|
||||||
void fixup_ports();
|
void fixup_ports();
|
||||||
|
|
||||||
|
pool<pair<RTLIL::Cell*, RTLIL::IdString>> bufNormQueue;
|
||||||
|
void bufNormalize();
|
||||||
|
|
||||||
template<typename T> void rewrite_sigspecs(T &functor);
|
template<typename T> void rewrite_sigspecs(T &functor);
|
||||||
template<typename T> void rewrite_sigspecs2(T &functor);
|
template<typename T> void rewrite_sigspecs2(T &functor);
|
||||||
void cloneInto(RTLIL::Module *new_mod) const;
|
void cloneInto(RTLIL::Module *new_mod) const;
|
||||||
|
@ -1280,6 +1287,7 @@ public:
|
||||||
|
|
||||||
RTLIL::Cell* addNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
RTLIL::Cell* addNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
||||||
RTLIL::Cell* addPos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
RTLIL::Cell* addPos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
||||||
|
RTLIL::Cell* addBuf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
||||||
RTLIL::Cell* addNeg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
RTLIL::Cell* addNeg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
||||||
|
|
||||||
RTLIL::Cell* addAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
RTLIL::Cell* addAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
||||||
|
@ -1414,6 +1422,7 @@ public:
|
||||||
|
|
||||||
RTLIL::SigSpec Not (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
RTLIL::SigSpec Not (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||||
RTLIL::SigSpec Pos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
RTLIL::SigSpec Pos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||||
|
RTLIL::SigSpec Buf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||||
RTLIL::SigSpec Neg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
RTLIL::SigSpec Neg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||||
|
|
||||||
RTLIL::SigSpec And (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
|
RTLIL::SigSpec And (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
|
||||||
|
@ -1501,6 +1510,10 @@ public:
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace RTLIL_BACKEND {
|
||||||
|
void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);
|
||||||
|
}
|
||||||
|
|
||||||
struct RTLIL::Wire : public RTLIL::AttrObject
|
struct RTLIL::Wire : public RTLIL::AttrObject
|
||||||
{
|
{
|
||||||
unsigned int hashidx_;
|
unsigned int hashidx_;
|
||||||
|
@ -1512,6 +1525,12 @@ protected:
|
||||||
Wire();
|
Wire();
|
||||||
~Wire();
|
~Wire();
|
||||||
|
|
||||||
|
friend struct RTLIL::Design;
|
||||||
|
friend struct RTLIL::Cell;
|
||||||
|
friend void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);
|
||||||
|
RTLIL::Cell *driverCell_ = nullptr;
|
||||||
|
RTLIL::IdString driverPort_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// do not simply copy wires
|
// do not simply copy wires
|
||||||
Wire(RTLIL::Wire &other) = delete;
|
Wire(RTLIL::Wire &other) = delete;
|
||||||
|
@ -1522,6 +1541,9 @@ public:
|
||||||
int width, start_offset, port_id;
|
int width, start_offset, port_id;
|
||||||
bool port_input, port_output, upto, is_signed;
|
bool port_input, port_output, upto, is_signed;
|
||||||
|
|
||||||
|
RTLIL::Cell *driverCell() const { log_assert(driverCell_); return driverCell_; };
|
||||||
|
RTLIL::IdString driverPort() const { log_assert(driverCell_); return driverPort_; };
|
||||||
|
|
||||||
#ifdef WITH_PYTHON
|
#ifdef WITH_PYTHON
|
||||||
static std::map<unsigned int, RTLIL::Wire*> *get_all_wires(void);
|
static std::map<unsigned int, RTLIL::Wire*> *get_all_wires(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -430,7 +430,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cell->type.in(ID($pos), ID($neg)))
|
if (cell->type.in(ID($pos), ID($buf), ID($neg)))
|
||||||
{
|
{
|
||||||
std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
|
std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
|
||||||
std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
|
std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
|
||||||
|
@ -438,7 +438,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
|
||||||
|
|
||||||
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
|
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
|
||||||
|
|
||||||
if (cell->type == ID($pos)) {
|
if (cell->type.in(ID($pos), ID($buf))) {
|
||||||
ez->assume(ez->vec_eq(a, yy));
|
ez->assume(ez->vec_eq(a, yy));
|
||||||
} else {
|
} else {
|
||||||
std::vector<int> zero(a.size(), ez->CONST_FALSE);
|
std::vector<int> zero(a.size(), ez->CONST_FALSE);
|
||||||
|
@ -451,7 +451,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
|
||||||
std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
|
std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
|
||||||
extendSignalWidthUnary(undef_a, undef_y, cell);
|
extendSignalWidthUnary(undef_a, undef_y, cell);
|
||||||
|
|
||||||
if (cell->type == ID($pos)) {
|
if (cell->type.in(ID($pos), ID($buf))) {
|
||||||
ez->assume(ez->vec_eq(undef_a, undef_y));
|
ez->assume(ez->vec_eq(undef_a, undef_y));
|
||||||
} else {
|
} else {
|
||||||
int undef_any_a = ez->expression(ezSAT::OpOr, undef_a);
|
int undef_any_a = ez->expression(ezSAT::OpOr, undef_a);
|
||||||
|
|
|
@ -41,6 +41,7 @@ OBJS += passes/techmap/nlutmap.o
|
||||||
OBJS += passes/techmap/shregmap.o
|
OBJS += passes/techmap/shregmap.o
|
||||||
OBJS += passes/techmap/deminout.o
|
OBJS += passes/techmap/deminout.o
|
||||||
OBJS += passes/techmap/insbuf.o
|
OBJS += passes/techmap/insbuf.o
|
||||||
|
OBJS += passes/techmap/bufnorm.o
|
||||||
OBJS += passes/techmap/attrmvcp.o
|
OBJS += passes/techmap/attrmvcp.o
|
||||||
OBJS += passes/techmap/attrmap.o
|
OBJS += passes/techmap/attrmap.o
|
||||||
OBJS += passes/techmap/zinit.o
|
OBJS += passes/techmap/zinit.o
|
||||||
|
|
|
@ -0,0 +1,512 @@
|
||||||
|
/*
|
||||||
|
* 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/yosys.h"
|
||||||
|
#include "kernel/sigtools.h"
|
||||||
|
|
||||||
|
USING_YOSYS_NAMESPACE
|
||||||
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct BufnormPass : public Pass {
|
||||||
|
BufnormPass() : Pass("bufnorm", "(experimental) convert design into buffered-normalized form") {
|
||||||
|
experimental();
|
||||||
|
}
|
||||||
|
void help() override
|
||||||
|
{
|
||||||
|
log("\n");
|
||||||
|
log(" bufnorm [options] [selection]\n");
|
||||||
|
log("\n");
|
||||||
|
log("Insert buffer cells into the design as needed, to make sure that each wire\n");
|
||||||
|
log("has exactly one driving cell port, and aliasing wires are buffered using\n");
|
||||||
|
log("buffer cells, than can be chained in a canonical order.\n");
|
||||||
|
log("\n");
|
||||||
|
log("Running 'bufnorm' on the whole design enters 'buffered-normalized mode'.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -buf\n");
|
||||||
|
log(" Create $buf cells for all buffers. The default is to use $_BUF_ cells\n");
|
||||||
|
log(" for sigle-bit buffers and $buf cells only for multi-bit buffers.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -chain\n");
|
||||||
|
log(" Chain all alias wires. By default only wires with positive-valued\n");
|
||||||
|
log(" 'chain' or 'keep' attribute on them are chained.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -output\n");
|
||||||
|
log(" Enable chaining of ouput ports wires.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -public\n");
|
||||||
|
log(" Enable chaining of wires wth public names.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -nochain\n");
|
||||||
|
log(" Disable chaining of wires with 'chain' attribute.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -nokeep\n");
|
||||||
|
log(" Disable chaining of wires with 'keep' attribute.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -flat\n");
|
||||||
|
log(" Alias for -nokeep and -nochain.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -nosticky\n");
|
||||||
|
log(" Disable 'sticky' behavior of output ports already driving whole\n");
|
||||||
|
log(" wires, and always enforce canonical sort order instead.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -alphasort\n");
|
||||||
|
log(" Strictly use alphanumeric sort for chain-order. (Default is\n");
|
||||||
|
log(" to chain 'keep' wires first, then ports in declaration order,\n");
|
||||||
|
log(" and then the other wires in alphanumeric sort order.)\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -noinit\n");
|
||||||
|
log(" Do not move 'init' attributes to the wires on FF output ports.\n");
|
||||||
|
log("\n");
|
||||||
|
log("Run 'bufnorm' with -pos, -bits, or -conn on the whole design to remove all\n");
|
||||||
|
log("$buf buffer cells and exit 'buffered-normalized mode' again.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -pos\n");
|
||||||
|
log(" Create (multi- and single-bit) $pos cells instead $buf and $_BUF_.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -bits\n");
|
||||||
|
log(" Create arrays of $_BUF_ cells instead of multi-bit $buf cells.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -conn\n");
|
||||||
|
log(" Create 'direct connections' instead of buffer cells.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -nomode\n");
|
||||||
|
log(" Do not automatically enter or leave 'buffered-normalized mode'.\n");
|
||||||
|
log("\n");
|
||||||
|
log("The 'bufnorm' command can also be used to just switch in and out of\n");
|
||||||
|
log("'buffered-normalized mode' and run the low-level re-normalizer.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -update\n");
|
||||||
|
log(" Enter 'buffered-normalized mode' and (re-)normalize.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -reset\n");
|
||||||
|
log(" Leave 'buffered-normalized mode' without changing the netlist.\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||||
|
{
|
||||||
|
bool buf_mode = false;
|
||||||
|
bool chain_mode = false;
|
||||||
|
bool output_mode = false;
|
||||||
|
bool public_mode = false;
|
||||||
|
bool nochain_mode = false;
|
||||||
|
bool nokeep_mode = false;
|
||||||
|
bool nosticky_mode = false;
|
||||||
|
bool alphasort_mode = false;
|
||||||
|
bool noinit_mode = false; // FIXME: Actually move init attributes
|
||||||
|
bool nomode_mode = false;
|
||||||
|
|
||||||
|
bool pos_mode = false;
|
||||||
|
bool bits_mode = false;
|
||||||
|
bool conn_mode = false;
|
||||||
|
|
||||||
|
bool update_mode = false;
|
||||||
|
bool reset_mode = false;
|
||||||
|
bool got_non_update_reset_opt = false;
|
||||||
|
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
|
{
|
||||||
|
std::string arg = args[argidx];
|
||||||
|
if (arg == "-buf") {
|
||||||
|
buf_mode = true;
|
||||||
|
got_non_update_reset_opt = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-chain") {
|
||||||
|
chain_mode = true;
|
||||||
|
got_non_update_reset_opt = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-output") {
|
||||||
|
output_mode = true;
|
||||||
|
got_non_update_reset_opt = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-public") {
|
||||||
|
public_mode = true;
|
||||||
|
got_non_update_reset_opt = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-nochain") {
|
||||||
|
nochain_mode = true;
|
||||||
|
got_non_update_reset_opt = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-nokeep") {
|
||||||
|
nokeep_mode = true;
|
||||||
|
got_non_update_reset_opt = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-flat") {
|
||||||
|
nochain_mode = true;
|
||||||
|
nokeep_mode = true;
|
||||||
|
got_non_update_reset_opt = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-nosticky") {
|
||||||
|
nosticky_mode = true;
|
||||||
|
got_non_update_reset_opt = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-alphasort") {
|
||||||
|
alphasort_mode = true;
|
||||||
|
got_non_update_reset_opt = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-noinit") {
|
||||||
|
noinit_mode = true;
|
||||||
|
got_non_update_reset_opt = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-pos") {
|
||||||
|
pos_mode = true;
|
||||||
|
got_non_update_reset_opt = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-bits") {
|
||||||
|
bits_mode = true;
|
||||||
|
got_non_update_reset_opt = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-conn") {
|
||||||
|
conn_mode = true;
|
||||||
|
got_non_update_reset_opt = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-nomode") {
|
||||||
|
nomode_mode = true;
|
||||||
|
got_non_update_reset_opt = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-update") {
|
||||||
|
update_mode = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-reset") {
|
||||||
|
reset_mode = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
|
if (buf_mode && pos_mode)
|
||||||
|
log_cmd_error("Options -buf and -pos are exclusive.\n");
|
||||||
|
|
||||||
|
if (buf_mode && conn_mode)
|
||||||
|
log_cmd_error("Options -buf and -conn are exclusive.\n");
|
||||||
|
|
||||||
|
if (pos_mode && conn_mode)
|
||||||
|
log_cmd_error("Options -pos and -conn are exclusive.\n");
|
||||||
|
|
||||||
|
if (update_mode && reset_mode)
|
||||||
|
log_cmd_error("Options -update and -reset are exclusive.\n");
|
||||||
|
|
||||||
|
if (update_mode && got_non_update_reset_opt)
|
||||||
|
log_cmd_error("Option -update 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");
|
||||||
|
|
||||||
|
if (update_mode) {
|
||||||
|
design->bufNormalize();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reset_mode) {
|
||||||
|
design->bufNormalize(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_header(design, "Executing BUFNORM pass (convert to buffer-normalized form).\n");
|
||||||
|
|
||||||
|
int count_removed_buffers = 0;
|
||||||
|
int count_updated_buffers = 0;
|
||||||
|
int count_kept_buffers = 0;
|
||||||
|
int count_created_buffers = 0;
|
||||||
|
int count_updated_cellports = 0;
|
||||||
|
|
||||||
|
if (!nomode_mode && (pos_mode || bits_mode || conn_mode)) {
|
||||||
|
if (design->selection().full_selection)
|
||||||
|
design->bufNormalize(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto module : design->selected_modules())
|
||||||
|
{
|
||||||
|
log("Buffer-normalizing module %s.\n", log_id(module));
|
||||||
|
|
||||||
|
SigMap sigmap(module);
|
||||||
|
module->new_connections({});
|
||||||
|
|
||||||
|
dict<pair<IdString, SigSpec>, Cell*> old_buffers;
|
||||||
|
|
||||||
|
{
|
||||||
|
vector<Cell*> old_dup_buffers;
|
||||||
|
for (auto cell : module->cells())
|
||||||
|
{
|
||||||
|
if (!cell->type.in(ID($buf), ID($_BUF_)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SigSpec insig = cell->getPort(ID::A);
|
||||||
|
SigSpec outsig = cell->getPort(ID::Y);
|
||||||
|
for (int i = 0; i < GetSize(insig) && i < GetSize(outsig); i++)
|
||||||
|
sigmap.add(insig[i], outsig[i]);
|
||||||
|
|
||||||
|
pair<IdString,Wire*> key(cell->type, outsig.as_wire());
|
||||||
|
if (old_buffers.count(key))
|
||||||
|
old_dup_buffers.push_back(cell);
|
||||||
|
else
|
||||||
|
old_buffers[key] = cell;
|
||||||
|
}
|
||||||
|
for (auto cell : old_dup_buffers)
|
||||||
|
module->remove(cell);
|
||||||
|
count_removed_buffers += GetSize(old_dup_buffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
dict<SigBit, pool<Wire*>> bit2wires;
|
||||||
|
dict<SigSpec, pool<Wire*>> whole_wires;
|
||||||
|
dict<SigBit, SigBit> mapped_bits;
|
||||||
|
pool<Wire*> unmapped_wires;
|
||||||
|
|
||||||
|
for (auto wire : module->wires())
|
||||||
|
{
|
||||||
|
SigSpec keysig = sigmap(wire);
|
||||||
|
whole_wires[keysig].insert(wire);
|
||||||
|
|
||||||
|
for (auto keybit : sigmap(wire))
|
||||||
|
bit2wires[keybit].insert(wire);
|
||||||
|
|
||||||
|
if (wire->port_input) {
|
||||||
|
log(" primary input: %s\n", log_id(wire));
|
||||||
|
for (auto bit : SigSpec(wire))
|
||||||
|
mapped_bits[sigmap(bit)] = bit;
|
||||||
|
} else {
|
||||||
|
unmapped_wires.insert(wire);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto chain_this_wire_f = [&](Wire *wire)
|
||||||
|
{
|
||||||
|
if (chain_mode)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (output_mode && wire->port_output)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (public_mode && wire->name.isPublic())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!nokeep_mode && wire->get_bool_attribute(ID::keep))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!nochain_mode && wire->get_bool_attribute(ID::chain))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto compare_wires_f = [&](Wire *a, Wire *b)
|
||||||
|
{
|
||||||
|
// Chaining wires first, then flat wires
|
||||||
|
bool chain_a = chain_this_wire_f(a);
|
||||||
|
bool chain_b = chain_this_wire_f(b);
|
||||||
|
if (chain_a != chain_b) return chain_a;
|
||||||
|
|
||||||
|
if (!alphasort_mode)
|
||||||
|
{
|
||||||
|
// Wires with 'chain' attribute first, high values before low values
|
||||||
|
if (!nochain_mode) {
|
||||||
|
int chain_a_val = a->attributes.at(ID::chain, Const(0)).as_int();
|
||||||
|
int chain_b_val = b->attributes.at(ID::chain, Const(0)).as_int();
|
||||||
|
if (chain_a_val != chain_b_val) return chain_a_val > chain_b_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then wires with 'keep' attribute
|
||||||
|
if (!nokeep_mode) {
|
||||||
|
bool keep_a = a->get_bool_attribute(ID::keep);
|
||||||
|
bool keep_b = b->get_bool_attribute(ID::keep);
|
||||||
|
if (keep_a != keep_b) return keep_a;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ports before non-ports
|
||||||
|
if ((a->port_id != 0) != (b->port_id != 0))
|
||||||
|
return a->port_id != 0;
|
||||||
|
|
||||||
|
// Ports in declaration order
|
||||||
|
if (a->port_id != b->port_id)
|
||||||
|
return a->port_id < b->port_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nets with public names first
|
||||||
|
if (a->name.isPublic() != b->name.isPublic())
|
||||||
|
return a->name.isPublic();
|
||||||
|
|
||||||
|
// Otherwise just sort by name alphanumerically
|
||||||
|
return a->name.str() < b->name.str();
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto cell : module->cells())
|
||||||
|
{
|
||||||
|
if (cell->type.in(ID($buf), ID($_BUF_)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (auto &conn : cell->connections())
|
||||||
|
{
|
||||||
|
if (!cell->output(conn.first))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Wire *w = nullptr;
|
||||||
|
|
||||||
|
if (!nosticky_mode && conn.second.is_wire())
|
||||||
|
w = conn.second.as_wire();
|
||||||
|
|
||||||
|
if (w == nullptr)
|
||||||
|
{
|
||||||
|
SigSpec keysig = sigmap(conn.second);
|
||||||
|
auto it = whole_wires.find(keysig);
|
||||||
|
if (it != whole_wires.end()) {
|
||||||
|
it->second.sort(compare_wires_f);
|
||||||
|
w = *(it->second.begin());
|
||||||
|
} else {
|
||||||
|
w = module->addWire(NEW_ID, GetSize(conn.second));
|
||||||
|
for (int i = 0; i < GetSize(w); i++)
|
||||||
|
sigmap.add(SigBit(w, i), keysig[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (w->name.isPublic())
|
||||||
|
log(" directly driven by cell %s port %s: %s\n",
|
||||||
|
log_id(cell), log_id(conn.first), log_id(w));
|
||||||
|
|
||||||
|
for (auto bit : SigSpec(w))
|
||||||
|
mapped_bits[sigmap(bit)] = bit;
|
||||||
|
unmapped_wires.erase(w);
|
||||||
|
|
||||||
|
cell->setPort(conn.first, w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pool<Cell*> added_buffers;
|
||||||
|
|
||||||
|
auto make_buffer_f = [&](const IdString &type, const SigSpec &src, const SigSpec &dst)
|
||||||
|
{
|
||||||
|
auto it = old_buffers.find(pair<IdString, SigSpec>(type, dst));
|
||||||
|
|
||||||
|
if (it != old_buffers.end())
|
||||||
|
{
|
||||||
|
Cell *cell = it->second;
|
||||||
|
old_buffers.erase(it);
|
||||||
|
added_buffers.insert(cell);
|
||||||
|
|
||||||
|
if (cell->getPort(ID::A) == src) {
|
||||||
|
count_kept_buffers++;
|
||||||
|
} else {
|
||||||
|
cell->setPort(ID::A, src);
|
||||||
|
count_updated_buffers++;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell *cell = module->addCell(NEW_ID, type);
|
||||||
|
added_buffers.insert(cell);
|
||||||
|
|
||||||
|
cell->setPort(ID::A, src);
|
||||||
|
cell->setPort(ID::Y, dst);
|
||||||
|
cell->fixup_parameters();
|
||||||
|
count_created_buffers++;
|
||||||
|
};
|
||||||
|
|
||||||
|
unmapped_wires.sort(compare_wires_f);
|
||||||
|
for (auto wire : unmapped_wires)
|
||||||
|
{
|
||||||
|
bool chain_this_wire = chain_this_wire_f(wire);
|
||||||
|
|
||||||
|
SigSpec keysig = sigmap(wire), insig = wire, outsig = wire;
|
||||||
|
for (int i = 0; i < GetSize(insig); i++)
|
||||||
|
insig[i] = mapped_bits.at(keysig[i], State::Sx);
|
||||||
|
if (chain_this_wire) {
|
||||||
|
for (int i = 0; i < GetSize(outsig); i++)
|
||||||
|
mapped_bits[keysig[i]] = outsig[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
log(" %s %s for %s -> %s\n",
|
||||||
|
chain_this_wire ? "chaining" : "adding",
|
||||||
|
conn_mode ? "connection" : "buffer",
|
||||||
|
log_signal(insig), log_signal(outsig));
|
||||||
|
|
||||||
|
if (conn_mode) {
|
||||||
|
if (bits_mode) {
|
||||||
|
for (int i = 0; i < GetSize(insig) && i < GetSize(outsig); i++)
|
||||||
|
module->connect(outsig[i], insig[i]);
|
||||||
|
} else {
|
||||||
|
module->connect(outsig, insig);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (bits_mode) {
|
||||||
|
IdString celltype = pos_mode ? ID($pos) : buf_mode ? ID($buf) : ID($_BUF_);
|
||||||
|
for (int i = 0; i < GetSize(insig) && i < GetSize(outsig); i++)
|
||||||
|
make_buffer_f(celltype, insig[i], outsig[i]);
|
||||||
|
} else {
|
||||||
|
IdString celltype = pos_mode ? ID($pos) : buf_mode ? ID($buf) :
|
||||||
|
GetSize(outsig) == 1 ? ID($_BUF_) : ID($buf);
|
||||||
|
make_buffer_f(celltype, insig, outsig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &it : old_buffers)
|
||||||
|
module->remove(it.second);
|
||||||
|
count_removed_buffers += GetSize(old_buffers);
|
||||||
|
|
||||||
|
for (auto cell : module->cells())
|
||||||
|
{
|
||||||
|
if (added_buffers.count(cell))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (auto &conn : cell->connections())
|
||||||
|
{
|
||||||
|
if (cell->output(conn.first))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SigSpec newsig = conn.second;
|
||||||
|
for (auto &bit : newsig)
|
||||||
|
bit = mapped_bits[sigmap(bit)];
|
||||||
|
|
||||||
|
if (conn.second != newsig) {
|
||||||
|
log(" fixing input signal on cell %s port %s: %s\n",
|
||||||
|
log_id(cell), log_id(conn.first), log_signal(newsig));
|
||||||
|
cell->setPort(conn.first, newsig);
|
||||||
|
count_updated_cellports++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log("Summary: removed %d, updated %d, kept %d, and created %d buffers, and updated %d cell ports.\n",
|
||||||
|
count_removed_buffers, count_updated_buffers, count_kept_buffers,
|
||||||
|
count_created_buffers, count_updated_cellports);
|
||||||
|
|
||||||
|
if (!nomode_mode && !(pos_mode || bits_mode || conn_mode)) {
|
||||||
|
if (design->selection().full_selection)
|
||||||
|
design->bufNormalize(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} BufnormPass;
|
||||||
|
|
||||||
|
PRIVATE_NAMESPACE_END
|
|
@ -58,7 +58,6 @@ endgenerate
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
|
|
||||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
@ -88,6 +87,27 @@ endmodule
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
|
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
//-
|
||||||
|
//- $buf (A, Y)
|
||||||
|
//-
|
||||||
|
//- A simple coarse-grain buffer cell type for the experimental buffered-normalized
|
||||||
|
//- mode. Note this cell does't get removed by 'opt_clean' and is not recommended
|
||||||
|
//- for general use.
|
||||||
|
//-
|
||||||
|
module \$buf (A, Y);
|
||||||
|
|
||||||
|
parameter WIDTH = 0;
|
||||||
|
|
||||||
|
input [WIDTH-1:0] A;
|
||||||
|
output [WIDTH-1:0] Y;
|
||||||
|
|
||||||
|
assign Y = A;
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// --------------------------------------------------------
|
||||||
|
|
||||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
//-
|
//-
|
||||||
//- $neg (A, Y)
|
//- $neg (A, Y)
|
||||||
|
|
Loading…
Reference in New Issue