mirror of https://github.com/YosysHQ/nextpnr.git
Merge pull request #1524 from YosysHQ/lofty/gatemate-mult-router
gatemate: multiplier router
This commit is contained in:
commit
8938c73fc9
|
|
@ -20,6 +20,7 @@ set(SOURCES
|
||||||
pack.h
|
pack.h
|
||||||
pll.cc
|
pll.cc
|
||||||
route_clock.cc
|
route_clock.cc
|
||||||
|
route_mult.cc
|
||||||
)
|
)
|
||||||
|
|
||||||
set(TEST_SOURCES
|
set(TEST_SOURCES
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "gatemate.h"
|
#include "gatemate.h"
|
||||||
#include "gatemate_util.h"
|
#include "gatemate_util.h"
|
||||||
|
#include "uarch/gatemate/pack.h"
|
||||||
|
|
||||||
#define HIMBAECHEL_CONSTIDS "uarch/gatemate/constids.inc"
|
#define HIMBAECHEL_CONSTIDS "uarch/gatemate/constids.inc"
|
||||||
#include "himbaechel_constids.h"
|
#include "himbaechel_constids.h"
|
||||||
|
|
@ -217,33 +218,62 @@ struct BitstreamBackend
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_multipliers()
|
void update_multiplier_input(IdString cell_name, dict<IdString, Property> ¶ms)
|
||||||
{
|
{
|
||||||
for (auto *mult : uarch->multipliers) {
|
auto *net = ctx->cells.at(cell_name)->ports.at(id_OUT).net;
|
||||||
NPNR_ASSERT(mult != nullptr);
|
|
||||||
|
|
||||||
auto should_be_inverted = mult->constr_x % 2 == 1;
|
int64_t driver_l10 = ctx->cells.at(cell_name)->params[id_INIT_L10].as_int64();
|
||||||
|
bool driver_is_inverted = driver_l10 == LUT_INV_D0;
|
||||||
|
|
||||||
// TODO: these are errors, but downgraded to allow providing *some* output.
|
bool all_correct = true;
|
||||||
|
bool all_inverted = true;
|
||||||
|
|
||||||
// IN8
|
for (PortRef user : net->users) {
|
||||||
if (need_inversion(mult, id_IN8) != should_be_inverted)
|
auto column_parity = user.cell->constr_x % 2;
|
||||||
log_warning("%s.IN8 has wrong inversion state\n", mult->name.c_str(ctx));
|
auto should_be_inverted = driver_is_inverted ? column_parity == 0 : column_parity == 1;
|
||||||
|
auto inversion = need_inversion(user.cell, user.port);
|
||||||
|
all_correct &= (inversion == should_be_inverted);
|
||||||
|
all_inverted &= (inversion != should_be_inverted);
|
||||||
|
}
|
||||||
|
|
||||||
// IN5
|
NPNR_ASSERT(!(all_correct && all_inverted) && "net doesn't drive any ports?");
|
||||||
if (need_inversion(mult, id_IN5) != should_be_inverted)
|
|
||||||
log_warning("%s.IN5 has wrong inversion state\n", mult->name.c_str(ctx));
|
|
||||||
|
|
||||||
// IN1
|
if (!all_correct && !all_inverted) {
|
||||||
if (need_inversion(mult, id_IN1) != should_be_inverted)
|
log_warning("multiplier net '%s' has inconsistent inversion\n", net->name.c_str(ctx));
|
||||||
log_warning("%s.IN1 has wrong inversion state\n", mult->name.c_str(ctx));
|
|
||||||
|
auto driver_loc = ctx->getBelLocation(net->driver.cell->bel);
|
||||||
|
log_warning("net is driven from (%d, %d)\n", driver_loc.x, driver_loc.y);
|
||||||
|
|
||||||
|
log_warning(" these ports are not inverted:\n");
|
||||||
|
for (PortRef user : net->users) {
|
||||||
|
auto loc = ctx->getBelLocation(user.cell->bel);
|
||||||
|
|
||||||
|
auto should_be_inverted = user.cell->constr_x % 2 == 1;
|
||||||
|
auto inversion = need_inversion(user.cell, user.port);
|
||||||
|
if (inversion == should_be_inverted)
|
||||||
|
log_warning(" %s.%s at (%d, %d)\n", user.cell->name.c_str(ctx), user.port.c_str(ctx), loc.x,
|
||||||
|
loc.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warning(" these ports are inverted:\n");
|
||||||
|
for (PortRef user : net->users) {
|
||||||
|
auto loc = ctx->getBelLocation(user.cell->bel);
|
||||||
|
|
||||||
|
auto should_be_inverted = user.cell->constr_x % 2 == 1;
|
||||||
|
auto inversion = need_inversion(user.cell, user.port);
|
||||||
|
if (inversion != should_be_inverted)
|
||||||
|
log_warning(" %s.%s at (%d, %d)\n", user.cell->name.c_str(ctx), user.port.c_str(ctx), loc.x,
|
||||||
|
loc.y);
|
||||||
|
}
|
||||||
|
} else if (all_inverted) {
|
||||||
|
params[id_INIT_L10] = Property(~driver_l10 & 0b1111, 4);
|
||||||
|
if (ctx->debug)
|
||||||
|
log_info("multiplier net '%s': fixed inversion\n", net->name.c_str(ctx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_bitstream()
|
void write_bitstream()
|
||||||
{
|
{
|
||||||
check_multipliers();
|
|
||||||
|
|
||||||
ChipConfig cc;
|
ChipConfig cc;
|
||||||
cc.chip_name = device;
|
cc.chip_name = device;
|
||||||
std::vector<std::array<int, 9>> bank(uarch->dies);
|
std::vector<std::array<int, 9>> bank(uarch->dies);
|
||||||
|
|
@ -281,6 +311,7 @@ struct BitstreamBackend
|
||||||
dict<IdString, Property> params = cell.second->params;
|
dict<IdString, Property> params = cell.second->params;
|
||||||
Loc l = ctx->getBelLocation(cell.second->bel);
|
Loc l = ctx->getBelLocation(cell.second->bel);
|
||||||
params.erase(id_L2T4_UPPER);
|
params.erase(id_L2T4_UPPER);
|
||||||
|
params.erase(id_MULT_INVERT);
|
||||||
int c_i1 = int_or_default(params, id_C_I1, 0);
|
int c_i1 = int_or_default(params, id_C_I1, 0);
|
||||||
int c_i2 = int_or_default(params, id_C_I2, 0);
|
int c_i2 = int_or_default(params, id_C_I2, 0);
|
||||||
int c_i3 = int_or_default(params, id_C_I3, 0);
|
int c_i3 = int_or_default(params, id_C_I3, 0);
|
||||||
|
|
@ -332,6 +363,12 @@ struct BitstreamBackend
|
||||||
else
|
else
|
||||||
update_cpe_inv(cell.second.get(), id_SR, id_C_CPE_RES, params);
|
update_cpe_inv(cell.second.get(), id_SR, id_C_CPE_RES, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (uarch->multiplier_a_passthru_lowers.count(cell.first) ||
|
||||||
|
uarch->multiplier_a_passthru_uppers.count(cell.first) ||
|
||||||
|
uarch->multiplier_zero_drivers.count(cell.first))
|
||||||
|
update_multiplier_input(cell.first, params);
|
||||||
|
|
||||||
int id = tile_extra_data(cell.second.get()->bel.tile)->prim_id;
|
int id = tile_extra_data(cell.second.get()->bel.tile)->prim_id;
|
||||||
for (auto &p : params) {
|
for (auto &p : params) {
|
||||||
IdString name = p.first;
|
IdString name = p.first;
|
||||||
|
|
|
||||||
|
|
@ -2272,3 +2272,4 @@ X(CPE_LATCH)
|
||||||
X(L2T4_UPPER)
|
X(L2T4_UPPER)
|
||||||
X(CPE_MX8)
|
X(CPE_MX8)
|
||||||
X(CPE_BRIDGE)
|
X(CPE_BRIDGE)
|
||||||
|
X(MULT_INVERT)
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,7 @@ void GateMateImpl::postPlace() { repack(); }
|
||||||
void GateMateImpl::preRoute()
|
void GateMateImpl::preRoute()
|
||||||
{
|
{
|
||||||
ctx->assignArchInfo();
|
ctx->assignArchInfo();
|
||||||
|
route_mult();
|
||||||
route_clock();
|
route_clock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,9 @@ struct GateMateImpl : HimbaechelAPI
|
||||||
dict<std::pair<IdString, int>, Loc> locations;
|
dict<std::pair<IdString, int>, Loc> locations;
|
||||||
int dies;
|
int dies;
|
||||||
int preferred_die;
|
int preferred_die;
|
||||||
std::vector<CellInfo *> multipliers;
|
pool<IdString> multiplier_a_passthru_lowers;
|
||||||
|
pool<IdString> multiplier_a_passthru_uppers;
|
||||||
|
pool<IdString> multiplier_zero_drivers;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool getChildPlacement(const BaseClusterInfo *cluster, Loc root_loc,
|
bool getChildPlacement(const BaseClusterInfo *cluster, Loc root_loc,
|
||||||
|
|
@ -84,6 +86,7 @@ struct GateMateImpl : HimbaechelAPI
|
||||||
|
|
||||||
void assign_cell_info();
|
void assign_cell_info();
|
||||||
void route_clock();
|
void route_clock();
|
||||||
|
void route_mult();
|
||||||
void repack();
|
void repack();
|
||||||
|
|
||||||
const GateMateBelExtraDataPOD *bel_extra_data(BelId bel) const;
|
const GateMateBelExtraDataPOD *bel_extra_data(BelId bel) const;
|
||||||
|
|
|
||||||
|
|
@ -397,7 +397,7 @@ void GateMateImpl::pack()
|
||||||
packer.pack_misc();
|
packer.pack_misc();
|
||||||
packer.pack_ram();
|
packer.pack_ram();
|
||||||
packer.pack_serdes();
|
packer.pack_serdes();
|
||||||
// packer.pack_mult();
|
packer.pack_mult();
|
||||||
packer.pack_addf();
|
packer.pack_addf();
|
||||||
packer.pack_cpe();
|
packer.pack_cpe();
|
||||||
packer.remove_constants();
|
packer.remove_constants();
|
||||||
|
|
|
||||||
|
|
@ -240,8 +240,8 @@ CarryGenCell::CarryGenCell(CellInfo *lower, CellInfo *upper, CellInfo *comp, Cel
|
||||||
{
|
{
|
||||||
lower->params[id_INIT_L00] = Property(LUT_D1, 4); // PINY1
|
lower->params[id_INIT_L00] = Property(LUT_D1, 4); // PINY1
|
||||||
lower->params[id_INIT_L01] = Property(LUT_ZERO, 4); // (overriden by CIN)
|
lower->params[id_INIT_L01] = Property(LUT_ZERO, 4); // (overriden by CIN)
|
||||||
lower->params[id_INIT_L10] = Property(is_odd_x ? LUT_OR : LUT_ZERO, 4);
|
lower->params[id_INIT_L10] = Property(is_odd_x ? LUT_OR : !enable_cinx ? LUT_ZERO : LUT_AND, 4);
|
||||||
lower->params[id_INIT_L20] = Property(is_odd_x ? LUT_OR : LUT_ZERO, 4);
|
lower->params[id_INIT_L20] = Property(is_odd_x ? LUT_OR : !enable_cinx ? LUT_ZERO : LUT_AND, 4);
|
||||||
lower->params[id_C_FUNCTION] = Property(C_EN_CIN, 3);
|
lower->params[id_C_FUNCTION] = Property(C_EN_CIN, 3);
|
||||||
lower->params[id_C_I3] = Property(1, 1); // PINY1 for L02
|
lower->params[id_C_I3] = Property(1, 1); // PINY1 for L02
|
||||||
lower->params[id_C_HORIZ] = Property(0, 1); // CINY1 for CIN_ for L03
|
lower->params[id_C_HORIZ] = Property(0, 1); // CINY1 for CIN_ for L03
|
||||||
|
|
@ -259,16 +259,12 @@ CarryGenCell::CarryGenCell(CellInfo *lower, CellInfo *upper, CellInfo *comp, Cel
|
||||||
cplines->params[id_C_CY2_I] = Property(1, 1); // CY2_VAL -> COUTY2
|
cplines->params[id_C_CY2_I] = Property(1, 1); // CY2_VAL -> COUTY2
|
||||||
cplines->params[id_C_SEL_C] = Property(1, 1); // COMP_OUT -> CY2_VAL
|
cplines->params[id_C_SEL_C] = Property(1, 1); // COMP_OUT -> CY2_VAL
|
||||||
cplines->params[id_C_SELY2] = Property(0, 1); // COMP_OUT -> CY2_VAL
|
cplines->params[id_C_SELY2] = Property(0, 1); // COMP_OUT -> CY2_VAL
|
||||||
|
|
||||||
// upper->params[id_C_O1] = Property(0b11, 2); // COMB1OUT -> OUT1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MultfabCell::MultfabCell(CellInfo *lower, CellInfo *upper, CellInfo *comp, CellInfo *cplines, IdString name,
|
MultfabCell::MultfabCell(CellInfo *lower, CellInfo *upper, CellInfo *comp, CellInfo *cplines, IdString name,
|
||||||
bool is_even_x, bool enable_cinx)
|
bool is_even_x, bool enable_cinx)
|
||||||
: lower{lower}, upper{upper}, comp{comp}, cplines{cplines}
|
: lower{lower}, upper{upper}, comp{comp}, cplines{cplines}
|
||||||
{
|
{
|
||||||
// TODO: perhaps C_I[1234] could be pips?
|
|
||||||
|
|
||||||
lower->params[id_INIT_L00] = Property(LUT_D1, 4); // PINY1
|
lower->params[id_INIT_L00] = Property(LUT_D1, 4); // PINY1
|
||||||
// lower->params[id_INIT_L01] = Property(LUT_ZERO, 4); // (unused)
|
// lower->params[id_INIT_L01] = Property(LUT_ZERO, 4); // (unused)
|
||||||
lower->params[id_INIT_L10] = Property(LUT_D0, 4); // L02
|
lower->params[id_INIT_L10] = Property(LUT_D0, 4); // L02
|
||||||
|
|
@ -286,7 +282,6 @@ MultfabCell::MultfabCell(CellInfo *lower, CellInfo *upper, CellInfo *comp, CellI
|
||||||
if (enable_cinx)
|
if (enable_cinx)
|
||||||
upper->params[id_C_I2] = Property(1, 1); // CINX for L01
|
upper->params[id_C_I2] = Property(1, 1); // CINX for L01
|
||||||
lower->params[id_C_I3] = Property(1, 1); // PINY1 for L02
|
lower->params[id_C_I3] = Property(1, 1); // PINY1 for L02
|
||||||
// upper->params[id_C_FUNCTION] = Property(C_ADDCIN, 3);
|
|
||||||
|
|
||||||
cplines->params[id_C_SELX] = Property(1, 1); // inverted CINY2 -> CX_VAL
|
cplines->params[id_C_SELX] = Property(1, 1); // inverted CINY2 -> CX_VAL
|
||||||
cplines->params[id_C_SEL_C] = Property(1, 1); // inverted CINY2 -> CX_VAL; COMP_OUT -> CY1_VAL
|
cplines->params[id_C_SEL_C] = Property(1, 1); // inverted CINY2 -> CX_VAL; COMP_OUT -> CY1_VAL
|
||||||
|
|
@ -296,16 +291,12 @@ MultfabCell::MultfabCell(CellInfo *lower, CellInfo *upper, CellInfo *comp, CellI
|
||||||
cplines->params[id_C_PY1_I] = Property(1, 1); // PY1_VAL -> POUTY1
|
cplines->params[id_C_PY1_I] = Property(1, 1); // PY1_VAL -> POUTY1
|
||||||
cplines->params[id_C_SEL_P] = Property(0, 1); // OUT1 -> PY1_VAL
|
cplines->params[id_C_SEL_P] = Property(0, 1); // OUT1 -> PY1_VAL
|
||||||
cplines->params[id_C_SELY1] = Property(0, 1); // COMP_OUT -> CY1_VAL; OUT1 -> PY1_VAL
|
cplines->params[id_C_SELY1] = Property(0, 1); // COMP_OUT -> CY1_VAL; OUT1 -> PY1_VAL
|
||||||
|
|
||||||
// upper->params[id_C_O1] = Property(0b11, 2); // COMB1OUT -> OUT1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FRoutingCell::FRoutingCell(CellInfo *lower, CellInfo *upper, CellInfo *comp, CellInfo *cplines, IdString name,
|
FRoutingCell::FRoutingCell(CellInfo *lower, CellInfo *upper, CellInfo *comp, CellInfo *cplines, IdString name,
|
||||||
bool is_even_x)
|
bool is_even_x)
|
||||||
: lower{lower}, upper{upper}, comp{comp}, cplines{cplines}
|
: lower{lower}, upper{upper}, comp{comp}, cplines{cplines}
|
||||||
{
|
{
|
||||||
// TODO: simplify AND with zero/OR with zero into something more sensical.
|
|
||||||
|
|
||||||
lower->params[id_INIT_L00] = Property(LUT_ZERO, 4); // (unused)
|
lower->params[id_INIT_L00] = Property(LUT_ZERO, 4); // (unused)
|
||||||
lower->params[id_INIT_L01] = Property(LUT_ZERO, 4); // (unused)
|
lower->params[id_INIT_L01] = Property(LUT_ZERO, 4); // (unused)
|
||||||
lower->params[id_INIT_L10] = Property(LUT_ZERO, 4);
|
lower->params[id_INIT_L10] = Property(LUT_ZERO, 4);
|
||||||
|
|
@ -319,7 +310,6 @@ FRoutingCell::FRoutingCell(CellInfo *lower, CellInfo *upper, CellInfo *comp, Cel
|
||||||
// upper->params[id_INIT_L01] = Property(LUT_ONE, 4); // (unused)
|
// upper->params[id_INIT_L01] = Property(LUT_ONE, 4); // (unused)
|
||||||
upper->params[id_INIT_L10] = Property(LUT_D0, 4);
|
upper->params[id_INIT_L10] = Property(LUT_D0, 4);
|
||||||
upper->params[id_C_I1] = Property(1, 1); // PINY1 for L00
|
upper->params[id_C_I1] = Property(1, 1); // PINY1 for L00
|
||||||
// upper->params[id_C_FUNCTION] = Property(C_ADDCIN, 3);
|
|
||||||
|
|
||||||
cplines->params[id_C_SELX] = Property(1, 1);
|
cplines->params[id_C_SELX] = Property(1, 1);
|
||||||
cplines->params[id_C_SEL_C] = Property(1, 1);
|
cplines->params[id_C_SEL_C] = Property(1, 1);
|
||||||
|
|
@ -329,9 +319,6 @@ FRoutingCell::FRoutingCell(CellInfo *lower, CellInfo *upper, CellInfo *comp, Cel
|
||||||
cplines->params[id_C_CY2_I] = Property(1, 1);
|
cplines->params[id_C_CY2_I] = Property(1, 1);
|
||||||
cplines->params[id_C_PY1_I] = Property(1, 1);
|
cplines->params[id_C_PY1_I] = Property(1, 1);
|
||||||
cplines->params[id_C_PY2_I] = Property(1, 1);
|
cplines->params[id_C_PY2_I] = Property(1, 1);
|
||||||
|
|
||||||
// upper->params[id_C_O1] = Property(0b11, 2); // COMB1OUT -> OUT1
|
|
||||||
// upper->params[id_C_O2] = Property(0b11, 2); // COMB2OUT -> OUT2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MultCell::MultCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_msb) : lower{lower}, upper{upper}
|
MultCell::MultCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_msb) : lower{lower}, upper{upper}
|
||||||
|
|
@ -339,7 +326,6 @@ MultCell::MultCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_msb)
|
||||||
lower->params[id_INIT_L02] = Property(LUT_AND, 4);
|
lower->params[id_INIT_L02] = Property(LUT_AND, 4);
|
||||||
lower->params[id_INIT_L03] = Property(LUT_D1, 4); // PINX
|
lower->params[id_INIT_L03] = Property(LUT_D1, 4); // PINX
|
||||||
lower->params[id_INIT_L11] = Property(LUT_XOR, 4);
|
lower->params[id_INIT_L11] = Property(LUT_XOR, 4);
|
||||||
// lower->params[id_INIT_L20] = Property(LUT_D1, 4); // L11
|
|
||||||
lower->params[id_C_FUNCTION] = Property(C_MULT, 3);
|
lower->params[id_C_FUNCTION] = Property(C_MULT, 3);
|
||||||
|
|
||||||
upper->params[id_INIT_L00] = Property(LUT_AND, 4);
|
upper->params[id_INIT_L00] = Property(LUT_AND, 4);
|
||||||
|
|
@ -360,18 +346,14 @@ MultCell::MultCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_msb)
|
||||||
lower->params[id_C_C_P] = Property(0, 1);
|
lower->params[id_C_C_P] = Property(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// upper->params[id_C_O1] = Property(0b10, 2); // CP_OUT1 -> OUT1
|
// Must force these, even if outputs are not used, to preserve logic
|
||||||
// upper->params[id_C_O2] = Property(0b10, 2); // CP_OUT2 -> OUT2
|
lower->params[id_C_O1] = Property(0b10, 2); // CP_OUT1 -> OUT1
|
||||||
|
lower->params[id_C_O2] = Property(0b10, 2); // CP_OUT2 -> OUT2
|
||||||
}
|
}
|
||||||
|
|
||||||
MsbRoutingCell::MsbRoutingCell(CellInfo *lower, CellInfo *upper, CellInfo *comp, CellInfo *cplines, IdString name)
|
MsbRoutingCell::MsbRoutingCell(CellInfo *lower, CellInfo *upper, CellInfo *comp, CellInfo *cplines, IdString name)
|
||||||
: lower{lower}, upper{upper}, comp{comp}, cplines{cplines}
|
: lower{lower}, upper{upper}, comp{comp}, cplines{cplines}
|
||||||
{
|
{
|
||||||
// lower->params[id_INIT_L02] = Property(LUT_ZERO, 4); // (unused)
|
|
||||||
// lower->params[id_INIT_L03] = Property(LUT_ZERO, 4); // (unused)
|
|
||||||
// lower->params[id_INIT_L11] = Property(LUT_ZERO, 4); // (unused)
|
|
||||||
// lower->params[id_INIT_L20] = Property(LUT_ZERO, 4); // (unused)
|
|
||||||
|
|
||||||
comp->params[id_INIT_L30] = Property(LUT_ONE, 4); // zero -> COMP_OUT (L30 is inverted)
|
comp->params[id_INIT_L30] = Property(LUT_ONE, 4); // zero -> COMP_OUT (L30 is inverted)
|
||||||
|
|
||||||
upper->params[id_INIT_L00] = Property(LUT_D1, 4); // PINY1
|
upper->params[id_INIT_L00] = Property(LUT_D1, 4); // PINY1
|
||||||
|
|
@ -387,8 +369,6 @@ MsbRoutingCell::MsbRoutingCell(CellInfo *lower, CellInfo *upper, CellInfo *comp,
|
||||||
cplines->params[id_C_PX_I] = Property(1, 1); // PX_VAL -> POUTX
|
cplines->params[id_C_PX_I] = Property(1, 1); // PX_VAL -> POUTX
|
||||||
cplines->params[id_C_PY1_I] = Property(1, 1); // PY1_VAL -> POUTY1
|
cplines->params[id_C_PY1_I] = Property(1, 1); // PY1_VAL -> POUTY1
|
||||||
cplines->params[id_C_PY2_I] = Property(1, 1); // PY2_VAL -> POUTY2
|
cplines->params[id_C_PY2_I] = Property(1, 1); // PY2_VAL -> POUTY2
|
||||||
|
|
||||||
// upper->params[id_C_O2] = Property(0b11, 2); // COMB2 -> OUT2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GateMatePacker::pack_mult()
|
void GateMatePacker::pack_mult()
|
||||||
|
|
@ -399,6 +379,9 @@ void GateMatePacker::pack_mult()
|
||||||
auto create_zero_driver = [&](IdString name) {
|
auto create_zero_driver = [&](IdString name) {
|
||||||
auto *zero_lower = create_cell_ptr(id_CPE_DUMMY, ctx->idf("%s$zero_lower", name.c_str(ctx)));
|
auto *zero_lower = create_cell_ptr(id_CPE_DUMMY, ctx->idf("%s$zero_lower", name.c_str(ctx)));
|
||||||
auto *zero_upper = create_cell_ptr(id_CPE_L2T4, ctx->idf("%s$zero", name.c_str(ctx)));
|
auto *zero_upper = create_cell_ptr(id_CPE_L2T4, ctx->idf("%s$zero", name.c_str(ctx)));
|
||||||
|
|
||||||
|
uarch->multiplier_zero_drivers.insert(zero_upper->name);
|
||||||
|
|
||||||
return ZeroDriver{zero_lower, zero_upper, name};
|
return ZeroDriver{zero_lower, zero_upper, name};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -412,11 +395,13 @@ void GateMatePacker::pack_mult()
|
||||||
a_passthru_comp->connectPort(id_COMPOUT, comp_conn);
|
a_passthru_comp->connectPort(id_COMPOUT, comp_conn);
|
||||||
a_passthru_lines->connectPort(id_COMPOUT, comp_conn);
|
a_passthru_lines->connectPort(id_COMPOUT, comp_conn);
|
||||||
|
|
||||||
|
uarch->multiplier_a_passthru_lowers.insert(a_passthru_lower->name);
|
||||||
|
uarch->multiplier_a_passthru_uppers.insert(a_passthru_upper->name);
|
||||||
|
|
||||||
return APassThroughCell{a_passthru_lower, a_passthru_upper, a_passthru_comp, a_passthru_lines, name};
|
return APassThroughCell{a_passthru_lower, a_passthru_upper, a_passthru_comp, a_passthru_lines, name};
|
||||||
};
|
};
|
||||||
|
|
||||||
auto create_mult_col = [&](IdString name, int a_width, bool is_even_x, bool carry_enable_cinx,
|
auto create_mult_col = [&](IdString name, int a_width, bool is_even_x, bool enable_cinx) {
|
||||||
bool multfab_enable_cinx) {
|
|
||||||
// Ideally this would be the MultiplierColumn constructor, but we need create_cell_ptr here.
|
// Ideally this would be the MultiplierColumn constructor, but we need create_cell_ptr here.
|
||||||
auto col = MultiplierColumn{};
|
auto col = MultiplierColumn{};
|
||||||
|
|
||||||
|
|
@ -443,6 +428,12 @@ void GateMatePacker::pack_mult()
|
||||||
auto *carry_comp = create_cell_ptr(id_CPE_COMP, ctx->idf("%s$carry_comp", name.c_str(ctx)));
|
auto *carry_comp = create_cell_ptr(id_CPE_COMP, ctx->idf("%s$carry_comp", name.c_str(ctx)));
|
||||||
auto *carry_lines = create_cell_ptr(id_CPE_CPLINES, ctx->idf("%s$carry_lines", name.c_str(ctx)));
|
auto *carry_lines = create_cell_ptr(id_CPE_CPLINES, ctx->idf("%s$carry_lines", name.c_str(ctx)));
|
||||||
|
|
||||||
|
NetInfo *comb2_conn = ctx->createNet(ctx->idf("%s$carrycomb2", name.c_str(ctx)));
|
||||||
|
carry_upper->connectPort(id_OUT, comb2_conn);
|
||||||
|
carry_lower->ports[id_COMBIN].name = id_COMBIN;
|
||||||
|
carry_lower->ports[id_COMBIN].type = PORT_IN;
|
||||||
|
carry_lower->connectPort(id_COMBIN, comb2_conn);
|
||||||
|
|
||||||
NetInfo *comp_in = ctx->createNet(ctx->idf("%s$carry$comp_in", name.c_str(ctx)));
|
NetInfo *comp_in = ctx->createNet(ctx->idf("%s$carry$comp_in", name.c_str(ctx)));
|
||||||
carry_lower->connectPort(id_OUT, comp_in);
|
carry_lower->connectPort(id_OUT, comp_in);
|
||||||
carry_comp->connectPort(id_COMB1, comp_in);
|
carry_comp->connectPort(id_COMB1, comp_in);
|
||||||
|
|
@ -451,8 +442,7 @@ void GateMatePacker::pack_mult()
|
||||||
carry_comp->connectPort(id_COMPOUT, comp_out);
|
carry_comp->connectPort(id_COMPOUT, comp_out);
|
||||||
carry_lines->connectPort(id_COMPOUT, comp_out);
|
carry_lines->connectPort(id_COMPOUT, comp_out);
|
||||||
|
|
||||||
col.carry = CarryGenCell{carry_lower, carry_upper, carry_comp, carry_lines,
|
col.carry = CarryGenCell{carry_lower, carry_upper, carry_comp, carry_lines, name, !is_even_x, enable_cinx};
|
||||||
name, !is_even_x, carry_enable_cinx};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -471,6 +461,9 @@ void GateMatePacker::pack_mult()
|
||||||
|
|
||||||
NetInfo *comb2_conn = ctx->createNet(ctx->idf("%s$multf%c$comb2", name.c_str(ctx), is_even_x ? 'a' : 'b'));
|
NetInfo *comb2_conn = ctx->createNet(ctx->idf("%s$multf%c$comb2", name.c_str(ctx), is_even_x ? 'a' : 'b'));
|
||||||
multfab_upper->connectPort(id_OUT, comb2_conn);
|
multfab_upper->connectPort(id_OUT, comb2_conn);
|
||||||
|
multfab_lower->ports[id_COMBIN].name = id_COMBIN;
|
||||||
|
multfab_lower->ports[id_COMBIN].type = PORT_IN;
|
||||||
|
multfab_lower->connectPort(id_COMBIN, comb2_conn);
|
||||||
multfab_comp->connectPort(id_COMB2, comb2_conn);
|
multfab_comp->connectPort(id_COMB2, comb2_conn);
|
||||||
|
|
||||||
NetInfo *comp_out = ctx->createNet(ctx->idf("%s$multf%c$comp_out", name.c_str(ctx), is_even_x ? 'a' : 'b'));
|
NetInfo *comp_out = ctx->createNet(ctx->idf("%s$multf%c$comp_out", name.c_str(ctx), is_even_x ? 'a' : 'b'));
|
||||||
|
|
@ -478,7 +471,7 @@ void GateMatePacker::pack_mult()
|
||||||
multfab_lines->connectPort(id_COMPOUT, comp_out);
|
multfab_lines->connectPort(id_COMPOUT, comp_out);
|
||||||
|
|
||||||
col.multfab = MultfabCell{multfab_lower, multfab_upper, multfab_comp, multfab_lines,
|
col.multfab = MultfabCell{multfab_lower, multfab_upper, multfab_comp, multfab_lines,
|
||||||
name, is_even_x, multfab_enable_cinx};
|
name, is_even_x, enable_cinx};
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -494,9 +487,8 @@ void GateMatePacker::pack_mult()
|
||||||
NetInfo *comb2_conn = ctx->createNet(ctx->idf("%s$f_route$comb2", name.c_str(ctx)));
|
NetInfo *comb2_conn = ctx->createNet(ctx->idf("%s$f_route$comb2", name.c_str(ctx)));
|
||||||
f_route_upper->connectPort(id_OUT, comb2_conn);
|
f_route_upper->connectPort(id_OUT, comb2_conn);
|
||||||
f_route_lines->connectPort(id_OUT2, comb2_conn);
|
f_route_lines->connectPort(id_OUT2, comb2_conn);
|
||||||
if (!is_even_x) {
|
if (!is_even_x)
|
||||||
f_route_comp->connectPort(id_COMB2, comb2_conn);
|
f_route_comp->connectPort(id_COMB2, comb2_conn);
|
||||||
}
|
|
||||||
|
|
||||||
NetInfo *comp_out = ctx->createNet(ctx->idf("%s$f_route$comp_out", name.c_str(ctx)));
|
NetInfo *comp_out = ctx->createNet(ctx->idf("%s$f_route$comp_out", name.c_str(ctx)));
|
||||||
f_route_comp->connectPort(id_COMPOUT, comp_out);
|
f_route_comp->connectPort(id_COMPOUT, comp_out);
|
||||||
|
|
@ -508,9 +500,9 @@ void GateMatePacker::pack_mult()
|
||||||
for (int i = 0; i < (a_width / 2); i++) {
|
for (int i = 0; i < (a_width / 2); i++) {
|
||||||
auto *mult_lower = create_cell_ptr(id_CPE_LT_L, ctx->idf("%s$row%d$mult_lower", name.c_str(ctx), i));
|
auto *mult_lower = create_cell_ptr(id_CPE_LT_L, ctx->idf("%s$row%d$mult_lower", name.c_str(ctx), i));
|
||||||
auto *mult_upper = create_cell_ptr(id_CPE_LT_U, ctx->idf("%s$row%d$mult_upper", name.c_str(ctx), i));
|
auto *mult_upper = create_cell_ptr(id_CPE_LT_U, ctx->idf("%s$row%d$mult_upper", name.c_str(ctx), i));
|
||||||
|
mult_lower->params[id_MULT_INVERT] = Property(is_even_x ? Property::State::S0 : Property::State::S1);
|
||||||
|
|
||||||
col.mults.push_back(MultCell{mult_lower, mult_upper, name, i == ((a_width / 2) - 1)});
|
col.mults.push_back(MultCell{mult_lower, mult_upper, name, i == ((a_width / 2) - 1)});
|
||||||
uarch->multipliers.push_back(mult_lower);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -523,6 +515,10 @@ void GateMatePacker::pack_mult()
|
||||||
msb_route_comp->connectPort(id_COMPOUT, comp_conn);
|
msb_route_comp->connectPort(id_COMPOUT, comp_conn);
|
||||||
msb_route_lines->connectPort(id_COMPOUT, comp_conn);
|
msb_route_lines->connectPort(id_COMPOUT, comp_conn);
|
||||||
|
|
||||||
|
NetInfo *out_conn = ctx->createNet(ctx->idf("%s$msb_route$out", name.c_str(ctx)));
|
||||||
|
msb_route_upper->connectPort(id_OUT, out_conn);
|
||||||
|
msb_route_lines->connectPort(id_OUT2, out_conn);
|
||||||
|
|
||||||
col.msb_route = MsbRoutingCell{msb_route_lower, msb_route_upper, msb_route_comp, msb_route_lines, name};
|
col.msb_route = MsbRoutingCell{msb_route_lower, msb_route_upper, msb_route_comp, msb_route_lines, name};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -543,15 +539,20 @@ void GateMatePacker::pack_mult()
|
||||||
auto a_width = int_or_default(mult->params, id_A_WIDTH);
|
auto a_width = int_or_default(mult->params, id_A_WIDTH);
|
||||||
auto b_width = int_or_default(mult->params, id_B_WIDTH);
|
auto b_width = int_or_default(mult->params, id_B_WIDTH);
|
||||||
auto p_width = int_or_default(mult->params, id_P_WIDTH);
|
auto p_width = int_or_default(mult->params, id_P_WIDTH);
|
||||||
|
mult->renamePort(id_A, ctx->id("A[0]"));
|
||||||
|
mult->renamePort(id_B, ctx->id("B[0]"));
|
||||||
|
mult->renamePort(id_P, ctx->id("P[0]"));
|
||||||
|
|
||||||
|
int a_size = (((a_width + 1) / 2) + 1) * 2;
|
||||||
|
int b_size = (((b_width + 1) / 2) + 1) * 2;
|
||||||
// Sign-extend odd A_WIDTH to even, because we're working with 2x2 multiplier cells.
|
// Sign-extend odd A_WIDTH to even, because we're working with 2x2 multiplier cells.
|
||||||
while (a_width < p_width || a_width % 2 == 1) {
|
while (a_width < a_size) {
|
||||||
mult->copyPortTo(ctx->idf("A[%d]", a_width - 1), mult, ctx->idf("A[%d]", a_width));
|
mult->copyPortTo(ctx->idf("A[%d]", a_width - 1), mult, ctx->idf("A[%d]", a_width));
|
||||||
a_width += 1;
|
a_width += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign-extend odd B_WIDTH to even, because we're working with 2x2 multiplier cells.
|
// Sign-extend odd B_WIDTH to even, because we're working with 2x2 multiplier cells.
|
||||||
while (b_width < p_width || b_width % 2 == 1) {
|
while (b_width < b_size) {
|
||||||
mult->copyPortTo(ctx->idf("B[%d]", b_width - 1), mult, ctx->idf("B[%d]", b_width));
|
mult->copyPortTo(ctx->idf("B[%d]", b_width - 1), mult, ctx->idf("B[%d]", b_width));
|
||||||
b_width += 1;
|
b_width += 1;
|
||||||
}
|
}
|
||||||
|
|
@ -566,8 +567,8 @@ void GateMatePacker::pack_mult()
|
||||||
for (int a = 0; a < a_width / 2; a++)
|
for (int a = 0; a < a_width / 2; a++)
|
||||||
m.a_passthrus.push_back(create_a_passthru(ctx->idf("%s$col0$row%d", mult->name.c_str(ctx), a)));
|
m.a_passthrus.push_back(create_a_passthru(ctx->idf("%s$col0$row%d", mult->name.c_str(ctx), a)));
|
||||||
for (int b = 0; b < b_width / 2; b++)
|
for (int b = 0; b < b_width / 2; b++)
|
||||||
m.cols.push_back(create_mult_col(ctx->idf("%s$col%d", mult->name.c_str(ctx), b + 1), a_width, b % 2 == 0,
|
m.cols.push_back(
|
||||||
b == 2 /* ??? */, b > 0 /* ??? */));
|
create_mult_col(ctx->idf("%s$col%d", mult->name.c_str(ctx), b + 1), a_width, b % 2 == 0, b > 0));
|
||||||
|
|
||||||
// Step 2: constrain them together.
|
// Step 2: constrain them together.
|
||||||
// We define (0, 0) to be the B passthrough cell of column 1.
|
// We define (0, 0) to be the B passthrough cell of column 1.
|
||||||
|
|
@ -700,8 +701,8 @@ void GateMatePacker::pack_mult()
|
||||||
auto &b_passthru = m.cols.at(b).b_passthru;
|
auto &b_passthru = m.cols.at(b).b_passthru;
|
||||||
|
|
||||||
// Connect B input passthrough cell.
|
// Connect B input passthrough cell.
|
||||||
mult->movePortTo(ctx->idf("B[%d]", 2 * b), b_passthru.upper, id_IN1);
|
mult->movePortTo(ctx->idf("B[%d]", 2 * b), b_passthru.lower, id_IN1);
|
||||||
mult->movePortTo(ctx->idf("B[%d]", 2 * b + 1), b_passthru.lower, id_IN1);
|
mult->movePortTo(ctx->idf("B[%d]", 2 * b + 1), b_passthru.upper, id_IN1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intermediate multiplier connections.
|
// Intermediate multiplier connections.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
Loading…
Reference in New Issue