diff --git a/leuctra/arch.cc b/leuctra/arch.cc index 61a96165..2f8f6182 100644 --- a/leuctra/arch.cc +++ b/leuctra/arch.cc @@ -802,6 +802,141 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port return info; } +// TODO: validate bel subtype (SLICEM vs SLICEL, IOBM vs IOBS, ...). +bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { + IdString type = getBelType(bel); + bool is_slice = false; + if (type == id("LEUCTRA_FF")) { + if (cell && !cell->constr_parent) { + if (0x924924ull & 1ull << bel.index) + return false; + } + is_slice = true; + } + if (type == id("LEUCTRA_LC")) { + if (cell) { + int mask = cell->attrs[id("LOCMASK")].as_int64(); + int lci = bel.index / 3 % 4; + if (!(mask & 1 << lci)) + return false; + if (cell->attrs[id("NEEDS_L")].as_bool()) { + if (!(getBelFlags(bel) & (BelPOD::FLAG_SLICEL | BelPOD::FLAG_SLICEM))) + return false; + } + if (cell->attrs[id("NEEDS_M")].as_bool()) { + if (!(getBelFlags(bel) & BelPOD::FLAG_SLICEM)) + return false; + } + } + is_slice = true; + } + if (type == id("RAMB8BWER") && cell) { + BelId obel = bel; + obel.index = 2; + if (getBoundBelCell(obel)) + return false; + } + if (type == id("RAMB16BWER") && cell) { + BelId obel = bel; + obel.index = 0; + if (getBoundBelCell(obel)) + return false; + obel.index = 1; + if (getBoundBelCell(obel)) + return false; + } + if (is_slice) { + int slice_z = bel.index / 12; + NetInfo *clk = nullptr; + NetInfo *we = nullptr; + NetInfo *ce = nullptr; + NetInfo *sr = nullptr; + Property ff_mode; + Property clk_inv; + bool had_ff = false; + CellInfo *lcs[4]; + CellInfo *ffs[8]; + bool ff_xi_used[4] = {0}; + for (int i = 0; i < 4; i++) { + BelId obel = bel; + obel.index = slice_z * 12 + i * 3; + if (obel == bel) + lcs[i] = cell; + else + lcs[i] = getBoundBelCell(obel); + obel.index++; + if (obel == bel) + ffs[2*i] = cell; + else + ffs[2*i] = getBoundBelCell(obel); + ff_xi_used[i] = ffs[2*i] && !ffs[2*i]->constr_parent; + obel.index++; + if (obel == bel) + ffs[2*i+1] = cell; + else + ffs[2*i+1] = getBoundBelCell(obel); + } + for (auto ff : ffs) { + if (ff) { + if (had_ff) { + if (clk != ff->ports[id("CLK")].net) + return false; + if (ce != ff->ports[id("CE")].net) + return false; + if (sr != ff->ports[id("SR")].net) + return false; + if (ff_mode != ff->params[id("MODE")]) + return false; + if (clk_inv != ff->params[id("CLKINV")]) + return false; + } else { + clk = ff->ports[id("CLK")].net; + ce = ff->ports[id("CE")].net; + sr = ff->ports[id("SR")].net; + ff_mode = ff->params[id("MODE")]; + clk_inv = ff->params[id("CLKINV")]; + } + had_ff = true; + } + } + for (int i = 0; i < 4; i++) { + CellInfo *lc = lcs[i]; + if (!lc) + continue; + if (lc->ports[id("XI")].net && ff_xi_used[i]) + return false; + if (lc->ports[id("WA7")].net && ff_xi_used[2]) + return false; + if (lc->ports[id("WA8")].net && ff_xi_used[1]) + return false; + if (lc->ports[id("DDI8")].net && ff_xi_used[3]) + return false; + if (lc->ports[id("DDI7")].net && ff_xi_used[i | 1]) + return false; + if (lc->ports[id("CLK")].net) { + if (clk) { + if (clk != lc->ports[id("CLK")].net) + return false; + if (clk_inv != lc->params[id("CLKINV")]) + return false; + } else { + clk = lc->ports[id("CLK")].net; + clk_inv = lc->params[id("CLKINV")]; + } + } + if (lc->ports[id("WE")].net) { + if (we) { + if (we != lc->ports[id("WE")].net) + return false; + } else { + we = lc->ports[id("WE")].net; + } + } + } + } + return true; +} + // Assign arch arg info void Arch::assignArchInfo() { diff --git a/leuctra/arch.h b/leuctra/arch.h index ee77c41c..d1360aff 100644 --- a/leuctra/arch.h +++ b/leuctra/arch.h @@ -1183,39 +1183,10 @@ struct Arch : BaseCtx // ------------------------------------------------- // Placement validity checks - // TODO: validate bel subtype (SLICEM vs SLICEL, IOBM vs IOBS, ...). - bool isValidBelForCell(CellInfo *cell, BelId bel) const { - if (cell->type == id("LEUCTRA_FF")) { - if (!cell->constr_parent) { - if (0x924924ull & 1ull << bel.index) - return false; - // XXX FIX FIX FIX - if (0xffcfffull & 1ull << bel.index) - return false; - } - } - if (cell->type == id("LEUCTRA_LC")) { - int mask = cell->attrs[id("LOCMASK")].as_int64(); - int lci = bel.index / 3 % 4; - if (!(mask & 1 << lci)) - return false; - if (cell->attrs[id("NEEDS_L")].as_bool()) { - if (!(getBelFlags(bel) & (BelPOD::FLAG_SLICEL | BelPOD::FLAG_SLICEM))) - return false; - } - if (cell->attrs[id("NEEDS_M")].as_bool()) { - if (!(getBelFlags(bel) & BelPOD::FLAG_SLICEM)) - return false; - } - // XXX more? - } - return true; - } + + bool isValidBelForCell(CellInfo *cell, BelId bel) const; bool isBelLocationValid(BelId bel) const { - CellInfo *cell = getBoundBelCell(bel); - if (cell && !isValidBelForCell(cell, bel)) - return false; - return true; + return isValidBelForCell(getBoundBelCell(bel), bel); } // Apply UCF constraints to the context diff --git a/leuctra/cells.cc b/leuctra/cells.cc index b3af0d53..3f216726 100644 --- a/leuctra/cells.cc +++ b/leuctra/cells.cc @@ -547,6 +547,7 @@ CellInfo *convert_carry4(Context *ctx, CellInfo *c4, CellInfo *link, std::vector if (co[i] || xo[i]) num = i + 1; } + NetInfo *vcc_net = nullptr; for (int i = 0; i < num; i++) { // XXX more cases if (i == 0 && !link) { @@ -607,7 +608,12 @@ CellInfo *convert_carry4(Context *ctx, CellInfo *c4, CellInfo *link, std::vector lcs[i]->constr_children.push_back(ff); ff->params[ctx->id("MODE")] = Property("COMB"); ff->params[ctx->id("CLKINV")] = Property("CLK_B"); - set_const_port(ctx, ff, ctx->id("CLK"), true, created_cells); + if (vcc_net) { + connect_port(ctx, vcc_net, ff, ctx->id("CLK")); + } else { + set_const_port(ctx, ff, ctx->id("CLK"), true, created_cells); + vcc_net = ff->ports[ctx->id("CLK")].net; + } connect_ports(ctx, lcs[i], ctx->id("CO"), ff, ctx->id("D")); connect_port(ctx, co[i], ff, ctx->id("Q")); }