diff --git a/ice40/arch.cc b/ice40/arch.cc index d6ef800d..6679217a 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -2,6 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -805,4 +806,53 @@ void Arch::assignCellInfo(CellInfo *cell) } } +std::unique_ptr Arch::spliceLUT(CellInfo *ci, IdString portId, bool onlyNonLUTs) +{ + auto port = ci->ports[portId]; + + NPNR_ASSERT(port.net != nullptr); + + + // Create pass-through LUT. + std::unique_ptr pt = + create_ice_cell(getCtx(), id("ICESTORM_LC"), ci->name.str(this) + "$nextpnr_ice40_pack_pll_lc"); + pt->params[id("LUT_INIT")] = "255"; // output is always I3 + + // Create LUT output net. + std::unique_ptr out_net = std::unique_ptr(new NetInfo); + out_net->name = id(ci->name.str(this) + "$nextnr_ice40_pack_pll_net"); + out_net->driver.cell = pt.get(); + out_net->driver.port = id("O"); + pt->ports.at(id("O")).net = out_net.get(); + + // New users of the original cell's port + std::vector new_users; + for (const auto &user : port.net->users) { + if (onlyNonLUTs && user.cell->type == id("ICESTORM_LC")) { + new_users.push_back(user); + continue; + } + // Rewrite pointer into net in user. + user.cell->ports[user.port].net = out_net.get(); + // Add user to net. + PortRef pr; + pr.cell = user.cell; + pr.port = user.port; + out_net->users.push_back(pr); + } + + // Add LUT to new users. + PortRef pr; + pr.cell = pt.get(); + pr.port = id("I3"); + new_users.push_back(pr); + pt->ports.at(id("I3")).net = port.net; + + // Replace users of the original net. + port.net->users = new_users; + + nets[out_net->name] = std::move(out_net); + return pt; +} + NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index d4d71cfc..15422aa7 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -746,6 +746,11 @@ struct Arch : BaseCtx IdString id_cen, id_clk, id_sr; IdString id_i0, id_i1, id_i2, id_i3; IdString id_dff_en, id_neg_clk; + + + // ------------------------------------------------- + // Insert a LUT/LC in between a given output port of a cell and all its' users. + std::unique_ptr spliceLUT(CellInfo *ci, IdString portId, bool onlyNonLUTs); }; NEXTPNR_NAMESPACE_END diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 77d92a89..2ee8a294 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -3,6 +3,7 @@ * * Copyright (C) 2018 Clifford Wolf * Copyright (C) 2018 David Shah + * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/ice40/pack.cc b/ice40/pack.cc index 6e56c49b..dc0db578 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -3,6 +3,7 @@ * * Copyright (C) 2018 Clifford Wolf * Copyright (C) 2018 David Shah + * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -673,84 +674,12 @@ static void pack_special(Context *ctx) } else if (found_lut && !all_luts && lut_count < 8) { // Strategy: create a pass-through LUT, move all non-LUT users behind it. log_info(" LUT strategy for %s: move non-LUT users to new LUT\n", port.name.c_str(ctx)); - // Create pass-through LUT. - std::unique_ptr pt = - create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "$nextpnr_ice40_pack_pll_lc"); - packed_cells.insert(pt->name); - pt->params[ctx->id("LUT_INIT")] = "255"; // all lower bits lit, so output is always I3 - - // Create net to which all non-LUTs will be moved. - std::unique_ptr out_net = std::unique_ptr(new NetInfo); - out_net->name = ctx->id(ci->name.str(ctx) + "$nextnr_ice40_pack_pll_net"); - out_net->driver.cell = pt.get(); - out_net->driver.port = ctx->id("O"); - pt->ports.at(ctx->id("O")).net = out_net.get(); - - // Move all non-LUTs to new net. - std::vector new_users; - for (const auto &user : port.net->users) { - if (user.cell->type == ctx->id("ICESTORM_LC")) { - new_users.push_back(user); - } - // Rewrite pointer into net in user. - user.cell->ports[user.port].net = out_net.get(); - // Add user to net. - PortRef pr; - pr.cell = user.cell; - pr.port = user.port; - out_net->users.push_back(pr); - } - // Add LUT to new users. - PortRef pr; - pr.cell = pt.get(); - pr.port = ctx->id("I3"); - new_users.push_back(pr); - pt->ports.at(ctx->id("I3")).net = port.net; - - // Replace users of the original net. - port.net->users = new_users; - - ctx->nets[out_net->name] = std::move(out_net); + auto pt = ctx->spliceLUT(packed.get(), port.name, true); new_cells.push_back(std::move(pt)); } else { // Strategy: create a pass-through LUT, move every user behind it. log_info(" LUT strategy for %s: move all users to new LUT\n", port.name.c_str(ctx)); - // Create pass-through LUT. - std::unique_ptr pt = - create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "$nextpnr_ice40_pack_pll_lc"); - packed_cells.insert(pt->name); - pt->params[ctx->id("LUT_INIT")] = "255"; // all lower bits lit, so output is always I3 - - // Create net to which all current users will be moved. - std::unique_ptr out_net = std::unique_ptr(new NetInfo); - out_net->name = ctx->id(ci->name.str(ctx) + "$nextnr_ice40_pack_pll_net"); - out_net->driver.cell = pt.get(); - out_net->driver.port = ctx->id("O"); - pt->ports.at(ctx->id("O")).net = out_net.get(); - - // Move all users to new net. - for (const auto &user : port.net->users) { - // Rewrite pointer into net in user. - user.cell->ports[user.port].net = out_net.get(); - // Add user to net. - PortRef pr; - pr.cell = user.cell; - pr.port = user.port; - out_net->users.push_back(pr); - } - - // Add LUT to new users. - std::vector new_users; - PortRef pr; - pr.cell = pt.get(); - pr.port = ctx->id("I3"); - new_users.push_back(pr); - pt->ports.at(ctx->id("I3")).net = port.net; - - // Replace users of the original net. - port.net->users = new_users; - - ctx->nets[out_net->name] = std::move(out_net); + auto pt = ctx->spliceLUT(packed.get(), port.name, false); new_cells.push_back(std::move(pt)); }