From 7ba83d3f886161aa9dd9ab349cf7df4817e959c7 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Tue, 22 Oct 2024 17:12:56 +1000 Subject: [PATCH] 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 --- himbaechel/uarch/gowin/gowin.cc | 119 ++++++++++++++++++++--- himbaechel/uarch/gowin/gowin_arch_gen.py | 9 +- himbaechel/uarch/gowin/gowin_utils.cc | 9 ++ himbaechel/uarch/gowin/gowin_utils.h | 3 + himbaechel/uarch/gowin/pack.cc | 74 ++++++-------- 5 files changed, 152 insertions(+), 62 deletions(-) diff --git a/himbaechel/uarch/gowin/gowin.cc b/himbaechel/uarch/gowin/gowin.cc index 1199ee45fe..0048c94e69 100644 --- a/himbaechel/uarch/gowin/gowin.cc +++ b/himbaechel/uarch/gowin/gowin.cc @@ -71,6 +71,9 @@ struct GowinImpl : HimbaechelAPI std::vector 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 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,73 @@ 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> new_cells; + // evenly use all 4 LUT inputs + const std::vector> lut_tmpl = { + {id_I0, 0xaaaa}, {id_I1, 0xcccc}, {id_I2, 0xf0f0}, {id_I3, 0xff00}}; + int cur_lut_tmpl = 3; + + 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 = lut_tmpl.at(cur_lut_tmpl).first; + int lut_init = lut_tmpl.at(cur_lut_tmpl).second; + cur_lut_tmpl = (cur_lut_tmpl + 1) % 4; + + 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 +876,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 +915,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 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; } } diff --git a/himbaechel/uarch/gowin/gowin_arch_gen.py b/himbaechel/uarch/gowin/gowin_arch_gen.py index 473efa21a9..77a2739874 100644 --- a/himbaechel/uarch/gowin/gowin_arch_gen.py +++ b/himbaechel/uarch/gowin/gowin_arch_gen.py @@ -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) diff --git a/himbaechel/uarch/gowin/gowin_utils.cc b/himbaechel/uarch/gowin/gowin_utils.cc index 1e1c220822..5e232c9a93 100644 --- a/himbaechel/uarch/gowin/gowin_utils.cc +++ b/himbaechel/uarch/gowin/gowin_utils.cc @@ -181,6 +181,15 @@ 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) +{ + std::string sfx(""); + if (idx) { + sfx = std::to_string(idx); + } + return ctx->id(main_name.str(ctx) + std::string(str_suffix) + sfx); +} + std::unique_ptr GowinUtils::create_cell(IdString name, IdString type) { NPNR_ASSERT(!ctx->cells.count(name)); diff --git a/himbaechel/uarch/gowin/gowin_utils.h b/himbaechel/uarch/gowin/gowin_utils.h index 71f60f8c99..ff622804f4 100644 --- a/himbaechel/uarch/gowin/gowin_utils.h +++ b/himbaechel/uarch/gowin/gowin_utils.h @@ -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 create_cell(IdString name, IdString type); diff --git a/himbaechel/uarch/gowin/pack.cc b/himbaechel/uarch/gowin/pack.cc index f774bbc32b..384c4bf9c9 100644 --- a/himbaechel/uarch/gowin/pack.cc +++ b/himbaechel/uarch/gowin/pack.cc @@ -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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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();