Remove IO buffers when fed by SB_IO

Signed-off-by: David Shah <davey1576@gmail.com>
This commit is contained in:
David Shah 2018-06-13 10:50:05 +02:00
parent ddf549b117
commit a76f5c5678
5 changed files with 98 additions and 15 deletions

View File

@ -22,6 +22,8 @@
#ifndef DESIGN_UTILS_H #ifndef DESIGN_UTILS_H
#define DESIGN_UTILS_H #define DESIGN_UTILS_H
#include <algorithm>
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
/* /*
@ -35,23 +37,36 @@ void replace_port(CellInfo *old_cell, IdString old_name, CellInfo *rep_cell,
// If a net drives a given port of a cell matching a predicate (in many // If a net drives a given port of a cell matching a predicate (in many
// cases more than one cell type, e.g. SB_DFFxx so a predicate is used), return // cases more than one cell type, e.g. SB_DFFxx so a predicate is used), return
// the first instance of that cell (otherwise nullptr). If exclusive is set to // the first instance of that cell (otherwise nullptr). If exclusive is set to
// true, then this cell must be the only load // true, then this cell must be the only load. If ignore_cell is set, that cell
// is not considered
template <typename F1> template <typename F1>
CellInfo *net_only_drives(NetInfo *net, F1 cell_pred, IdString port, CellInfo *net_only_drives(NetInfo *net, F1 cell_pred, IdString port,
bool exclusive = false) bool exclusive = false, CellInfo *exclude = nullptr)
{ {
if (net == nullptr) if (net == nullptr)
return nullptr; return nullptr;
if (exclusive && (net->users.size() != 1)) { if (exclusive) {
return nullptr; if (exclude == nullptr) {
} else { if (net->users.size() != 1)
for (const auto &load : net->users) { return nullptr;
if (cell_pred(load.cell) && load.port == port) { } else {
return load.cell; if (net->users.size() > 2) {
return nullptr;
} else if (net->users.size() == 2) {
if (std::find_if(net->users.begin(), net->users.end(),
[exclude](const PortRef &ref) {
return ref.cell == exclude;
}) == net->users.end())
return nullptr;
} }
} }
return nullptr;
} }
for (const auto &load : net->users) {
if (load.cell != exclude && cell_pred(load.cell) && load.port == port) {
return load.cell;
}
}
return nullptr;
} }
// If a net is driven by a given port of a cell matching a predicate, return // If a net is driven by a given port of a cell matching a predicate, return

View File

@ -693,12 +693,16 @@ static void insert_iobuf(Design *design, NetInfo *net, PortType type,
design->cells[iobuf->name] = iobuf; design->cells[iobuf->name] = iobuf;
} }
void json_import_toplevel_port(Design *design, const string &modname, const string& portname, JsonNode *node) { void json_import_toplevel_port(Design *design, const string &modname,
const string &portname, JsonNode *node)
{
JsonNode *dir_node = node->data_dict.at("direction"); JsonNode *dir_node = node->data_dict.at("direction");
JsonNode *nets_node = node->data_dict.at("bits"); JsonNode *nets_node = node->data_dict.at("bits");
json_import_ports(design, modname, "Top Level IO", portname, dir_node, nets_node, [design](PortType type, const std::string &name, NetInfo *net){ json_import_ports(
insert_iobuf(design, net, type, name); design, modname, "Top Level IO", portname, dir_node, nets_node,
}); [design](PortType type, const std::string &name, NetInfo *net) {
insert_iobuf(design, net, type, name);
});
} }
void json_import(Design *design, string modname, JsonNode *node) void json_import(Design *design, string modname, JsonNode *node)
@ -738,7 +742,9 @@ void json_import(Design *design, string modname, JsonNode *node)
here = ports_parent->data_dict.at( here = ports_parent->data_dict.at(
ports_parent->data_dict_keys[portid]); ports_parent->data_dict_keys[portid]);
json_import_toplevel_port(design, modname, ports_parent->data_dict_keys[portid], here); json_import_toplevel_port(design, modname,
ports_parent->data_dict_keys[portid],
here);
} }
} }
check_all_nets_driven(design); check_all_nets_driven(design);

View File

@ -47,6 +47,9 @@ inline bool is_ff(const CellInfo *cell)
cell->type == "SB_DFFNESS" || cell->type == "SB_DFFNES"; cell->type == "SB_DFFNESS" || cell->type == "SB_DFFNES";
} }
// Return true if a cell is a SB_IO
inline bool is_sb_io(const CellInfo *cell) { return cell->type == "SB_IO"; }
// Convert a SB_LUT primitive to (part of) an ICESTORM_LC, swapping ports // Convert a SB_LUT primitive to (part of) an ICESTORM_LC, swapping ports
// as needed. Set no_dff if a DFF is not being used, so that the output // as needed. Set no_dff if a DFF is not being used, so that the output
// can be reconnected // can be reconnected

View File

@ -134,10 +134,69 @@ static void pack_constants(Design *design)
} }
} }
static bool is_nextpnr_iob(CellInfo *cell)
{
return cell->type == "$nextpnr_ibuf" || cell->type == "$nextpnr_obuf" ||
cell->type == "$nextpnr_iobuf";
}
// Pack IO buffers
static void pack_io(Design *design)
{
std::unordered_set<IdString> packed_cells;
std::vector<CellInfo *> new_cells;
for (auto cell : design->cells) {
CellInfo *ci = cell.second;
if (is_nextpnr_iob(ci)) {
if (ci->type == "$nextpnr_ibuf" || ci->type == "$nextpnr_iobuf") {
CellInfo *sb = net_only_drives(ci->ports.at("O").net, is_sb_io,
"PACKAGE_PIN", true, ci);
if (sb != nullptr) {
// Trivial case, SB_IO used. Just destroy the net and the
// iobuf
packed_cells.insert(ci->name);
log_info("%s feeds SB_IO %s, removing %s %s.\n",
ci->name.c_str(), sb->name.c_str(),
ci->type.c_str(), ci->name.c_str());
NetInfo *net = sb->ports.at("PACKAGE_PIN").net;
if (net != nullptr) {
design->nets.erase(net->name);
sb->ports.at("PACKAGE_PIN").net = nullptr;
}
}
} else if (ci->type == "$nextpnr_obuf") {
CellInfo *sb = net_only_drives(ci->ports.at("I").net, is_sb_io,
"PACKAGE_PIN", true, ci);
if (sb != nullptr) {
// Trivial case, SB_IO used. Just destroy the net and the
// iobuf
packed_cells.insert(ci->name);
log_info("%s feeds SB_IO %s, removing %s %s.\n",
ci->name.c_str(), sb->name.c_str(),
ci->type.c_str(), ci->name.c_str());
NetInfo *net = sb->ports.at("PACKAGE_PIN").net;
if (net != nullptr) {
design->nets.erase(net->name);
sb->ports.at("PACKAGE_PIN").net = nullptr;
}
}
}
}
}
for (auto pcell : packed_cells) {
design->cells.erase(pcell);
}
for (auto ncell : new_cells) {
design->cells[ncell->name] = ncell;
}
}
// Main pack function // Main pack function
void pack_design(Design *design) void pack_design(Design *design)
{ {
pack_constants(design); pack_constants(design);
pack_io(design);
pack_lut_lutffs(design); pack_lut_lutffs(design);
pack_nonlut_ffs(design); pack_nonlut_ffs(design);
} }

View File

@ -153,7 +153,7 @@ module io_wrapper(input clk_pin, cen_pin, rst_pin, ina_pin, inb_pin,
.PULLUP(1'b0), .PULLUP(1'b0),
.NEG_TRIGGER(1'b0) .NEG_TRIGGER(1'b0)
) outd_iob ( ) outd_iob (
.PACKAGE_PIN(outa_pin), .PACKAGE_PIN(outd_pin),
.LATCH_INPUT_VALUE(), .LATCH_INPUT_VALUE(),
.CLOCK_ENABLE(), .CLOCK_ENABLE(),
.INPUT_CLK(), .INPUT_CLK(),