From 07fb4702ceae5c5b03864bb0c961c40edbb2d955 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 19 Aug 2018 19:16:24 -0700 Subject: [PATCH] Populate LUT masks --- xc7/cells.cc | 6 ++--- xc7/pack.cc | 6 ++--- xc7/xdl.cc | 73 +++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 72 insertions(+), 13 deletions(-) diff --git a/xc7/cells.cc b/xc7/cells.cc index c43af075..f5f23f5a 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -44,7 +44,7 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri new_cell->type = type; if (type == ctx->id("XC7_LC")) { new_cell->type = id_SLICE_LUT6; - new_cell->params[ctx->id("LUT_INIT")] = "0"; + new_cell->params[ctx->id("INIT")] = "0"; new_cell->params[ctx->id("NEG_CLK")] = "0"; new_cell->params[ctx->id("CARRY_ENABLE")] = "0"; new_cell->params[ctx->id("DFF_ENABLE")] = "0"; @@ -258,7 +258,7 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) { - lc->params[ctx->id("LUT_INIT")] = lut->params[ctx->id("LUT_INIT")]; + lc->params[ctx->id("INIT")] = lut->params[ctx->id("INIT")]; replace_port(lut, ctx->id("I0"), lc, id_I1); if (get_net_or_empty(lut, id_I1)) replace_port(lut, id_I1, lc, id_I2); @@ -317,7 +317,7 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l NPNR_ASSERT(citer == config.end()); if (pass_thru_lut) { - lc->params[ctx->id("LUT_INIT")] = "2"; + lc->params[ctx->id("INIT")] = "1"; replace_port(dff, ctx->id("D"), lc, id_I1); } diff --git a/xc7/pack.cc b/xc7/pack.cc index 1e27f8a3..ee9682f1 100644 --- a/xc7/pack.cc +++ b/xc7/pack.cc @@ -332,7 +332,7 @@ static void pack_constants(Context *ctx) log_info("Packing constants..\n"); std::unique_ptr gnd_cell = create_ice_cell(ctx, ctx->id("XC7_LC"), "$PACKER_GND"); - gnd_cell->params[ctx->id("LUT_INIT")] = "0"; + gnd_cell->params[ctx->id("INIT")] = "0"; std::unique_ptr gnd_net = std::unique_ptr(new NetInfo); gnd_net->name = ctx->id("$PACKER_GND_NET"); gnd_net->driver.cell = gnd_cell.get(); @@ -340,7 +340,7 @@ static void pack_constants(Context *ctx) gnd_cell->ports.at(id_O).net = gnd_net.get(); std::unique_ptr vcc_cell = create_ice_cell(ctx, ctx->id("XC7_LC"), "$PACKER_VCC"); - vcc_cell->params[ctx->id("LUT_INIT")] = "1"; + vcc_cell->params[ctx->id("INIT")] = "1"; std::unique_ptr vcc_net = std::unique_ptr(new NetInfo); vcc_net->name = ctx->id("$PACKER_VCC_NET"); vcc_net->driver.cell = vcc_cell.get(); @@ -585,7 +585,7 @@ static std::unique_ptr spliceLUT(Context *ctx, CellInfo *ci, IdString // Create pass-through LUT. std::unique_ptr pt = create_ice_cell(ctx, ctx->id("XC7_LC"), ci->name.str(ctx) + "$nextpnr_" + portId.str(ctx) + "_lut_through"); - pt->params[ctx->id("LUT_INIT")] = "65280"; // output is always I3 + pt->params[ctx->id("INIT")] = "65280"; // output is always I3 // Create LUT output net. std::unique_ptr out_net = std::unique_ptr(new NetInfo); diff --git a/xc7/xdl.cc b/xc7/xdl.cc index c627c4db..cb7157ab 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -38,6 +38,8 @@ void write_xdl(const Context *ctx, std::ostream &out) auto designPtr = Factory::newDesignPtr("name", torc_info->ddb->getDeviceName(), "clg484", "", ""); std::unordered_map site_to_instance; + std::vector> lut_inputs; + lut_inputs.reserve(6); for (const auto& cell : ctx->cells) { const char* type; @@ -63,16 +65,73 @@ void write_xdl(const Context *ctx, std::ostream &out) instPtr = ret.first->second; if (cell.second->type == id_SLICE_LUT6) { - std::string config; + std::string setting, value; + std::string lut; switch (torc_info->bel_to_z[cell.second->bel.index]) { - case 0: case 4: config += 'A'; break; - case 1: case 5: config += 'B'; break; - case 2: case 6: config += 'C'; break; - case 3: case 7: config += 'D'; break; + case 0: case 4: lut = 'A'; break; + case 1: case 5: lut = 'B'; break; + case 2: case 6: lut = 'C'; break; + case 3: case 7: lut = 'D'; break; default: throw; } - config += "6LUT"; - instPtr->setConfig(config, cell.second->name.str(ctx), "#LUT:O6="); + + setting = lut + "6LUT"; + value = "#LUT:O6="; + lut_inputs.clear(); + if (get_net_or_empty(cell.second.get(), id_I1)) lut_inputs.emplace_back(lut + "1", "~" + lut + "1"); + if (get_net_or_empty(cell.second.get(), id_I2)) lut_inputs.emplace_back(lut + "2", "~" + lut + "2"); + if (get_net_or_empty(cell.second.get(), id_I3)) lut_inputs.emplace_back(lut + "3", "~" + lut + "3"); + if (get_net_or_empty(cell.second.get(), id_I4)) lut_inputs.emplace_back(lut + "4", "~" + lut + "4"); + if (get_net_or_empty(cell.second.get(), id_I5)) lut_inputs.emplace_back(lut + "5", "~" + lut + "5"); + if (get_net_or_empty(cell.second.get(), id_I6)) lut_inputs.emplace_back(lut + "6", "~" + lut + "6"); + const auto& init = cell.second->params[ctx->id("INIT")]; + // Assume from Yosys that INIT masks of less than 32 bits are output as uint32_t + if (lut_inputs.size() < 6) { + auto init_as_uint = boost::lexical_cast(init); + NPNR_ASSERT(init_as_uint < (1ull << (1u << lut_inputs.size()))); + if (lut_inputs.empty()) + value += init; + else + for (unsigned o = 0; o < (1u << lut_inputs.size()); ++o) { + if ((init_as_uint >> o) & 0x1) continue; + if (o > 0) value += "+"; + value += "("; + value += (o & 1) ? lut_inputs[0].first : lut_inputs[0].second; + for (unsigned i = 1; i < lut_inputs.size(); ++i) { + value += "*"; + value += o & (1 << i) ? lut_inputs[i].first : lut_inputs[i].second; + } + value += ")"; + } + } + // Otherwise as a bit string + else { + NPNR_ASSERT(init.size() == (1u << lut_inputs.size())); + for (unsigned i = 0; i < (1u << lut_inputs.size()); ++i) { + if (init[i] == '0') continue; + if (i > 0) value += "+"; + value += "("; + value += (i & 1) ? lut_inputs[0].first : lut_inputs[0].second; + for (unsigned i = 1; i < lut_inputs.size(); ++i) { + value += "*"; + value += i & (1 << i) ? lut_inputs[i].first : lut_inputs[i].second; + } + value += ")"; + } + } + + auto O = get_net_or_empty(cell.second.get(), id_O); + if (O) + instPtr->setConfig(setting, O->name.str(ctx), value); + else + instPtr->setConfig(setting, cell.second->name.str(ctx), value); + + auto OQ = get_net_or_empty(cell.second.get(), id_OQ); + if (OQ) { + setting = lut; + setting += "FF"; + instPtr->setConfig(setting, OQ->name.c_str(ctx), "#FF"); + } } else if (cell.second->type == id_IOB33S) { if (get_net_or_empty(cell.second.get(), id_I)) {