aboutsummaryrefslogtreecommitdiffstats
path: root/ice40
diff options
context:
space:
mode:
Diffstat (limited to 'ice40')
-rw-r--r--ice40/cells.h3
-rw-r--r--ice40/pack.cc59
-rw-r--r--ice40/pack_tests/io_wrapper.v2
3 files changed, 63 insertions, 1 deletions
diff --git a/ice40/cells.h b/ice40/cells.h
index 34a034cd..da4e2bd8 100644
--- a/ice40/cells.h
+++ b/ice40/cells.h
@@ -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
diff --git a/ice40/pack.cc b/ice40/pack.cc
index 8f770a07..73ba0e3d 100644
--- a/ice40/pack.cc
+++ b/ice40/pack.cc
@@ -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);
}
diff --git a/ice40/pack_tests/io_wrapper.v b/ice40/pack_tests/io_wrapper.v
index b58d6c0c..e10ec419 100644
--- a/ice40/pack_tests/io_wrapper.v
+++ b/ice40/pack_tests/io_wrapper.v
@@ -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(),