Gowin. FFs placement. (#1386)

* Gowin. FFs placement.

* Allow clusters to be created from FFs and LUTs;

* Immediately create pass-through LUTs from free LUTs adjacent to FF - at the same time ensure alternating use of LUT inputs;

* In case of constant networks, such pass-through LUTs are disconnected from networks altogether;

* Allow FF to be placed directly into SSRAM slides - this is useful when using synchronous reading.

Signed-off-by: YRabbit <rabbit@yrabbit.cyou>

* Gowin. Fix aux name creation

Signed-off-by: YRabbit <rabbit@yrabbit.cyou>

* Gowin. Use I3 for pass-trough LUTs

Signed-off-by: YRabbit <rabbit@yrabbit.cyou>

---------

Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
YRabbit 2024-10-22 20:49:44 +10:00 committed by GitHub
parent f36a6571c1
commit 9c2d96f86e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 143 additions and 62 deletions

View File

@ -71,6 +71,9 @@ struct GowinImpl : HimbaechelAPI
std::vector<GowinCellInfo> fast_cell_info;
void assign_cell_info();
// If there is an unused LUT adjacent to FF, use it
void create_passthrough_luts(void);
// Remember HCLK sections that have been reserved to route HCLK signals
std::set<BelId> routing_reserved_hclk_sections;
@ -531,6 +534,7 @@ void GowinImpl::postPlace()
// adjust cell pin to bel pin mapping for DSP cells (CE, CLK and RESET pins)
adjust_dsp_pin_mapping();
create_passthrough_luts();
}
void GowinImpl::preRoute() { gowin_route_globals(ctx); }
@ -590,8 +594,15 @@ bool GowinImpl::isBelLocationValid(BelId bel, bool explain_invalid) const
case ID_ALU:
return slice_valid(l.x, l.y, l.z - BelZ::ALU0_Z);
case ID_RAM16SDP4:
// only slices 4 and 5 are critical for RAM
return slice_valid(l.x, l.y, l.z - BelZ::RAMW_Z + 5) && slice_valid(l.x, l.y, l.z - BelZ::RAMW_Z + 4);
return slice_valid(l.x, l.y, 0);
case ID_MUX2_LUT5:
return slice_valid(l.x, l.y, (l.z - BelZ::MUX20_Z) / 2);
case ID_MUX2_LUT6:
return slice_valid(l.x, l.y, (l.z - BelZ::MUX21_Z) / 2 + 1);
case ID_MUX2_LUT7:
return slice_valid(l.x, l.y, 3);
case ID_MUX2_LUT8:
return slice_valid(l.x, l.y, 7);
case ID_PADD9: /* fall-through */
case ID_PADD18: /* fall-through */
case ID_MULT9X9: /* fall-through */
@ -725,6 +736,67 @@ void GowinImpl::assign_cell_info()
}
}
// If there is an unused LUT next to the DFF, use its inputs for the D input
void GowinImpl::create_passthrough_luts(void)
{
std::vector<std::unique_ptr<CellInfo>> new_cells;
for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second.get();
if (is_dff(ci)) {
Loc loc = ctx->getBelLocation(ci->bel);
BelId lut_bel = ctx->getBelByLocation(Loc(loc.x, loc.y, loc.z - 1));
CellInfo *lut = ctx->getBoundBelCell(lut_bel);
CellInfo *alu = ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, loc.z / 2 + BelZ::ALU0_Z)));
const CellInfo *ramw = ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, BelZ::RAMW_Z)));
if (!(lut || alu || ramw)) {
if (ctx->debug) {
log_info("Found an unused LUT:%s, ", ctx->nameOfBel(lut_bel));
}
// make LUT
auto lut_cell = gwu.create_cell(gwu.create_aux_name(ci->name, 0, "_passthrough_lut$"), id_LUT4);
CellInfo *lut = lut_cell.get();
NetInfo *d_net = ci->getPort(id_D);
NPNR_ASSERT(d_net != nullptr);
if (d_net->name == ctx->id("$PACKER_GND") || d_net->name == ctx->id("$PACKER_VCC")) {
if (ctx->debug) {
log("make a constant %s.\n", d_net->name == ctx->id("$PACKER_VCC") ? "VCC" : "GND");
}
ci->disconnectPort(id_D);
if (d_net->name == ctx->id("$PACKER_GND")) {
lut->setParam(id_INIT, 0x0000);
} else {
lut->setParam(id_INIT, 0xffff);
}
} else {
if (ctx->debug) {
log("make a pass-through.\n");
}
IdString lut_input = id_I3;
int lut_init = 0xff00;
lut->addInput(lut_input);
lut->cell_bel_pins[lut_input].clear();
lut->cell_bel_pins.at(lut_input).push_back(lut_input);
ci->movePortTo(id_D, lut, lut_input);
lut->setParam(id_INIT, lut_init);
}
lut->addOutput(id_F);
lut->cell_bel_pins[id_F].clear();
lut->cell_bel_pins.at(id_F).push_back(id_F);
ci->connectPorts(id_D, lut, id_F);
ctx->bindBel(lut_bel, lut, PlaceStrength::STRENGTH_LOCKED);
new_cells.push_back(std::move(lut_cell));
}
}
}
for (auto &cell : new_cells) {
ctx->cells[cell->name] = std::move(cell);
}
}
// DFFs must be same type or compatible
inline bool incompatible_ffs(const CellInfo *ff, const CellInfo *adj_ff)
{
@ -798,22 +870,30 @@ bool GowinImpl::dsp_valid(Loc l, IdString bel_type, bool explain_invalid) const
bool GowinImpl::slice_valid(int x, int y, int z) const
{
const CellInfo *lut = ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, z * 2)));
const bool lut_in_4_5 = lut && (z == 4 || z == 5);
const CellInfo *ff = ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, z * 2 + 1)));
// There are only 6 ALUs
const CellInfo *alu = (z < 6) ? ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, z + BelZ::ALU0_Z))) : nullptr;
const CellInfo *ramw =
(z == 4 || z == 5) ? ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, BelZ::RAMW_Z))) : nullptr;
const CellInfo *ramw = ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, BelZ::RAMW_Z)));
if (alu && lut) {
return false;
}
if (ramw) {
if (alu || ff || lut_in_4_5) {
// FFs in slices 4 and 5 are not allowed
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, 4 * 2 + 1))) ||
ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, 5 * 2 + 1)))) {
return false;
}
return true;
// ALU/LUTs in slices 4, 5, 6, 7 are not allowed
for (int i = 4; i < 8; ++i) {
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, i * 2)))) {
return false;
}
if (i < 6 && ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, i + BelZ::ALU0_Z)))) {
return false;
}
}
}
// check for ALU/LUT in the adjacent cell
@ -829,18 +909,19 @@ bool GowinImpl::slice_valid(int x, int y, int z) const
return false;
}
// if there is DFF it must be connected to this LUT or ALU
if (ff) {
static std::vector<int> mux_z = {BelZ::MUX20_Z, BelZ::MUX21_Z, BelZ::MUX20_Z + 4, BelZ::MUX23_Z,
BelZ::MUX20_Z + 8, BelZ::MUX21_Z + 8, BelZ::MUX20_Z + 12, BelZ::MUX27_Z};
const auto &ff_data = fast_cell_info.at(ff->flat_index);
if (lut) {
const auto &lut_data = fast_cell_info.at(lut->flat_index);
if (ff_data.ff_d != lut_data.lut_f) {
return false;
const NetInfo *src;
// check implcit LUT(ALU) -> FF connection
if (lut || alu) {
if (lut) {
src = fast_cell_info.at(lut->flat_index).lut_f;
} else {
src = fast_cell_info.at(alu->flat_index).alu_sum;
}
}
if (alu) {
const auto &alu_data = fast_cell_info.at(alu->flat_index);
if (ff_data.ff_d != alu_data.alu_sum) {
if (ff_data.ff_d != src) {
return false;
}
}

View File

@ -817,11 +817,12 @@ def create_logic_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int, tde
tt.add_bel_pin(lut, f"I{j}", f"{inp_name}{i}", PinType.INPUT)
tt.add_bel_pin(lut, "F", f"F{i}", PinType.OUTPUT)
if i < 6:
# FF data can come from LUT output, but we pretend that we can use
# any LUT input
tt.create_pip(f"F{i}", f"XD{i}", get_tm_class(db, f"F{i}"))
for inp_name in lut_inputs:
tt.create_pip(f"{inp_name}{i}", f"XD{i}", get_tm_class(db, f"{inp_name}{i}"))
# also experimental input for FF using SEL wire - this theory will
# allow to place unrelated LUT and FF next to each other
# don't create for now
#tt.create_pip(f"SEL{i}", f"XD{i}", get_tm_class(db, f"SEL{i}"))
# FF
ff = tt.create_bel(f"DFF{i}", "DFF", z =(i * 2 + 1))
tt.add_bel_pin(ff, "D", f"XD{i}", PinType.INPUT)

View File

@ -181,6 +181,12 @@ bool GowinUtils::need_BLKSEL_fix(void)
return extra->chip_flags & Extra_chip_data_POD::NEED_BLKSEL_FIX;
}
IdString GowinUtils::create_aux_name(IdString main_name, int idx, const char *str_suffix)
{
return idx ? ctx->idf("%s%s%d", main_name.c_str(ctx), str_suffix, idx)
: ctx->idf("%s%s", main_name.c_str(ctx), str_suffix);
}
std::unique_ptr<CellInfo> GowinUtils::create_cell(IdString name, IdString type)
{
NPNR_ASSERT(!ctx->cells.count(name));

View File

@ -107,6 +107,9 @@ struct GowinUtils
return is_global_wire(ctx->getPipSrcWire(pip)) || is_global_wire(ctx->getPipDstWire(pip));
}
// construct name
IdString create_aux_name(IdString main_name, int idx = 0, const char *str_suffix = "_aux$");
// make cell but do not include it in the list of chip cells.
std::unique_ptr<CellInfo> create_cell(IdString name, IdString type);

View File

@ -508,15 +508,6 @@ struct GowinPacker
make_iob_nets(*out_iob);
}
IdString create_aux_name(IdString main_name, int idx = 0, const char *str_suffix = "_aux$")
{
std::string sfx("");
if (idx) {
sfx = std::to_string(idx);
}
return ctx->id(main_name.str(ctx) + std::string(str_suffix) + sfx);
}
BelId get_aux_iologic_bel(const CellInfo &ci)
{
return ctx->getBelByLocation(gwu.get_pair_iologic_bel(ctx->getBelLocation(ci.bel)));
@ -529,7 +520,7 @@ struct GowinPacker
if (ci.type.in(id_ODDR, id_ODDRC, id_OSER4, id_IDDR, id_IDDRC, id_IDES4)) {
return nullptr;
}
IdString aux_name = create_aux_name(ci.name, idx);
IdString aux_name = gwu.create_aux_name(ci.name, idx);
BelId bel = get_aux_iologic_bel(ci);
BelId io_bel = gwu.get_io_bel_from_iologic(bel);
if (!ctx->checkBelAvail(io_bel)) {
@ -720,9 +711,9 @@ struct GowinPacker
// to simplify packaging, the parts of the OSER16 are presented as IOLOGIC cells
// and one of these aux cells is declared as main
IdString main_name = create_aux_name(ci.name);
IdString main_name = gwu.create_aux_name(ci.name);
IdString aux_name = create_aux_name(ci.name, 1);
IdString aux_name = gwu.create_aux_name(ci.name, 1);
ctx->createCell(aux_name, id_IOLOGIC_DUMMY);
CellInfo *aux = ctx->cells.at(aux_name).get();
@ -794,9 +785,9 @@ struct GowinPacker
// to simplify packaging, the parts of the IDES16 are presented as IOLOGIC cells
// and one of these aux cells is declared as main
IdString main_name = create_aux_name(ci.name);
IdString main_name = gwu.create_aux_name(ci.name);
IdString aux_name = create_aux_name(ci.name, 1);
IdString aux_name = gwu.create_aux_name(ci.name, 1);
ctx->createCell(aux_name, id_IOLOGIC_DUMMY);
CellInfo *aux = ctx->cells.at(aux_name).get();
@ -1229,7 +1220,7 @@ struct GowinPacker
{id_DFFP, id_D}, {id_DFFPE, id_D}, {id_DFFNP, id_D}, {id_DFFNPE, id_D},
{id_DFFC, id_D}, {id_DFFCE, id_D}, {id_DFFNC, id_D}, {id_DFFNCE, id_D}};
int lutffs = h.constrain_cell_pairs(lut_outs, dff_ins, 0);
int lutffs = h.constrain_cell_pairs(lut_outs, dff_ins, 1, 1);
log_info("Constrained %d LUTFF pairs.\n", lutffs);
}
@ -1365,7 +1356,7 @@ struct GowinPacker
}
// Make a decoder
auto lut_cell = gwu.create_cell(create_aux_name(ci->name, 0, "_blksel_lut$"), id_LUT4);
auto lut_cell = gwu.create_cell(gwu.create_aux_name(ci->name, 0, "_blksel_lut$"), id_LUT4);
CellInfo *lut = lut_cell.get();
lut->addInput(id_I3);
ci->movePortTo(id_CE, lut, id_I3);
@ -1441,7 +1432,7 @@ struct GowinPacker
}
// create DFF
auto cache_dff_cell = gwu.create_cell(create_aux_name(ci->name, i, "_cache_dff$"), dff_type);
auto cache_dff_cell = gwu.create_cell(gwu.create_aux_name(ci->name, i, "_cache_dff$"), dff_type);
CellInfo *cache_dff = cache_dff_cell.get();
cache_dff->addInput(id_CE);
cache_dff->connectPort(id_CE, oce_net);
@ -1477,7 +1468,7 @@ struct GowinPacker
log_info(" apply the SP fix\n");
}
// create WRE LUT
auto wre_lut_cell = gwu.create_cell(create_aux_name(ci->name, 0, "_wre_lut$"), id_LUT4);
auto wre_lut_cell = gwu.create_cell(gwu.create_aux_name(ci->name, 0, "_wre_lut$"), id_LUT4);
CellInfo *wre_lut = wre_lut_cell.get();
wre_lut->setParam(id_INIT, 0x8888);
ci->movePortTo(id_CE, wre_lut, id_I0);
@ -1486,7 +1477,7 @@ struct GowinPacker
ci->connectPorts(id_WRE, wre_lut, id_F);
// create CE LUT
auto ce_lut_cell = gwu.create_cell(create_aux_name(ci->name, 0, "_ce_lut$"), id_LUT4);
auto ce_lut_cell = gwu.create_cell(gwu.create_aux_name(ci->name, 0, "_ce_lut$"), id_LUT4);
CellInfo *ce_lut = ce_lut_cell.get();
ce_lut->setParam(id_INIT, 0xeeee);
wre_lut->copyPortTo(id_I0, ce_lut, id_I0);
@ -1497,7 +1488,7 @@ struct GowinPacker
// create ce reg
int write_mode = ci->params.at(id_WRITE_MODE).as_int64();
IdString dff_type = write_mode ? id_DFF : id_DFFR;
auto ce_pre_dff_cell = gwu.create_cell(create_aux_name(ci->name, 0, "_ce_pre_dff$"), dff_type);
auto ce_pre_dff_cell = gwu.create_cell(gwu.create_aux_name(ci->name, 0, "_ce_pre_dff$"), dff_type);
CellInfo *ce_pre_dff = ce_pre_dff_cell.get();
ce_pre_dff->addInput(id_D);
ce_lut->copyPortTo(id_I0, ce_pre_dff, id_D);
@ -1513,7 +1504,7 @@ struct GowinPacker
// add delay register in pipeline mode
int read_mode = ci->params.at(id_READ_MODE).as_int64();
if (read_mode) {
auto ce_pipe_dff_cell = gwu.create_cell(create_aux_name(ci->name, 0, "_ce_pipe_dff$"), id_DFF);
auto ce_pipe_dff_cell = gwu.create_cell(gwu.create_aux_name(ci->name, 0, "_ce_pipe_dff$"), id_DFF);
new_cells.push_back(std::move(ce_pipe_dff_cell));
CellInfo *ce_pipe_dff = new_cells.back().get();
ce_pipe_dff->addInput(id_D);
@ -1533,7 +1524,7 @@ struct GowinPacker
continue;
}
// create cache lut
auto cache_lut_cell = gwu.create_cell(create_aux_name(ci->name, i, "_cache_lut$"), id_LUT4);
auto cache_lut_cell = gwu.create_cell(gwu.create_aux_name(ci->name, i, "_cache_lut$"), id_LUT4);
CellInfo *cache_lut = cache_lut_cell.get();
cache_lut->setParam(id_INIT, 0xcaca);
cache_lut->addInput(id_I0);
@ -1544,7 +1535,7 @@ struct GowinPacker
new_ce_net_src->connectPorts(id_Q, cache_lut, id_I2);
// create cache DFF
auto cache_dff_cell = gwu.create_cell(create_aux_name(ci->name, i, "_cache_dff$"), id_DFFE);
auto cache_dff_cell = gwu.create_cell(gwu.create_aux_name(ci->name, i, "_cache_dff$"), id_DFFE);
CellInfo *cache_dff = cache_dff_cell.get();
cache_dff->addInput(id_CE);
cache_dff->addInput(id_D);
@ -1950,7 +1941,7 @@ struct GowinPacker
ci->constr_y = 0;
ci->constr_y = 0;
IdString mult_name = create_aux_name(ci->name);
IdString mult_name = gwu.create_aux_name(ci->name);
std::unique_ptr<CellInfo> mult_cell = gwu.create_cell(mult_name, id_DUMMY_CELL);
new_cells.push_back(std::move(mult_cell));
CellInfo *mult_ci = new_cells.back().get();
@ -2009,7 +2000,7 @@ struct GowinPacker
ci->constr_children.clear();
for (int i = 0; i < 2; ++i) {
IdString padd_name = create_aux_name(ci->name, i * 2);
IdString padd_name = gwu.create_aux_name(ci->name, i * 2);
std::unique_ptr<CellInfo> padd_cell = gwu.create_cell(padd_name, id_DUMMY_CELL);
new_cells.push_back(std::move(padd_cell));
CellInfo *padd_ci = new_cells.back().get();
@ -2020,7 +2011,7 @@ struct GowinPacker
padd_ci->constr_y = 0;
padd_ci->constr_z = BelZ::PADD9_0_0_Z - BelZ::PADD18_0_0_Z + i;
IdString mult_name = create_aux_name(ci->name, i * 2 + 1);
IdString mult_name = gwu.create_aux_name(ci->name, i * 2 + 1);
std::unique_ptr<CellInfo> mult_cell = gwu.create_cell(mult_name, id_DUMMY_CELL);
new_cells.push_back(std::move(mult_cell));
CellInfo *mult_ci = new_cells.back().get();
@ -2061,7 +2052,7 @@ struct GowinPacker
ci->constr_z = 0;
ci->constr_children.clear();
IdString padd_name = create_aux_name(ci->name);
IdString padd_name = gwu.create_aux_name(ci->name);
std::unique_ptr<CellInfo> padd_cell = gwu.create_cell(padd_name, id_DUMMY_CELL);
new_cells.push_back(std::move(padd_cell));
CellInfo *padd_ci = new_cells.back().get();
@ -2103,7 +2094,7 @@ struct GowinPacker
ci->constr_children.clear();
for (int i = 0; i < 2; ++i) {
IdString padd_name = create_aux_name(ci->name, i * 2);
IdString padd_name = gwu.create_aux_name(ci->name, i * 2);
std::unique_ptr<CellInfo> padd_cell = gwu.create_cell(padd_name, id_DUMMY_CELL);
new_cells.push_back(std::move(padd_cell));
CellInfo *padd_ci = new_cells.back().get();
@ -2114,7 +2105,7 @@ struct GowinPacker
padd_ci->constr_y = 0;
padd_ci->constr_z = BelZ::PADD9_0_0_Z - BelZ::MULT18X18_0_0_Z + i;
IdString mult_name = create_aux_name(ci->name, i * 2 + 1);
IdString mult_name = gwu.create_aux_name(ci->name, i * 2 + 1);
std::unique_ptr<CellInfo> mult_cell = gwu.create_cell(mult_name, id_DUMMY_CELL);
new_cells.push_back(std::move(mult_cell));
CellInfo *mult_ci = new_cells.back().get();
@ -2161,7 +2152,7 @@ struct GowinPacker
ci->constr_children.clear();
for (int i = 0; i < 4; ++i) {
IdString padd_name = create_aux_name(ci->name, i * 2);
IdString padd_name = gwu.create_aux_name(ci->name, i * 2);
std::unique_ptr<CellInfo> padd_cell = gwu.create_cell(padd_name, id_DUMMY_CELL);
new_cells.push_back(std::move(padd_cell));
CellInfo *padd_ci = new_cells.back().get();
@ -2172,7 +2163,7 @@ struct GowinPacker
padd_ci->constr_y = 0;
padd_ci->constr_z = BelZ::PADD9_0_0_Z - BelZ::ALU54D_0_Z + 4 * (i / 2) + (i % 2);
IdString mult_name = create_aux_name(ci->name, i * 2 + 1);
IdString mult_name = gwu.create_aux_name(ci->name, i * 2 + 1);
std::unique_ptr<CellInfo> mult_cell = gwu.create_cell(mult_name, id_DUMMY_CELL);
new_cells.push_back(std::move(mult_cell));
CellInfo *mult_ci = new_cells.back().get();
@ -2266,7 +2257,7 @@ struct GowinPacker
ci->constr_children.clear();
for (int i = 0; i < 2; ++i) {
IdString padd_name = create_aux_name(ci->name, i * 2);
IdString padd_name = gwu.create_aux_name(ci->name, i * 2);
std::unique_ptr<CellInfo> padd_cell = gwu.create_cell(padd_name, id_DUMMY_CELL);
new_cells.push_back(std::move(padd_cell));
CellInfo *padd_ci = new_cells.back().get();
@ -2277,7 +2268,7 @@ struct GowinPacker
padd_ci->constr_y = 0;
padd_ci->constr_z = BelZ::PADD9_0_0_Z - BelZ::MULTALU18X18_0_Z + i;
IdString mult_name = create_aux_name(ci->name, i * 2 + 1);
IdString mult_name = gwu.create_aux_name(ci->name, i * 2 + 1);
std::unique_ptr<CellInfo> mult_cell = gwu.create_cell(mult_name, id_DUMMY_CELL);
new_cells.push_back(std::move(mult_cell));
CellInfo *mult_ci = new_cells.back().get();
@ -2369,7 +2360,7 @@ struct GowinPacker
ci->constr_children.clear();
for (int i = 0; i < 2; ++i) {
IdString padd_name = create_aux_name(ci->name, i * 2);
IdString padd_name = gwu.create_aux_name(ci->name, i * 2);
std::unique_ptr<CellInfo> padd_cell = gwu.create_cell(padd_name, id_DUMMY_CELL);
new_cells.push_back(std::move(padd_cell));
CellInfo *padd_ci = new_cells.back().get();
@ -2380,7 +2371,7 @@ struct GowinPacker
padd_ci->constr_y = 0;
padd_ci->constr_z = BelZ::PADD9_0_0_Z - BelZ::MULTALU36X18_0_Z + i;
IdString mult_name = create_aux_name(ci->name, i * 2 + 1);
IdString mult_name = gwu.create_aux_name(ci->name, i * 2 + 1);
std::unique_ptr<CellInfo> mult_cell = gwu.create_cell(mult_name, id_DUMMY_CELL);
new_cells.push_back(std::move(mult_cell));
CellInfo *mult_ci = new_cells.back().get();
@ -2463,7 +2454,7 @@ struct GowinPacker
ci->constr_children.clear();
for (int i = 0; i < 2; ++i) {
IdString padd_name = create_aux_name(ci->name, i * 2);
IdString padd_name = gwu.create_aux_name(ci->name, i * 2);
std::unique_ptr<CellInfo> padd_cell = gwu.create_cell(padd_name, id_DUMMY_CELL);
new_cells.push_back(std::move(padd_cell));
CellInfo *padd_ci = new_cells.back().get();
@ -2474,7 +2465,7 @@ struct GowinPacker
padd_ci->constr_y = 0;
padd_ci->constr_z = BelZ::PADD9_0_0_Z - BelZ::MULTADDALU18X18_0_Z + i;
IdString mult_name = create_aux_name(ci->name, i * 2 + 1);
IdString mult_name = gwu.create_aux_name(ci->name, i * 2 + 1);
std::unique_ptr<CellInfo> mult_cell = gwu.create_cell(mult_name, id_DUMMY_CELL);
new_cells.push_back(std::move(mult_cell));
CellInfo *mult_ci = new_cells.back().get();
@ -2549,7 +2540,7 @@ struct GowinPacker
ci->constr_children.clear();
for (int i = 0; i < 8; ++i) {
IdString padd_name = create_aux_name(ci->name, i * 2);
IdString padd_name = gwu.create_aux_name(ci->name, i * 2);
std::unique_ptr<CellInfo> padd_cell = gwu.create_cell(padd_name, id_DUMMY_CELL);
new_cells.push_back(std::move(padd_cell));
CellInfo *padd_ci = new_cells.back().get();
@ -2562,7 +2553,7 @@ struct GowinPacker
padd_ci->constr_y = 0;
padd_ci->constr_z = padd_z[i / 2] - BelZ::MULT36X36_Z + i % 2;
IdString mult_name = create_aux_name(ci->name, i * 2 + 1);
IdString mult_name = gwu.create_aux_name(ci->name, i * 2 + 1);
std::unique_ptr<CellInfo> mult_cell = gwu.create_cell(mult_name, id_DUMMY_CELL);
new_cells.push_back(std::move(mult_cell));
CellInfo *mult_ci = new_cells.back().get();
@ -3165,7 +3156,7 @@ struct GowinPacker
}
std::unique_ptr<CellInfo> lut_cell =
gwu.create_cell(create_aux_name(ci.name, lut_idx, "_lut$"), id_LUT4);
gwu.create_cell(gwu.create_aux_name(ci.name, lut_idx, "_lut$"), id_LUT4);
new_cells.push_back(std::move(lut_cell));
CellInfo *lut = new_cells.back().get();
lut->addInput(id_I0);
@ -3340,8 +3331,7 @@ struct GowinPacker
pack_alus();
ctx->check();
// XXX Leads to the impossibility of placement on lower models.
// constrain_lutffs();
constrain_lutffs();
ctx->check();
pack_pll();