aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Shah <davey1576@gmail.com>2018-06-13 15:10:42 +0200
committerDavid Shah <davey1576@gmail.com>2018-06-13 15:10:42 +0200
commit14b5e46b5df76973dccd26bb07dc12c26e5d6efc (patch)
treedfdef863b1e195fc0dd660663ca9d0088081f723
parentd80e60cce210b58c036003f6812eb876c632d19e (diff)
downloadnextpnr-14b5e46b5df76973dccd26bb07dc12c26e5d6efc.tar.gz
nextpnr-14b5e46b5df76973dccd26bb07dc12c26e5d6efc.tar.bz2
nextpnr-14b5e46b5df76973dccd26bb07dc12c26e5d6efc.zip
ice40: Promote one clock to a global buffer
Signed-off-by: David Shah <davey1576@gmail.com>
-rw-r--r--ice40/cells.cc8
-rw-r--r--ice40/cells.h6
-rw-r--r--ice40/pack.cc48
3 files changed, 61 insertions, 1 deletions
diff --git a/ice40/cells.cc b/ice40/cells.cc
index b038db68..604baccb 100644
--- a/ice40/cells.cc
+++ b/ice40/cells.cc
@@ -79,7 +79,9 @@ CellInfo *create_ice_cell(Design *design, IdString type, IdString name)
add_port(new_cell, "D_IN_0", PORT_OUT);
add_port(new_cell, "D_IN_1", PORT_OUT);
-
+ } else if (type == "SB_GB") {
+ add_port(new_cell, "USER_SIGNAL_TO_GLOBAL_BUFFER", PORT_IN);
+ add_port(new_cell, "GLOBAL_BUFFER_OUTPUT", PORT_OUT);
} else {
log_error("unable to create iCE40 cell of type %s", type.c_str());
}
@@ -164,4 +166,8 @@ void nxio_to_sb(CellInfo *nxio, CellInfo *sbio)
}
}
+bool is_global_net(NetInfo *net) {
+ return bool(net_driven_by(net, is_gbuf, "GLOBAL_BUFFER_OUTPUT"));
+}
+
NEXTPNR_NAMESPACE_END
diff --git a/ice40/cells.h b/ice40/cells.h
index 3cf0b718..660c7265 100644
--- a/ice40/cells.h
+++ b/ice40/cells.h
@@ -50,6 +50,9 @@ inline bool is_ff(const CellInfo *cell)
// Return true if a cell is a SB_IO
inline bool is_sb_io(const CellInfo *cell) { return cell->type == "SB_IO"; }
+// Return true if a cell is a global buffer
+inline bool is_gbuf(const CellInfo *cell) {return cell->type == "SB_GB"; }
+
// 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
@@ -64,6 +67,9 @@ void dff_to_lc(CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false);
// Convert a nextpnr IO buffer to a SB_IO
void nxio_to_sb(CellInfo *nxio, CellInfo *sbio);
+// Return true if a net is a global net
+bool is_global_net(NetInfo *net);
+
NEXTPNR_NAMESPACE_END
#endif
diff --git a/ice40/pack.cc b/ice40/pack.cc
index 49c95ad6..e8876283 100644
--- a/ice40/pack.cc
+++ b/ice40/pack.cc
@@ -222,10 +222,58 @@ static void pack_io(Design *design)
}
}
+// Simple global promoter (clock only)
+static void promote_globals(Design *design)
+{
+ std::unordered_map<IdString, int> clock_count;
+ for (auto net : design->nets) {
+ NetInfo *ni = net.second;
+ if (ni->driver.cell != nullptr && !is_global_net(ni)) {
+ clock_count[net.first] = 0;
+ for (auto user : ni->users) {
+ if (user.cell != nullptr && is_ff(user.cell) && user.port == "C")
+ clock_count[net.first]++;
+ }
+ }
+ }
+ auto global_clock = std::max_element(clock_count.begin(), clock_count.end(), [](
+ const std::pair<IdString, int> &a, const std::pair<IdString, int> &b) {
+ return a.second < b.second;
+ });
+ if (global_clock->second > 0) {
+ NetInfo *clknet = design->nets[global_clock->first];
+ CellInfo *gb = create_ice_cell(design, "SB_GB");
+ gb->ports["USER_SIGNAL_TO_GLOBAL_BUFFER"].net = clknet;
+ PortRef pr;
+ pr.cell = gb;
+ pr.port = "USER_SIGNAL_TO_GLOBAL_BUFFER";
+ clknet->users.push_back(pr);
+
+ pr.cell = gb;
+ pr.port = "GLOBAL_BUFFER_OUTPUT";
+ NetInfo *glbnet = new NetInfo();
+ glbnet->name = clknet->name.str() + "_glb";
+ glbnet->driver = pr;
+ design->nets[glbnet->name] = glbnet;
+ std::vector<PortRef> keep_users;
+ for (auto user : clknet->users) {
+ if (user.cell != nullptr && is_ff(user.cell) && user.port == "C") {
+ user.cell->ports[user.port].net = glbnet;
+ glbnet->users.push_back(user);
+ } else {
+ keep_users.push_back(user);
+ }
+ }
+ clknet->users = keep_users;
+ design->cells[gb->name] = gb;
+ }
+}
+
// Main pack function
void pack_design(Design *design)
{
pack_constants(design);
+ promote_globals(design);
pack_io(design);
pack_lut_lutffs(design);
pack_nonlut_ffs(design);