diff options
-rw-r--r-- | ice40/cells.cc | 3 | ||||
-rw-r--r-- | ice40/cells.h | 9 | ||||
-rw-r--r-- | ice40/pack.cc | 42 |
3 files changed, 46 insertions, 8 deletions
diff --git a/ice40/cells.cc b/ice40/cells.cc index 604baccb..a8200d76 100644 --- a/ice40/cells.cc +++ b/ice40/cells.cc @@ -166,7 +166,8 @@ void nxio_to_sb(CellInfo *nxio, CellInfo *sbio) } } -bool is_global_net(NetInfo *net) { +bool is_global_net(NetInfo *net) +{ return bool(net_driven_by(net, is_gbuf, "GLOBAL_BUFFER_OUTPUT")); } diff --git a/ice40/cells.h b/ice40/cells.h index 660c7265..e5b4fa9c 100644 --- a/ice40/cells.h +++ b/ice40/cells.h @@ -51,7 +51,14 @@ inline bool is_ff(const CellInfo *cell) 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"; } +inline bool is_gbuf(const CellInfo *cell) { return cell->type == "SB_GB"; } + +// Return true if a cell is a RAM +inline bool is_ram(const CellInfo *cell) +{ + return cell->type == "SB_RAM40_4K" || cell->type == "SB_RAM40_4KNR" || + cell->type == "SB_RAM40_4KNW" || cell->type == "SB_RAM40_4KNRNW"; +} // 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 diff --git a/ice40/pack.cc b/ice40/pack.cc index e8876283..be8d1db1 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -110,6 +110,23 @@ static void pack_nonlut_ffs(Design *design) } } +// "Pack" RAMs +static void pack_ram(Design *design) +{ + for (auto cell : design->cells) { + CellInfo *ci = cell.second; + if (is_ram(ci)) { + ci->params["NEG_CLK_W"] = + std::to_string(ci->type == "SB_RAM40_4KNW" || + ci->type == "SB_RAM40_4KNRNW"); + ci->params["NEG_CLK_R"] = + std::to_string(ci->type == "SB_RAM40_4KNR" || + ci->type == "SB_RAM40_4KNRNW"); + ci->type = "ICESTORM_RAM"; + } + } +} + // Merge a net into a constant net static void set_net_constant(NetInfo *orig, NetInfo *constnet, bool constval) { @@ -222,6 +239,17 @@ static void pack_io(Design *design) } } +static bool is_clock_port(const PortRef &port) +{ + if (port.cell == nullptr) + return false; + if (is_ff(port.cell)) + return port.port == "C"; + if (is_ram(port.cell)) + return port.port == "RCLK" || port.port == "WCLK"; + return false; +} + // Simple global promoter (clock only) static void promote_globals(Design *design) { @@ -231,15 +259,16 @@ static void promote_globals(Design *design) 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") + if (is_clock_port(user)) 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; - }); + 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"); @@ -257,7 +286,7 @@ static void promote_globals(Design *design) 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") { + if (is_clock_port(user)) { user.cell->ports[user.port].net = glbnet; glbnet->users.push_back(user); } else { @@ -277,6 +306,7 @@ void pack_design(Design *design) pack_io(design); pack_lut_lutffs(design); pack_nonlut_ffs(design); + pack_ram(design); } NEXTPNR_NAMESPACE_END |