aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Shah <davey1576@gmail.com>2018-11-16 09:58:34 +0000
committerGitHub <noreply@github.com>2018-11-16 09:58:34 +0000
commitfe4f98f26fb295b3b8d09c3303f1172c91698407 (patch)
tree706e1b76f81861b7cb7917b404b29b8d805ddfb5
parent9472b6d78f68544d430feeae6d75dbd2dc43019d (diff)
parentf07bd98d59765f2c565815d1a6483db04c57a9d1 (diff)
downloadnextpnr-fe4f98f26fb295b3b8d09c3303f1172c91698407.tar.gz
nextpnr-fe4f98f26fb295b3b8d09c3303f1172c91698407.tar.bz2
nextpnr-fe4f98f26fb295b3b8d09c3303f1172c91698407.zip
Merge pull request #118 from daveshah1/dcu
Adding ECP5 DCU support
-rw-r--r--ecp5/arch.cc27
-rw-r--r--ecp5/arch_place.cc2
-rw-r--r--ecp5/archdefs.h15
-rw-r--r--ecp5/bitstream.cc134
-rw-r--r--ecp5/constids.inc307
-rw-r--r--ecp5/dcu_bitstream.h254
-rw-r--r--ecp5/globals.cc54
-rw-r--r--ecp5/pack.cc170
-rwxr-xr-xecp5/trellis_import.py11
9 files changed, 935 insertions, 39 deletions
diff --git a/ecp5/arch.cc b/ecp5/arch.cc
index fe6a9545..afea8d4a 100644
--- a/ecp5/arch.cc
+++ b/ecp5/arch.cc
@@ -651,6 +651,16 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in
return TMG_IGNORE; // FIXME
} else if (cell->type == id_EHXPLLL) {
return TMG_IGNORE;
+ } else if (cell->type == id_DCUA || cell->type == id_EXTREFB || cell->type == id_PCSCLKDIV) {
+ if (port == id_CH0_FF_TXI_CLK || port == id_CH0_FF_RXI_CLK || port == id_CH1_FF_TXI_CLK ||
+ port == id_CH1_FF_RXI_CLK)
+ return TMG_CLOCK_INPUT;
+ std::string prefix = port.str(this).substr(0, 9);
+ if (prefix == "CH0_FF_TX" || prefix == "CH0_FF_RX" || prefix == "CH1_FF_TX" || prefix == "CH1_FF_RX") {
+ clockInfoCount = 1;
+ return (cell->ports.at(port).type == PORT_OUT) ? TMG_REGISTER_OUTPUT : TMG_REGISTER_INPUT;
+ }
+ return TMG_IGNORE;
} else {
NPNR_ASSERT_FALSE_STR("no timing data for cell type '" + cell->type.str(this) + "'");
}
@@ -706,6 +716,23 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
info.setup.delay = 100;
info.hold.delay = 0;
}
+ } else if (cell->type == id_DCUA) {
+ std::string prefix = port.str(this).substr(0, 9);
+ info.edge = RISING_EDGE;
+ if (prefix == "CH0_FF_TX")
+ info.clock_port = id_CH0_FF_TXI_CLK;
+ else if (prefix == "CH0_FF_RX")
+ info.clock_port = id_CH0_FF_RXI_CLK;
+ else if (prefix == "CH1_FF_TX")
+ info.clock_port = id_CH1_FF_TXI_CLK;
+ else if (prefix == "CH1_FF_RX")
+ info.clock_port = id_CH1_FF_RXI_CLK;
+ if (cell->ports.at(port).type == PORT_OUT) {
+ info.clockToQ.delay = 660;
+ } else {
+ info.setup.delay = 1000;
+ info.hold.delay = 0;
+ }
}
return info;
}
diff --git a/ecp5/arch_place.cc b/ecp5/arch_place.cc
index 6fcd8bde..41f87cb8 100644
--- a/ecp5/arch_place.cc
+++ b/ecp5/arch_place.cc
@@ -101,6 +101,8 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
bel_cells.push_back(cell);
return slicesCompatible(bel_cells);
+ } else if (cell->type == id_DCUA || cell->type == id_EXTREFB || cell->type == id_PCSCLKDIV) {
+ return args.type != ArchArgs::LFE5U_25F && args.type != ArchArgs::LFE5U_45F && args.type != ArchArgs::LFE5U_85F;
} else {
// other checks
return true;
diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h
index 01cbad46..b2c23134 100644
--- a/ecp5/archdefs.h
+++ b/ecp5/archdefs.h
@@ -87,7 +87,10 @@ struct BelId
bool operator==(const BelId &other) const { return index == other.index && location == other.location; }
bool operator!=(const BelId &other) const { return index != other.index || location != other.location; }
- bool operator<(const BelId &other) const { return location == other.location ? index < other.index : location < other.location; }
+ bool operator<(const BelId &other) const
+ {
+ return location == other.location ? index < other.index : location < other.location;
+ }
};
struct WireId
@@ -97,7 +100,10 @@ struct WireId
bool operator==(const WireId &other) const { return index == other.index && location == other.location; }
bool operator!=(const WireId &other) const { return index != other.index || location != other.location; }
- bool operator<(const WireId &other) const { return location == other.location ? index < other.index : location < other.location; }
+ bool operator<(const WireId &other) const
+ {
+ return location == other.location ? index < other.index : location < other.location;
+ }
};
struct PipId
@@ -107,7 +113,10 @@ struct PipId
bool operator==(const PipId &other) const { return index == other.index && location == other.location; }
bool operator!=(const PipId &other) const { return index != other.index || location != other.location; }
- bool operator<(const PipId &other) const { return location == other.location ? index < other.index : location < other.location; }
+ bool operator<(const PipId &other) const
+ {
+ return location == other.location ? index < other.index : location < other.location;
+ }
};
struct GroupId
diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc
index 6d43b369..5e3ff694 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 "io.h"
#include "log.h"
@@ -379,6 +379,16 @@ 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)
{
@@ -408,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
@@ -456,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);
@@ -464,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;
@@ -481,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) {
@@ -1000,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");
}
diff --git a/ecp5/constids.inc b/ecp5/constids.inc
index bdcbc1ea..11ecc240 100644
--- a/ecp5/constids.inc
+++ b/ecp5/constids.inc
@@ -810,3 +810,310 @@ X(LOCK)
X(INTLOCK)
X(REFCLK)
X(CLKINTFB)
+
+
+X(EXTREFB)
+X(REFCLKP)
+X(REFCLKN)
+X(REFCLKO)
+
+X(DCUA)
+X(CH0_HDINP)
+X(CH1_HDINP)
+X(CH0_HDINN)
+X(CH1_HDINN)
+X(D_TXBIT_CLKP_FROM_ND)
+X(D_TXBIT_CLKN_FROM_ND)
+X(D_SYNC_ND)
+X(D_TXPLL_LOL_FROM_ND)
+X(CH0_RX_REFCLK)
+X(CH1_RX_REFCLK)
+X(CH0_FF_RXI_CLK)
+X(CH1_FF_RXI_CLK)
+X(CH0_FF_TXI_CLK)
+X(CH1_FF_TXI_CLK)
+X(CH0_FF_EBRD_CLK)
+X(CH1_FF_EBRD_CLK)
+X(CH0_FF_TX_D_0)
+X(CH1_FF_TX_D_0)
+X(CH0_FF_TX_D_1)
+X(CH1_FF_TX_D_1)
+X(CH0_FF_TX_D_2)
+X(CH1_FF_TX_D_2)
+X(CH0_FF_TX_D_3)
+X(CH1_FF_TX_D_3)
+X(CH0_FF_TX_D_4)
+X(CH1_FF_TX_D_4)
+X(CH0_FF_TX_D_5)
+X(CH1_FF_TX_D_5)
+X(CH0_FF_TX_D_6)
+X(CH1_FF_TX_D_6)
+X(CH0_FF_TX_D_7)
+X(CH1_FF_TX_D_7)
+X(CH0_FF_TX_D_8)
+X(CH1_FF_TX_D_8)
+X(CH0_FF_TX_D_9)
+X(CH1_FF_TX_D_9)
+X(CH0_FF_TX_D_10)
+X(CH1_FF_TX_D_10)
+X(CH0_FF_TX_D_11)
+X(CH1_FF_TX_D_11)
+X(CH0_FF_TX_D_12)
+X(CH1_FF_TX_D_12)
+X(CH0_FF_TX_D_13)
+X(CH1_FF_TX_D_13)
+X(CH0_FF_TX_D_14)
+X(CH1_FF_TX_D_14)
+X(CH0_FF_TX_D_15)
+X(CH1_FF_TX_D_15)
+X(CH0_FF_TX_D_16)
+X(CH1_FF_TX_D_16)
+X(CH0_FF_TX_D_17)
+X(CH1_FF_TX_D_17)
+X(CH0_FF_TX_D_18)
+X(CH1_FF_TX_D_18)
+X(CH0_FF_TX_D_19)
+X(CH1_FF_TX_D_19)
+X(CH0_FF_TX_D_20)
+X(CH1_FF_TX_D_20)
+X(CH0_FF_TX_D_21)
+X(CH1_FF_TX_D_21)
+X(CH0_FF_TX_D_22)
+X(CH1_FF_TX_D_22)
+X(CH0_FF_TX_D_23)
+X(CH1_FF_TX_D_23)
+X(CH0_FFC_EI_EN)
+X(CH1_FFC_EI_EN)
+X(CH0_FFC_PCIE_DET_EN)
+X(CH1_FFC_PCIE_DET_EN)
+X(CH0_FFC_PCIE_CT)
+X(CH1_FFC_PCIE_CT)
+X(CH0_FFC_SB_INV_RX)
+X(CH1_FFC_SB_INV_RX)
+X(CH0_FFC_ENABLE_CGALIGN)
+X(CH1_FFC_ENABLE_CGALIGN)
+X(CH0_FFC_SIGNAL_DETECT)
+X(CH1_FFC_SIGNAL_DETECT)
+X(CH0_FFC_FB_LOOPBACK)
+X(CH1_FFC_FB_LOOPBACK)
+X(CH0_FFC_SB_PFIFO_LP)
+X(CH1_FFC_SB_PFIFO_LP)
+X(CH0_FFC_PFIFO_CLR)
+X(CH1_FFC_PFIFO_CLR)
+X(CH0_FFC_RATE_MODE_RX)
+X(CH1_FFC_RATE_MODE_RX)
+X(CH0_FFC_RATE_MODE_TX)
+X(CH1_FFC_RATE_MODE_TX)
+X(CH0_FFC_DIV11_MODE_RX)
+X(CH1_FFC_DIV11_MODE_RX)
+X(CH0_FFC_RX_GEAR_MODE)
+X(CH1_FFC_RX_GEAR_MODE)
+X(CH0_FFC_TX_GEAR_MODE)
+X(CH1_FFC_TX_GEAR_MODE)
+X(CH0_FFC_DIV11_MODE_TX)
+X(CH1_FFC_DIV11_MODE_TX)
+X(CH0_FFC_LDR_CORE2TX_EN)
+X(CH1_FFC_LDR_CORE2TX_EN)
+X(CH0_FFC_LANE_TX_RST)
+X(CH1_FFC_LANE_TX_RST)
+X(CH0_FFC_LANE_RX_RST)
+X(CH1_FFC_LANE_RX_RST)
+X(CH0_FFC_RRST)
+X(CH1_FFC_RRST)
+X(CH0_FFC_TXPWDNB)
+X(CH1_FFC_TXPWDNB)
+X(CH0_FFC_RXPWDNB)
+X(CH1_FFC_RXPWDNB)
+X(CH0_LDR_CORE2TX)
+X(CH1_LDR_CORE2TX)
+X(D_SCIWDATA0)
+X(D_SCIWDATA1)
+X(D_SCIWDATA2)
+X(D_SCIWDATA3)
+X(D_SCIWDATA4)
+X(D_SCIWDATA5)
+X(D_SCIWDATA6)
+X(D_SCIWDATA7)
+X(D_SCIADDR0)
+X(D_SCIADDR1)
+X(D_SCIADDR2)
+X(D_SCIADDR3)
+X(D_SCIADDR4)
+X(D_SCIADDR5)
+X(D_SCIENAUX)
+X(D_SCISELAUX)
+X(CH0_SCIEN)
+X(CH1_SCIEN)
+X(CH0_SCISEL)
+X(CH1_SCISEL)
+X(D_SCIRD)
+X(D_SCIWSTN)
+X(D_CYAWSTN)
+X(D_FFC_SYNC_TOGGLE)
+X(D_FFC_DUAL_RST)
+X(D_FFC_MACRO_RST)
+X(D_FFC_MACROPDB)
+X(D_FFC_TRST)
+X(CH0_FFC_CDR_EN_BITSLIP)
+X(CH1_FFC_CDR_EN_BITSLIP)
+X(D_SCAN_ENABLE)
+X(D_SCAN_IN_0)
+X(D_SCAN_IN_1)
+X(D_SCAN_IN_2)
+X(D_SCAN_IN_3)
+X(D_SCAN_IN_4)
+X(D_SCAN_IN_5)
+X(D_SCAN_IN_6)
+X(D_SCAN_IN_7)
+X(D_SCAN_MODE)
+X(D_SCAN_RESET)
+X(D_CIN0)
+X(D_CIN1)
+X(D_CIN2)
+X(D_CIN3)
+X(D_CIN4)
+X(D_CIN5)
+X(D_CIN6)
+X(D_CIN7)
+X(D_CIN8)
+X(D_CIN9)
+X(D_CIN10)
+X(D_CIN11)
+X(CH0_HDOUTP)
+X(CH1_HDOUTP)
+X(CH0_HDOUTN)
+X(CH1_HDOUTN)
+X(D_TXBIT_CLKP_TO_ND)
+X(D_TXBIT_CLKN_TO_ND)
+X(D_SYNC_PULSE2ND)
+X(D_TXPLL_LOL_TO_ND)
+X(CH0_FF_RX_F_CLK)
+X(CH1_FF_RX_F_CLK)
+X(CH0_FF_RX_H_CLK)
+X(CH1_FF_RX_H_CLK)
+X(CH0_FF_TX_F_CLK)
+X(CH1_FF_TX_F_CLK)
+X(CH0_FF_TX_H_CLK)
+X(CH1_FF_TX_H_CLK)
+X(CH0_FF_RX_PCLK)
+X(CH1_FF_RX_PCLK)
+X(CH0_FF_TX_PCLK)
+X(CH1_FF_TX_PCLK)
+X(CH0_FF_RX_D_0)
+X(CH1_FF_RX_D_0)
+X(CH0_FF_RX_D_1)
+X(CH1_FF_RX_D_1)
+X(CH0_FF_RX_D_2)
+X(CH1_FF_RX_D_2)
+X(CH0_FF_RX_D_3)
+X(CH1_FF_RX_D_3)
+X(CH0_FF_RX_D_4)
+X(CH1_FF_RX_D_4)
+X(CH0_FF_RX_D_5)
+X(CH1_FF_RX_D_5)
+X(CH0_FF_RX_D_6)
+X(CH1_FF_RX_D_6)
+X(CH0_FF_RX_D_7)
+X(CH1_FF_RX_D_7)
+X(CH0_FF_RX_D_8)
+X(CH1_FF_RX_D_8)
+X(CH0_FF_RX_D_9)
+X(CH1_FF_RX_D_9)
+X(CH0_FF_RX_D_10)
+X(CH1_FF_RX_D_10)
+X(CH0_FF_RX_D_11)
+X(CH1_FF_RX_D_11)
+X(CH0_FF_RX_D_12)
+X(CH1_FF_RX_D_12)
+X(CH0_FF_RX_D_13)
+X(CH1_FF_RX_D_13)
+X(CH0_FF_RX_D_14)
+X(CH1_FF_RX_D_14)
+X(CH0_FF_RX_D_15)
+X(CH1_FF_RX_D_15)
+X(CH0_FF_RX_D_16)
+X(CH1_FF_RX_D_16)
+X(CH0_FF_RX_D_17)
+X(CH1_FF_RX_D_17)
+X(CH0_FF_RX_D_18)
+X(CH1_FF_RX_D_18)
+X(CH0_FF_RX_D_19)
+X(CH1_FF_RX_D_19)
+X(CH0_FF_RX_D_20)
+X(CH1_FF_RX_D_20)
+X(CH0_FF_RX_D_21)
+X(CH1_FF_RX_D_21)
+X(CH0_FF_RX_D_22)
+X(CH1_FF_RX_D_22)
+X(CH0_FF_RX_D_23)
+X(CH1_FF_RX_D_23)
+X(CH0_FFS_PCIE_DONE)
+X(CH1_FFS_PCIE_DONE)
+X(CH0_FFS_PCIE_CON)
+X(CH1_FFS_PCIE_CON)
+X(CH0_FFS_RLOS)
+X(CH1_FFS_RLOS)
+X(CH0_FFS_LS_SYNC_STATUS)
+X(CH1_FFS_LS_SYNC_STATUS)
+X(CH0_FFS_CC_UNDERRUN)
+X(CH1_FFS_CC_UNDERRUN)
+X(CH0_FFS_CC_OVERRUN)
+X(CH1_FFS_CC_OVERRUN)
+X(CH0_FFS_RXFBFIFO_ERROR)
+X(CH1_FFS_RXFBFIFO_ERROR)
+X(CH0_FFS_TXFBFIFO_ERROR)
+X(CH1_FFS_TXFBFIFO_ERROR)
+X(CH0_FFS_RLOL)
+X(CH1_FFS_RLOL)
+X(CH0_FFS_SKP_ADDED)
+X(CH1_FFS_SKP_ADDED)
+X(CH0_FFS_SKP_DELETED)
+X(CH1_FFS_SKP_DELETED)
+X(CH0_LDR_RX2CORE)
+X(CH1_LDR_RX2CORE)
+X(D_SCIRDATA0)
+X(D_SCIRDATA1)
+X(D_SCIRDATA2)
+X(D_SCIRDATA3)
+X(D_SCIRDATA4)
+X(D_SCIRDATA5)
+X(D_SCIRDATA6)
+X(D_SCIRDATA7)
+X(D_SCIINT)
+X(D_SCAN_OUT_0)
+X(D_SCAN_OUT_1)
+X(D_SCAN_OUT_2)
+X(D_SCAN_OUT_3)
+X(D_SCAN_OUT_4)
+X(D_SCAN_OUT_5)
+X(D_SCAN_OUT_6)
+X(D_SCAN_OUT_7)
+X(D_COUT0)
+X(D_COUT1)
+X(D_COUT2)
+X(D_COUT3)
+X(D_COUT4)
+X(D_COUT5)
+X(D_COUT6)
+X(D_COUT7)
+X(D_COUT8)
+X(D_COUT9)
+X(D_COUT10)
+X(D_COUT11)
+X(D_COUT12)
+X(D_COUT13)
+X(D_COUT14)
+X(D_COUT15)
+X(D_COUT16)
+X(D_COUT17)
+X(D_COUT18)
+X(D_COUT19)
+X(D_REFCLKI)
+X(D_FFS_PLOL)
+
+X(PCSCLKDIV)
+X(SEL2)
+X(SEL1)
+X(SEL0)
+X(CDIV1)
+X(CDIVX) \ No newline at end of file
diff --git a/ecp5/dcu_bitstream.h b/ecp5/dcu_bitstream.h
new file mode 100644
index 00000000..0a5028d2
--- /dev/null
+++ b/ecp5/dcu_bitstream.h
@@ -0,0 +1,254 @@
+tg.config.add_word("DCU.CH0_AUTO_CALIB_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH0_AUTO_CALIB_EN"), "0"), 1));
+tg.config.add_word("DCU.CH0_AUTO_FACQ_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH0_AUTO_FACQ_EN"), "0"), 1));
+tg.config.add_word("DCU.CH0_BAND_THRESHOLD", parse_config_str(str_or_default(ci->params, ctx->id("CH0_BAND_THRESHOLD"), "0"), 6));
+tg.config.add_word("DCU.CH0_CALIB_CK_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_CALIB_CK_MODE"), "0"), 1));
+tg.config.add_word("DCU.CH0_CC_MATCH_1", parse_config_str(str_or_default(ci->params, ctx->id("CH0_CC_MATCH_1"), "0"), 10));
+tg.config.add_word("DCU.CH0_CC_MATCH_2", parse_config_str(str_or_default(ci->params, ctx->id("CH0_CC_MATCH_2"), "0"), 10));
+tg.config.add_word("DCU.CH0_CC_MATCH_3", parse_config_str(str_or_default(ci->params, ctx->id("CH0_CC_MATCH_3"), "0"), 10));
+tg.config.add_word("DCU.CH0_CC_MATCH_4", parse_config_str(str_or_default(ci->params, ctx->id("CH0_CC_MATCH_4"), "0"), 10));
+tg.config.add_word("DCU.CH0_CDR_CNT4SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_CDR_CNT4SEL"), "0"), 2));
+tg.config.add_word("DCU.CH0_CDR_CNT8SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_CDR_CNT8SEL"), "0"), 2));
+tg.config.add_word("DCU.CH0_CTC_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH0_CTC_BYPASS"), "0"), 1));
+tg.config.add_word("DCU.CH0_DCOATDCFG", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOATDCFG"), "0"), 2));
+tg.config.add_word("DCU.CH0_DCOATDDLY", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOATDDLY"), "0"), 2));
+tg.config.add_word("DCU.CH0_DCOBYPSATD", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOBYPSATD"), "0"), 1));
+tg.config.add_word("DCU.CH0_DCOCALDIV", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOCALDIV"), "0"), 3));
+tg.config.add_word("DCU.CH0_DCOCTLGI", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOCTLGI"), "0"), 3));
+tg.config.add_word("DCU.CH0_DCODISBDAVOID", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCODISBDAVOID"), "0"), 1));
+tg.config.add_word("DCU.CH0_DCOFLTDAC", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOFLTDAC"), "0"), 2));
+tg.config.add_word("DCU.CH0_DCOFTNRG", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOFTNRG"), "0"), 3));
+tg.config.add_word("DCU.CH0_DCOIOSTUNE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOIOSTUNE"), "0"), 3));
+tg.config.add_word("DCU.CH0_DCOITUNE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOITUNE"), "0"), 2));
+tg.config.add_word("DCU.CH0_DCOITUNE4LSB", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOITUNE4LSB"), "0"), 3));
+tg.config.add_word("DCU.CH0_DCOIUPDNX2", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOIUPDNX2"), "0"), 1));
+tg.config.add_word("DCU.CH0_DCONUOFLSB", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCONUOFLSB"), "0"), 3));
+tg.config.add_word("DCU.CH0_DCOSCALEI", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOSCALEI"), "0"), 2));
+tg.config.add_word("DCU.CH0_DCOSTARTVAL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOSTARTVAL"), "0"), 3));
+tg.config.add_word("DCU.CH0_DCOSTEP", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOSTEP"), "0"), 2));
+tg.config.add_word("DCU.CH0_DEC_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DEC_BYPASS"), "0"), 1));
+tg.config.add_word("DCU.CH0_ENABLE_CG_ALIGN", parse_config_str(str_or_default(ci->params, ctx->id("CH0_ENABLE_CG_ALIGN"), "0"), 1));
+tg.config.add_word("DCU.CH0_ENC_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH0_ENC_BYPASS"), "0"), 1));
+tg.config.add_word("DCU.CH0_FF_RX_F_CLK_DIS", parse_config_str(str_or_default(ci->params, ctx->id("CH0_FF_RX_F_CLK_DIS"), "0"), 1));
+tg.config.add_word("DCU.CH0_FF_RX_H_CLK_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH0_FF_RX_H_CLK_EN"), "0"), 1));
+tg.config.add_word("DCU.CH0_FF_TX_F_CLK_DIS", parse_config_str(str_or_default(ci->params, ctx->id("CH0_FF_TX_F_CLK_DIS"), "0"), 1));
+tg.config.add_word("DCU.CH0_FF_TX_H_CLK_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH0_FF_TX_H_CLK_EN"), "0"), 1));
+tg.config.add_word("DCU.CH0_GE_AN_ENABLE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_GE_AN_ENABLE"), "0"), 1));
+tg.config.add_word("DCU.CH0_INVERT_RX", parse_config_str(str_or_default(ci->params, ctx->id("CH0_INVERT_RX"), "0"), 1));
+tg.config.add_word("DCU.CH0_INVERT_TX", parse_config_str(str_or_default(ci->params, ctx->id("CH0_INVERT_TX"), "0"), 1));
+tg.config.add_word("DCU.CH0_LDR_CORE2TX_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_LDR_CORE2TX_SEL"), "0"), 1));
+tg.config.add_word("DCU.CH0_LDR_RX2CORE_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_LDR_RX2CORE_SEL"), "0"), 1));
+tg.config.add_word("DCU.CH0_LEQ_OFFSET_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_LEQ_OFFSET_SEL"), "0"), 1));
+tg.config.add_word("DCU.CH0_LEQ_OFFSET_TRIM", parse_config_str(str_or_default(ci->params, ctx->id("CH0_LEQ_OFFSET_TRIM"), "0"), 3));
+tg.config.add_word("DCU.CH0_LSM_DISABLE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_LSM_DISABLE"), "0"), 1));
+tg.config.add_word("DCU.CH0_MATCH_2_ENABLE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_MATCH_2_ENABLE"), "0"), 1));
+tg.config.add_word("DCU.CH0_MATCH_4_ENABLE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_MATCH_4_ENABLE"), "0"), 1));
+tg.config.add_word("DCU.CH0_MIN_IPG_CNT", parse_config_str(str_or_default(ci->params, ctx->id("CH0_MIN_IPG_CNT"), "0"), 2));
+tg.config.add_word("DCU.CH0_PCIE_EI_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH0_PCIE_EI_EN"), "0"), 1));
+tg.config.add_word("DCU.CH0_PCIE_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_PCIE_MODE"), "0"), 1));
+tg.config.add_word("DCU.CH0_PCS_DET_TIME_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_PCS_DET_TIME_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH0_PDEN_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_PDEN_SEL"), "0"), 1));
+tg.config.add_word("DCU.CH0_PRBS_ENABLE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_PRBS_ENABLE"), "0"), 1));
+tg.config.add_word("DCU.CH0_PRBS_LOCK", parse_config_str(str_or_default(ci->params, ctx->id("CH0_PRBS_LOCK"), "0"), 1));
+tg.config.add_word("DCU.CH0_PRBS_SELECTION", parse_config_str(str_or_default(ci->params, ctx->id("CH0_PRBS_SELECTION"), "0"), 1));
+tg.config.add_word("DCU.CH0_RATE_MODE_RX", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RATE_MODE_RX"), "0"), 1));
+tg.config.add_word("DCU.CH0_RATE_MODE_TX", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RATE_MODE_TX"), "0"), 1));
+tg.config.add_word("DCU.CH0_RCV_DCC_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RCV_DCC_EN"), "0"), 1));
+tg.config.add_word("DCU.CH0_REG_BAND_OFFSET", parse_config_str(str_or_default(ci->params, ctx->id("CH0_REG_BAND_OFFSET"), "0"), 4));
+tg.config.add_word("DCU.CH0_REG_BAND_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_REG_BAND_SEL"), "0"), 6));
+tg.config.add_word("DCU.CH0_REG_IDAC_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH0_REG_IDAC_EN"), "0"), 1));
+tg.config.add_word("DCU.CH0_REG_IDAC_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_REG_IDAC_SEL"), "0"), 10));
+tg.config.add_word("DCU.CH0_REQ_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH0_REQ_EN"), "0"), 1));
+tg.config.add_word("DCU.CH0_REQ_LVL_SET", parse_config_str(str_or_default(ci->params, ctx->id("CH0_REQ_LVL_SET"), "0"), 2));
+tg.config.add_word("DCU.CH0_RIO_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RIO_MODE"), "0"), 1));
+tg.config.add_word("DCU.CH0_RLOS_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RLOS_SEL"), "0"), 1));
+tg.config.add_word("DCU.CH0_RPWDNB", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RPWDNB"), "0"), 1));
+tg.config.add_word("DCU.CH0_RTERM_RX", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RTERM_RX"), "0"), 5));
+tg.config.add_word("DCU.CH0_RTERM_TX", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RTERM_TX"), "0"), 5));
+tg.config.add_word("DCU.CH0_RXIN_CM", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RXIN_CM"), "0"), 2));
+tg.config.add_word("DCU.CH0_RXTERM_CM", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RXTERM_CM"), "0"), 2));
+tg.config.add_word("DCU.CH0_RX_DCO_CK_DIV", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_DCO_CK_DIV"), "0"), 3));
+tg.config.add_word("DCU.CH0_RX_DIV11_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_DIV11_SEL"), "0"), 1));
+tg.config.add_word("DCU.CH0_RX_GEAR_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_GEAR_BYPASS"), "0"), 1));
+tg.config.add_word("DCU.CH0_RX_GEAR_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_GEAR_MODE"), "0"), 1));
+tg.config.add_word("DCU.CH0_RX_LOS_CEQ", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_LOS_CEQ"), "0"), 2));
+tg.config.add_word("DCU.CH0_RX_LOS_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_LOS_EN"), "0"), 1));
+tg.config.add_word("DCU.CH0_RX_LOS_HYST_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_LOS_HYST_EN"), "0"), 1));
+tg.config.add_word("DCU.CH0_RX_LOS_LVL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_LOS_LVL"), "0"), 3));
+tg.config.add_word("DCU.CH0_RX_RATE_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_RATE_SEL"), "0"), 4));
+tg.config.add_word("DCU.CH0_RX_SB_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_SB_BYPASS"), "0"), 1));
+tg.config.add_word("DCU.CH0_SB_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH0_SB_BYPASS"), "0"), 1));
+tg.config.add_word("DCU.CH0_SEL_SD_RX_CLK", parse_config_str(str_or_default(ci->params, ctx->id("CH0_SEL_SD_RX_CLK"), "0"), 1));
+tg.config.add_word("DCU.CH0_TDRV_DAT_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_DAT_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH0_TDRV_POST_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_POST_EN"), "0"), 1));
+tg.config.add_word("DCU.CH0_TDRV_PRE_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_PRE_EN"), "0"), 1));
+tg.config.add_word("DCU.CH0_TDRV_SLICE0_CUR", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE0_CUR"), "0"), 3));
+tg.config.add_word("DCU.CH0_TDRV_SLICE0_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE0_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH0_TDRV_SLICE1_CUR", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE1_CUR"), "0"), 3));
+tg.config.add_word("DCU.CH0_TDRV_SLICE1_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE1_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH0_TDRV_SLICE2_CUR", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE2_CUR"), "0"), 2));
+tg.config.add_word("DCU.CH0_TDRV_SLICE2_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE2_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH0_TDRV_SLICE3_CUR", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE3_CUR"), "0"), 2));
+tg.config.add_word("DCU.CH0_TDRV_SLICE3_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE3_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH0_TDRV_SLICE4_CUR", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE4_CUR"), "0"), 2));
+tg.config.add_word("DCU.CH0_TDRV_SLICE4_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE4_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH0_TDRV_SLICE5_CUR", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE5_CUR"), "0"), 2));
+tg.config.add_word("DCU.CH0_TDRV_SLICE5_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE5_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH0_TPWDNB", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TPWDNB"), "0"), 1));
+tg.config.add_word("DCU.CH0_TX_CM_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TX_CM_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH0_TX_DIV11_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TX_DIV11_SEL"), "0"), 1));
+tg.config.add_word("DCU.CH0_TX_GEAR_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TX_GEAR_BYPASS"), "0"), 1));
+tg.config.add_word("DCU.CH0_TX_GEAR_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TX_GEAR_MODE"), "0"), 1));
+tg.config.add_word("DCU.CH0_TX_POST_SIGN", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TX_POST_SIGN"), "0"), 1));
+tg.config.add_word("DCU.CH0_TX_PRE_SIGN", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TX_PRE_SIGN"), "0"), 1));
+tg.config.add_word("DCU.CH0_UC_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_UC_MODE"), "0"), 1));
+tg.config.add_word("DCU.CH0_UDF_COMMA_A", parse_config_str(str_or_default(ci->params, ctx->id("CH0_UDF_COMMA_A"), "0"), 10));
+tg.config.add_word("DCU.CH0_UDF_COMMA_B", parse_config_str(str_or_default(ci->params, ctx->id("CH0_UDF_COMMA_B"), "0"), 10));
+tg.config.add_word("DCU.CH0_UDF_COMMA_MASK", parse_config_str(str_or_default(ci->params, ctx->id("CH0_UDF_COMMA_MASK"), "0"), 10));
+tg.config.add_word("DCU.CH0_WA_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH0_WA_BYPASS"), "0"), 1));
+tg.config.add_word("DCU.CH0_WA_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_WA_MODE"), "0"), 1));
+tg.config.add_word("DCU.CH1_AUTO_CALIB_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH1_AUTO_CALIB_EN"), "0"), 1));
+tg.config.add_word("DCU.CH1_AUTO_FACQ_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH1_AUTO_FACQ_EN"), "0"), 1));
+tg.config.add_word("DCU.CH1_BAND_THRESHOLD", parse_config_str(str_or_default(ci->params, ctx->id("CH1_BAND_THRESHOLD"), "0"), 6));
+tg.config.add_word("DCU.CH1_CALIB_CK_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_CALIB_CK_MODE"), "0"), 1));
+tg.config.add_word("DCU.CH1_CC_MATCH_1", parse_config_str(str_or_default(ci->params, ctx->id("CH1_CC_MATCH_1"), "0"), 10));
+tg.config.add_word("DCU.CH1_CC_MATCH_2", parse_config_str(str_or_default(ci->params, ctx->id("CH1_CC_MATCH_2"), "0"), 10));
+tg.config.add_word("DCU.CH1_CC_MATCH_3", parse_config_str(str_or_default(ci->params, ctx->id("CH1_CC_MATCH_3"), "0"), 10));
+tg.config.add_word("DCU.CH1_CC_MATCH_4", parse_config_str(str_or_default(ci->params, ctx->id("CH1_CC_MATCH_4"), "0"), 10));
+tg.config.add_word("DCU.CH1_CDR_CNT4SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_CDR_CNT4SEL"), "0"), 2));
+tg.config.add_word("DCU.CH1_CDR_CNT8SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_CDR_CNT8SEL"), "0"), 2));
+tg.config.add_word("DCU.CH1_CTC_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH1_CTC_BYPASS"), "0"), 1));
+tg.config.add_word("DCU.CH1_DCOATDCFG", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOATDCFG"), "0"), 2));
+tg.config.add_word("DCU.CH1_DCOATDDLY", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOATDDLY"), "0"), 2));
+tg.config.add_word("DCU.CH1_DCOBYPSATD", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOBYPSATD"), "0"), 1));
+tg.config.add_word("DCU.CH1_DCOCALDIV", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOCALDIV"), "0"), 3));
+tg.config.add_word("DCU.CH1_DCOCTLGI", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOCTLGI"), "0"), 3));
+tg.config.add_word("DCU.CH1_DCODISBDAVOID", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCODISBDAVOID"), "0"), 1));
+tg.config.add_word("DCU.CH1_DCOFLTDAC", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOFLTDAC"), "0"), 2));
+tg.config.add_word("DCU.CH1_DCOFTNRG", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOFTNRG"), "0"), 3));
+tg.config.add_word("DCU.CH1_DCOIOSTUNE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOIOSTUNE"), "0"), 3));
+tg.config.add_word("DCU.CH1_DCOITUNE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOITUNE"), "0"), 2));
+tg.config.add_word("DCU.CH1_DCOITUNE4LSB", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOITUNE4LSB"), "0"), 3));
+tg.config.add_word("DCU.CH1_DCOIUPDNX2", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOIUPDNX2"), "0"), 1));
+tg.config.add_word("DCU.CH1_DCONUOFLSB", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCONUOFLSB"), "0"), 3));
+tg.config.add_word("DCU.CH1_DCOSCALEI", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOSCALEI"), "0"), 2));
+tg.config.add_word("DCU.CH1_DCOSTARTVAL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOSTARTVAL"), "0"), 3));
+tg.config.add_word("DCU.CH1_DCOSTEP", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOSTEP"), "0"), 2));
+tg.config.add_word("DCU.CH1_DEC_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DEC_BYPASS"), "0"), 1));
+tg.config.add_word("DCU.CH1_ENABLE_CG_ALIGN", parse_config_str(str_or_default(ci->params, ctx->id("CH1_ENABLE_CG_ALIGN"), "0"), 1));
+tg.config.add_word("DCU.CH1_ENC_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH1_ENC_BYPASS"), "0"), 1));
+tg.config.add_word("DCU.CH1_FF_RX_F_CLK_DIS", parse_config_str(str_or_default(ci->params, ctx->id("CH1_FF_RX_F_CLK_DIS"), "0"), 1));
+tg.config.add_word("DCU.CH1_FF_RX_H_CLK_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH1_FF_RX_H_CLK_EN"), "0"), 1));
+tg.config.add_word("DCU.CH1_FF_TX_F_CLK_DIS", parse_config_str(str_or_default(ci->params, ctx->id("CH1_FF_TX_F_CLK_DIS"), "0"), 1));
+tg.config.add_word("DCU.CH1_FF_TX_H_CLK_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH1_FF_TX_H_CLK_EN"), "0"), 1));
+tg.config.add_word("DCU.CH1_GE_AN_ENABLE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_GE_AN_ENABLE"), "0"), 1));
+tg.config.add_word("DCU.CH1_INVERT_RX", parse_config_str(str_or_default(ci->params, ctx->id("CH1_INVERT_RX"), "0"), 1));
+tg.config.add_word("DCU.CH1_INVERT_TX", parse_config_str(str_or_default(ci->params, ctx->id("CH1_INVERT_TX"), "0"), 1));
+tg.config.add_word("DCU.CH1_LDR_CORE2TX_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_LDR_CORE2TX_SEL"), "0"), 1));
+tg.config.add_word("DCU.CH1_LDR_RX2CORE_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_LDR_RX2CORE_SEL"), "0"), 1));
+tg.config.add_word("DCU.CH1_LEQ_OFFSET_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_LEQ_OFFSET_SEL"), "0"), 1));
+tg.config.add_word("DCU.CH1_LEQ_OFFSET_TRIM", parse_config_str(str_or_default(ci->params, ctx->id("CH1_LEQ_OFFSET_TRIM"), "0"), 3));
+tg.config.add_word("DCU.CH1_LSM_DISABLE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_LSM_DISABLE"), "0"), 1));
+tg.config.add_word("DCU.CH1_MATCH_2_ENABLE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_MATCH_2_ENABLE"), "0"), 1));
+tg.config.add_word("DCU.CH1_MATCH_4_ENABLE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_MATCH_4_ENABLE"), "0"), 1));
+tg.config.add_word("DCU.CH1_MIN_IPG_CNT", parse_config_str(str_or_default(ci->params, ctx->id("CH1_MIN_IPG_CNT"), "0"), 2));
+tg.config.add_word("DCU.CH1_PCIE_EI_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH1_PCIE_EI_EN"), "0"), 1));
+tg.config.add_word("DCU.CH1_PCIE_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_PCIE_MODE"), "0"), 1));
+tg.config.add_word("DCU.CH1_PCS_DET_TIME_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_PCS_DET_TIME_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH1_PDEN_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_PDEN_SEL"), "0"), 1));
+tg.config.add_word("DCU.CH1_PRBS_ENABLE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_PRBS_ENABLE"), "0"), 1));
+tg.config.add_word("DCU.CH1_PRBS_LOCK", parse_config_str(str_or_default(ci->params, ctx->id("CH1_PRBS_LOCK"), "0"), 1));
+tg.config.add_word("DCU.CH1_PRBS_SELECTION", parse_config_str(str_or_default(ci->params, ctx->id("CH1_PRBS_SELECTION"), "0"), 1));
+tg.config.add_word("DCU.CH1_RATE_MODE_RX", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RATE_MODE_RX"), "0"), 1));
+tg.config.add_word("DCU.CH1_RATE_MODE_TX", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RATE_MODE_TX"), "0"), 1));
+tg.config.add_word("DCU.CH1_RCV_DCC_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RCV_DCC_EN"), "0"), 1));
+tg.config.add_word("DCU.CH1_REG_BAND_OFFSET", parse_config_str(str_or_default(ci->params, ctx->id("CH1_REG_BAND_OFFSET"), "0"), 4));
+tg.config.add_word("DCU.CH1_REG_BAND_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_REG_BAND_SEL"), "0"), 6));
+tg.config.add_word("DCU.CH1_REG_IDAC_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH1_REG_IDAC_EN"), "0"), 1));
+tg.config.add_word("DCU.CH1_REG_IDAC_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_REG_IDAC_SEL"), "0"), 10));
+tg.config.add_word("DCU.CH1_REQ_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH1_REQ_EN"), "0"), 1));
+tg.config.add_word("DCU.CH1_REQ_LVL_SET", parse_config_str(str_or_default(ci->params, ctx->id("CH1_REQ_LVL_SET"), "0"), 2));
+tg.config.add_word("DCU.CH1_RIO_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RIO_MODE"), "0"), 1));
+tg.config.add_word("DCU.CH1_RLOS_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RLOS_SEL"), "0"), 1));
+tg.config.add_word("DCU.CH1_RPWDNB", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RPWDNB"), "0"), 1));
+tg.config.add_word("DCU.CH1_RTERM_RX", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RTERM_RX"), "0"), 5));
+tg.config.add_word("DCU.CH1_RTERM_TX", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RTERM_TX"), "0"), 5));
+tg.config.add_word("DCU.CH1_RXIN_CM", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RXIN_CM"), "0"), 2));
+tg.config.add_word("DCU.CH1_RXTERM_CM", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RXTERM_CM"), "0"), 2));
+tg.config.add_word("DCU.CH1_RX_DCO_CK_DIV", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_DCO_CK_DIV"), "0"), 3));
+tg.config.add_word("DCU.CH1_RX_DIV11_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_DIV11_SEL"), "0"), 1));
+tg.config.add_word("DCU.CH1_RX_GEAR_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_GEAR_BYPASS"), "0"), 1));
+tg.config.add_word("DCU.CH1_RX_GEAR_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_GEAR_MODE"), "0"), 1));
+tg.config.add_word("DCU.CH1_RX_LOS_CEQ", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_LOS_CEQ"), "0"), 2));
+tg.config.add_word("DCU.CH1_RX_LOS_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_LOS_EN"), "0"), 1));
+tg.config.add_word("DCU.CH1_RX_LOS_HYST_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_LOS_HYST_EN"), "0"), 1));
+tg.config.add_word("DCU.CH1_RX_LOS_LVL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_LOS_LVL"), "0"), 3));
+tg.config.add_word("DCU.CH1_RX_RATE_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_RATE_SEL"), "0"), 4));
+tg.config.add_word("DCU.CH1_RX_SB_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_SB_BYPASS"), "0"), 1));
+tg.config.add_word("DCU.CH1_SB_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH1_SB_BYPASS"), "0"), 1));
+tg.config.add_word("DCU.CH1_SEL_SD_RX_CLK", parse_config_str(str_or_default(ci->params, ctx->id("CH1_SEL_SD_RX_CLK"), "0"), 1));
+tg.config.add_word("DCU.CH1_TDRV_DAT_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_DAT_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH1_TDRV_POST_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_POST_EN"), "0"), 1));
+tg.config.add_word("DCU.CH1_TDRV_PRE_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_PRE_EN"), "0"), 1));
+tg.config.add_word("DCU.CH1_TDRV_SLICE0_CUR", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE0_CUR"), "0"), 3));
+tg.config.add_word("DCU.CH1_TDRV_SLICE0_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE0_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH1_TDRV_SLICE1_CUR", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE1_CUR"), "0"), 3));
+tg.config.add_word("DCU.CH1_TDRV_SLICE1_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE1_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH1_TDRV_SLICE2_CUR", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE2_CUR"), "0"), 2));
+tg.config.add_word("DCU.CH1_TDRV_SLICE2_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE2_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH1_TDRV_SLICE3_CUR", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE3_CUR"), "0"), 2));
+tg.config.add_word("DCU.CH1_TDRV_SLICE3_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE3_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH1_TDRV_SLICE4_CUR", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE4_CUR"), "0"), 2));
+tg.config.add_word("DCU.CH1_TDRV_SLICE4_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE4_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH1_TDRV_SLICE5_CUR", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE5_CUR"), "0"), 2));
+tg.config.add_word("DCU.CH1_TDRV_SLICE5_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE5_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH1_TPWDNB", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TPWDNB"), "0"), 1));
+tg.config.add_word("DCU.CH1_TX_CM_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TX_CM_SEL"), "0"), 2));
+tg.config.add_word("DCU.CH1_TX_DIV11_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TX_DIV11_SEL"), "0"), 1));
+tg.config.add_word("DCU.CH1_TX_GEAR_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TX_GEAR_BYPASS"), "0"), 1));
+tg.config.add_word("DCU.CH1_TX_GEAR_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TX_GEAR_MODE"), "0"), 1));
+tg.config.add_word("DCU.CH1_TX_POST_SIGN", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TX_POST_SIGN"), "0"), 1));
+tg.config.add_word("DCU.CH1_TX_PRE_SIGN", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TX_PRE_SIGN"), "0"), 1));
+tg.config.add_word("DCU.CH1_UC_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_UC_MODE"), "0"), 1));
+tg.config.add_word("DCU.CH1_UDF_COMMA_A", parse_config_str(str_or_default(ci->params, ctx->id("CH1_UDF_COMMA_A"), "0"), 10));
+tg.config.add_word("DCU.CH1_UDF_COMMA_B", parse_config_str(str_or_default(ci->params, ctx->id("CH1_UDF_COMMA_B"), "0"), 10));
+tg.config.add_word("DCU.CH1_UDF_COMMA_MASK", parse_config_str(str_or_default(ci->params, ctx->id("CH1_UDF_COMMA_MASK"), "0"), 10));
+tg.config.add_word("DCU.CH1_WA_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH1_WA_BYPASS"), "0"), 1));
+tg.config.add_word("DCU.CH1_WA_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_WA_MODE"), "0"), 1));
+tg.config.add_word("DCU.D_BITCLK_FROM_ND_EN", parse_config_str(str_or_default(ci->params, ctx->id("D_BITCLK_FROM_ND_EN"), "0"), 1));
+tg.config.add_word("DCU.D_BITCLK_LOCAL_EN", parse_config_str(str_or_default(ci->params, ctx->id("D_BITCLK_LOCAL_EN"), "0"), 1));
+tg.config.add_word("DCU.D_BITCLK_ND_EN", parse_config_str(str_or_default(ci->params, ctx->id("D_BITCLK_ND_EN"), "0"), 1));
+tg.config.add_word("DCU.D_BUS8BIT_SEL", parse_config_str(str_or_default(ci->params, ctx->id("D_BUS8BIT_SEL"), "0"), 1));
+tg.config.add_word("DCU.D_CDR_LOL_SET", parse_config_str(str_or_default(ci->params, ctx->id("D_CDR_LOL_SET"), "0"), 2));
+tg.config.add_word("DCU.D_CMUSETBIASI", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETBIASI"), "0"), 2));
+tg.config.add_word("DCU.D_CMUSETI4CPP", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETI4CPP"), "0"), 4));
+tg.config.add_word("DCU.D_CMUSETI4CPZ", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETI4CPZ"), "0"), 4));
+tg.config.add_word("DCU.D_CMUSETI4VCO", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETI4VCO"), "0"), 2));
+tg.config.add_word("DCU.D_CMUSETICP4P", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETICP4P"), "0"), 2));
+tg.config.add_word("DCU.D_CMUSETICP4Z", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETICP4Z"), "0"), 3));
+tg.config.add_word("DCU.D_CMUSETINITVCT", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETINITVCT"), "0"), 2));
+tg.config.add_word("DCU.D_CMUSETISCL4VCO", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETISCL4VCO"), "0"), 3));
+tg.config.add_word("DCU.D_CMUSETP1GM", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETP1GM"), "0"), 3));
+tg.config.add_word("DCU.D_CMUSETP2AGM", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETP2AGM"), "0"), 3));
+tg.config.add_word("DCU.D_CMUSETZGM", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETZGM"), "0"), 3));
+tg.config.add_word("DCU.D_DCO_CALIB_TIME_SEL", parse_config_str(str_or_default(ci->params, ctx->id("D_DCO_CALIB_TIME_SEL"), "0"), 2));
+tg.config.add_word("DCU.D_HIGH_MARK", parse_config_str(str_or_default(ci->params, ctx->id("D_HIGH_MARK"), "0"), 4));
+tg.config.add_word("DCU.D_IB_PWDNB", parse_config_str(str_or_default(ci->params, ctx->id("D_IB_PWDNB"), "0"), 1));
+tg.config.add_word("DCU.D_ISETLOS", parse_config_str(str_or_default(ci->params, ctx->id("D_ISETLOS"), "0"), 8));
+tg.config.add_word("DCU.D_LOW_MARK", parse_config_str(str_or_default(ci->params, ctx->id("D_LOW_MARK"), "0"), 4));
+tg.config.add_word("DCU.D_MACROPDB", parse_config_str(str_or_default(ci->params, ctx->id("D_MACROPDB"), "0"), 1));
+tg.config.add_word("DCU.D_PD_ISET", parse_config_str(str_or_default(ci->params, ctx->id("D_PD_ISET"), "0"), 2));
+tg.config.add_word("DCU.D_PLL_LOL_SET", parse_config_str(str_or_default(ci->params, ctx->id("D_PLL_LOL_SET"), "0"), 2));
+tg.config.add_word("DCU.D_REFCK_MODE", parse_config_str(str_or_default(ci->params, ctx->id("D_REFCK_MODE"), "0"), 3));
+tg.config.add_word("DCU.D_REQ_ISET", parse_config_str(str_or_default(ci->params, ctx->id("D_REQ_ISET"), "0"), 3));
+tg.config.add_word("DCU.D_RG_EN", parse_config_str(str_or_default(ci->params, ctx->id("D_RG_EN"), "0"), 1));
+tg.config.add_word("DCU.D_RG_SET", parse_config_str(str_or_default(ci->params, ctx->id("D_RG_SET"), "0"), 2));
+tg.config.add_word("DCU.D_SETICONST_AUX", parse_config_str(str_or_default(ci->params, ctx->id("D_SETICONST_AUX"), "0"), 2));
+tg.config.add_word("DCU.D_SETICONST_CH", parse_config_str(str_or_default(ci->params, ctx->id("D_SETICONST_CH"), "0"), 2));
+tg.config.add_word("DCU.D_SETIRPOLY_AUX", parse_config_str(str_or_default(ci->params, ctx->id("D_SETIRPOLY_AUX"), "0"), 2));
+tg.config.add_word("DCU.D_SETIRPOLY_CH", parse_config_str(str_or_default(ci->params, ctx->id("D_SETIRPOLY_CH"), "0"), 2));
+tg.config.add_word("DCU.D_SETPLLRC", parse_config_str(str_or_default(ci->params, ctx->id("D_SETPLLRC"), "0"), 6));
+tg.config.add_word("DCU.D_SYNC_LOCAL_EN", parse_config_str(str_or_default(ci->params, ctx->id("D_SYNC_LOCAL_EN"), "0"), 1));
+tg.config.add_word("DCU.D_SYNC_ND_EN", parse_config_str(str_or_default(ci->params, ctx->id("D_SYNC_ND_EN"), "0"), 1));
+tg.config.add_word("DCU.D_TXPLL_PWDNB", parse_config_str(str_or_default(ci->params, ctx->id("D_TXPLL_PWDNB"), "0"), 1));
+tg.config.add_word("DCU.D_TX_VCO_CK_DIV", parse_config_str(str_or_default(ci->params, ctx->id("D_TX_VCO_CK_DIV"), "0"), 3));
+tg.config.add_word("DCU.D_XGE_MODE", parse_config_str(str_or_default(ci->params, ctx->id("D_XGE_MODE"), "0"), 1));
diff --git a/ecp5/globals.cc b/ecp5/globals.cc
index 9b0928a4..66c62024 100644
--- a/ecp5/globals.cc
+++ b/ecp5/globals.cc
@@ -55,6 +55,9 @@ class Ecp5GlobalRouter
{
if (user.cell->type == id_TRELLIS_SLICE && (user.port == id_CLK || user.port == id_WCK))
return true;
+ if (user.cell->type == id_DCUA && (user.port == id_CH0_FF_RXI_CLK || user.port == id_CH1_FF_RXI_CLK ||
+ user.port == id_CH0_FF_TXI_CLK || user.port == id_CH1_FF_TXI_CLK))
+ return true;
return false;
}
@@ -65,8 +68,11 @@ class Ecp5GlobalRouter
NetInfo *ni = net.second.get();
clockCount[ni->name] = 0;
for (const auto &user : ni->users) {
- if (is_clock_port(user))
+ if (is_clock_port(user)) {
clockCount[ni->name]++;
+ if (user.cell->type == id_DCUA)
+ clockCount[ni->name] += 100;
+ }
}
// log_info("clkcount %s: %d\n", ni->name.c_str(ctx),clockCount[ni->name]);
}
@@ -290,6 +296,10 @@ class Ecp5GlobalRouter
float tns;
return get_net_metric(ctx, clki, MetricType::WIRELENGTH, tns);
} else {
+ // Check for dedicated routing
+ if (has_short_route(ctx->getBelPinWire(drv_bel, drv.port), ctx->getBelPinWire(dcc->bel, id_CLKI))) {
+ return 0;
+ }
// Driver is locked
Loc dcc_loc = ctx->getBelLocation(dcc->bel);
Loc drv_loc = ctx->getBelLocation(drv_bel);
@@ -297,6 +307,46 @@ class Ecp5GlobalRouter
}
}
+ // Return true if a short (<5) route exists between two wires
+ bool has_short_route(WireId src, WireId dst, int thresh = 5)
+ {
+ std::queue<WireId> visit;
+ std::unordered_map<WireId, PipId> backtrace;
+ visit.push(src);
+ WireId cursor;
+ while (true) {
+
+ if (visit.empty() || visit.size() > 1000) {
+ // log_info ("dist %s -> %s = inf\n", ctx->getWireName(src).c_str(ctx),
+ // ctx->getWireName(dst).c_str(ctx));
+ return false;
+ }
+ cursor = visit.front();
+ visit.pop();
+
+ if (cursor == dst)
+ break;
+ for (auto dh : ctx->getPipsDownhill(cursor)) {
+ WireId pipDst = ctx->getPipDstWire(dh);
+ if (backtrace.count(pipDst))
+ continue;
+ backtrace[pipDst] = dh;
+ visit.push(pipDst);
+ }
+ }
+ int length = 0;
+ while (true) {
+ auto fnd = backtrace.find(cursor);
+ if (fnd == backtrace.end())
+ break;
+ cursor = ctx->getPipSrcWire(fnd->second);
+ length++;
+ }
+ // log_info ("dist %s -> %s = %d\n", ctx->getWireName(src).c_str(ctx), ctx->getWireName(dst).c_str(ctx),
+ // length);
+ return length < thresh;
+ }
+
// Attempt to place a DCC
void place_dcc(CellInfo *dcc)
{
@@ -335,6 +385,8 @@ class Ecp5GlobalRouter
for (auto user : net->users) {
if (user.port == id_CLKFB) {
keep_users.push_back(user);
+ } else if (net->driver.cell->type == id_EXTREFB && user.cell->type == id_DCUA) {
+ keep_users.push_back(user);
} else {
glbnet->users.push_back(user);
user.cell->ports.at(user.port).net = glbnet.get();
diff --git a/ecp5/pack.cc b/ecp5/pack.cc
index 73e15609..2d2f7578 100644
--- a/ecp5/pack.cc
+++ b/ecp5/pack.cc
@@ -235,6 +235,46 @@ class Ecp5Packer
}
}
+ // Return true if an port is a top level port that provides its own IOBUF
+ bool is_top_port(PortRef &port)
+ {
+ if (port.cell == nullptr)
+ return false;
+ if (port.cell->type == id_DCUA) {
+ return port.port == id_CH0_HDINP || port.port == id_CH0_HDINN || port.port == id_CH0_HDOUTP ||
+ port.port == id_CH0_HDOUTN || port.port == id_CH1_HDINP || port.port == id_CH1_HDINN ||
+ port.port == id_CH1_HDOUTP || port.port == id_CH1_HDOUTN;
+ } else if (port.cell->type == id_EXTREFB) {
+ return port.port == id_REFCLKP || port.port == id_REFCLKN;
+ } else {
+ return false;
+ }
+ }
+
+ // Return true if a net only drives a top port
+ bool drives_top_port(NetInfo *net, PortRef &tp)
+ {
+ if (net == nullptr)
+ return false;
+ for (auto user : net->users) {
+ if (is_top_port(user)) {
+ if (net->users.size() > 1)
+ log_error(" port %s.%s must be connected to (and only to) a top level pin\n",
+ user.cell->name.c_str(ctx), user.port.c_str(ctx));
+ tp = user;
+ return true;
+ }
+ }
+ if (net->driver.cell != nullptr && is_top_port(net->driver)) {
+ if (net->users.size() > 1)
+ log_error(" port %s.%s must be connected to (and only to) a top level pin\n",
+ net->driver.cell->name.c_str(ctx), net->driver.port.c_str(ctx));
+ tp = net->driver;
+ return true;
+ }
+ return false;
+ }
+
// Simple "packer" to remove nextpnr IOBUFs, this assumes IOBUFs are manually instantiated
void pack_io()
{
@@ -244,10 +284,14 @@ class Ecp5Packer
CellInfo *ci = cell.second;
if (is_nextpnr_iob(ctx, ci)) {
CellInfo *trio = nullptr;
+ NetInfo *ionet = nullptr;
+ PortRef tp;
if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) {
- trio = net_only_drives(ctx, ci->ports.at(ctx->id("O")).net, is_trellis_io, ctx->id("B"), true, ci);
+ ionet = ci->ports.at(ctx->id("O")).net;
+ trio = net_only_drives(ctx, ionet, is_trellis_io, ctx->id("B"), true, ci);
} else if (ci->type == ctx->id("$nextpnr_obuf")) {
+ ionet = ci->ports.at(ctx->id("I")).net;
trio = net_only_drives(ctx, ci->ports.at(ctx->id("I")).net, is_trellis_io, ctx->id("B"), true, ci);
}
if (trio != nullptr) {
@@ -266,6 +310,19 @@ class Ecp5Packer
ctx->nets.erase(net2->name);
}
}
+ } else if (drives_top_port(ionet, tp)) {
+ log_info("%s feeds %s %s.%s, removing %s %s.\n", ci->name.c_str(ctx), tp.cell->type.c_str(ctx),
+ tp.cell->name.c_str(ctx), tp.port.c_str(ctx), ci->type.c_str(ctx), ci->name.c_str(ctx));
+ if (ionet != nullptr) {
+ ctx->nets.erase(ionet->name);
+ tp.cell->ports.at(tp.port).net = nullptr;
+ }
+ if (ci->type == ctx->id("$nextpnr_iobuf")) {
+ NetInfo *net2 = ci->ports.at(ctx->id("I")).net;
+ if (net2 != nullptr) {
+ ctx->nets.erase(net2->name);
+ }
+ }
} else {
// Create a TRELLIS_IO buffer
std::unique_ptr<CellInfo> tr_cell =
@@ -276,21 +333,23 @@ class Ecp5Packer
}
packed_cells.insert(ci->name);
- for (const auto &attr : ci->attrs)
- trio->attrs[attr.first] = attr.second;
-
- auto loc_attr = trio->attrs.find(ctx->id("LOC"));
- if (loc_attr != trio->attrs.end()) {
- std::string pin = loc_attr->second;
- BelId pinBel = ctx->getPackagePinBel(pin);
- if (pinBel == BelId()) {
- log_error("IO pin '%s' constrained to pin '%s', which does not exist for package '%s'.\n",
- trio->name.c_str(ctx), pin.c_str(), ctx->args.package.c_str());
- } else {
- log_info("pin '%s' constrained to Bel '%s'.\n", trio->name.c_str(ctx),
- ctx->getBelName(pinBel).c_str(ctx));
+ if (trio != nullptr) {
+ for (const auto &attr : ci->attrs)
+ trio->attrs[attr.first] = attr.second;
+
+ auto loc_attr = trio->attrs.find(ctx->id("LOC"));
+ if (loc_attr != trio->attrs.end()) {
+ std::string pin = loc_attr->second;
+ BelId pinBel = ctx->getPackagePinBel(pin);
+ if (pinBel == BelId()) {
+ log_error("IO pin '%s' constrained to pin '%s', which does not exist for package '%s'.\n",
+ trio->name.c_str(ctx), pin.c_str(), ctx->args.package.c_str());
+ } else {
+ log_info("pin '%s' constrained to Bel '%s'.\n", trio->name.c_str(ctx),
+ ctx->getBelName(pinBel).c_str(ctx));
+ }
+ trio->attrs[ctx->id("BEL")] = ctx->getBelName(pinBel).str(ctx);
}
- trio->attrs[ctx->id("BEL")] = ctx->getBelName(pinBel).str(ctx);
}
}
}
@@ -1033,12 +1092,93 @@ class Ecp5Packer
}
}
+ // "Pack" DCUs
+ void pack_dcus()
+ {
+ for (auto cell : sorted(ctx->cells)) {
+ CellInfo *ci = cell.second;
+ if (ci->type == id_DCUA) {
+ if (ci->attrs.count(ctx->id("LOC"))) {
+ std::string loc = ci->attrs.at(ctx->id("LOC"));
+ if (loc == "DCU0" &&
+ (ctx->args.type == ArchArgs::LFE5UM_25F || ctx->args.type == ArchArgs::LFE5UM5G_25F))
+ ci->attrs[ctx->id("BEL")] = "X42/Y50/DCU";
+ else if (loc == "DCU0" &&
+ (ctx->args.type == ArchArgs::LFE5UM_45F || ctx->args.type == ArchArgs::LFE5UM5G_45F))
+ ci->attrs[ctx->id("BEL")] = "X42/Y71/DCU";
+ else if (loc == "DCU1" &&
+ (ctx->args.type == ArchArgs::LFE5UM_45F || ctx->args.type == ArchArgs::LFE5UM5G_45F))
+ ci->attrs[ctx->id("BEL")] = "X69/Y71/DCU";
+ else if (loc == "DCU0" &&
+ (ctx->args.type == ArchArgs::LFE5UM_85F || ctx->args.type == ArchArgs::LFE5UM5G_85F))
+ ci->attrs[ctx->id("BEL")] = "X46/Y95/DCU";
+ else if (loc == "DCU1" &&
+ (ctx->args.type == ArchArgs::LFE5UM_85F || ctx->args.type == ArchArgs::LFE5UM5G_85F))
+ ci->attrs[ctx->id("BEL")] = "X71/Y95/DCU";
+ else
+ log_error("no DCU location '%s' in device '%s'\n", loc.c_str(), ctx->getChipName().c_str());
+ }
+ if (!ci->attrs.count(ctx->id("BEL")))
+ log_error("DCU must be constrained to a Bel!\n");
+ // Empty port auto-creation to generate correct tie-downs
+ BelId exemplar_bel;
+ for (auto bel : ctx->getBels()) {
+ if (ctx->getBelType(bel) == id_DCUA) {
+ exemplar_bel = bel;
+ break;
+ }
+ }
+ NPNR_ASSERT(exemplar_bel != BelId());
+ for (auto pin : ctx->getBelPins(exemplar_bel))
+ if (ctx->getBelPinType(exemplar_bel, pin) == PORT_IN)
+ autocreate_empty_port(ci, pin);
+ }
+ }
+ for (auto cell : sorted(ctx->cells)) {
+ CellInfo *ci = cell.second;
+ if (ci->type == id_EXTREFB) {
+ const NetInfo *refo = net_or_nullptr(ci, id_REFCLKO);
+ CellInfo *dcu = nullptr;
+ if (refo == nullptr)
+ log_error("EXTREFB REFCLKO must not be unconnected\n");
+ for (auto user : refo->users) {
+ if (user.cell->type != id_DCUA)
+ continue;
+ if (dcu != nullptr && dcu != user.cell)
+ log_error("EXTREFB REFCLKO must only drive a single DCUA\n");
+ dcu = user.cell;
+ }
+ if (!dcu->attrs.count(ctx->id("BEL")))
+ log_error("DCU must be constrained to a Bel!\n");
+ std::string bel = dcu->attrs.at(ctx->id("BEL"));
+ NPNR_ASSERT(bel.substr(bel.length() - 3) == "DCU");
+ bel.replace(bel.length() - 3, 3, "EXTREF");
+ ci->attrs[ctx->id("BEL")] = bel;
+ } else if (ci->type == id_PCSCLKDIV) {
+ const NetInfo *clki = net_or_nullptr(ci, id_CLKI);
+ if (clki != nullptr && clki->driver.cell != nullptr && clki->driver.cell->type == id_DCUA) {
+ CellInfo *dcu = clki->driver.cell;
+ if (!dcu->attrs.count(ctx->id("BEL")))
+ log_error("DCU must be constrained to a Bel!\n");
+ BelId bel = ctx->getBelByName(ctx->id(dcu->attrs.at(ctx->id("BEL"))));
+ if (bel == BelId())
+ log_error("Invalid DCU bel '%s'\n", dcu->attrs.at(ctx->id("BEL")).c_str());
+ Loc loc = ctx->getBelLocation(bel);
+ // DCU0 -> CLKDIV z=0; DCU1 -> CLKDIV z=1
+ ci->constr_abs_z = true;
+ ci->constr_z = (loc.x >= 69) ? 1 : 0;
+ }
+ }
+ }
+ }
+
public:
void pack()
{
pack_io();
pack_ebr();
pack_dsps();
+ pack_dcus();
pack_constants();
pack_dram();
pack_carries();
diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py
index 9a26b605..99fe7ba9 100755
--- a/ecp5/trellis_import.py
+++ b/ecp5/trellis_import.py
@@ -200,9 +200,14 @@ def write_database(dev_name, chip, ddrg, endianness):
write_loc(arc.sinkWire.rel, "dst")
bba.u32(arc.srcWire.id, "src_idx")
bba.u32(arc.sinkWire.id, "dst_idx")
- bba.u32(get_pip_delay(get_wire_name(idx, arc.srcWire.rel, arc.srcWire.id), get_wire_name(idx, arc.sinkWire.rel, arc.sinkWire.id)), "delay") # TODO:delay
+ src_name = get_wire_name(idx, arc.srcWire.rel, arc.srcWire.id)
+ snk_name = get_wire_name(idx, arc.sinkWire.rel, arc.sinkWire.id)
+ bba.u32(get_pip_delay(src_name, snk_name), "delay") # TODO:delay
bba.u16(get_tiletype_index(ddrg.to_str(arc.tiletype)), "tile_type")
- bba.u8(int(arc.cls), "pip_type")
+ cls = arc.cls
+ if cls == 1 and "PCS" in snk_name or "DCU" in snk_name or "DCU" in src_name:
+ cls = 2
+ bba.u8(cls, "pip_type")
bba.u8(0, "padding")
if len(loctype.wires) > 0:
for wire_idx in range(len(loctype.wires)):
@@ -340,7 +345,7 @@ def write_database(dev_name, chip, ddrg, endianness):
bba.pop()
return bba
-dev_names = {"25k": "LFE5U-25F", "45k": "LFE5U-45F", "85k": "LFE5U-85F"}
+dev_names = {"25k": "LFE5UM5G-25F", "45k": "LFE5UM5G-45F", "85k": "LFE5UM5G-85F"}
def main():
global max_row, max_col