Reworked the plugin code to allow for single parameter control multiple registered ports of a DSP cell Signed-off-by: Maciej Kurc <mkurc@antmicro.com>
diff --git a/dsp-ff-plugin/dsp_ff.cc b/dsp-ff-plugin/dsp_ff.cc index bceb080..09c7e41 100644 --- a/dsp-ff-plugin/dsp_ff.cc +++ b/dsp-ff-plugin/dsp_ff.cc
@@ -65,16 +65,20 @@ }; /// Describes a DSP cell port that has built-in register (flip-flops) - struct DspPortType { + struct PortType { RTLIL::IdString name; /// Range of port pins that have FFs (low to high, inclusive) std::pair<int, int> bits; - /// A dict of associated cell ports indexed by their function (like "clk, "rst") /// along with the default value to connect when unused. dict<RTLIL::IdString, std::pair<RTLIL::IdString, RTLIL::Const>> assoc; + }; + /// Describes a DSP register + struct RegisterType { + + /// Control parameters struct { /// A dict of parameters to be set in the cell after integration dict<RTLIL::IdString, RTLIL::Const> set; @@ -85,14 +89,26 @@ /// A list of ports to be connected to specific constants after flip-flop /// integration. dict<RTLIL::IdString, RTLIL::Const> connect; + + unsigned int hash() const { + unsigned int h = 0; + h = mkhash_add(h, params.set.hash()); + h = mkhash_add(h, params.map.hash()); + h = mkhash_add(h, connect.hash()); + return h; + } + + bool operator == (const RegisterType& ref) const { + return (params.set == ref.params.set) && + (params.map == ref.params.map) && + (connect == ref.connect); + } }; /// Describes a DSP cell type struct DspType { RTLIL::IdString name; - - /// A list of data ports with registers - std::vector<DspPortType> ports; + dict<RegisterType, std::vector<PortType>> registers; }; /// Describes a changes made to a DSP cell @@ -203,7 +219,12 @@ log_error(" Error opening file!\n"); } - std::vector<DspType> dspTypes; + // Parse each port as if it was associated with its own DSP register. + // Group them each time a port definition is complete. + PortType portType; + RegisterType registerType; + + std::vector<DspType> dspTypes; std::vector<FlopType> flopTypes; std::vector<RTLIL::IdString> dspAliases; @@ -259,6 +280,7 @@ tok.pop_back(); const auto dspType = dspTypes.back(); + for (const auto &alias : dspAliases) { dspTypes.push_back(dspType); dspTypes.back().name = alias; @@ -277,13 +299,15 @@ auto spec = parsePortName(fields[1]); - auto &ports = dspTypes.back().ports; - ports.resize(ports.size() + 1); - ports.back().name = RTLIL::escape_id(std::get<0>(spec)); - ports.back().bits = std::make_pair(std::get<2>(spec), std::get<1>(spec)); - ports.back().assoc.insert(std::make_pair(RTLIL::escape_id("clk"), std::make_pair(RTLIL::IdString(), RTLIL::Sx))); - ports.back().assoc.insert(std::make_pair(RTLIL::escape_id("rst"), std::make_pair(RTLIL::IdString(), RTLIL::Sx))); - ports.back().assoc.insert(std::make_pair(RTLIL::escape_id("ena"), std::make_pair(RTLIL::IdString(), RTLIL::Sx))); + portType = PortType(); + portType.name = RTLIL::escape_id(std::get<0>(spec)); + portType.bits = std::make_pair(std::get<2>(spec), std::get<1>(spec)); + portType.assoc.insert(std::make_pair(RTLIL::escape_id("clk"), std::make_pair(RTLIL::IdString(), RTLIL::Sx))); + portType.assoc.insert(std::make_pair(RTLIL::escape_id("rst"), std::make_pair(RTLIL::IdString(), RTLIL::Sx))); + portType.assoc.insert(std::make_pair(RTLIL::escape_id("ena"), std::make_pair(RTLIL::IdString(), RTLIL::Sx))); + + registerType = RegisterType(); + } else if (fields[0] == "endport") { if (fields.size() != 1) { log_error(" syntax error: '%s'\n", line.c_str()); @@ -292,6 +316,9 @@ log_error(" unexpected keyword '%s'\n", fields[0].c_str()); } tok.pop_back(); + + auto& dspType = dspTypes.back(); + dspType.registers[registerType].push_back(portType); } // Flip-flop type section @@ -332,8 +359,7 @@ if (fields.size() != 3) { log_error(" syntax error: '%s'\n", line.c_str()); } - auto &ports = dspTypes.back().ports; - ports.back().assoc[RTLIL::escape_id("clk")] = std::make_pair(RTLIL::escape_id(fields[1]), RTLIL::Const::from_string(fields[2])); + portType.assoc[RTLIL::escape_id("clk")] = std::make_pair(RTLIL::escape_id(fields[1]), RTLIL::Const::from_string(fields[2])); } else if (tok.back() == "ff") { if (fields.size() != 2) { log_error(" syntax error: '%s'\n", line.c_str()); @@ -350,8 +376,7 @@ if (fields.size() != 3) { log_error(" syntax error: '%s'\n", line.c_str()); } - auto &ports = dspTypes.back().ports; - ports.back().assoc[RTLIL::escape_id("rst")] = std::make_pair(RTLIL::escape_id(fields[1]), RTLIL::Const::from_string(fields[2])); + portType.assoc[RTLIL::escape_id("rst")] = std::make_pair(RTLIL::escape_id(fields[1]), RTLIL::Const::from_string(fields[2])); } else if (tok.back() == "ff") { if (fields.size() != 2) { log_error(" syntax error: '%s'\n", line.c_str()); @@ -368,8 +393,7 @@ if (fields.size() != 3) { log_error(" syntax error: '%s'\n", line.c_str()); } - auto &ports = dspTypes.back().ports; - ports.back().assoc[RTLIL::escape_id("ena")] = std::make_pair(RTLIL::escape_id(fields[1]), RTLIL::Const::from_string(fields[2])); + portType.assoc[RTLIL::escape_id("ena")] = std::make_pair(RTLIL::escape_id(fields[1]), RTLIL::Const::from_string(fields[2])); } else if (tok.back() == "ff") { if (fields.size() != 2) { log_error(" syntax error: '%s'\n", line.c_str()); @@ -441,8 +465,7 @@ } if (tok.back() == "port") { - auto &ports = dspTypes.back().ports; - ports.back().params.set.swap(set); + registerType.params.set.swap(set); } else if (tok.back() == "ff") { flopTypes.back().params.set.swap(set); } @@ -463,8 +486,7 @@ } if (tok.back() == "port") { - auto &ports = dspTypes.back().ports; - ports.back().params.map.swap(map); + registerType.params.map.swap(map); } else if (tok.back() == "ff") { flopTypes.back().params.map.swap(map); } @@ -479,9 +501,8 @@ } const auto vec = parseNameValue(fields); - auto &ports = dspTypes.back().ports; for (const auto &it : vec) { - ports.back().connect.insert(std::make_pair(RTLIL::escape_id(it.first), RTLIL::Const(it.second))); + registerType.connect.insert(std::make_pair(RTLIL::escape_id(it.first), RTLIL::Const(it.second))); } } @@ -510,40 +531,44 @@ // Dump DSP types log("DSP types:\n"); - for (const auto &it : m_DspTypes) { - const auto &dsp = it.second; + for (const auto &it1 : m_DspTypes) { + const auto &dsp = it1.second; log(" %s\n", dsp.name.c_str()); - log(" ports:\n"); - for (const auto &port : dsp.ports) { + for (const auto& it2 : dsp.registers) { + const auto& reg = it2.first; + const auto& ports = it2.second; + log(" ports:\n"); + for (const auto &port : ports) { - std::string range; - if (port.bits.first != -1 && port.bits.second != -1) { - range = stringf("[%d:%d]", port.bits.second, port.bits.first); - } - - log(" %s.%s%s\n", dsp.name.c_str(), port.name.c_str(), range.c_str()); - - for (const auto &it : port.assoc) { - log(" %.3s: %s\n", it.first.c_str(), !it.second.first.empty() ? it.second.first.c_str() : "<none>"); - } - - if (!port.params.set.empty()) { - log(" set params:\n"); - for (const auto &it : port.params.set) { - log(" %s=%s\n", it.first.c_str(), it.second.decode_string().c_str()); + std::string range; + if (port.bits.first != -1 && port.bits.second != -1) { + range = stringf("[%d:%d]", port.bits.second, port.bits.first); } - } - if (!port.params.map.empty()) { - log(" map params:\n"); - for (const auto &it : port.params.map) { - log(" %s=%s\n", it.first.c_str(), it.second.c_str()); + + log(" %s.%s%s\n", dsp.name.c_str(), port.name.c_str(), range.c_str()); + + for (const auto &it : port.assoc) { + log(" %.3s: %s\n", it.first.c_str(), !it.second.first.empty() ? it.second.first.c_str() : "<none>"); } - } - if (!port.connect.empty()) { - log(" connect ports:\n"); - for (const auto &it : port.connect) { - log(" %s.%s=%s\n", dsp.name.c_str(), it.first.c_str(), it.second.as_string().c_str()); + + if (!reg.params.set.empty()) { + log(" set params:\n"); + for (const auto &it : reg.params.set) { + log(" %s=%s\n", it.first.c_str(), it.second.decode_string().c_str()); + } + } + if (!reg.params.map.empty()) { + log(" map params:\n"); + for (const auto &it : reg.params.map) { + log(" %s=%s\n", it.first.c_str(), it.second.c_str()); + } + } + if (!reg.connect.empty()) { + log(" connect ports:\n"); + for (const auto &it : reg.connect) { + log(" %s.%s=%s\n", dsp.name.c_str(), it.first.c_str(), it.second.as_string().c_str()); + } } } } @@ -732,17 +757,10 @@ continue; } - // Check ports - auto &rule = m_DspTypes.at(cell->type); - for (auto &portRule : rule.ports) { - - // Sanity check - if (!cell->hasPort(portRule.name)) { - log(" The DSP cell '%s' does not have a port named '%s'!\n", cell->type.c_str(), portRule.name.c_str()); - continue; - } - - processPort(cell, portRule); + // Process all registers + auto &dspType = m_DspTypes.at(cell->type); + for (auto& rule : dspType.registers) { + processRegister(cell, rule.first, rule.second); } } @@ -763,28 +781,12 @@ // // TODO: // } - bool checkDspPort(RTLIL::Cell *a_Cell, const DspPortType &a_PortRule) - { - bool isOk = true; - - // The cell register control parameters must not be set - for (const auto &it : a_PortRule.params.set) { - const auto curr = a_Cell->getParam(it.first); - if (curr == it.second) { - log_debug(" the param '%s' is already set to '%s'\n", it.first.c_str(), it.second.decode_string().c_str()); - isOk = false; - } - } - - return isOk; - } - bool checkFlop(RTLIL::Cell *a_Cell) { const auto &flopType = m_FlopTypes.at(a_Cell->type); bool isOk = true; - log_debug(" Checking connected flip-flop '%s' of type '%s'... ", a_Cell->name.c_str(), a_Cell->type.c_str()); + log_debug(" checking connected flip-flop '%s' of type '%s'... ", a_Cell->name.c_str(), a_Cell->type.c_str()); // Must not have the "keep" attribute if (a_Cell->has_keep_attr()) { @@ -810,33 +812,37 @@ return isOk; } - bool checkFlopDataAgainstDspPort(const FlopData &a_FlopData, RTLIL::Cell *a_Cell, const DspPortType &a_PortRule) + bool checkFlopDataAgainstDspRegister(const FlopData &a_FlopData, RTLIL::Cell *a_Cell, + const RegisterType &a_Register, + const std::vector<PortType>& a_Ports) { const auto &flopType = m_FlopTypes.at(a_FlopData.type); const auto &changes = m_DspChanges[a_Cell]; bool isOk = true; - log_debug(" Checking connected flip-flop settings against the DSP port... "); + log_debug(" checking connected flip-flop settings against the DSP register... "); // Check control signal connections - for (const auto &it : a_PortRule.assoc) { - const auto &key = it.first; - const auto &port = it.second.first; + for (const auto& port : a_Ports) { + for (const auto &it : port.assoc) { + const auto &key = it.first; + const auto &port = it.second.first; - SigBit conn(RTLIL::Sx); - if (!port.empty() && a_Cell->hasPort(port)) { - auto sigspec = a_Cell->getPort(port); - auto sigbits = sigspec.bits(); - log_assert(sigbits.size() <= 1); - if (!sigbits.empty()) { - conn = m_SigMap(sigbits[0]); + SigBit conn(RTLIL::Sx); + if (!port.empty() && a_Cell->hasPort(port)) { + auto sigspec = a_Cell->getPort(port); + auto sigbits = sigspec.bits(); + log_assert(sigbits.size() <= 1); + if (!sigbits.empty()) { + conn = m_SigMap(sigbits[0]); + } } - } - if (conn.is_wire() || (!conn.is_wire() && conn.data != RTLIL::Sx)) { - if (conn != a_FlopData.conns.at(key)) { - log_debug("\n connection to port '%s' mismatch", port.c_str()); - isOk = false; + if (conn.is_wire() || (!conn.is_wire() && conn.data != RTLIL::Sx)) { + if (conn != a_FlopData.conns.at(key)) { + log_debug("\n connection to port '%s' mismatch", port.c_str()); + isOk = false; + } } } } @@ -852,7 +858,7 @@ }; // Check parameters to be mapped (by the port rule) - for (const auto &it : a_PortRule.params.map) { + for (const auto &it : a_Register.params.map) { if (a_Cell->hasParam(it.first) && a_FlopData.params.dsp.count(it.second)) { const auto curr = a_Cell->getParam(it.first); const auto flop = a_FlopData.params.dsp.at(it.second); @@ -861,7 +867,7 @@ } // Check parameters to be set (by the port rule) - for (const auto &it : a_PortRule.params.set) { + for (const auto &it : a_Register.params.set) { if (a_Cell->hasParam(it.first)) { const auto curr = a_Cell->getParam(it.first); checkParam(it.first, curr, it.second); @@ -920,212 +926,243 @@ // .......................................... - void processPort(RTLIL::Cell *a_Cell, const DspPortType &a_PortRule) + void processRegister(RTLIL::Cell *a_Cell, const RegisterType& a_Register, + const std::vector<PortType>& a_Ports) { - log_debug(" Attempting flip-flop integration for %s.%s of %s\n", a_Cell->type.c_str(), a_PortRule.name.c_str(), a_Cell->name.c_str()); - - // Check if the port can be used for FF integration - log_assert(a_Cell->output(a_PortRule.name) || a_Cell->input(a_PortRule.name)); - if (!checkDspPort(a_Cell, a_PortRule)) { - log_debug(" port check failed\n"); - return; + // The cell register control parameter(s) must not be set + for (const auto &it : a_Register.params.set) { + const auto curr = a_Cell->getParam(it.first); + if (curr == it.second) { + log_debug(" the param '%s' is already set to '%s'\n", it.first.c_str(), it.second.decode_string().c_str()); + return; + } } - // Get port connections - auto sigspec = a_Cell->getPort(a_PortRule.name); - auto sigbits = sigspec.bits(); + pool<FlopData> groups; + dict<RTLIL::IdString, std::vector<RTLIL::Cell*>> flops; - // Collect flip-flops, identify their group count - dict<FlopData, int> groups; + // Process ports + bool flopsOk = true; + for (const auto& port : a_Ports) { + log_debug(" attempting flip-flop integration for %s.%s of %s\n", a_Cell->type.c_str(), port.name.c_str(), a_Cell->name.c_str()); + log_assert(a_Cell->output(port.name) || a_Cell->input(port.name)); - std::vector<std::pair<RTLIL::Cell *, int>> flops(sigbits.size(), std::make_pair(nullptr, -1)); + // Get port connections + auto sigspec = a_Cell->getPort(port.name); + auto sigbits = sigspec.bits(); - for (size_t i = 0; i < sigbits.size(); ++i) { - auto sigbit = sigbits[i]; - if (!sigbit.wire) { - continue; - } - - // Skip bits out of the specified range - if ((a_PortRule.bits.first >= 0 && (int)i < a_PortRule.bits.first) || (a_PortRule.bits.second >= 0 && (int)i > a_PortRule.bits.second)) { - continue; - } - - pool<CellPin> others; - - // Get sinks(s), discard the port completely if more than one sink - // is found. - if (a_Cell->output(a_PortRule.name)) { - others = getSinks(CellPin(a_Cell, a_PortRule.name, i)); - if (others.size() > 1) { - log_debug(" multiple sinks found, cannot integrate.\n"); - return; - } - } - // Get driver. Discard if the driver drives something else too - // TODO: This is slow - we are first looking for a driver and then - // for all its sinks. - else if (a_Cell->input(a_PortRule.name)) { - auto driver = getDriver(CellPin(a_Cell, a_PortRule.name, i)); - if (driver.cell != nullptr) { - auto sinks = getSinks(driver); - if (sinks.size() > 1) { - log_debug(" multiple sinks found, cannot integrate.\n"); - return; - } - } - others.insert(driver); - } - - // No others - unconnected - if (others.empty()) { - continue; - } - - // Get the sink, check if this is a flip-flop - auto &other = *others.begin(); - auto *flop = other.cell; - - if (flop == nullptr) { - if (!other.port.empty()) { - log_debug(" port connection reaches outside of the module, cannot integrate\n"); - return; - } else { + flops[port.name] = std::vector<RTLIL::Cell*>(sigbits.size(), nullptr); + for (size_t i = 0; i < sigbits.size(); ++i) { + auto sigbit = sigbits[i]; + if (!sigbit.wire) { continue; } - } - if (!m_FlopTypes.count(flop->type)) { - log_debug(" non-flip-flop connected, cannot integrate\n"); - return; - } - - // Check if the connection goes to the data input/output port - const auto &flopType = m_FlopTypes.at(flop->type); - RTLIL::IdString flopPort; - if (a_Cell->output(a_PortRule.name)) { - flopPort = flopType.ports.at(RTLIL::escape_id("d")); - } else if (a_Cell->input(a_PortRule.name)) { - flopPort = flopType.ports.at(RTLIL::escape_id("q")); - } - - if (flopPort != other.port) { - log_debug(" connection to non-data port of a flip-flip, cannot integrate\n"); - return; - } - - // Check the flip-flop configuration - if (!checkFlop(flop)) { - return; - } - - // Get parameters to be mapped to the DSP according to the port - // rule. - dict<RTLIL::IdString, RTLIL::Const> mappedParams; - for (const auto &it : a_PortRule.params.map) { - if (flop->hasParam(it.second)) { - const auto &value = flop->getParam(it.second); - mappedParams.insert(std::make_pair(it.first, value)); + // Skip bits out of the specified range + if ((port.bits.first >= 0 && (int)i < port.bits.first) || (port.bits.second >= 0 && (int)i > port.bits.second)) { + continue; } - } - // Store the flop and its data - auto res = groups.insert(std::make_pair(getFlopData(flop, mappedParams), groups.size())); - flops[i] = std::make_pair(flop, res.first->second); + pool<CellPin> others; + + // Get sinks(s), discard the port completely if more than one sink + // is found. + if (a_Cell->output(port.name)) { + others = getSinks(CellPin(a_Cell, port.name, i)); + if (others.size() > 1) { + log_debug(" multiple sinks found\n"); + flopsOk = false; + continue; + } + } + // Get driver. Discard if the driver drives something else too + // TODO: This is slow - we are first looking for a driver and then + // for all its sinks. + else if (a_Cell->input(port.name)) { + auto driver = getDriver(CellPin(a_Cell, port.name, i)); + if (driver.cell != nullptr) { + auto sinks = getSinks(driver); + if (sinks.size() > 1) { + log_debug(" multiple sinks found\n"); + flopsOk = false; + continue; + } + } + others.insert(driver); + } + + // No others - unconnected + if (others.empty()) { + continue; + } + + // Get the sink, check if this is a flip-flop + auto &other = *others.begin(); + auto *flop = other.cell; + + if (flop == nullptr) { + if (!other.port.empty()) { + log_debug(" port connection reaches outside of the module\n"); + flopsOk = false; + } + continue; + } + + if (!m_FlopTypes.count(flop->type)) { + log_debug(" non-flip-flop connected\n"); + flopsOk = false; + continue; + } + + // Check if the connection goes to the data input/output port + const auto &flopType = m_FlopTypes.at(flop->type); + RTLIL::IdString flopPort; + if (a_Cell->output(port.name)) { + flopPort = flopType.ports.at(RTLIL::escape_id("d")); + } else if (a_Cell->input(port.name)) { + flopPort = flopType.ports.at(RTLIL::escape_id("q")); + } + + if (flopPort != other.port) { + log_debug(" connection to non-data port of a flip-flip"); + flopsOk = false; + continue; + } + + // Check the flip-flop configuration + if (!checkFlop(flop)) { + flopsOk = false; + continue; + } + + // Get parameters to be mapped to the DSP according to the port + // rule. + dict<RTLIL::IdString, RTLIL::Const> mappedParams; + for (const auto &it : a_Register.params.map) { + if (flop->hasParam(it.second)) { + const auto &value = flop->getParam(it.second); + mappedParams.insert(std::make_pair(it.first, value)); + } + } + + // Store the flop and its data + groups.insert(getFlopData(flop, mappedParams)); + flops[port.name][i] = flop; + } + } + + // Cannot integrate for various reasons + if (!flopsOk) { + log_debug(" cannot use the DSP register\n"); + return; } // No matching flip-flop groups if (groups.empty()) { - log_debug(" no matching flip-flops found\n"); + log_debug(" no matching flip-flops found\n"); return; } // Do not allow more than a single group if (groups.size() != 1) { - log_debug(" %zu flip-flop groups, only a single one allowed\n", groups.size()); + log_debug(" %zu flip-flop groups, only a single one allowed\n", groups.size()); return; } // Validate the flip flop data agains the DSP cell - const auto &flopData = groups.begin()->first; - if (!checkFlopDataAgainstDspPort(flopData, a_Cell, a_PortRule)) { - log_debug(" flip-flop vs. DSP check failed\n"); + const auto &flopData = *groups.begin(); + if (!checkFlopDataAgainstDspRegister(flopData, a_Cell, a_Register, a_Ports)) { + log_debug(" flip-flops vs. DSP check failed\n"); return; } // Debug log - log(" %s %s.%s\n", a_Cell->type.c_str(), a_Cell->name.c_str(), a_PortRule.name.c_str()); - for (size_t i = 0; i < flops.size(); ++i) { - if (flops[i].first != nullptr) { - log_debug(" %2zu. (%d) %s %s\n", i, flops[i].second, flops[i].first->type.c_str(), flops[i].first->name.c_str()); - } else if ((a_PortRule.bits.first >= 0 && (int)i < a_PortRule.bits.first) || - (a_PortRule.bits.second >= 0 && (int)i > a_PortRule.bits.second)) { - log_debug(" %2zu. (excluded)\n", i); - } else { - log_debug(" %2zu. None\n", i); + for (const auto& port : a_Ports) { + log(" %s %s.%s\n", a_Cell->type.c_str(), a_Cell->name.c_str(), port.name.c_str()); + + const auto& conns = flops.at(port.name); + for (size_t i = 0; i < conns.size(); ++i) { + if (conns[i] != nullptr) { + log_debug(" %2zu. %s %s\n", i, conns[i]->type.c_str(), conns[i]->name.c_str()); + } else if ((port.bits.first >= 0 && (int)i < port.bits.first) || + (port.bits.second >= 0 && (int)i > port.bits.second)) { + log_debug(" %2zu. (excluded)\n", i); + } else { + log_debug(" %2zu. None\n", i); + } } } // Reconnect data signals, mark the flip-flop for removal const auto &flopType = m_FlopTypes.at(flopData.type); - for (size_t i = 0; i < flops.size(); ++i) { + for (const auto& port : a_Ports) { - auto *flop = flops[i].first; - if (flop == nullptr) { - continue; + const auto& conns = flops.at(port.name); + auto sigspec = a_Cell->getPort(port.name); + auto sigbits = sigspec.bits(); + + for (size_t i = 0; i < conns.size(); ++i) { + + auto *flop = conns[i]; + if (flop == nullptr) { + continue; + } + + RTLIL::IdString flopPort; + if (a_Cell->output(port.name)) { + flopPort = flopType.ports.at(RTLIL::escape_id("q")); + } else if (a_Cell->input(port.name)) { + flopPort = flopType.ports.at(RTLIL::escape_id("d")); + } + + if (!flop->hasPort(flopPort)) { + log_error("cell '%s' does not have port '%s'!\n", flop->type.c_str(), flopPort.c_str()); + } + + sigbits[i] = SigBit(RTLIL::Sx); + auto sigspec = flop->getPort(flopPort); + log_assert(sigspec.bits().size() <= 1); + if (sigspec.bits().size() == 1) { + sigbits[i] = sigspec.bits()[0]; + } + + m_CellsToRemove.insert(flop); } - RTLIL::IdString port; - if (a_Cell->output(a_PortRule.name)) { - port = flopType.ports.at(RTLIL::escape_id("q")); - } else if (a_Cell->input(a_PortRule.name)) { - port = flopType.ports.at(RTLIL::escape_id("d")); - } - - if (!flop->hasPort(port)) { - log_error(" cell '%s' does not have port '%s'!\n", flop->type.c_str(), port.c_str()); - } - - sigbits[i] = SigBit(RTLIL::Sx); - auto sigspec = flop->getPort(port); - log_assert(sigspec.bits().size() <= 1); - if (sigspec.bits().size() == 1) { - sigbits[i] = sigspec.bits()[0]; - } - - m_CellsToRemove.insert(flop); + a_Cell->setPort(port.name, RTLIL::SigSpec(sigbits)); } - a_Cell->setPort(a_PortRule.name, RTLIL::SigSpec(sigbits)); // Reconnect (map) control signals. Connect the default value if // a particular signal is not present in the flip-flop. - for (const auto &it : a_PortRule.assoc) { - const auto &key = it.first; - const auto &port = it.second.first; + for (const auto& port : a_Ports) { + for (const auto &it : port.assoc) { + const auto &key = it.first; + const auto &port = it.second.first; - auto conn = RTLIL::SigBit(RTLIL::SigChunk(it.second.second)); - if (flopData.conns.count(key)) { - conn = flopData.conns.at(key); + auto conn = RTLIL::SigBit(RTLIL::SigChunk(it.second.second)); + if (flopData.conns.count(key)) { + conn = flopData.conns.at(key); + } + + log_debug(" connecting %s.%s to %s\n", a_Cell->type.c_str(), port.c_str(), sigBitName(conn).c_str()); + a_Cell->setPort(port, conn); + m_DspChanges[a_Cell].conns.insert(port); } - - log_debug(" connecting %s.%s to %s\n", a_Cell->type.c_str(), port.c_str(), sigBitName(conn).c_str()); - a_Cell->setPort(port, conn); - m_DspChanges[a_Cell].conns.insert(port); } - // Connect control signals according to DSP port rule - for (const auto &it : a_PortRule.connect) { - log_debug(" connecting %s.%s to %s\n", a_Cell->type.c_str(), it.first.c_str(), it.second.as_string().c_str()); + // Connect control signals according to the register rule + for (const auto &it : a_Register.connect) { + log_debug(" connecting %s.%s to %s\n", a_Cell->type.c_str(), it.first.c_str(), it.second.as_string().c_str()); a_Cell->setPort(it.first, it.second); m_DspChanges[a_Cell].conns.insert(it.first); } - // Map parameters (port rule) - for (const auto &it : a_PortRule.params.map) { + // Map parameters (register rule) + for (const auto &it : a_Register.params.map) { if (flopData.params.dsp.count(it.second)) { const auto ¶m = flopData.params.dsp.at(it.second); - log_debug(" setting param '%s' to '%s'\n", it.first.c_str(), param.decode_string().c_str()); + log_debug(" setting param '%s' to '%s'\n", it.first.c_str(), param.decode_string().c_str()); a_Cell->setParam(it.first, param); m_DspChanges[a_Cell].params.insert(it.first); } @@ -1135,22 +1172,22 @@ for (const auto &it : flopType.params.map) { if (flopData.params.dsp.count(it.second)) { const auto ¶m = flopData.params.dsp.at(it.second); - log_debug(" setting param '%s' to '%s'\n", it.first.c_str(), param.decode_string().c_str()); + log_debug(" setting param '%s' to '%s'\n", it.first.c_str(), param.decode_string().c_str()); a_Cell->setParam(it.first, param); m_DspChanges[a_Cell].params.insert(it.first); } } // Set parameters (port rule) - for (const auto &it : a_PortRule.params.set) { - log_debug(" setting param '%s' to '%s'\n", it.first.c_str(), it.second.decode_string().c_str()); + for (const auto &it : a_Register.params.set) { + log_debug(" setting param '%s' to '%s'\n", it.first.c_str(), it.second.decode_string().c_str()); a_Cell->setParam(it.first, it.second); m_DspChanges[a_Cell].params.insert(it.first); } // Set parameters (flip-flop rule) for (const auto &it : flopType.params.set) { - log_debug(" setting param '%s' to '%s'\n", it.first.c_str(), it.second.decode_string().c_str()); + log_debug(" setting param '%s' to '%s'\n", it.first.c_str(), it.second.decode_string().c_str()); a_Cell->setParam(it.first, it.second); m_DspChanges[a_Cell].params.insert(it.first); }