mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-23 09:05:32 +00:00
Merge pull request #914 from YosysHQ/xc7srl
synth_xilinx to now infer SRL16E/SRLC32E
This commit is contained in:
commit
d9daf09cf3
8 changed files with 382 additions and 41 deletions
|
@ -26,7 +26,9 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
struct ShregmapTech
|
||||
{
|
||||
virtual ~ShregmapTech() { }
|
||||
virtual bool analyze(vector<int> &taps) = 0;
|
||||
virtual void init(const Module * /*module*/, const SigMap &/*sigmap*/) {}
|
||||
virtual void non_chain_user(const SigBit &/*bit*/, const Cell* /*cell*/, IdString /*port*/) {}
|
||||
virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) = 0;
|
||||
virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) = 0;
|
||||
};
|
||||
|
||||
|
@ -54,7 +56,7 @@ struct ShregmapOptions
|
|||
|
||||
struct ShregmapTechGreenpak4 : ShregmapTech
|
||||
{
|
||||
bool analyze(vector<int> &taps)
|
||||
bool analyze(vector<int> &taps, const vector<SigBit> &/*qbits*/)
|
||||
{
|
||||
if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) {
|
||||
taps.clear();
|
||||
|
@ -91,6 +93,145 @@ struct ShregmapTechGreenpak4 : ShregmapTech
|
|||
}
|
||||
};
|
||||
|
||||
struct ShregmapTechXilinx7 : ShregmapTech
|
||||
{
|
||||
dict<SigBit, std::tuple<Cell*,int,int>> sigbit_to_shiftx_offset;
|
||||
const ShregmapOptions &opts;
|
||||
|
||||
ShregmapTechXilinx7(const ShregmapOptions &opts) : opts(opts) {}
|
||||
|
||||
virtual void init(const Module* module, const SigMap &sigmap) override
|
||||
{
|
||||
for (const auto &i : module->cells_) {
|
||||
auto cell = i.second;
|
||||
if (cell->type == "$shiftx") {
|
||||
if (cell->getParam("\\Y_WIDTH") != 1) continue;
|
||||
int j = 0;
|
||||
for (auto bit : sigmap(cell->getPort("\\A")))
|
||||
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j++, 0);
|
||||
log_assert(j == cell->getParam("\\A_WIDTH").as_int());
|
||||
}
|
||||
else if (cell->type == "$mux") {
|
||||
int j = 0;
|
||||
for (auto bit : sigmap(cell->getPort("\\A")))
|
||||
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++);
|
||||
j = 0;
|
||||
for (auto bit : sigmap(cell->getPort("\\B")))
|
||||
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void non_chain_user(const SigBit &bit, const Cell *cell, IdString port) override
|
||||
{
|
||||
auto it = sigbit_to_shiftx_offset.find(bit);
|
||||
if (it == sigbit_to_shiftx_offset.end())
|
||||
return;
|
||||
if (cell) {
|
||||
if (cell->type == "$shiftx" && port == "\\A")
|
||||
return;
|
||||
if (cell->type == "$mux" && (port == "\\A" || port == "\\B"))
|
||||
return;
|
||||
}
|
||||
sigbit_to_shiftx_offset.erase(it);
|
||||
}
|
||||
|
||||
virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) override
|
||||
{
|
||||
if (GetSize(taps) == 1)
|
||||
return taps[0] >= opts.minlen-1 && sigbit_to_shiftx_offset.count(qbits[0]);
|
||||
|
||||
if (taps.back() < opts.minlen-1)
|
||||
return false;
|
||||
|
||||
Cell *shiftx = nullptr;
|
||||
int group = 0;
|
||||
for (int i = 0; i < GetSize(taps); ++i) {
|
||||
auto it = sigbit_to_shiftx_offset.find(qbits[i]);
|
||||
if (it == sigbit_to_shiftx_offset.end())
|
||||
return false;
|
||||
|
||||
// Check taps are sequential
|
||||
if (i != taps[i])
|
||||
return false;
|
||||
// Check taps are not connected to a shift register,
|
||||
// or sequential to the same shift register
|
||||
if (i == 0) {
|
||||
int offset;
|
||||
std::tie(shiftx,offset,group) = it->second;
|
||||
if (offset != i)
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
Cell *shiftx_ = std::get<0>(it->second);
|
||||
if (shiftx_ != shiftx)
|
||||
return false;
|
||||
int offset = std::get<1>(it->second);
|
||||
if (offset != i)
|
||||
return false;
|
||||
int group_ = std::get<2>(it->second);
|
||||
if (group_ != group)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
log_assert(shiftx);
|
||||
|
||||
// Only map if $shiftx exclusively covers the shift register
|
||||
if (shiftx->type == "$shiftx") {
|
||||
if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int())
|
||||
return false;
|
||||
}
|
||||
else if (shiftx->type == "$mux") {
|
||||
if (GetSize(taps) != 2)
|
||||
return false;
|
||||
}
|
||||
else log_abort();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) override
|
||||
{
|
||||
const auto &tap = *taps.begin();
|
||||
auto bit = tap.second;
|
||||
|
||||
auto it = sigbit_to_shiftx_offset.find(bit);
|
||||
log_assert(it != sigbit_to_shiftx_offset.end());
|
||||
|
||||
auto newcell = cell->module->addCell(NEW_ID, "$__XILINX_SHREG_");
|
||||
newcell->set_src_attribute(cell->get_src_attribute());
|
||||
newcell->setParam("\\DEPTH", cell->getParam("\\DEPTH"));
|
||||
newcell->setParam("\\INIT", cell->getParam("\\INIT"));
|
||||
newcell->setParam("\\CLKPOL", cell->getParam("\\CLKPOL"));
|
||||
newcell->setParam("\\ENPOL", cell->getParam("\\ENPOL"));
|
||||
|
||||
newcell->setPort("\\C", cell->getPort("\\C"));
|
||||
newcell->setPort("\\D", cell->getPort("\\D"));
|
||||
if (cell->hasPort("\\E"))
|
||||
newcell->setPort("\\E", cell->getPort("\\E"));
|
||||
|
||||
Cell* shiftx = std::get<0>(it->second);
|
||||
RTLIL::SigSpec l_wire, q_wire;
|
||||
if (shiftx->type == "$shiftx") {
|
||||
l_wire = shiftx->getPort("\\B");
|
||||
q_wire = shiftx->getPort("\\Y");
|
||||
shiftx->setPort("\\Y", cell->module->addWire(NEW_ID));
|
||||
}
|
||||
else if (shiftx->type == "$mux") {
|
||||
l_wire = shiftx->getPort("\\S");
|
||||
q_wire = shiftx->getPort("\\Y");
|
||||
shiftx->setPort("\\Y", cell->module->addWire(NEW_ID));
|
||||
}
|
||||
else log_abort();
|
||||
|
||||
newcell->setPort("\\Q", q_wire);
|
||||
newcell->setPort("\\L", l_wire);
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ShregmapWorker
|
||||
{
|
||||
Module *module;
|
||||
|
@ -113,8 +254,10 @@ struct ShregmapWorker
|
|||
for (auto wire : module->wires())
|
||||
{
|
||||
if (wire->port_output || wire->get_bool_attribute("\\keep")) {
|
||||
for (auto bit : sigmap(wire))
|
||||
for (auto bit : sigmap(wire)) {
|
||||
sigbit_with_non_chain_users.insert(bit);
|
||||
if (opts.tech) opts.tech->non_chain_user(bit, nullptr, {});
|
||||
}
|
||||
}
|
||||
|
||||
if (wire->attributes.count("\\init")) {
|
||||
|
@ -152,8 +295,10 @@ struct ShregmapWorker
|
|||
|
||||
for (auto conn : cell->connections())
|
||||
if (cell->input(conn.first))
|
||||
for (auto bit : sigmap(conn.second))
|
||||
for (auto bit : sigmap(conn.second)) {
|
||||
sigbit_with_non_chain_users.insert(bit);
|
||||
if (opts.tech) opts.tech->non_chain_user(bit, cell, conn.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,7 +403,7 @@ struct ShregmapWorker
|
|||
if (taps.empty() || taps.back() < depth-1)
|
||||
taps.push_back(depth-1);
|
||||
|
||||
if (opts.tech->analyze(taps))
|
||||
if (opts.tech->analyze(taps, qbits))
|
||||
break;
|
||||
|
||||
taps.pop_back();
|
||||
|
@ -377,6 +522,9 @@ struct ShregmapWorker
|
|||
ShregmapWorker(Module *module, const ShregmapOptions &opts) :
|
||||
module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0)
|
||||
{
|
||||
if (opts.tech)
|
||||
opts.tech->init(module, sigmap);
|
||||
|
||||
make_sigbit_chain_next_prev();
|
||||
find_chain_start_cells();
|
||||
|
||||
|
@ -501,6 +649,12 @@ struct ShregmapPass : public Pass {
|
|||
clkpol = "pos";
|
||||
opts.zinit = true;
|
||||
opts.tech = new ShregmapTechGreenpak4;
|
||||
}
|
||||
else if (tech == "xilinx") {
|
||||
opts.init = true;
|
||||
opts.params = true;
|
||||
enpol = "any_or_none";
|
||||
opts.tech = new ShregmapTechXilinx7(opts);
|
||||
} else {
|
||||
argidx--;
|
||||
break;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue