aboutsummaryrefslogtreecommitdiffstats
path: root/nexus
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2020-10-22 16:02:58 +0100
committerDavid Shah <dave@ds0.me>2020-11-30 08:45:28 +0000
commitf8dca82a713d2d90d29c70357c5c276bed5d7862 (patch)
tree31299885e38b431f9a0d83999003742bd96a69bf /nexus
parentf749038959b589467ce0605cf60f68f18d7573cd (diff)
downloadnextpnr-f8dca82a713d2d90d29c70357c5c276bed5d7862.tar.gz
nextpnr-f8dca82a713d2d90d29c70357c5c276bed5d7862.tar.bz2
nextpnr-f8dca82a713d2d90d29c70357c5c276bed5d7862.zip
nexus: Basic support for differential IO types
Signed-off-by: David Shah <dave@ds0.me>
Diffstat (limited to 'nexus')
-rw-r--r--nexus/arch.h31
-rw-r--r--nexus/fasm.cc89
-rw-r--r--nexus/io.cc70
-rw-r--r--nexus/pack.cc13
-rw-r--r--nexus/pins.cc6
5 files changed, 206 insertions, 3 deletions
diff --git a/nexus/arch.h b/nexus/arch.h
index 5924732b..85278272 100644
--- a/nexus/arch.h
+++ b/nexus/arch.h
@@ -813,6 +813,30 @@ enum CellPinMux
PINMUX_INV = 3,
};
+// This represents the various kinds of IO pins
+enum IOStyle
+{
+ IOBANK_WR = 0x1, // needs wide range IO bank
+ IOBANK_HP = 0x2, // needs high perf IO bank
+
+ IOMODE_REF = 0x10, // IO is referenced
+ IOMODE_DIFF = 0x20, // IO is true differential
+ IOMODE_PSEUDO_DIFF = 0x40, // IO is pseduo differential
+
+ IOSTYLE_SE_WR = 0x01, // single ended, wide range
+ IOSTYLE_SE_HP = 0x02, // single ended, high perf
+ IOSTYLE_PD_WR = 0x41, // pseudo diff, wide range
+
+ IOSTYLE_REF_HP = 0x12, // referenced high perf
+ IOSTYLE_DIFF_HP = 0x22, // differential high perf
+};
+
+struct IOTypeData
+{
+ IOStyle style;
+ int vcco; // required Vcco in 10mV
+};
+
// -----------------------------------------------------------------------
const int bba_version =
@@ -1456,6 +1480,13 @@ struct Arch : BaseCtx
std::string get_pad_functions(const PadInfoPOD *pad) const;
// -------------------------------------------------
+ // Data about different IO standard, mostly used by bitgen
+ static const std::unordered_map<std::string, IOTypeData> io_types;
+ int get_io_type_vcc(const std::string &io_type) const;
+ bool is_io_type_diff(const std::string &io_type) const;
+ bool is_io_type_ref(const std::string &io_type) const;
+
+ // -------------------------------------------------
// List of IO constraints, used by PDC parser
std::unordered_map<IdString, std::unordered_map<IdString, Property>> io_attr;
diff --git a/nexus/fasm.cc b/nexus/fasm.cc
index fdab3bca..bd710ae4 100644
--- a/nexus/fasm.cc
+++ b/nexus/fasm.cc
@@ -125,6 +125,18 @@ struct NexusFasmWriter
write_bit(stringf("%s.%s", name.c_str(), fnd->second.c_str()));
}
}
+ void write_ioattr_postfix(const CellInfo *cell, const std::string &name, const std::string &postfix,
+ const std::string &defval = "")
+ {
+ auto fnd = cell->attrs.find(ctx->id(name));
+ if (fnd == cell->attrs.end()) {
+ if (!defval.empty())
+ write_bit(stringf("%s_%s.%s", name.c_str(), postfix.c_str(), defval.c_str()));
+ } else {
+ write_bit(stringf("%s_%s.%s", name.c_str(), postfix.c_str(), fnd->second.c_str()));
+ }
+ }
+
// Gets the full name of a tile
std::string tile_name(int loc, const PhysicalTileInfoPOD &tile)
{
@@ -321,6 +333,16 @@ struct NexusFasmWriter
std::unordered_set<BelId> used_io;
+ struct BankConfig
+ {
+ bool diff_used = false;
+ bool lvds_used = false;
+ bool slvs_used = false;
+ bool dphy_used = false;
+ };
+
+ std::map<int, BankConfig> bank_cfg;
+
// Write config for an SEIO33_CORE cell
void write_io33(const CellInfo *cell)
{
@@ -359,6 +381,54 @@ struct NexusFasmWriter
const char *iodir = is_input ? "INPUT" : (is_output ? "OUTPUT" : "BIDIR");
write_bit(stringf("BASE_TYPE.%s_%s", iodir, str_or_default(cell->attrs, id_IO_TYPE, "LVCMOS18H").c_str()));
write_ioattr(cell, "PULLMODE", "NONE");
+ pop();
+ write_cell_muxes(cell);
+ pop();
+ }
+ // Write config for an SEIO18_CORE cell
+ void write_diffio18(const CellInfo *cell)
+ {
+ BelId bel = cell->bel;
+
+ Loc bel_loc = ctx->getBelLocation(bel);
+ for (int i = 0; i < 2; i++) {
+ // Mark both A and B pins as used
+ used_io.insert(ctx->getBelByLocation(Loc(bel_loc.x, bel_loc.y, i)));
+ }
+ push_belgroup(bel);
+ push("PIOA");
+ push("DIFFIO18");
+
+ auto &bank = bank_cfg[ctx->get_bel_pad(ctx->getBelByLocation(Loc(bel_loc.x, bel_loc.y, 0)))->bank];
+
+ bank.diff_used = true;
+
+ const NetInfo *t = get_net_or_empty(cell, id_T);
+ auto tmux = ctx->get_cell_pinmux(cell, id_T);
+ bool is_input = false, is_output = false;
+ if (tmux == PINMUX_0) {
+ is_output = true;
+ } else if (tmux == PINMUX_1 || t == nullptr) {
+ is_input = true;
+ }
+
+ const char *iodir = is_input ? "INPUT" : (is_output ? "OUTPUT" : "BIDIR");
+ std::string type = str_or_default(cell->attrs, id_IO_TYPE, "LVDS");
+ write_bit(stringf("BASE_TYPE.%s_%s", iodir, type.c_str()));
+ if (type == "LVDS") {
+ write_ioattr_postfix(cell, "DIFFDRIVE", "LVDS", "3P5");
+ bank.lvds_used = true;
+ } else if (type == "SLVS") {
+ write_ioattr_postfix(cell, "DIFFDRIVE", "SLVS", "2P0");
+ bank.slvs_used = true;
+ } else if (type == "MIPI_DPHY") {
+ write_ioattr_postfix(cell, "DIFFDRIVE", "MIPI_DPHY", "2P0");
+ bank.dphy_used = true;
+ }
+
+ write_ioattr(cell, "PULLMODE", "FAILSAFE");
+ write_ioattr(cell, "DIFFRESISTOR");
+ pop();
write_cell_muxes(cell);
pop(2);
}
@@ -505,9 +575,20 @@ struct NexusFasmWriter
void write_bankcfg()
{
for (int i = 0; i < 8; i++) {
- if (i >= 3 && i <= 5)
- continue; // 1.8V banks, skip for now
- write_bit(stringf("GLOBAL.BANK%d.VCC.3V3", i));
+ if (i >= 3 && i <= 5) {
+ // 1.8V banks
+ push(stringf("GLOBAL.BANK%d", i));
+ auto &bank = bank_cfg[i];
+ write_bit("DIFF_IO.ON", bank.diff_used);
+ write_bit("LVDS_IO.ON", bank.lvds_used);
+ write_bit("SLVS_IO.ON", bank.slvs_used);
+ write_bit("MIPI_DPHY_IO.ON", bank.dphy_used);
+
+ pop();
+ } else {
+ // 3.3V banks, this should eventually be set based on the bank config
+ write_bit(stringf("GLOBAL.BANK%d.VCC.3V3", i));
+ }
}
blank();
}
@@ -536,6 +617,8 @@ struct NexusFasmWriter
write_io33(ci);
else if (ci->type == id_SEIO18_CORE)
write_io18(ci);
+ else if (ci->type == id_DIFFIO18_CORE)
+ write_diffio18(ci);
else if (ci->type == id_OSC_CORE)
write_osc(ci);
else if (ci->type == id_OXIDE_EBR)
diff --git a/nexus/io.cc b/nexus/io.cc
new file mode 100644
index 00000000..fd5e584f
--- /dev/null
+++ b/nexus/io.cc
@@ -0,0 +1,70 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2020 David Shah <dave@ds0.me>
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "log.h"
+#include "nextpnr.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+const std::unordered_map<std::string, IOTypeData> Arch::io_types = {
+ {"LVCMOS33", {IOSTYLE_SE_WR, 330}}, {"LVCMOS25", {IOSTYLE_SE_WR, 250}},
+ {"LVCMOS18", {IOSTYLE_SE_WR, 180}}, {"LVCMOS15", {IOSTYLE_SE_WR, 150}},
+ {"LVCMOS12", {IOSTYLE_SE_WR, 120}}, {"LVCMOS10", {IOSTYLE_SE_WR, 120}},
+
+ {"LVCMOS33D", {IOSTYLE_PD_WR, 330}}, {"LVCMOS25D", {IOSTYLE_PD_WR, 250}},
+
+ {"LVCMOS18H", {IOSTYLE_SE_HP, 180}}, {"LVCMOS15H", {IOSTYLE_SE_HP, 150}},
+ {"LVCMOS12H", {IOSTYLE_SE_HP, 120}}, {"LVCMOS10R", {IOSTYLE_SE_HP, 120}},
+ {"LVCMOS10H", {IOSTYLE_SE_HP, 100}},
+
+ {"HSTL15_I", {IOSTYLE_REF_HP, 150}}, {"SSTL15_I", {IOSTYLE_REF_HP, 150}},
+ {"SSTL15_II", {IOSTYLE_REF_HP, 150}}, {"SSTL135_I", {IOSTYLE_REF_HP, 135}},
+ {"SSTL135_II", {IOSTYLE_REF_HP, 135}}, {"HSUL12", {IOSTYLE_REF_HP, 120}},
+
+ {"LVDS", {IOSTYLE_DIFF_HP, 180}}, {"SLVS", {IOSTYLE_DIFF_HP, 120}},
+ {"MIPI_DPHY", {IOSTYLE_DIFF_HP, 120}}, {"HSUL12D", {IOSTYLE_DIFF_HP, 120}},
+
+ {"HSTL15D_I", {IOSTYLE_DIFF_HP, 150}}, {"SSTL15D_I", {IOSTYLE_DIFF_HP, 150}},
+ {"SSTL15D_II", {IOSTYLE_DIFF_HP, 150}}, {"SSTL135D_I", {IOSTYLE_DIFF_HP, 135}},
+ {"SSTL135D_II", {IOSTYLE_DIFF_HP, 135}}, {"HSUL12D", {IOSTYLE_DIFF_HP, 120}},
+};
+
+int Arch::get_io_type_vcc(const std::string &io_type) const
+{
+ if (!io_types.count(io_type))
+ log_error("IO type '%s' not supported.\n", io_type.c_str());
+ return io_types.at(io_type).vcco;
+}
+
+bool Arch::is_io_type_diff(const std::string &io_type) const
+{
+ if (!io_types.count(io_type))
+ log_error("IO type '%s' not supported.\n", io_type.c_str());
+ return io_types.at(io_type).style & IOMODE_DIFF;
+}
+
+bool Arch::is_io_type_ref(const std::string &io_type) const
+{
+ if (!io_types.count(io_type))
+ log_error("IO type '%s' not supported.\n", io_type.c_str());
+ return io_types.at(io_type).style & IOMODE_REF;
+}
+
+NEXTPNR_NAMESPACE_END
diff --git a/nexus/pack.cc b/nexus/pack.cc
index abe963ba..e12ce305 100644
--- a/nexus/pack.cc
+++ b/nexus/pack.cc
@@ -594,6 +594,19 @@ struct NexusPacker
// Get IO type for reporting purposes
std::string io_type = str_or_default(ci->attrs, id_IO_TYPE, "LVCMOS33");
+ if (ctx->is_io_type_diff(io_type)) {
+ // Convert from SEIO18 to DIFFIO18
+ if (ctx->getBelType(bel) != id_SEIO18_CORE)
+ log_error("IO '%s' uses differential type '%s' but is placed on wide range pin '%s'\n",
+ ctx->nameOf(ci), io_type.c_str(), loc.c_str());
+ Loc bel_loc = ctx->getBelLocation(bel);
+ if (bel_loc.z != 0)
+ log_error("IO '%s' uses differential type '%s' but is placed on 'B' side pin '%s'\n",
+ ctx->nameOf(ci), io_type.c_str(), loc.c_str());
+ bel_loc.z = 2;
+ bel = ctx->getBelByLocation(bel_loc);
+ }
+
log_info("Constraining %s IO '%s' to pin %s (%s%sbel %s)\n", io_type.c_str(), ctx->nameOf(ci),
loc.c_str(), func.c_str(), func.empty() ? "" : "; ", ctx->nameOfBel(bel));
ci->attrs[id_BEL] = ctx->getBelName(bel).str(ctx);
diff --git a/nexus/pins.cc b/nexus/pins.cc
index de92f2b6..f2946657 100644
--- a/nexus/pins.cc
+++ b/nexus/pins.cc
@@ -58,6 +58,12 @@ static const std::unordered_map<IdString, Arch::CellPinsData> base_cell_pin_data
{id_B, PINSTYLE_DEDI},
{{}, PINSTYLE_PU},
}},
+ {id_DIFFIO18_CORE,
+ {
+ {id_T, PINSTYLE_T},
+ {id_B, PINSTYLE_DEDI},
+ {{}, PINSTYLE_PU},
+ }},
{id_SEIO33_CORE,
{
{id_T, PINSTYLE_T},