Remove IO buffers when fed by SB_IO
Signed-off-by: David Shah <davey1576@gmail.com>
This commit is contained in:
parent
ddf549b117
commit
a76f5c5678
@ -22,6 +22,8 @@
|
||||
#ifndef DESIGN_UTILS_H
|
||||
#define DESIGN_UTILS_H
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
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
|
||||
// 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
|
||||
// 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>
|
||||
CellInfo *net_only_drives(NetInfo *net, F1 cell_pred, IdString port,
|
||||
bool exclusive = false)
|
||||
bool exclusive = false, CellInfo *exclude = nullptr)
|
||||
{
|
||||
if (net == nullptr)
|
||||
return nullptr;
|
||||
if (exclusive && (net->users.size() != 1)) {
|
||||
return nullptr;
|
||||
} else {
|
||||
for (const auto &load : net->users) {
|
||||
if (cell_pred(load.cell) && load.port == port) {
|
||||
return load.cell;
|
||||
if (exclusive) {
|
||||
if (exclude == nullptr) {
|
||||
if (net->users.size() != 1)
|
||||
return nullptr;
|
||||
} else {
|
||||
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
|
||||
|
@ -693,12 +693,16 @@ static void insert_iobuf(Design *design, NetInfo *net, PortType type,
|
||||
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 *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){
|
||||
insert_iobuf(design, net, type, name);
|
||||
});
|
||||
json_import_ports(
|
||||
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)
|
||||
@ -738,7 +742,9 @@ void json_import(Design *design, string modname, JsonNode *node)
|
||||
|
||||
here = ports_parent->data_dict.at(
|
||||
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);
|
||||
|
@ -47,6 +47,9 @@ inline bool is_ff(const CellInfo *cell)
|
||||
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
|
||||
// as needed. Set no_dff if a DFF is not being used, so that the output
|
||||
// can be reconnected
|
||||
|
@ -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
|
||||
void pack_design(Design *design)
|
||||
{
|
||||
pack_constants(design);
|
||||
pack_io(design);
|
||||
pack_lut_lutffs(design);
|
||||
pack_nonlut_ffs(design);
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ module io_wrapper(input clk_pin, cen_pin, rst_pin, ina_pin, inb_pin,
|
||||
.PULLUP(1'b0),
|
||||
.NEG_TRIGGER(1'b0)
|
||||
) outd_iob (
|
||||
.PACKAGE_PIN(outa_pin),
|
||||
.PACKAGE_PIN(outd_pin),
|
||||
.LATCH_INPUT_VALUE(),
|
||||
.CLOCK_ENABLE(),
|
||||
.INPUT_CLK(),
|
||||
|
Loading…
Reference in New Issue
Block a user