Populate LUT masks

This commit is contained in:
Eddie Hung 2018-08-19 19:16:24 -07:00
parent a7ccc01c45
commit 07fb4702ce
3 changed files with 72 additions and 13 deletions

View File

@ -44,7 +44,7 @@ std::unique_ptr<CellInfo> 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<CellInfo> 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);
}

View File

@ -332,7 +332,7 @@ static void pack_constants(Context *ctx)
log_info("Packing constants..\n");
std::unique_ptr<CellInfo> 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<NetInfo> gnd_net = std::unique_ptr<NetInfo>(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<CellInfo> 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<NetInfo> vcc_net = std::unique_ptr<NetInfo>(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<CellInfo> spliceLUT(Context *ctx, CellInfo *ci, IdString
// Create pass-through LUT.
std::unique_ptr<CellInfo> 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<NetInfo> out_net = std::unique_ptr<NetInfo>(new NetInfo);

View File

@ -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<int32_t,InstanceSharedPtr> site_to_instance;
std::vector<std::pair<std::string,std::string>> 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<uint32_t>(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)) {