Skip to content

Commit

Permalink
Merge pull request #3967 from YosysHQ/claire/bufnorm
Browse files Browse the repository at this point in the history
Add "buffered-normalized mode", add $buf cell type, and add "bufnorm" command
  • Loading branch information
povik authored Sep 17, 2024
2 parents c884624 + eeffca9 commit a553b7c
Show file tree
Hide file tree
Showing 13 changed files with 744 additions and 12 deletions.
4 changes: 4 additions & 0 deletions backends/rtlil/rtlil_backend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::
dump_const(f, it.second);
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());
if (wire->width != 1)
f << stringf("width %d ", wire->width);
Expand Down
8 changes: 8 additions & 0 deletions kernel/calc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,14 @@ RTLIL::Const RTLIL::const_pos(const RTLIL::Const &arg1, const RTLIL::Const&, boo
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 arg1_ext = arg1;
Expand Down
2 changes: 1 addition & 1 deletion kernel/cellaigs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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++) {
int A = mk.inport(ID::A, i);
Expand Down
4 changes: 2 additions & 2 deletions kernel/celledges.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN

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 y_width = GetSize(cell->getPort(ID::Y));

Expand Down Expand Up @@ -392,7 +392,7 @@ PRIVATE_NAMESPACE_END

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);
return true;
}
Expand Down
5 changes: 3 additions & 2 deletions kernel/celltypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ struct CellTypes
void setup_internals_eval()
{
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($logic_not), ID($slice), ID($lut), ID($sop)
};
Expand Down Expand Up @@ -339,7 +339,7 @@ struct CellTypes
type = ID($shl);

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)
signed1 = false, signed2 = false;
}
Expand Down Expand Up @@ -381,6 +381,7 @@ struct CellTypes
HANDLE_CELL_TYPE(modfloor)
HANDLE_CELL_TYPE(pow)
HANDLE_CELL_TYPE(pos)
HANDLE_CELL_TYPE(buf)
HANDLE_CELL_TYPE(neg)
#undef HANDLE_CELL_TYPE

Expand Down
1 change: 1 addition & 0 deletions kernel/constids.inc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ X(CE_OVER_SRST)
X(CFG_ABITS)
X(CFG_DBITS)
X(CFG_INIT)
X(chain)
X(CI)
X(CLK)
X(clkbuf_driver)
Expand Down
2 changes: 1 addition & 1 deletion kernel/qcsat.cc
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ void QuickConeSat::prepare()

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;
if (cell->type.in(ID($not), ID($and), ID($or), ID($xor), ID($xnor),
ID($reduce_and), ID($reduce_or), ID($reduce_xor),
Expand Down
167 changes: 165 additions & 2 deletions kernel/rtlil.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "kernel/macc.h"
#include "kernel/celltypes.h"
#include "kernel/binding.h"
#include "kernel/sigtools.h"
#include "frontends/verilog/verilog_frontend.h"
#include "frontends/verilog/preproc.h"
#include "backends/rtlil/rtlil_backend.h"
Expand Down Expand Up @@ -1108,6 +1109,13 @@ namespace {
cell->type.begins_with("$verific$") || cell->type.begins_with("$array:") || cell->type.begins_with("$extern:"))
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))) {
param_bool(ID::A_SIGNED);
port(ID::A, param(ID::A_WIDTH));
Expand Down Expand Up @@ -2493,6 +2501,23 @@ DEF_METHOD(ReduceBool, 1, ID($reduce_bool))
DEF_METHOD(LogicNot, 1, ID($logic_not))
#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) \
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); \
Expand Down Expand Up @@ -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)
{
auto r = connections_.insert(portname);
Expand All @@ -3559,6 +3688,40 @@ void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal
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);
}

Expand Down Expand Up @@ -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:"))
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]);
if (type != ID($mux))
if (type != ID($buf) && type != ID($mux))
parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]);
check();
return;
Expand Down
22 changes: 22 additions & 0 deletions kernel/rtlil.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_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_mux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3);
Expand Down Expand Up @@ -1065,6 +1066,9 @@ struct RTLIL::Design
pool<RTLIL::Monitor*> monitors;
dict<std::string, std::string> scratchpad;

bool flagBufferedNormalized = false;
void bufNormalize(bool enable=true);

int refcount_modules_;
dict<RTLIL::IdString, RTLIL::Module*> modules_;
std::vector<RTLIL::Binding*> bindings_;
Expand Down Expand Up @@ -1209,6 +1213,9 @@ struct RTLIL::Module : public RTLIL::AttrObject
std::vector<RTLIL::IdString> 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_sigspecs2(T &functor);
void cloneInto(RTLIL::Module *new_mod) const;
Expand Down Expand Up @@ -1280,6 +1287,7 @@ struct RTLIL::Module : public RTLIL::AttrObject

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* 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* 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 = "");
Expand Down Expand Up @@ -1414,6 +1422,7 @@ struct RTLIL::Module : public RTLIL::AttrObject

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 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 And (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
Expand Down Expand Up @@ -1501,6 +1510,10 @@ struct RTLIL::Module : public RTLIL::AttrObject
#endif
};

namespace RTLIL_BACKEND {
void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);
}

struct RTLIL::Wire : public RTLIL::AttrObject
{
unsigned int hashidx_;
Expand All @@ -1512,6 +1525,12 @@ struct RTLIL::Wire : public RTLIL::AttrObject
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:
// do not simply copy wires
Wire(RTLIL::Wire &other) = delete;
Expand All @@ -1522,6 +1541,9 @@ struct RTLIL::Wire : public RTLIL::AttrObject
int width, start_offset, port_id;
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
static std::map<unsigned int, RTLIL::Wire*> *get_all_wires(void);
#endif
Expand Down
Loading

0 comments on commit a553b7c

Please sign in to comment.