|
|
|
|
@ -0,0 +1,845 @@
|
|
|
|
|
/*
|
|
|
|
|
* nextpnr -- Next Generation Place and Route
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2024 The Project Peppercorn Authors.
|
|
|
|
|
*
|
|
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "gatemate.h"
|
|
|
|
|
#include "log.h"
|
|
|
|
|
|
|
|
|
|
#define HIMBAECHEL_CONSTIDS "uarch/gatemate/constids.inc"
|
|
|
|
|
#include "himbaechel_constids.h"
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
USING_NEXTPNR_NAMESPACE;
|
|
|
|
|
|
|
|
|
|
void find_and_bind_downhill_pip(Context *ctx, WireId from, WireId to, NetInfo *net)
|
|
|
|
|
{
|
|
|
|
|
NPNR_ASSERT(from != WireId());
|
|
|
|
|
NPNR_ASSERT(to != WireId());
|
|
|
|
|
for (auto pip : ctx->getPipsDownhill(from)) {
|
|
|
|
|
if (ctx->getPipDstWire(pip) == to) {
|
|
|
|
|
if (ctx->debug)
|
|
|
|
|
log_info(" pip %s: %s -> %s\n", ctx->nameOfPip(pip), ctx->nameOfWire(from), ctx->nameOfWire(to));
|
|
|
|
|
|
|
|
|
|
ctx->bindPip(pip, net, STRENGTH_LOCKED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
log_error("Couldn't find pip from %s to %s\n", ctx->nameOfWire(from), ctx->nameOfWire(to));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void route_mult_diag(Context *ctx, NetInfo *net, Loc loc, WireId last_wire, int plane)
|
|
|
|
|
{
|
|
|
|
|
auto hops = 0;
|
|
|
|
|
auto in_port = ctx->idf("IN%d", plane);
|
|
|
|
|
for (auto user : net->users) {
|
|
|
|
|
if (user.port == in_port)
|
|
|
|
|
hops++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ctx->debug)
|
|
|
|
|
log_info(" routing diagonal: %d hops\n", hops);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < hops; i++) {
|
|
|
|
|
auto cpe_in = ctx->getWireByName(
|
|
|
|
|
IdStringList::concat(ctx->idf("X%dY%d", loc.x + i, loc.y + i), ctx->idf("CPE.IN%d", plane)));
|
|
|
|
|
auto cpe_in_int = ctx->getWireByName(
|
|
|
|
|
IdStringList::concat(ctx->idf("X%dY%d", loc.x + i, loc.y + i), ctx->idf("CPE.IN%d_int", plane)));
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, last_wire, cpe_in, net); // inverting
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_in, cpe_in_int, net);
|
|
|
|
|
|
|
|
|
|
last_wire = cpe_in;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void route_mult_x1y1_lower(Context *ctx, NetInfo *net, CellInfo *lower, Loc loc, bool is_fourgroup_a)
|
|
|
|
|
{
|
|
|
|
|
if (ctx->debug)
|
|
|
|
|
log_info(" routing net '%s' -> IN5 using x1y1\n", net->name.c_str(ctx));
|
|
|
|
|
|
|
|
|
|
auto x1y1 = ctx->idf("X%dY%d", loc.x, loc.y);
|
|
|
|
|
auto x2y1 = ctx->idf("X%dY%d", loc.x + 1, loc.y);
|
|
|
|
|
|
|
|
|
|
auto cpe_combout1 = ctx->getBelPinWire(lower->bel, id_OUT);
|
|
|
|
|
auto cpe_out1_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("CPE.OUT1_int")));
|
|
|
|
|
auto in_mux = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("IM.P05.D0")));
|
|
|
|
|
|
|
|
|
|
ctx->bindWire(cpe_combout1, net, STRENGTH_LOCKED);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_combout1, cpe_out1_int, net);
|
|
|
|
|
|
|
|
|
|
if (is_fourgroup_a) {
|
|
|
|
|
auto sb_big = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P05.D0")));
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out1_int, sb_big, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big, in_mux, net); // inverting
|
|
|
|
|
} else {
|
|
|
|
|
auto sb_sml_d0 = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P05.D0")));
|
|
|
|
|
auto sb_sml_y1_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P05.Y1_int")));
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out1_int, sb_sml_d0, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_d0, sb_sml_y1_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_y1_int, in_mux, net); // inverting
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
route_mult_diag(ctx, net, Loc{loc.x + 1, loc.y, 0}, in_mux, 5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void route_mult_x1y1_upper_in1(Context *ctx, NetInfo *net, CellInfo *upper, Loc loc, bool is_fourgroup_a)
|
|
|
|
|
{
|
|
|
|
|
if (ctx->debug)
|
|
|
|
|
log_info(" routing net '%s' -> IN1 using x1y1\n", net->name.c_str(ctx));
|
|
|
|
|
|
|
|
|
|
auto x1y1 = ctx->idf("X%dY%d", loc.x, loc.y);
|
|
|
|
|
auto x2y1 = ctx->idf("X%dY%d", loc.x + 1, loc.y);
|
|
|
|
|
|
|
|
|
|
auto cpe_combout2 = ctx->getBelPinWire(upper->bel, id_OUT);
|
|
|
|
|
auto cpe_out2_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("CPE.OUT2_int")));
|
|
|
|
|
auto in_mux = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("IM.P01.D0")));
|
|
|
|
|
|
|
|
|
|
ctx->bindWire(cpe_combout2, net, STRENGTH_LOCKED);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_combout2, cpe_out2_int, net);
|
|
|
|
|
|
|
|
|
|
if (is_fourgroup_a) {
|
|
|
|
|
auto sb_big = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P01.D0")));
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out2_int, sb_big, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big, in_mux, net); // inverting
|
|
|
|
|
} else {
|
|
|
|
|
auto sb_sml_d0 = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P01.D0")));
|
|
|
|
|
auto sb_sml_y1_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P01.Y1_int")));
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out2_int, sb_sml_d0, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_d0, sb_sml_y1_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_y1_int, in_mux, net); // inverting
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
route_mult_diag(ctx, net, Loc{loc.x + 1, loc.y, 0}, in_mux, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void route_mult_x1y1_upper_in8(Context *ctx, NetInfo *net, CellInfo *upper, Loc loc, bool is_fourgroup_a,
|
|
|
|
|
bool bind_route_start = false)
|
|
|
|
|
{
|
|
|
|
|
if (ctx->debug)
|
|
|
|
|
log_info(" routing net '%s' -> IN8 using x1y1\n", net->name.c_str(ctx));
|
|
|
|
|
|
|
|
|
|
auto x1y1 = ctx->idf("X%dY%d", loc.x, loc.y);
|
|
|
|
|
auto x2y2 = ctx->idf("X%dY%d", loc.x + 1, loc.y + 1);
|
|
|
|
|
auto x4y2 = ctx->idf("X%dY%d", loc.x + 3, loc.y + 1);
|
|
|
|
|
|
|
|
|
|
auto cpe_combout2 = ctx->getBelPinWire(upper->bel, id_OUT);
|
|
|
|
|
auto cpe_out2_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("CPE.OUT2_int")));
|
|
|
|
|
auto out_mux_d0 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("OM.P12.D0")));
|
|
|
|
|
auto out_mux_y = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("OM.P12.Y")));
|
|
|
|
|
auto in_mux_p12 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P12.D2")));
|
|
|
|
|
|
|
|
|
|
if (bind_route_start) {
|
|
|
|
|
ctx->bindWire(cpe_combout2, net, STRENGTH_LOCKED);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_combout2, cpe_out2_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out2_int, out_mux_d0, net);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, out_mux_d0, out_mux_y, net); // inverting
|
|
|
|
|
|
|
|
|
|
if (is_fourgroup_a) {
|
|
|
|
|
auto sb_sml = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("SB_SML.P12.Y1_int")));
|
|
|
|
|
auto sb_big_d2_1 = ctx->getWireByName(IdStringList::concat(x4y2, ctx->idf("SB_BIG.P12.D2_1")));
|
|
|
|
|
auto sb_big_y1 = ctx->getWireByName(IdStringList::concat(x4y2, ctx->idf("SB_BIG.P12.Y1")));
|
|
|
|
|
auto sb_big_ydiag = ctx->getWireByName(IdStringList::concat(x4y2, ctx->idf("SB_BIG.P12.YDIAG")));
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, out_mux_y, sb_sml, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml, sb_big_d2_1, net); // inverting
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_d2_1, sb_big_y1, net); // inverting
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_y1, sb_big_ydiag, net); // inverting
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_ydiag, in_mux_p12, net); // inverting
|
|
|
|
|
} else {
|
|
|
|
|
auto sb_big =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("SB_BIG.P12.Y1"))); // aka x4y2/SB_SML.P12.D2_1
|
|
|
|
|
auto sb_sml_y1_int = ctx->getWireByName(IdStringList::concat(x4y2, ctx->idf("SB_SML.P12.Y1_int")));
|
|
|
|
|
auto sb_sml_ydiag_int = ctx->getWireByName(IdStringList::concat(x4y2, ctx->idf("SB_SML.P12.YDIAG_int")));
|
|
|
|
|
auto sb_sml_y3_int = ctx->getWireByName(IdStringList::concat(x4y2, ctx->idf("SB_SML.P12.Y3_int")));
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, out_mux_y, sb_big, net); // inverting
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big, sb_sml_y1_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_y1_int, sb_sml_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_ydiag_int, sb_sml_y3_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_y3_int, in_mux_p12, net); // inverting
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto in_mux_p04 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P04.D7"))); // aka IM.P12.Y
|
|
|
|
|
auto in_mux_p08 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P08.D6"))); // aka IM.P04.Y
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, in_mux_p12, in_mux_p04, net); // inverting
|
|
|
|
|
find_and_bind_downhill_pip(ctx, in_mux_p04, in_mux_p08, net); // inverting
|
|
|
|
|
|
|
|
|
|
route_mult_diag(ctx, net, Loc{loc.x + 1, loc.y + 1, 0}, in_mux_p08, 8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void route_mult_x1y2_lower(Context *ctx, NetInfo *net, CellInfo *lower, Loc loc, bool is_fourgroup_a)
|
|
|
|
|
{
|
|
|
|
|
if (ctx->debug)
|
|
|
|
|
log_info(" routing net '%s' -> IN5 using x1y2\n", net->name.c_str(ctx));
|
|
|
|
|
|
|
|
|
|
auto x1y1 = ctx->idf("X%dY%d", loc.x, loc.y);
|
|
|
|
|
auto x2y1 = ctx->idf("X%dY%d", loc.x + 1, loc.y);
|
|
|
|
|
auto x4y1 = ctx->idf("X%dY%d", loc.x + 3, loc.y);
|
|
|
|
|
|
|
|
|
|
auto cpe_combout1 = ctx->getBelPinWire(lower->bel, id_OUT);
|
|
|
|
|
auto cpe_out1_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("CPE.OUT1_int")));
|
|
|
|
|
auto in_mux = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("IM.P05.D2")));
|
|
|
|
|
|
|
|
|
|
ctx->bindWire(cpe_combout1, net, STRENGTH_LOCKED);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_combout1, cpe_out1_int, net);
|
|
|
|
|
|
|
|
|
|
if (is_fourgroup_a) {
|
|
|
|
|
auto sb_sml_p06_d0 = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_SML.P06.D0")));
|
|
|
|
|
auto sb_sml_p06_y1_int = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_SML.P06.Y1_int")));
|
|
|
|
|
auto sb_sml_p06_ydiag_int = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_SML.P06.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p06_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_SML.P06.YDIAG"))); // AKA SB_SML.P05.X23
|
|
|
|
|
auto sb_sml_p05_ydiag_int = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_SML.P05.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p05_y1_int = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_SML.P05.Y1_int")));
|
|
|
|
|
auto sb_sml_p05_y1 = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_SML.P05.Y1")));
|
|
|
|
|
auto sb_big_y1 = ctx->getWireByName(IdStringList::concat(x4y1, ctx->idf("SB_BIG.P05.Y1")));
|
|
|
|
|
auto sb_big_ydiag = ctx->getWireByName(IdStringList::concat(x4y1, ctx->idf("SB_BIG.P05.YDIAG")));
|
|
|
|
|
// x2y1/IM.P05.D2 is x4y1/SB_BIG.P05.Y3
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out1_int, sb_sml_p06_d0, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p06_d0, sb_sml_p06_y1_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p06_y1_int, sb_sml_p06_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p06_ydiag_int, sb_sml_p06_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p06_ydiag, sb_sml_p05_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p05_ydiag_int, sb_sml_p05_y1_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p05_y1_int, sb_sml_p05_y1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p05_y1, sb_big_y1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_y1, sb_big_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_ydiag, in_mux, net);
|
|
|
|
|
} else {
|
|
|
|
|
auto sb_big_p06_d0 = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_BIG.P06.D0")));
|
|
|
|
|
auto sb_big_p06_y1 = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_BIG.P06.Y1")));
|
|
|
|
|
auto sb_big_p06_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_BIG.P06.YDIAG"))); // AKA SB_BIG.P05.X23
|
|
|
|
|
auto sb_big_p05_ydiag = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_BIG.P05.YDIAG")));
|
|
|
|
|
auto sb_big_p05_y1 = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_BIG.P05.Y1")));
|
|
|
|
|
auto sb_sml_y1_int = ctx->getWireByName(IdStringList::concat(x4y1, ctx->idf("SB_SML.P05.Y1_int")));
|
|
|
|
|
auto sb_sml_ydiag_int = ctx->getWireByName(IdStringList::concat(x4y1, ctx->idf("SB_SML.P05.YDIAG_int")));
|
|
|
|
|
auto sb_sml_y3_int = ctx->getWireByName(IdStringList::concat(x4y1, ctx->idf("SB_SML.P05.Y3_int")));
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out1_int, sb_big_p06_d0, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p06_d0, sb_big_p06_y1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p06_y1, sb_big_p06_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p06_ydiag, sb_big_p05_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p05_ydiag, sb_big_p05_y1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p05_y1, sb_sml_y1_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_y1_int, sb_sml_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_ydiag_int, sb_sml_y3_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_y3_int, in_mux, net);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
route_mult_diag(ctx, net, Loc{loc.x + 1, loc.y, 0}, in_mux, 5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void route_mult_x1y2_upper_in1(Context *ctx, NetInfo *net, CellInfo *upper, Loc loc, bool is_fourgroup_a)
|
|
|
|
|
{
|
|
|
|
|
if (ctx->debug)
|
|
|
|
|
log_info(" routing net '%s' -> IN1 using x1y2\n", net->name.c_str(ctx));
|
|
|
|
|
|
|
|
|
|
auto x1y1 = ctx->idf("X%dY%d", loc.x, loc.y);
|
|
|
|
|
auto x2y1 = ctx->idf("X%dY%d", loc.x + 1, loc.y);
|
|
|
|
|
auto x4y1 = ctx->idf("X%dY%d", loc.x + 3, loc.y);
|
|
|
|
|
|
|
|
|
|
auto cpe_combout2 = ctx->getBelPinWire(upper->bel, id_OUT);
|
|
|
|
|
auto cpe_out2_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("CPE.OUT2_int")));
|
|
|
|
|
|
|
|
|
|
ctx->bindWire(cpe_combout2, net, STRENGTH_LOCKED);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_combout2, cpe_out2_int, net);
|
|
|
|
|
|
|
|
|
|
auto in_mux = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("IM.P01.D2")));
|
|
|
|
|
|
|
|
|
|
if (is_fourgroup_a) {
|
|
|
|
|
auto sb_sml_p02_d0 = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_SML.P02.D0")));
|
|
|
|
|
auto sb_sml_p02_y1 = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_SML.P02.Y1_int")));
|
|
|
|
|
auto sb_sml_p02_ydiag_int = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_SML.P02.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p02_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_SML.P02.YDIAG"))); // AKA SB_SML.P01.X23
|
|
|
|
|
auto sb_sml_p01_ydiag = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_SML.P01.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p01_y1 = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_SML.P01.Y1_int")));
|
|
|
|
|
auto sb_big_d2_1 = ctx->getWireByName(IdStringList::concat(x4y1, ctx->idf("SB_BIG.P01.D2_1")));
|
|
|
|
|
auto sb_big_y1 = ctx->getWireByName(IdStringList::concat(x4y1, ctx->idf("SB_BIG.P01.Y1")));
|
|
|
|
|
auto sb_big_ydiag = ctx->getWireByName(IdStringList::concat(x4y1, ctx->idf("SB_BIG.P01.YDIAG")));
|
|
|
|
|
// x2y1/IM.P01.D2 is x4y1/SB_BIG.P01.Y3
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out2_int, sb_sml_p02_d0, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p02_d0, sb_sml_p02_y1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p02_y1, sb_sml_p02_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p02_ydiag_int, sb_sml_p02_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p02_ydiag, sb_sml_p01_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p01_ydiag, sb_sml_p01_y1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p01_y1, sb_big_d2_1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_d2_1, sb_big_y1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_y1, sb_big_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_ydiag, in_mux, net);
|
|
|
|
|
} else {
|
|
|
|
|
auto sb_big_p02_d0 = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_BIG.P02.D0")));
|
|
|
|
|
auto sb_big_p02_y1 = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_BIG.P02.Y1")));
|
|
|
|
|
auto sb_big_p02_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_BIG.P02.YDIAG"))); // AKA SB_BIG.P01.X23
|
|
|
|
|
auto sb_big_p01_ydiag = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_BIG.P01.YDIAG")));
|
|
|
|
|
auto sb_big_p01_y1 = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_BIG.P01.Y1")));
|
|
|
|
|
auto sb_sml_y1 = ctx->getWireByName(IdStringList::concat(x4y1, ctx->idf("SB_SML.P01.Y1_int")));
|
|
|
|
|
auto sb_sml_ydiag = ctx->getWireByName(IdStringList::concat(x4y1, ctx->idf("SB_SML.P01.YDIAG_int")));
|
|
|
|
|
auto sb_sml_y3 = ctx->getWireByName(IdStringList::concat(x4y1, ctx->idf("SB_SML.P01.Y3_int")));
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out2_int, sb_big_p02_d0, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p02_d0, sb_big_p02_y1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p02_y1, sb_big_p02_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p02_ydiag, sb_big_p01_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p01_ydiag, sb_big_p01_y1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p01_y1, sb_sml_y1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_y1, sb_sml_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_ydiag, sb_sml_y3, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_y3, in_mux, net);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
route_mult_diag(ctx, net, Loc{loc.x + 1, loc.y, 0}, in_mux, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void route_mult_x1y2_upper_in8(Context *ctx, NetInfo *net, CellInfo *upper, Loc loc, bool is_fourgroup_a,
|
|
|
|
|
bool bind_route_start = false)
|
|
|
|
|
{
|
|
|
|
|
if (ctx->debug)
|
|
|
|
|
log_info(" routing net '%s' -> IN8 using x1y2\n", net->name.c_str(ctx));
|
|
|
|
|
|
|
|
|
|
auto x1y1 = ctx->idf("X%dY%d", loc.x, loc.y);
|
|
|
|
|
auto x2y1 = ctx->idf("X%dY%d", loc.x + 1, loc.y);
|
|
|
|
|
auto x2y2 = ctx->idf("X%dY%d", loc.x + 1, loc.y + 1);
|
|
|
|
|
|
|
|
|
|
auto cpe_combout2 = ctx->getBelPinWire(upper->bel, id_OUT);
|
|
|
|
|
auto cpe_out2_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("CPE.OUT2_int")));
|
|
|
|
|
auto out_mux_d1 = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("OM.P10.D1")));
|
|
|
|
|
auto out_mux_y = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("OM.P10.Y")));
|
|
|
|
|
auto in_mux_p10 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P10.D1")));
|
|
|
|
|
|
|
|
|
|
if (bind_route_start) {
|
|
|
|
|
ctx->bindWire(cpe_combout2, net, STRENGTH_LOCKED);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_combout2, cpe_out2_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out2_int, out_mux_d1, net);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, out_mux_d1, out_mux_y, net); // inverting
|
|
|
|
|
|
|
|
|
|
if (is_fourgroup_a) {
|
|
|
|
|
auto sb_sml = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("SB_SML.P10.Y2_int")));
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, out_mux_y, sb_sml, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml, in_mux_p10, net); // inverting
|
|
|
|
|
} else {
|
|
|
|
|
// x2y1/OM.P10.Y is x2y1/SB_BIG.P10.D0
|
|
|
|
|
// x2y2/IM.P10.D1 is x2y1/SB_BIG.P10.Y2
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, out_mux_y, in_mux_p10, net); // inverting
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto in_mux_p12 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P12.D6"))); // aka IM.P10.Y
|
|
|
|
|
auto in_mux_p04 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P04.D7"))); // aka IM.P12.Y
|
|
|
|
|
auto in_mux_p08 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P08.D6"))); // aka IM.P04.Y
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, in_mux_p10, in_mux_p12, net); // inverting
|
|
|
|
|
find_and_bind_downhill_pip(ctx, in_mux_p12, in_mux_p04, net); // inverting
|
|
|
|
|
find_and_bind_downhill_pip(ctx, in_mux_p04, in_mux_p08, net); // inverting
|
|
|
|
|
|
|
|
|
|
route_mult_diag(ctx, net, Loc{loc.x + 1, loc.y + 1, 0}, in_mux_p08, 8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void route_mult_x2y1_lower(Context *ctx, NetInfo *net, CellInfo *lower, Loc loc, bool is_fourgroup_a)
|
|
|
|
|
{
|
|
|
|
|
if (ctx->debug)
|
|
|
|
|
log_info(" routing net '%s' -> IN5 using x2y1\n", net->name.c_str(ctx));
|
|
|
|
|
|
|
|
|
|
auto x0y1 = ctx->idf("X%dY%d", loc.x - 1, loc.y);
|
|
|
|
|
auto x1y1 = ctx->idf("X%dY%d", loc.x, loc.y);
|
|
|
|
|
auto x2y1 = ctx->idf("X%dY%d", loc.x + 1, loc.y);
|
|
|
|
|
|
|
|
|
|
auto cpe_combout1 = ctx->getBelPinWire(lower->bel, id_OUT);
|
|
|
|
|
auto cpe_out1_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("CPE.OUT1_int")));
|
|
|
|
|
auto in_mux = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("IM.P05.D0")));
|
|
|
|
|
|
|
|
|
|
ctx->bindWire(cpe_combout1, net, STRENGTH_LOCKED);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_combout1, cpe_out1_int, net);
|
|
|
|
|
|
|
|
|
|
if (is_fourgroup_a) {
|
|
|
|
|
auto sb_big_p07_d0 = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_BIG.P07.D0")));
|
|
|
|
|
auto sb_big_p07_y1 = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_BIG.P07.Y1")));
|
|
|
|
|
auto sb_big_p07_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_BIG.P07.YDIAG"))); // AKA SB_BIG.P06.X23
|
|
|
|
|
auto sb_big_p06_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_BIG.P06.YDIAG"))); // AKA SB_BIG.P05.X23
|
|
|
|
|
auto sb_big_p05_ydiag = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_BIG.P05.YDIAG")));
|
|
|
|
|
// x2y1/IM.P05.D0 is x0y1/SB_BIG.P05.Y1
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out1_int, sb_big_p07_d0, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p07_d0, sb_big_p07_y1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p07_y1, sb_big_p07_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p07_ydiag, sb_big_p06_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p06_ydiag, sb_big_p05_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p05_ydiag, in_mux, net);
|
|
|
|
|
} else {
|
|
|
|
|
auto sb_sml_p07_d0 = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_SML.P07.D0")));
|
|
|
|
|
auto sb_sml_p07_y1_int = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_SML.P07.Y1_int")));
|
|
|
|
|
auto sb_sml_p07_ydiag_int = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_SML.P07.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p07_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_SML.P07.YDIAG"))); // AKA SB_SML.P06.X23
|
|
|
|
|
auto sb_sml_p06_ydiag_int = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_SML.P06.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p06_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_SML.P06.YDIAG"))); // AKA SB_SML.P05.X23
|
|
|
|
|
auto sb_sml_p05_ydiag_int = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_SML.P05.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p05_y1_int = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_SML.P05.Y1_int")));
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out1_int, sb_sml_p07_d0, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p07_d0, sb_sml_p07_y1_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p07_y1_int, sb_sml_p07_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p07_ydiag_int, sb_sml_p07_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p07_ydiag, sb_sml_p06_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p06_ydiag_int, sb_sml_p06_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p06_ydiag, sb_sml_p05_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p05_ydiag_int, sb_sml_p05_y1_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p05_y1_int, in_mux, net);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
route_mult_diag(ctx, net, Loc{loc.x + 1, loc.y, 0}, in_mux, 5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void route_mult_x2y1_upper_in1(Context *ctx, NetInfo *net, CellInfo *upper, Loc loc, bool is_fourgroup_a)
|
|
|
|
|
{
|
|
|
|
|
if (ctx->debug)
|
|
|
|
|
log_info(" routing net '%s' -> IN1 using x2y1\n", net->name.c_str(ctx));
|
|
|
|
|
|
|
|
|
|
auto x0y1 = ctx->idf("X%dY%d", loc.x - 1, loc.y);
|
|
|
|
|
auto x1y1 = ctx->idf("X%dY%d", loc.x, loc.y);
|
|
|
|
|
auto x2y1 = ctx->idf("X%dY%d", loc.x + 1, loc.y);
|
|
|
|
|
|
|
|
|
|
auto cpe_combout2 = ctx->getBelPinWire(upper->bel, id_OUT);
|
|
|
|
|
auto cpe_out2_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("CPE.OUT2_int")));
|
|
|
|
|
auto in_mux = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("IM.P01.D0")));
|
|
|
|
|
|
|
|
|
|
ctx->bindWire(cpe_combout2, net, STRENGTH_LOCKED);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_combout2, cpe_out2_int, net);
|
|
|
|
|
|
|
|
|
|
if (is_fourgroup_a) {
|
|
|
|
|
auto sb_big_p03_d0 = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_BIG.P03.D0")));
|
|
|
|
|
auto sb_big_p03_y1 = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_BIG.P03.Y1")));
|
|
|
|
|
auto sb_big_p03_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_BIG.P03.YDIAG"))); // AKA SB_BIG.P02.X23
|
|
|
|
|
auto sb_big_p02_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_BIG.P02.YDIAG"))); // AKA SB_BIG.P01.X23
|
|
|
|
|
auto sb_big_p01_ydiag = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_BIG.P01.YDIAG")));
|
|
|
|
|
// x2y1/IM.P01.D0 is x0y1/SB_BIG.P01.Y1
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out2_int, sb_big_p03_d0, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p03_d0, sb_big_p03_y1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p03_y1, sb_big_p03_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p03_ydiag, sb_big_p02_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p02_ydiag, sb_big_p01_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p01_ydiag, in_mux, net);
|
|
|
|
|
} else {
|
|
|
|
|
auto sb_sml_p03_d0 = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_SML.P03.D0")));
|
|
|
|
|
auto sb_sml_p03_y1_int = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_SML.P03.Y1_int")));
|
|
|
|
|
auto sb_sml_p03_ydiag_int = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_SML.P03.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p03_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_SML.P03.YDIAG"))); // AKA SB_SML.P02.X23
|
|
|
|
|
auto sb_sml_p02_ydiag_int = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_SML.P02.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p02_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_SML.P02.YDIAG"))); // AKA SB_SML.P01.X23
|
|
|
|
|
auto sb_sml_p01_ydiag_int = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_SML.P01.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p01_y1_int = ctx->getWireByName(IdStringList::concat(x0y1, ctx->idf("SB_SML.P01.Y1_int")));
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out2_int, sb_sml_p03_d0, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p03_d0, sb_sml_p03_y1_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p03_y1_int, sb_sml_p03_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p03_ydiag_int, sb_sml_p03_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p03_ydiag, sb_sml_p02_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p02_ydiag_int, sb_sml_p02_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p02_ydiag, sb_sml_p01_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p01_ydiag_int, sb_sml_p01_y1_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p01_y1_int, in_mux, net);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
route_mult_diag(ctx, net, Loc{loc.x + 1, loc.y, 0}, in_mux, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void route_mult_x2y1_upper_in8(Context *ctx, NetInfo *net, CellInfo *upper, Loc loc, bool is_fourgroup_a,
|
|
|
|
|
bool bind_route_start = false)
|
|
|
|
|
{
|
|
|
|
|
if (ctx->debug)
|
|
|
|
|
log_info(" routing net '%s' -> IN8 using x2y1\n", net->name.c_str(ctx));
|
|
|
|
|
|
|
|
|
|
auto x1y1 = ctx->idf("X%dY%d", loc.x, loc.y);
|
|
|
|
|
auto x1y2 = ctx->idf("X%dY%d", loc.x, loc.y + 1);
|
|
|
|
|
auto x2y2 = ctx->idf("X%dY%d", loc.x + 1, loc.y + 1);
|
|
|
|
|
|
|
|
|
|
auto cpe_combout2 = ctx->getBelPinWire(upper->bel, id_OUT);
|
|
|
|
|
auto cpe_out2_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("CPE.OUT2_int")));
|
|
|
|
|
auto out_mux_d2 = ctx->getWireByName(IdStringList::concat(x1y2, ctx->idf("OM.P09.D2")));
|
|
|
|
|
auto out_mux_y = ctx->getWireByName(IdStringList::concat(x1y2, ctx->idf("OM.P09.Y")));
|
|
|
|
|
auto in_mux_p09 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P09.D0")));
|
|
|
|
|
|
|
|
|
|
if (bind_route_start) {
|
|
|
|
|
ctx->bindWire(cpe_combout2, net, STRENGTH_LOCKED);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_combout2, cpe_out2_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out2_int, out_mux_d2, net);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, out_mux_d2, out_mux_y, net); // inverting
|
|
|
|
|
|
|
|
|
|
if (is_fourgroup_a) {
|
|
|
|
|
auto sb_sml = ctx->getWireByName(IdStringList::concat(x1y2, ctx->idf("SB_SML.P09.Y1_int")));
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, out_mux_y, sb_sml, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml, in_mux_p09, net); // inverting
|
|
|
|
|
} else {
|
|
|
|
|
// x1y2/OM.P09.Y is x1y2/SB_BIG.P09.D0
|
|
|
|
|
// x2y2/IM.P09.D0 is x2y1/SB_BIG.P09.Y1
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, out_mux_y, in_mux_p09, net); // inverting
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto in_mux_p12 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P12.D7"))); // aka IM.P09.Y
|
|
|
|
|
auto in_mux_p04 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P04.D7"))); // aka IM.P12.Y
|
|
|
|
|
auto in_mux_p08 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P08.D6"))); // aka IM.P04.Y
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, in_mux_p09, in_mux_p12, net); // inverting
|
|
|
|
|
find_and_bind_downhill_pip(ctx, in_mux_p12, in_mux_p04, net); // inverting
|
|
|
|
|
find_and_bind_downhill_pip(ctx, in_mux_p04, in_mux_p08, net); // inverting
|
|
|
|
|
|
|
|
|
|
route_mult_diag(ctx, net, Loc{loc.x + 1, loc.y + 1, 0}, in_mux_p08, 8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void route_mult_x2y2_lower(Context *ctx, NetInfo *net, CellInfo *lower, Loc loc, bool is_fourgroup_a)
|
|
|
|
|
{
|
|
|
|
|
if (ctx->debug)
|
|
|
|
|
log_info(" routing net '%s' -> IN5 using x2y2\n", net->name.c_str(ctx));
|
|
|
|
|
|
|
|
|
|
auto x1y1 = ctx->idf("X%dY%d", loc.x, loc.y);
|
|
|
|
|
auto x2y1 = ctx->idf("X%dY%d", loc.x + 1, loc.y);
|
|
|
|
|
|
|
|
|
|
auto cpe_combout1 = ctx->getBelPinWire(lower->bel, id_OUT);
|
|
|
|
|
auto cpe_out1_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("CPE.OUT1_int")));
|
|
|
|
|
auto in_mux = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("IM.P05.D0")));
|
|
|
|
|
|
|
|
|
|
ctx->bindWire(cpe_combout1, net, STRENGTH_LOCKED);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_combout1, cpe_out1_int, net);
|
|
|
|
|
|
|
|
|
|
if (is_fourgroup_a) {
|
|
|
|
|
auto sb_sml_p08_d0 = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P08.D0")));
|
|
|
|
|
auto sb_sml_p08_y1_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P08.Y1_int")));
|
|
|
|
|
auto sb_sml_p08_ydiag_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P08.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p08_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P08.YDIAG"))); // AKA SB_SML.P07.X23
|
|
|
|
|
auto sb_sml_p07_ydiag_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P07.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p07_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P07.YDIAG"))); // AKA SB_SML.P06.X23
|
|
|
|
|
auto sb_sml_p06_ydiag_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P06.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p06_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P06.YDIAG"))); // AKA SB_SML.P05.X23
|
|
|
|
|
auto sb_sml_p05_ydiag_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P05.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p05_y1_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P05.Y1_int")));
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out1_int, sb_sml_p08_d0, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p08_d0, sb_sml_p08_y1_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p08_y1_int, sb_sml_p08_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p08_ydiag_int, sb_sml_p08_ydiag, net); // inverting
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p08_ydiag, sb_sml_p07_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p07_ydiag_int, sb_sml_p07_ydiag, net); // inverting
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p07_ydiag, sb_sml_p06_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p06_ydiag_int, sb_sml_p06_ydiag, net); // inverting
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p06_ydiag, sb_sml_p05_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p05_ydiag_int, sb_sml_p05_y1_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p05_y1_int, in_mux, net); // inverting
|
|
|
|
|
} else {
|
|
|
|
|
auto sb_big_p08_d0 = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P08.D0")));
|
|
|
|
|
auto sb_big_p08_y1 = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P08.Y1")));
|
|
|
|
|
auto sb_big_p08_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P08.YDIAG"))); // AKA SB_BIG.P07.X23
|
|
|
|
|
auto sb_big_p07_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P07.YDIAG"))); // AKA SB_BIG.P06.X23
|
|
|
|
|
auto sb_big_p06_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P06.YDIAG"))); // AKA SB_BIG.P05.X23
|
|
|
|
|
auto sb_big_p05_ydiag = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P05.YDIAG")));
|
|
|
|
|
// x2y1/IM.P05.D0 is x1y1/SB_BIG.P05.Y1
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out1_int, sb_big_p08_d0, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p08_d0, sb_big_p08_y1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p08_y1, sb_big_p08_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p08_ydiag, sb_big_p07_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p07_ydiag, sb_big_p06_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p06_ydiag, sb_big_p05_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p05_ydiag, in_mux, net);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
route_mult_diag(ctx, net, Loc{loc.x + 1, loc.y, 0}, in_mux, 5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void route_mult_x2y2_upper_in1(Context *ctx, NetInfo *net, CellInfo *upper, Loc loc, bool is_fourgroup_a)
|
|
|
|
|
{
|
|
|
|
|
if (ctx->debug)
|
|
|
|
|
log_info(" routing net '%s' -> IN1 using x2y2\n", net->name.c_str(ctx));
|
|
|
|
|
|
|
|
|
|
auto x1y1 = ctx->idf("X%dY%d", loc.x, loc.y);
|
|
|
|
|
auto x2y1 = ctx->idf("X%dY%d", loc.x + 1, loc.y);
|
|
|
|
|
|
|
|
|
|
auto cpe_combout2 = ctx->getBelPinWire(upper->bel, id_OUT);
|
|
|
|
|
auto cpe_out2_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("CPE.OUT2_int")));
|
|
|
|
|
auto in_mux = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("IM.P01.D0")));
|
|
|
|
|
|
|
|
|
|
ctx->bindWire(cpe_combout2, net, STRENGTH_LOCKED);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_combout2, cpe_out2_int, net);
|
|
|
|
|
|
|
|
|
|
if (is_fourgroup_a) {
|
|
|
|
|
auto sb_sml_p04_d0 = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P04.D0")));
|
|
|
|
|
auto sb_sml_p04_y1_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P04.Y1_int")));
|
|
|
|
|
auto sb_sml_p04_ydiag_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P04.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p04_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P04.YDIAG"))); // AKA SB_SML.P03.X23
|
|
|
|
|
auto sb_sml_p03_ydiag_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P03.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p03_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P03.YDIAG"))); // AKA SB_SML.P02.X23
|
|
|
|
|
auto sb_sml_p02_ydiag_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P02.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p02_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P02.YDIAG"))); // AKA SB_SML.P01.X23
|
|
|
|
|
auto sb_sml_p01_ydiag_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P01.YDIAG_int")));
|
|
|
|
|
auto sb_sml_p01_y1_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_SML.P01.Y1_int")));
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out2_int, sb_sml_p04_d0, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p04_d0, sb_sml_p04_y1_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p04_y1_int, sb_sml_p04_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p04_ydiag_int, sb_sml_p04_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p04_ydiag, sb_sml_p03_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p03_ydiag_int, sb_sml_p03_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p03_ydiag, sb_sml_p02_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p02_ydiag_int, sb_sml_p02_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p02_ydiag, sb_sml_p01_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p01_ydiag_int, sb_sml_p01_y1_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_p01_y1_int, in_mux, net);
|
|
|
|
|
} else {
|
|
|
|
|
auto sb_big_p04_d0 = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P04.D0")));
|
|
|
|
|
auto sb_big_p04_y1 = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P04.Y1")));
|
|
|
|
|
auto sb_big_p04_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P04.YDIAG"))); // AKA SB_BIG.P07.X23
|
|
|
|
|
auto sb_big_p03_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P03.YDIAG"))); // AKA SB_BIG.P05.X23
|
|
|
|
|
auto sb_big_p02_ydiag =
|
|
|
|
|
ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P02.YDIAG"))); // AKA SB_BIG.P05.X23
|
|
|
|
|
auto sb_big_p01_ydiag = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P01.YDIAG")));
|
|
|
|
|
// x2y1/IM.P05.D0 is x1y1/SB_BIG.P05.Y1
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out2_int, sb_big_p04_d0, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p04_d0, sb_big_p04_y1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p04_y1, sb_big_p04_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p04_ydiag, sb_big_p03_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p03_ydiag, sb_big_p02_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p02_ydiag, sb_big_p01_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_p01_ydiag, in_mux, net);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
route_mult_diag(ctx, net, Loc{loc.x + 1, loc.y, 0}, in_mux, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void route_mult_x2y2_upper_in8(Context *ctx, NetInfo *net, CellInfo *upper, Loc loc, bool is_fourgroup_a,
|
|
|
|
|
bool bind_route_start = false)
|
|
|
|
|
{
|
|
|
|
|
if (ctx->debug)
|
|
|
|
|
log_info(" routing net '%s' -> IN8 using x2y2\n", net->name.c_str(ctx));
|
|
|
|
|
|
|
|
|
|
auto x0y0 = ctx->idf("X%dY%d", loc.x - 1, loc.y - 1);
|
|
|
|
|
auto x1y1 = ctx->idf("X%dY%d", loc.x, loc.y);
|
|
|
|
|
auto x2y0 = ctx->idf("X%dY%d", loc.x + 1, loc.y - 1);
|
|
|
|
|
auto x2y2 = ctx->idf("X%dY%d", loc.x + 1, loc.y + 1);
|
|
|
|
|
|
|
|
|
|
auto cpe_combout2 = ctx->getBelPinWire(upper->bel, id_OUT);
|
|
|
|
|
auto cpe_out2_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("CPE.OUT2_int")));
|
|
|
|
|
auto in_mux = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P08.D1")));
|
|
|
|
|
|
|
|
|
|
if (bind_route_start) {
|
|
|
|
|
ctx->bindWire(cpe_combout2, net, STRENGTH_LOCKED);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_combout2, cpe_out2_int, net);
|
|
|
|
|
if (is_fourgroup_a) {
|
|
|
|
|
auto sb_big_d0 = ctx->getWireByName(IdStringList::concat(x0y0, ctx->idf("SB_BIG.P08.D0")));
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out2_int, sb_big_d0, net);
|
|
|
|
|
} else {
|
|
|
|
|
auto sb_sml_d0 = ctx->getWireByName(IdStringList::concat(x0y0, ctx->idf("SB_SML.P08.D0")));
|
|
|
|
|
find_and_bind_downhill_pip(ctx, cpe_out2_int, sb_sml_d0, net);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_fourgroup_a) {
|
|
|
|
|
auto sb_big_d0 = ctx->getWireByName(IdStringList::concat(x0y0, ctx->idf("SB_BIG.P08.D0")));
|
|
|
|
|
auto sb_big_y1 = ctx->getWireByName(IdStringList::concat(x0y0, ctx->idf("SB_BIG.P08.Y1")));
|
|
|
|
|
auto sb_sml_y1_int = ctx->getWireByName(IdStringList::concat(x2y0, ctx->idf("SB_SML.P08.Y1_int")));
|
|
|
|
|
auto sb_sml_ydiag_int = ctx->getWireByName(IdStringList::concat(x2y0, ctx->idf("SB_SML.P08.YDIAG_int")));
|
|
|
|
|
auto sb_sml_y2_int = ctx->getWireByName(IdStringList::concat(x2y0, ctx->idf("SB_SML.P08.Y2_int")));
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_d0, sb_big_y1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_y1, sb_sml_y1_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_y1_int, sb_sml_ydiag_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_ydiag_int, sb_sml_y2_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_y2_int, in_mux, net);
|
|
|
|
|
} else {
|
|
|
|
|
auto sb_sml_d0 = ctx->getWireByName(IdStringList::concat(x0y0, ctx->idf("SB_SML.P08.D0")));
|
|
|
|
|
auto sb_sml_y1_int = ctx->getWireByName(IdStringList::concat(x0y0, ctx->idf("SB_SML.P08.Y1_int")));
|
|
|
|
|
auto sb_sml_y1 = ctx->getWireByName(IdStringList::concat(x0y0, ctx->idf("SB_SML.P08.Y1")));
|
|
|
|
|
auto sb_big_y1 = ctx->getWireByName(IdStringList::concat(x2y0, ctx->idf("SB_BIG.P08.Y1")));
|
|
|
|
|
auto sb_big_ydiag = ctx->getWireByName(IdStringList::concat(x2y0, ctx->idf("SB_BIG.P08.YDIAG")));
|
|
|
|
|
// x2y2/IM.P08.D0 is x2y0/SB_BIG.P08.Y2
|
|
|
|
|
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_d0, sb_sml_y1_int, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_y1_int, sb_sml_y1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_sml_y1, sb_big_y1, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_y1, sb_big_ydiag, net);
|
|
|
|
|
find_and_bind_downhill_pip(ctx, sb_big_ydiag, in_mux, net);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
route_mult_diag(ctx, net, Loc{loc.x + 1, loc.y + 1, 0}, in_mux, 8);
|
|
|
|
|
}
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
NEXTPNR_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
|
|
void GateMateImpl::route_mult()
|
|
|
|
|
{
|
|
|
|
|
log_info("Routing multipliers...\n");
|
|
|
|
|
|
|
|
|
|
// I am fully aware the nextpnr API is absolutely not designed around naming specific pips.
|
|
|
|
|
// Unfortunately, this is the easiest way to describe the specific routing required.
|
|
|
|
|
// Myrtle, please forgive me.
|
|
|
|
|
for (auto a_passthru_lower : this->multiplier_a_passthru_lowers) {
|
|
|
|
|
auto *lower = ctx->cells.at(a_passthru_lower).get();
|
|
|
|
|
auto *lower_out = lower->ports.at(id_OUT).net;
|
|
|
|
|
|
|
|
|
|
auto loc = ctx->getBelLocation(lower->bel);
|
|
|
|
|
|
|
|
|
|
auto x_fourgroup = (loc.x - 3) % 4;
|
|
|
|
|
auto y_fourgroup = (loc.y - 3) % 4;
|
|
|
|
|
bool is_fourgroup_a = (x_fourgroup < 2 && y_fourgroup < 2) || (x_fourgroup >= 2 && y_fourgroup >= 2);
|
|
|
|
|
auto x_within_fourgroup = (loc.x - 3) % 2;
|
|
|
|
|
auto y_within_fourgroup = (loc.y - 3) % 2;
|
|
|
|
|
|
|
|
|
|
if (ctx->debug) {
|
|
|
|
|
log_info(" A passthrough at (%d, %d) has 4-group %c\n", loc.x, loc.y, is_fourgroup_a ? 'A' : 'B');
|
|
|
|
|
|
|
|
|
|
log_info(" lower.OUT [OUT1] = %s\n", ctx->nameOfWire(ctx->getBelPinWire(lower->bel, id_OUT)));
|
|
|
|
|
for (auto sink_port : lower->ports.at(id_OUT).net->users) {
|
|
|
|
|
auto sink_loc = ctx->getBelLocation(sink_port.cell->bel);
|
|
|
|
|
log_info(" -> %s.%s at (%d, %d)\n", sink_port.cell->name.c_str(ctx), sink_port.port.c_str(ctx),
|
|
|
|
|
sink_loc.x, sink_loc.y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (x_within_fourgroup == 0 && y_within_fourgroup == 0) {
|
|
|
|
|
route_mult_x1y1_lower(ctx, lower_out, lower, loc, is_fourgroup_a);
|
|
|
|
|
} else if (x_within_fourgroup == 0 && y_within_fourgroup == 1) {
|
|
|
|
|
route_mult_x1y2_lower(ctx, lower_out, lower, loc, is_fourgroup_a);
|
|
|
|
|
} else if (x_within_fourgroup == 1 && y_within_fourgroup == 0) {
|
|
|
|
|
route_mult_x2y1_lower(ctx, lower_out, lower, loc, is_fourgroup_a);
|
|
|
|
|
} else /* if (x_within_fourgroup == 1 && y_within_fourgroup == 1) */ {
|
|
|
|
|
route_mult_x2y2_lower(ctx, lower_out, lower, loc, is_fourgroup_a);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto a_passthru_upper : this->multiplier_a_passthru_uppers) {
|
|
|
|
|
auto *upper = ctx->cells.at(a_passthru_upper).get();
|
|
|
|
|
auto *upper_out = upper->ports.at(id_OUT).net;
|
|
|
|
|
|
|
|
|
|
auto loc = ctx->getBelLocation(upper->bel);
|
|
|
|
|
|
|
|
|
|
auto x_fourgroup = (loc.x - 3) % 4;
|
|
|
|
|
auto y_fourgroup = (loc.y - 3) % 4;
|
|
|
|
|
bool is_fourgroup_a = (x_fourgroup < 2 && y_fourgroup < 2) || (x_fourgroup >= 2 && y_fourgroup >= 2);
|
|
|
|
|
auto x_within_fourgroup = (loc.x - 3) % 2;
|
|
|
|
|
auto y_within_fourgroup = (loc.y - 3) % 2;
|
|
|
|
|
|
|
|
|
|
bool needs_in8_route = false;
|
|
|
|
|
|
|
|
|
|
if (ctx->debug) {
|
|
|
|
|
log_info(" A passthrough at (%d, %d) has 4-group %c\n", loc.x, loc.y, is_fourgroup_a ? 'A' : 'B');
|
|
|
|
|
|
|
|
|
|
log_info(" upper.OUT [OUT2] = %s\n", ctx->nameOfWire(ctx->getBelPinWire(upper->bel, id_OUT)));
|
|
|
|
|
}
|
|
|
|
|
for (auto sink_port : upper->ports.at(id_OUT).net->users) {
|
|
|
|
|
if (sink_port.port == id_IN8)
|
|
|
|
|
needs_in8_route = true;
|
|
|
|
|
auto sink_loc = ctx->getBelLocation(sink_port.cell->bel);
|
|
|
|
|
if (ctx->debug)
|
|
|
|
|
log_info(" -> %s.%s at (%d, %d)\n", sink_port.cell->name.c_str(ctx), sink_port.port.c_str(ctx),
|
|
|
|
|
sink_loc.x, sink_loc.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (x_within_fourgroup == 0 && y_within_fourgroup == 0) {
|
|
|
|
|
route_mult_x1y1_upper_in1(ctx, upper_out, upper, loc, is_fourgroup_a);
|
|
|
|
|
if (needs_in8_route)
|
|
|
|
|
route_mult_x1y1_upper_in8(ctx, upper_out, upper, loc, is_fourgroup_a);
|
|
|
|
|
} else if (x_within_fourgroup == 0 && y_within_fourgroup == 1) {
|
|
|
|
|
route_mult_x1y2_upper_in1(ctx, upper_out, upper, loc, is_fourgroup_a);
|
|
|
|
|
if (needs_in8_route)
|
|
|
|
|
route_mult_x1y2_upper_in8(ctx, upper_out, upper, loc, is_fourgroup_a);
|
|
|
|
|
} else if (x_within_fourgroup == 1 && y_within_fourgroup == 0) {
|
|
|
|
|
route_mult_x2y1_upper_in1(ctx, upper_out, upper, loc, is_fourgroup_a);
|
|
|
|
|
if (needs_in8_route)
|
|
|
|
|
route_mult_x2y1_upper_in8(ctx, upper_out, upper, loc, is_fourgroup_a);
|
|
|
|
|
} else /* if (x_within_fourgroup == 1 && y_within_fourgroup == 1) */ {
|
|
|
|
|
route_mult_x2y2_upper_in1(ctx, upper_out, upper, loc, is_fourgroup_a);
|
|
|
|
|
if (needs_in8_route)
|
|
|
|
|
route_mult_x2y2_upper_in8(ctx, upper_out, upper, loc, is_fourgroup_a);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto zero_driver_name : this->multiplier_zero_drivers) {
|
|
|
|
|
auto *zero_driver = ctx->cells.at(zero_driver_name).get();
|
|
|
|
|
auto *out = zero_driver->ports.at(id_OUT).net;
|
|
|
|
|
|
|
|
|
|
auto loc = ctx->getBelLocation(zero_driver->bel);
|
|
|
|
|
|
|
|
|
|
auto x_fourgroup = (loc.x - 3) % 4;
|
|
|
|
|
auto y_fourgroup = (loc.y - 3) % 4;
|
|
|
|
|
bool is_fourgroup_a = (x_fourgroup < 2 && y_fourgroup < 2) || (x_fourgroup >= 2 && y_fourgroup >= 2);
|
|
|
|
|
auto x_within_fourgroup = (loc.x - 3) % 2;
|
|
|
|
|
auto y_within_fourgroup = (loc.y - 3) % 2;
|
|
|
|
|
|
|
|
|
|
if (ctx->debug) {
|
|
|
|
|
log_info(" Zero driver at (%d, %d) has 4-group %c\n", loc.x, loc.y, is_fourgroup_a ? 'A' : 'B');
|
|
|
|
|
|
|
|
|
|
log_info(" zero_driver.OUT [OUT2] = %s\n",
|
|
|
|
|
ctx->nameOfWire(ctx->getBelPinWire(zero_driver->bel, id_OUT)));
|
|
|
|
|
for (auto sink_port : zero_driver->ports.at(id_OUT).net->users) {
|
|
|
|
|
auto sink_loc = ctx->getBelLocation(sink_port.cell->bel);
|
|
|
|
|
log_info(" -> %s.%s at (%d, %d)\n", sink_port.cell->name.c_str(ctx), sink_port.port.c_str(ctx),
|
|
|
|
|
sink_loc.x, sink_loc.y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (x_within_fourgroup == 0 && y_within_fourgroup == 0) {
|
|
|
|
|
route_mult_x1y1_upper_in8(ctx, out, zero_driver, loc, is_fourgroup_a, /*bind_route_start=*/true);
|
|
|
|
|
} else if (x_within_fourgroup == 0 && y_within_fourgroup == 1) {
|
|
|
|
|
route_mult_x1y2_upper_in8(ctx, out, zero_driver, loc, is_fourgroup_a, /*bind_route_start=*/true);
|
|
|
|
|
} else if (x_within_fourgroup == 1 && y_within_fourgroup == 0) {
|
|
|
|
|
route_mult_x2y1_upper_in8(ctx, out, zero_driver, loc, is_fourgroup_a, /*bind_route_start=*/true);
|
|
|
|
|
} else /* if (x_within_fourgroup == 1 && y_within_fourgroup == 1) */ {
|
|
|
|
|
route_mult_x2y2_upper_in8(ctx, out, zero_driver, loc, is_fourgroup_a, /*bind_route_start=*/true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NEXTPNR_NAMESPACE_END
|