diff options
Diffstat (limited to 'ecp5/bitstream.cc')
-rw-r--r-- | ecp5/bitstream.cc | 238 |
1 files changed, 229 insertions, 9 deletions
diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index df16946d..a9c82524 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -34,6 +34,18 @@ NEXTPNR_NAMESPACE_BEGIN +namespace BaseConfigs { +void config_empty_lfe5u_25f(ChipConfig &cc); +void config_empty_lfe5u_45f(ChipConfig &cc); +void config_empty_lfe5u_85f(ChipConfig &cc); +void config_empty_lfe5um_25f(ChipConfig &cc); +void config_empty_lfe5um_45f(ChipConfig &cc); +void config_empty_lfe5um_85f(ChipConfig &cc); +void config_empty_lfe5um5g_25f(ChipConfig &cc); +void config_empty_lfe5um5g_45f(ChipConfig &cc); +void config_empty_lfe5um5g_85f(ChipConfig &cc); +} // namespace BaseConfigs + // Convert an absolute wire name to a relative Trellis one static std::string get_trellis_wirename(Context *ctx, Location loc, WireId wire) { @@ -538,8 +550,37 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex } config_file >> cc; } else { - cc.chip_name = ctx->getChipName(); - // TODO: .bit metadata + switch (ctx->args.type) { + case ArchArgs::LFE5U_25F: + BaseConfigs::config_empty_lfe5u_25f(cc); + break; + case ArchArgs::LFE5U_45F: + BaseConfigs::config_empty_lfe5u_45f(cc); + break; + case ArchArgs::LFE5U_85F: + BaseConfigs::config_empty_lfe5u_85f(cc); + break; + case ArchArgs::LFE5UM_25F: + BaseConfigs::config_empty_lfe5um_25f(cc); + break; + case ArchArgs::LFE5UM_45F: + BaseConfigs::config_empty_lfe5um_45f(cc); + break; + case ArchArgs::LFE5UM_85F: + BaseConfigs::config_empty_lfe5um_85f(cc); + break; + case ArchArgs::LFE5UM5G_25F: + BaseConfigs::config_empty_lfe5um5g_25f(cc); + break; + case ArchArgs::LFE5UM5G_45F: + BaseConfigs::config_empty_lfe5um5g_45f(cc); + break; + case ArchArgs::LFE5UM5G_85F: + BaseConfigs::config_empty_lfe5um5g_85f(cc); + break; + default: + NPNR_ASSERT_FALSE("Unsupported device type"); + } } // Clear out DCU tieoffs in base config if DCU used @@ -578,7 +619,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex } // Find bank voltages std::unordered_map<int, IOVoltage> bankVcc; - std::unordered_map<int, bool> bankLvds; + std::unordered_map<int, bool> bankLvds, bankVref; for (auto &cell : ctx->cells) { CellInfo *ci = cell.second.get(); @@ -587,7 +628,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex std::string dir = str_or_default(ci->params, ctx->id("DIR"), "INPUT"); std::string iotype = str_or_default(ci->attrs, ctx->id("IO_TYPE"), "LVCMOS33"); - if (dir != "INPUT") { + if (dir != "INPUT" || is_referenced(ioType_from_str(iotype))) { IOVoltage vcc = get_vccio(ioType_from_str(iotype)); if (bankVcc.find(bank) != bankVcc.end()) { // TODO: strong and weak constraints @@ -603,6 +644,8 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex if (iotype == "LVDS") bankLvds[bank] = true; + if ((dir == "INPUT" || dir == "BIDIR") && is_referenced(ioType_from_str(iotype))) + bankVref[bank] = true; } } @@ -614,17 +657,67 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex std::string type = tile.second; if (type.find("BANKREF") != std::string::npos && type != "BANKREF8") { int bank = std::stoi(type.substr(7)); - if (bankVcc.find(bank) != bankVcc.end()) - cc.tiles[tile.first].add_enum("BANK.VCCIO", iovoltage_to_str(bankVcc[bank])); + if (bankVcc.find(bank) != bankVcc.end()) { + if (bankVcc[bank] == IOVoltage::VCC_1V35) + cc.tiles[tile.first].add_enum("BANK.VCCIO", "1V2"); + else + cc.tiles[tile.first].add_enum("BANK.VCCIO", iovoltage_to_str(bankVcc[bank])); + } if (bankLvds[bank]) { cc.tiles[tile.first].add_enum("BANK.DIFF_REF", "ON"); cc.tiles[tile.first].add_enum("BANK.LVDSO", "ON"); } + if (bankVref[bank]) { + cc.tiles[tile.first].add_enum("BANK.DIFF_REF", "ON"); + cc.tiles[tile.first].add_enum("BANK.VREF", "ON"); + } } } } } + // Create dummy outputs used as Vref input buffer for banks where Vref is used + for (auto bv : bankVref) { + if (!bv.second) + continue; + BelId vrefIO = ctx->getPioByFunctionName(fmt_str("VREF1_" << bv.first)); + if (vrefIO == BelId()) + log_error("unable to find VREF input for bank %d\n", bv.first); + if (!ctx->checkBelAvail(vrefIO)) { + CellInfo *bound = ctx->getBoundBelCell(vrefIO); + if (bound != nullptr) + log_error("VREF pin %s of bank %d is occupied by IO '%s'\n", ctx->getBelPackagePin(vrefIO).c_str(), + bv.first, bound->name.c_str(ctx)); + else + log_error("VREF pin %s of bank %d is unavailable\n", ctx->getBelPackagePin(vrefIO).c_str(), bv.first); + } + log_info("Using pin %s as VREF for bank %d\n", ctx->getBelPackagePin(vrefIO).c_str(), bv.first); + std::string pio_tile = get_pio_tile(ctx, vrefIO); + + std::string iotype; + switch (bankVcc[bv.first]) { + case IOVoltage::VCC_1V2: + iotype = "HSUL12"; + break; + case IOVoltage::VCC_1V35: + iotype = "SSTL18_I"; + break; + case IOVoltage::VCC_1V5: + iotype = "SSTL18_I"; + break; + case IOVoltage::VCC_1V8: + iotype = "SSTL18_I"; + break; + default: + log_error("Referenced inputs are not supported with bank VccIO of %s.\n", + iovoltage_to_str(bankVcc[bv.first]).c_str()); + } + + std::string pio = ctx->locInfo(vrefIO)->bel_data[vrefIO.index].name.get(); + cc.tiles[pio_tile].add_enum(pio + ".BASE_TYPE", "OUTPUT_" + iotype); + cc.tiles[pio_tile].add_enum(pio + ".PULLMODE", "NONE"); + } + // Configure slices for (auto &cell : ctx->cells) { CellInfo *ci = cell.second.get(); @@ -727,9 +820,13 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex // cc.tiles[pic_tile].add_enum(other + ".BASE_TYPE", "_NONE_"); cc.tiles[pio_tile].add_enum(other + ".PULLMODE", "NONE"); cc.tiles[pio_tile].add_enum(pio + ".PULLMODE", "NONE"); + } else if (is_referenced(ioType_from_str(iotype))) { + cc.tiles[pio_tile].add_enum(pio + ".PULLMODE", "NONE"); } if (dir != "INPUT" && - (ci->ports.find(ctx->id("T")) == ci->ports.end() || ci->ports.at(ctx->id("T")).net == nullptr)) { + (ci->ports.find(ctx->id("T")) == ci->ports.end() || ci->ports.at(ctx->id("T")).net == nullptr) && + (ci->ports.find(ctx->id("IOLTO")) == ci->ports.end() || + ci->ports.at(ctx->id("IOLTO")).net == nullptr)) { // Tie tristate low if unconnected for outputs or bidir std::string jpt = fmt_str("X" << bel.location.x << "/Y" << bel.location.y << "/JPADDT" << pio.back()); WireId jpt_wire = ctx->getWireByName(ctx->id(jpt)); @@ -740,11 +837,43 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex std::string cib_wirename = ctx->locInfo(cib_wire)->wire_data[cib_wire.index].name.get(); cc.tiles[cib_tile].add_enum("CIB." + cib_wirename + "MUX", "0"); } - if (dir == "INPUT" && !is_differential(ioType_from_str(iotype))) { + if (dir == "INPUT" && !is_differential(ioType_from_str(iotype)) && + !is_referenced(ioType_from_str(iotype))) { cc.tiles[pio_tile].add_enum(pio + ".HYSTERESIS", "ON"); } - if (ci->attrs.count(ctx->id("SLEWRATE"))) + if (ci->attrs.count(ctx->id("SLEWRATE")) && !is_referenced(ioType_from_str(iotype))) cc.tiles[pio_tile].add_enum(pio + ".SLEWRATE", str_or_default(ci->attrs, ctx->id("SLEWRATE"), "SLOW")); + if (ci->attrs.count(ctx->id("PULLMODE"))) + cc.tiles[pio_tile].add_enum(pio + ".PULLMODE", str_or_default(ci->attrs, ctx->id("PULLMODE"), "NONE")); + if (ci->attrs.count(ctx->id("DIFFRESISTOR"))) + cc.tiles[pio_tile].add_enum(pio + ".DIFFRESISTOR", + str_or_default(ci->attrs, ctx->id("DIFFRESISTOR"), "OFF")); + if (ci->attrs.count(ctx->id("TERMINATION"))) { + auto vccio = get_vccio(ioType_from_str(iotype)); + switch (vccio) { + case IOVoltage::VCC_1V8: + cc.tiles[pio_tile].add_enum(pio + ".TERMINATION_1V8", + str_or_default(ci->attrs, ctx->id("TERMINATION"), "OFF")); + break; + case IOVoltage::VCC_1V5: + cc.tiles[pio_tile].add_enum(pio + ".TERMINATION_1V5", + str_or_default(ci->attrs, ctx->id("TERMINATION"), "OFF")); + break; + case IOVoltage::VCC_1V35: + cc.tiles[pio_tile].add_enum(pio + ".TERMINATION_1V35", + str_or_default(ci->attrs, ctx->id("TERMINATION"), "OFF")); + break; + default: + log_error("TERMINATION is not supported with Vcc = %s (on PIO %s)\n", + iovoltage_to_str(vccio).c_str(), ci->name.c_str(ctx)); + } + } + std::string datamux_oddr = str_or_default(ci->params, ctx->id("DATAMUX_ODDR"), "PADDO"); + if (datamux_oddr != "PADDO") + cc.tiles[pic_tile].add_enum(pio + ".DATAMUX_ODDR", datamux_oddr); + std::string datamux_mddr = str_or_default(ci->params, ctx->id("DATAMUX_MDDR"), "PADDO"); + if (datamux_mddr != "PADDO") + cc.tiles[pic_tile].add_enum(pio + ".DATAMUX_MDDR", datamux_mddr); } else if (ci->type == ctx->id("DCCA")) { // Nothing to do } else if (ci->type == ctx->id("DP16KD")) { @@ -1078,6 +1207,18 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex int_to_bitvector(int_or_default(ci->attrs, ctx->id("MFG_ENABLE_FILTEROPAMP"), 0), 1)); cc.tilegroups.push_back(tg); + } else if (ci->type == id_IOLOGIC || ci->type == id_SIOLOGIC) { + Loc pio_loc = ctx->getBelLocation(ci->bel); + pio_loc.z -= ci->type == id_SIOLOGIC ? 2 : 4; + std::string pic_tile = get_pic_tile(ctx, ctx->getBelByLocation(pio_loc)); + std::string prim = std::string("IOLOGIC") + "ABCD"[pio_loc.z]; + for (auto ¶m : ci->params) { + if (param.first == ctx->id("DELAY.DEL_VALUE")) + cc.tiles[pic_tile].add_word(prim + "." + param.first.str(ctx), + int_to_bitvector(std::stoi(param.second), 7)); + else + cc.tiles[pic_tile].add_enum(prim + "." + param.first.str(ctx), param.second); + } } else if (ci->type == id_DCUA) { TileGroup tg; tg.tiles = get_dcu_tiles(ctx, ci->bel); @@ -1100,6 +1241,85 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex std::string tname = ctx->getTileByTypeAndLocation(loc.y + 1, loc.x, "BMID_0H"); cc.tiles[tname].add_enum("PCSCLKDIV" + std::to_string(loc.z), str_or_default(ci->params, ctx->id("GSR"), "ENABLED")); + } else if (ci->type == id_DTR) { + cc.tiles[ctx->getTileByType("DTR")].add_enum("DTR.MODE", "DTR"); + } else if (ci->type == id_OSCG) { + int div = int_or_default(ci->params, ctx->id("DIV"), 128); + if (div == 128) + div = 127; + cc.tiles[ctx->getTileByType("EFB0_PICB0")].add_enum("OSC.DIV", std::to_string(div)); + cc.tiles[ctx->getTileByType("EFB1_PICB1")].add_enum("OSC.DIV", std::to_string(div)); + cc.tiles[ctx->getTileByType("EFB1_PICB1")].add_enum("OSC.MODE", "OSCG"); + cc.tiles[ctx->getTileByType("EFB1_PICB1")].add_enum("CCLK.MODE", "_NONE_"); + } else if (ci->type == id_USRMCLK) { + cc.tiles[ctx->getTileByType("EFB3_PICB1")].add_enum("CCLK.MODE", "USRMCLK"); + } else if (ci->type == id_GSR) { + cc.tiles[ctx->getTileByType("EFB0_PICB0")].add_enum( + "GSR.GSRMODE", str_or_default(ci->params, ctx->id("MODE"), "ACTIVE_HIGH")); + cc.tiles[ctx->getTileByType("VIQ_BUF")].add_enum("GSR.SYNCMODE", + str_or_default(ci->params, ctx->id("SYNCMODE"), "ASYNC")); + } else if (ci->type == id_JTAGG) { + cc.tiles[ctx->getTileByType("EFB0_PICB0")].add_enum("JTAG.ER1", + str_or_default(ci->params, ctx->id("ER1"), "ENABLED")); + cc.tiles[ctx->getTileByType("EFB0_PICB0")].add_enum("JTAG.ER2", + str_or_default(ci->params, ctx->id("ER2"), "ENABLED")); + } else if (ci->type == id_CLKDIVF) { + Loc loc = ctx->getBelLocation(ci->bel); + bool r = loc.x > 5; + std::string clkdiv = std::string("CLKDIV_") + (r ? "R" : "L") + std::to_string(loc.z); + std::string tile = ctx->getTileByType(std::string("ECLK_") + (r ? "R" : "L")); + cc.tiles[tile].add_enum(clkdiv + ".DIV", str_or_default(ci->params, ctx->id("DIV"), "2.0")); + cc.tiles[tile].add_enum(clkdiv + ".GSR", str_or_default(ci->params, ctx->id("GSR"), "DISABLED")); + } else if (ci->type == id_TRELLIS_ECLKBUF) { + } else if (ci->type == id_DQSBUFM) { + Loc loc = ctx->getBelLocation(ci->bel); + bool l = loc.x < 10; + std::string pic = l ? "PICL" : "PICR"; + TileGroup tg; + tg.tiles.push_back(ctx->getTileByTypeAndLocation(loc.y - 2, loc.x, pic + "1_DQS0")); + tg.tiles.push_back(ctx->getTileByTypeAndLocation(loc.y - 1, loc.x, pic + "2_DQS1")); + tg.tiles.push_back(ctx->getTileByTypeAndLocation(loc.y, loc.x, pic + "0_DQS2")); + tg.tiles.push_back(ctx->getTileByTypeAndLocation(loc.y + 1, loc.x, pic + "1_DQS3")); + tg.config.add_enum("DQS.MODE", "DQSBUFM"); + tg.config.add_enum("DQS.DQS_LI_DEL_ADJ", str_or_default(ci->params, ctx->id("DQS_LI_DEL_ADJ"), "PLUS")); + tg.config.add_enum("DQS.DQS_LO_DEL_ADJ", str_or_default(ci->params, ctx->id("DQS_LO_DEL_ADJ"), "PLUS")); + int li_del_value = int_or_default(ci->params, ctx->id("DQS_LI_DEL_VAL"), 0); + if (str_or_default(ci->params, ctx->id("DQS_LI_DEL_ADJ"), "PLUS") == "MINUS") + li_del_value = (256 - li_del_value) & 0xFF; + int lo_del_value = int_or_default(ci->params, ctx->id("DQS_LO_DEL_VAL"), 0); + if (str_or_default(ci->params, ctx->id("DQS_LO_DEL_ADJ"), "PLUS") == "MINUS") + lo_del_value = (256 - lo_del_value) & 0xFF; + tg.config.add_word("DQS.DQS_LI_DEL_VAL", int_to_bitvector(li_del_value, 8)); + tg.config.add_word("DQS.DQS_LO_DEL_VAL", int_to_bitvector(lo_del_value, 8)); + tg.config.add_enum("DQS.WRLOADN_USED", get_net_or_empty(ci, id_WRLOADN) != nullptr ? "YES" : "NO"); + tg.config.add_enum("DQS.RDLOADN_USED", get_net_or_empty(ci, id_RDLOADN) != nullptr ? "YES" : "NO"); + tg.config.add_enum("DQS.PAUSE_USED", get_net_or_empty(ci, id_PAUSE) != nullptr ? "YES" : "NO"); + tg.config.add_enum("DQS.READ_USED", + (get_net_or_empty(ci, id_READ0) != nullptr || get_net_or_empty(ci, id_READ1) != nullptr) + ? "YES" + : "NO"); + tg.config.add_enum("DQS.DDRDEL", get_net_or_empty(ci, id_DDRDEL) != nullptr ? "DDRDEL" : "0"); + tg.config.add_enum("DQS.GSR", str_or_default(ci->params, ctx->id("GSR"), "DISABLED")); + cc.tilegroups.push_back(tg); + } else if (ci->type == id_ECLKSYNCB) { + Loc loc = ctx->getBelLocation(ci->bel); + bool r = loc.x > 5; + std::string eclksync = ctx->locInfo(bel)->bel_data[bel.index].name.get(); + std::string tile = ctx->getTileByType(std::string("ECLK_") + (r ? "R" : "L")); + if (get_net_or_empty(ci, id_STOP) != nullptr) + cc.tiles[tile].add_enum(eclksync + ".MODE", "ECLKSYNCB"); + } else if (ci->type == id_DDRDLL) { + Loc loc = ctx->getBelLocation(ci->bel); + bool u = loc.y<15, r = loc.x> 15; + std::string tiletype = fmt_str("DDRDLL_" << (u ? 'U' : 'L') << (r ? 'R' : 'L')); + if (ctx->args.type == ArchArgs::LFE5U_25F || ctx->args.type == ArchArgs::LFE5UM_25F || + ctx->args.type == ArchArgs::LFE5UM5G_25F) + tiletype += "A"; + std::string tile = ctx->getTileByType(tiletype); + cc.tiles[tile].add_enum("DDRDLL.MODE", "DDRDLLA"); + cc.tiles[tile].add_enum("DDRDLL.GSR", str_or_default(ci->params, ctx->id("GSR"), "DISABLED")); + cc.tiles[tile].add_enum("DDRDLL.FORCE_MAX_DELAY", + str_or_default(ci->params, ctx->id("FORCE_MAX_DELAY"), "NO")); } else { NPNR_ASSERT_FALSE("unsupported cell type"); } |