From 1e6124309fb02824c43549e0861d4023fc5827d8 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sat, 16 Jun 2018 17:44:35 +0200 Subject: ice40: Proper global promotion Signed-off-by: David Shah --- ice40/arch_place.cc | 8 +++++- ice40/cells.cc | 17 +++++++++++- ice40/cells.h | 3 ++ ice40/pack.cc | 79 ++++++++++++++++++++++++++++++++++++++--------------- 4 files changed, 83 insertions(+), 24 deletions(-) (limited to 'ice40') diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index 19c95816..c991af13 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -105,12 +105,18 @@ bool isValidBelForCell(Design *design, CellInfo *cell, BelId bel) for (auto user : cell->ports.at("GLOBAL_BUFFER_OUTPUT").net->users) { if (is_reset_port(user)) is_reset = true; + if (is_enable_port(user)) + is_cen = true; } IdString glb_net = chip.getWireName( chip.getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT)); int glb_id = std::stoi(std::string("") + glb_net.str().back()); - if (is_reset) + if (is_reset && is_cen) + return false; + else if (is_reset) return (glb_id % 2) == 0; + else if (is_cen) + return (glb_id % 2) == 1; else return true; } else { diff --git a/ice40/cells.cc b/ice40/cells.cc index 52356711..4cc4f29c 100644 --- a/ice40/cells.cc +++ b/ice40/cells.cc @@ -196,7 +196,9 @@ bool is_clock_port(const PortRef &port) return false; if (is_ff(port.cell)) return port.port == "C"; - if (is_ram(port.cell)) + if (port.cell->type == "ICESTORM_LC") + return port.port == "CLK"; + if (is_ram(port.cell) || port.cell->type == "ICESTORM_RAM") return port.port == "RCLK" || port.port == "WCLK"; return false; } @@ -207,6 +209,19 @@ bool is_reset_port(const PortRef &port) return false; if (is_ff(port.cell)) return port.port == "R" || port.port == "S"; + if (port.cell->type == "ICESTORM_LC") + return port.port == "SR"; + return false; +} + +bool is_enable_port(const PortRef &port) +{ + if (port.cell == nullptr) + return false; + if (is_ff(port.cell)) + return port.port == "E"; + if (port.cell->type == "ICESTORM_LC") + return port.port == "CEN"; return false; } diff --git a/ice40/cells.h b/ice40/cells.h index f1bc5d1f..ff8cc93d 100644 --- a/ice40/cells.h +++ b/ice40/cells.h @@ -83,6 +83,9 @@ bool is_clock_port(const PortRef &port); // Return true if a port is a reset port bool is_reset_port(const PortRef &port); +// Return true if a port is a clock enable port +bool is_enable_port(const PortRef &port); + NEXTPNR_NAMESPACE_END #endif diff --git a/ice40/pack.cc b/ice40/pack.cc index d88870e0..dde8ed57 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -289,13 +289,15 @@ static void insert_global(Design *design, NetInfo *net, bool is_reset, pr.cell = gb; pr.port = "GLOBAL_BUFFER_OUTPUT"; NetInfo *glbnet = new NetInfo(); - glbnet->name = net->name.str() + "_glb"; + glbnet->name = net->name.str() + std::string("_glb_") + + (is_reset ? "sr" : (is_cen ? "ce" : "clk")); glbnet->driver = pr; design->nets[glbnet->name] = glbnet; gb->ports["GLOBAL_BUFFER_OUTPUT"].net = glbnet; std::vector keep_users; for (auto user : net->users) { - if (is_clock_port(user) || (is_reset && is_reset_port(user))) { + if (is_clock_port(user) || (is_reset && is_reset_port(user)) || + (is_cen && is_enable_port(user))) { user.cell->ports[user.port].net = glbnet; glbnet->users.push_back(user); } else { @@ -311,39 +313,72 @@ static void promote_globals(Design *design) { log_info("Promoting globals..\n"); - std::unordered_map clock_count; - std::unordered_map reset_count; - + std::unordered_map clock_count, reset_count, cen_count; for (auto net : design->nets) { NetInfo *ni = net.second; if (ni->driver.cell != nullptr && !is_global_net(ni)) { clock_count[net.first] = 0; reset_count[net.first] = 0; + cen_count[net.first] = 0; + for (auto user : ni->users) { if (is_clock_port(user)) clock_count[net.first]++; if (is_reset_port(user)) reset_count[net.first]++; + if (is_enable_port(user)) + cen_count[net.first]++; } } } - auto global_clock = std::max_element(clock_count.begin(), clock_count.end(), - [](const std::pair &a, - const std::pair &b) { - return a.second < b.second; - }); - if (global_clock->second > 0) { - NetInfo *clknet = design->nets[global_clock->first]; - insert_global(design, clknet, false, false); - } - auto global_reset = std::max_element(reset_count.begin(), reset_count.end(), - [](const std::pair &a, - const std::pair &b) { - return a.second < b.second; - }); - if (global_reset->second > 0) { - NetInfo *rstnet = design->nets[global_reset->first]; - insert_global(design, rstnet, true, false); + int prom_globals = 0, prom_resets = 0, prom_cens = 0; + int gbs_available = 8; + for (auto cell : design->cells) + if (is_gbuf(cell.second)) + --gbs_available; + while (prom_globals < gbs_available) { + auto global_clock = + std::max_element(clock_count.begin(), clock_count.end(), + [](const std::pair &a, + const std::pair &b) { + return a.second < b.second; + }); + + auto global_reset = + std::max_element(reset_count.begin(), reset_count.end(), + [](const std::pair &a, + const std::pair &b) { + return a.second < b.second; + }); + auto global_cen = + std::max_element(cen_count.begin(), cen_count.end(), + [](const std::pair &a, + const std::pair &b) { + return a.second < b.second; + }); + if (global_reset->second > global_clock->second && prom_resets < 4) { + NetInfo *rstnet = design->nets[global_reset->first]; + insert_global(design, rstnet, true, false); + ++prom_globals; + ++prom_resets; + clock_count.erase(rstnet->name); + reset_count.erase(rstnet->name); + + } else if (global_cen->second > global_clock->second && prom_cens < 4) { + NetInfo *cennet = design->nets[global_cen->first]; + insert_global(design, cennet, false, true); + ++prom_globals; + ++prom_cens; + cen_count.erase(cennet->name); + clock_count.erase(cennet->name); + } else if (global_clock->second != 0) { + NetInfo *clknet = design->nets[global_clock->first]; + insert_global(design, clknet, false, false); + ++prom_globals; + clock_count.erase(clknet->name); + } else { + break; + } } } -- cgit v1.2.3