aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5/bitstream.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ecp5/bitstream.cc')
-rw-r--r--ecp5/bitstream.cc137
1 files changed, 119 insertions, 18 deletions
diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc
index 1c150ae2..961a3956 100644
--- a/ecp5/bitstream.cc
+++ b/ecp5/bitstream.cc
@@ -24,7 +24,7 @@
#include <queue>
#include <regex>
#include <streambuf>
-
+#include <boost/algorithm/string/predicate.hpp>
#include "config.h"
#include "pio.h"
#include "log.h"
@@ -379,12 +379,23 @@ std::vector<std::string> get_dsp_tiles(Context *ctx, BelId bel)
return tiles;
}
+// Get the list of tiles corresponding to a DCU
+std::vector<std::string> get_dcu_tiles(Context *ctx, BelId bel)
+{
+ std::vector<std::string> tiles;
+ Loc loc = ctx->getBelLocation(bel);
+ for (int i = 0; i < 9; i++)
+ tiles.push_back(ctx->getTileByTypeAndLocation(loc.y, loc.x + i, "DCU" + std::to_string(i)));
+ return tiles;
+}
+
// Get the list of tiles corresponding to a PLL
std::vector<std::string> get_pll_tiles(Context *ctx, BelId bel)
{
std::string name = ctx->locInfo(bel)->bel_data[bel.index].name.get();
std::vector<std::string> tiles;
Loc loc = ctx->getBelLocation(bel);
+ static const std::set<std::string> pll1_lr = {"PLL1_LR", "BANKREF4"};
if (name == "EHXPLL_UL") {
tiles.push_back(ctx->getTileByTypeAndLocation(loc.y, loc.x - 1, "PLL0_UL"));
@@ -394,7 +405,7 @@ std::vector<std::string> get_pll_tiles(Context *ctx, BelId bel)
tiles.push_back(ctx->getTileByTypeAndLocation(loc.y + 1, loc.x + 1, "BANKREF8"));
} else if (name == "EHXPLL_LR") {
tiles.push_back(ctx->getTileByTypeAndLocation(loc.y + 1, loc.x, "PLL0_LR"));
- tiles.push_back(ctx->getTileByTypeAndLocation(loc.y + 1, loc.x - 1, "PLL1_LR"));
+ tiles.push_back(ctx->getTileByTypeAndLocation(loc.y + 1, loc.x - 1, pll1_lr));
} else if (name == "EHXPLL_UR") {
tiles.push_back(ctx->getTileByTypeAndLocation(loc.y, loc.x - 1, "PLL0_UR"));
tiles.push_back(ctx->getTileByTypeAndLocation(loc.y + 1, loc.x - 1, "PLL1_UR"));
@@ -407,26 +418,23 @@ std::vector<std::string> get_pll_tiles(Context *ctx, BelId bel)
void fix_tile_names(Context *ctx, ChipConfig &cc)
{
// Remove the V prefix/suffix on certain tiles if device is a SERDES variant
- if (ctx->args.type == ArchArgs::LFE5UM_25F || ctx->args.type == ArchArgs::LFE5UM_45F ||
- ctx->args.type == ArchArgs::LFE5UM_85F || ctx->args.type == ArchArgs::LFE5UM5G_25F ||
- ctx->args.type == ArchArgs::LFE5UM5G_45F || ctx->args.type == ArchArgs::LFE5UM5G_85F) {
+ if (ctx->args.type == ArchArgs::LFE5U_25F || ctx->args.type == ArchArgs::LFE5U_45F ||
+ ctx->args.type == ArchArgs::LFE5U_85F) {
std::map<std::string, std::string> tiletype_xform;
for (const auto &tile : cc.tiles) {
std::string newname = tile.first;
- auto vcib = tile.first.find("VCIB");
- if (vcib != std::string::npos) {
- // Remove the V
- newname.erase(vcib, 1);
+ auto cibdcu = tile.first.find("CIB_DCU");
+ if (cibdcu != std::string::npos) {
+ // Add the V
+ if (newname.at(cibdcu - 1) != 'V')
+ newname.insert(cibdcu, 1, 'V');
+ tiletype_xform[tile.first] = newname;
+ } else if (boost::ends_with(tile.first, "BMID_0H")) {
+ newname.back() = 'V';
+ tiletype_xform[tile.first] = newname;
+ } else if (boost::ends_with(tile.first, "BMID_2")) {
+ newname.push_back('V');
tiletype_xform[tile.first] = newname;
- } else if (tile.first.back() == 'V') {
- // BMID_0V or BMID_2V
- if (tile.first.at(tile.first.size() - 2) == '0') {
- newname.at(tile.first.size() - 1) = 'H';
- tiletype_xform[tile.first] = newname;
- } else if (tile.first.at(tile.first.size() - 2) == '2') {
- newname.pop_back();
- tiletype_xform[tile.first] = newname;
- }
}
}
// Apply the name changes
@@ -455,6 +463,20 @@ void tieoff_dsp_ports(Context *ctx, ChipConfig &cc, CellInfo *ci)
}
}
+void tieoff_dcu_ports(Context *ctx, ChipConfig &cc, CellInfo *ci)
+{
+ for (auto port : ci->ports) {
+ if (port.second.net == nullptr && port.second.type == PORT_IN) {
+ if (port.first.str(ctx).find("CLK") != std::string::npos ||
+ port.first.str(ctx).find("HDIN") != std::string::npos ||
+ port.first.str(ctx).find("HDOUT") != std::string::npos)
+ continue;
+ bool value = bool_or_default(ci->params, ctx->id(port.first.str(ctx) + "MUX"), false);
+ tie_cib_signal(ctx, cc, ctx->getBelPinWire(ci->bel, port.first), value);
+ }
+ }
+}
+
static void set_pip(Context *ctx, ChipConfig &cc, PipId pip)
{
std::string tile = ctx->getPipTilename(pip);
@@ -463,6 +485,46 @@ static void set_pip(Context *ctx, ChipConfig &cc, PipId pip)
cc.tiles[tile].add_arc(sink, source);
}
+static std::vector<bool> parse_config_str(std::string str, int length)
+{
+ // For DCU config which might be bin, hex or dec using prefices accordingly
+ std::string base = str.substr(0, 2);
+ std::vector<bool> word;
+ word.resize(length, false);
+ if (base == "0b") {
+ for (int i = 0; i < int(str.length()) - 2; i++) {
+ char c = str.at((str.size() - 1) - i);
+ NPNR_ASSERT(c == '0' || c == '1');
+ word.at(i) = (c == '1');
+ }
+ } else if (base == "0x") {
+ for (int i = 0; i < int(str.length()) - 2; i++) {
+ char c = str.at((str.size() - i) - 1);
+ int nibble = chtohex(c);
+ word.at(i * 4) = nibble & 0x1;
+ if (i * 4 + 1 < length)
+ word.at(i * 4 + 1) = nibble & 0x2;
+ if (i * 4 + 2 < length)
+ word.at(i * 4 + 2) = nibble & 0x4;
+ if (i * 4 + 3 < length)
+ word.at(i * 4 + 3) = nibble & 0x8;
+ }
+ } else if (base == "0d") {
+ NPNR_ASSERT(length < 64);
+ unsigned long long value = std::stoull(str.substr(2));
+ for (int i = 0; i < length; i++)
+ if (value & (1 << i))
+ word.at(i) = true;
+ } else {
+ NPNR_ASSERT(length < 64);
+ unsigned long long value = std::stoull(str);
+ for (int i = 0; i < length; i++)
+ if (value & (1 << i))
+ word.at(i) = true;
+ }
+ return word;
+}
+
void write_bitstream(Context *ctx, std::string base_config_file, std::string text_config_file)
{
ChipConfig cc;
@@ -480,6 +542,23 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
// TODO: .bit metadata
}
+ // Clear out DCU tieoffs in base config if DCU used
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
+ if (ci->type == id_DCUA) {
+ Loc loc = ctx->getBelLocation(ci->bel);
+ for (int i = 0; i < 12; i++) {
+ auto tiles = ctx->getTilesAtLocation(loc.y - 1, loc.x + i);
+ for (const auto &tile : tiles) {
+ auto cc_tile = cc.tiles.find(tile.first);
+ if (cc_tile != cc.tiles.end()) {
+ cc_tile->second.cenums.clear();
+ cc_tile->second.cunknowns.clear();
+ }
+ }
+ }
+ }
+ }
// Add all set, configurable pips to the config
for (auto pip : ctx->getPips()) {
if (ctx->getBoundPipNet(pip) != nullptr) {
@@ -999,6 +1078,28 @@ 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_DCUA) {
+ TileGroup tg;
+ tg.tiles = get_dcu_tiles(ctx, ci->bel);
+ tg.config.add_enum("DCU.MODE", "DCUA");
+#include "dcu_bitstream.h"
+ cc.tilegroups.push_back(tg);
+ tieoff_dcu_ports(ctx, cc, ci);
+ } else if (ci->type == id_EXTREFB) {
+ TileGroup tg;
+ tg.tiles = get_dcu_tiles(ctx, ci->bel);
+ tg.config.add_word("EXTREF.REFCK_DCBIAS_EN",
+ parse_config_str(str_or_default(ci->params, ctx->id("REFCK_DCBIAS_EN"), "0"), 1));
+ tg.config.add_word("EXTREF.REFCK_RTERM",
+ parse_config_str(str_or_default(ci->params, ctx->id("REFCK_RTERM"), "0"), 1));
+ tg.config.add_word("EXTREF.REFCK_PWDNB",
+ parse_config_str(str_or_default(ci->params, ctx->id("REFCK_PWDNB"), "0"), 1));
+ cc.tilegroups.push_back(tg);
+ } else if (ci->type == id_PCSCLKDIV) {
+ Loc loc = ctx->getBelLocation(ci->bel);
+ 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 {
NPNR_ASSERT_FALSE("unsupported cell type");
}