aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gowin/constids.inc5
-rw-r--r--gowin/pack.cc82
2 files changed, 87 insertions, 0 deletions
diff --git a/gowin/constids.inc b/gowin/constids.inc
index be016e0e..3e72340a 100644
--- a/gowin/constids.inc
+++ b/gowin/constids.inc
@@ -636,6 +636,8 @@ X(I)
X(O)
X(IO)
X(OE)
+X(OB)
+
// bels
X(DFF0)
X(DFF1)
@@ -735,6 +737,7 @@ X(IBUF)
X(OBUF)
X(IOBUF)
X(TBUF)
+X(TLVDS_OBUF)
// primitive attributes
X(INIT)
@@ -744,6 +747,8 @@ X(INPUT_USED)
X(OUTPUT_USED)
X(ENABLE_USED)
X(BEL)
+X(DIFF)
+X(DIFF_TYPE)
// ports
X(EN)
diff --git a/gowin/pack.cc b/gowin/pack.cc
index 268f26ef..cc715864 100644
--- a/gowin/pack.cc
+++ b/gowin/pack.cc
@@ -678,6 +678,85 @@ static bool is_gowin_iob(const Context *ctx, const CellInfo *cell)
}
}
+static bool is_gowin_diff_iob(const Context *ctx, const CellInfo *cell)
+{
+ switch (cell->type.index) {
+ case ID_TLVDS_OBUF:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool is_iob(const Context *ctx, const CellInfo *cell) { return (cell->type.index == ID_IOB); }
+
+// Pack differential IO buffers
+static void pack_diff_io(Context *ctx)
+{
+ pool<IdString> packed_cells;
+ pool<IdString> delete_nets;
+
+ std::vector<std::unique_ptr<CellInfo>> new_cells;
+ log_info("Packing diff IOs..\n");
+
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
+ if (ctx->verbose)
+ log_info("cell '%s' is of type '%s'\n", ctx->nameOf(ci), ci->type.c_str(ctx));
+ if (is_gowin_diff_iob(ctx, ci)) {
+ CellInfo *iob_p = nullptr;
+ CellInfo *iob_n = nullptr;
+ switch (ci->type.index) {
+ case ID_TLVDS_OBUF: {
+ iob_p = net_only_drives(ctx, ci->ports.at(id_O).net, is_iob, id_I);
+ iob_n = net_only_drives(ctx, ci->ports.at(id_OB).net, is_iob, id_I);
+ NPNR_ASSERT(iob_p != nullptr);
+ NPNR_ASSERT(iob_n != nullptr);
+ auto iob_p_bel_a = iob_p->attrs.find(id_BEL);
+ if (iob_p_bel_a == ci->attrs.end()) {
+ log_error("LVDS '%s' must be restricted.\n", ctx->nameOf(ci));
+ continue;
+ }
+ BelId iob_p_bel = ctx->getBelByNameStr(iob_p_bel_a->second.as_string());
+ Loc loc_p = ctx->getBelLocation(iob_p_bel);
+ if (loc_p.z != 0) {
+ log_error("LVDS '%s' positive pin is not A.\n", ctx->nameOf(ci));
+ continue;
+ }
+ // restrict the N buffer
+ loc_p.z = 1;
+ iob_n->attrs[id_BEL] = ctx->getBelName(ctx->getBelByLocation(loc_p)).str(ctx);
+ // mark IOBs as part of DS pair
+ iob_n->attrs[id_DIFF] = std::string("N");
+ iob_n->attrs[id_DIFF_TYPE] = std::string("TLVDS_OBUF");
+ iob_p->attrs[id_DIFF] = std::string("P");
+ iob_p->attrs[id_DIFF_TYPE] = std::string("TLVDS_OBUF");
+ // disconnect N input: it is wired internally
+ delete_nets.insert(iob_n->ports.at(id_I).net->name);
+ iob_n->disconnectPort(id_I);
+ ci->disconnectPort(id_OB);
+ // disconnect P output
+ delete_nets.insert(ci->ports.at(id_O).net->name);
+ ci->disconnectPort(id_O);
+ // connect TLVDS input to P input
+ ci->movePortTo(id_I, iob_p, id_I);
+ packed_cells.insert(ci->name);
+ } break;
+ default:
+ break;
+ }
+ }
+ }
+ for (auto pcell : packed_cells) {
+ ctx->cells.erase(pcell);
+ }
+ for (auto dnet : delete_nets) {
+ ctx->nets.erase(dnet);
+ }
+ for (auto &ncell : new_cells) {
+ ctx->cells[ncell->name] = std::move(ncell);
+ }
+}
// Pack IO buffers
static void pack_io(Context *ctx)
{
@@ -689,6 +768,8 @@ static void pack_io(Context *ctx)
for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second.get();
+ if (ctx->verbose)
+ log_info("cell '%s' is of type '%s'\n", ctx->nameOf(ci), ci->type.c_str(ctx));
if (is_gowin_iob(ctx, ci)) {
CellInfo *iob = nullptr;
switch (ci->type.index) {
@@ -776,6 +857,7 @@ bool Arch::pack()
log_break();
pack_constants(ctx);
pack_io(ctx);
+ pack_diff_io(ctx);
pack_wideluts(ctx);
pack_alus(ctx);
pack_lut_lutffs(ctx);