From 519d4e2af8d8e7d8e2d1d873b9cd9681ef83cc62 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sat, 17 Nov 2018 13:04:14 +0100 Subject: [PATCH] ice40: Add support for SB_GB_IO During packing we replace them by standard SB_IO cells and create the 'fake' SB_GB that matches that IO site global buffer connection. It's done in a separate pass because we need to make sure the nextpnr iob have been dealt first so we have our final Bel location on the SB_IO. Signed-off-by: Sylvain Munaut --- ice40/arch.cc | 1 + ice40/archdefs.h | 1 + ice40/bitstream.cc | 1 + ice40/cells.h | 3 +++ ice40/pack.cc | 33 +++++++++++++++++++++++++-------- 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index 3138b813..259eec67 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -1044,6 +1044,7 @@ void Arch::assignCellInfo(CellInfo *cell) cell->lcInfo.inputCount++; } else if (cell->type == id_SB_IO) { cell->ioInfo.lvds = str_or_default(cell->params, id_IO_STANDARD, "SB_LVCMOS") == "SB_LVDS_INPUT"; + cell->ioInfo.global = bool_or_default(cell->attrs, this->id("GLOBAL")); } else if (cell->type == id_SB_GB) { cell->gbInfo.forPadIn = bool_or_default(cell->attrs, this->id("FOR_PAD_IN")); } diff --git a/ice40/archdefs.h b/ice40/archdefs.h index 8dcf0365..2bffe667 100644 --- a/ice40/archdefs.h +++ b/ice40/archdefs.h @@ -150,6 +150,7 @@ struct ArchCellInfo struct { bool lvds; + bool global; // TODO: clk packing checks... } ioInfo; struct diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index d2c2ac16..44d385e4 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -514,6 +514,7 @@ void write_asc(const Context *ctx, std::ostream &out) } input_en = (input_en & !used_by_pll_out) | used_by_pll_pad; + input_en |= cell.second->ioInfo.global; if (ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K) { set_config(ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), !input_en); diff --git a/ice40/cells.h b/ice40/cells.h index 7f349020..270292ed 100644 --- a/ice40/cells.h +++ b/ice40/cells.h @@ -53,6 +53,9 @@ inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type // Return true if a cell is a SB_IO inline bool is_sb_io(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_IO"); } +// Return true if a cell is a SB_GB_IO +inline bool is_sb_gb_io(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_GB_IO"); } + // Return true if a cell is a global buffer inline bool is_gbuf(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_GB"); } diff --git a/ice40/pack.cc b/ice40/pack.cc index ca67baab..a40f0878 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -414,6 +414,11 @@ static bool is_nextpnr_iob(Context *ctx, CellInfo *cell) cell->type == ctx->id("$nextpnr_iobuf"); } +static bool is_ice_iob(const Context *ctx, const CellInfo *cell) +{ + return is_sb_io(ctx, cell) || is_sb_gb_io(ctx, cell); +} + // Pack IO buffers static void pack_io(Context *ctx) { @@ -428,10 +433,10 @@ static void pack_io(Context *ctx) if (is_nextpnr_iob(ctx, ci)) { CellInfo *sb = nullptr; if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) { - sb = net_only_drives(ctx, ci->ports.at(ctx->id("O")).net, is_sb_io, ctx->id("PACKAGE_PIN"), true, ci); + sb = net_only_drives(ctx, ci->ports.at(ctx->id("O")).net, is_ice_iob, ctx->id("PACKAGE_PIN"), true, ci); } else if (ci->type == ctx->id("$nextpnr_obuf")) { - sb = net_only_drives(ctx, ci->ports.at(ctx->id("I")).net, is_sb_io, ctx->id("PACKAGE_PIN"), true, ci); + sb = net_only_drives(ctx, ci->ports.at(ctx->id("I")).net, is_ice_iob, ctx->id("PACKAGE_PIN"), true, ci); } if (sb != nullptr) { // Trivial case, SB_IO used. Just destroy the net and the @@ -442,8 +447,8 @@ static void pack_io(Context *ctx) if (((ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) && net->users.size() > 1) || (ci->type == ctx->id("$nextpnr_obuf") && (net->users.size() > 2 || net->driver.cell != nullptr))) - log_error("PACKAGE_PIN of SB_IO '%s' connected to more than a single top level IO.\n", - sb->name.c_str(ctx)); + log_error("PACKAGE_PIN of %s '%s' connected to more than a single top level IO.\n", + sb->type.c_str(ctx), sb->name.c_str(ctx)); if (net != nullptr) { delete_nets.insert(net->name); @@ -465,13 +470,26 @@ static void pack_io(Context *ctx) } packed_cells.insert(ci->name); std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(sb->attrs, sb->attrs.begin())); - } else if (is_sb_io(ctx, ci)) { + } else if (is_sb_io(ctx, ci) || is_sb_gb_io(ctx, ci)) { NetInfo *net = ci->ports.at(ctx->id("PACKAGE_PIN")).net; if ((net != nullptr) && (net->users.size() > 1)) - log_error("PACKAGE_PIN of SB_IO '%s' connected to more than a single top level IO.\n", + log_error("PACKAGE_PIN of %s '%s' connected to more than a single top level IO.\n", ci->type.c_str(ctx), ci->name.c_str(ctx)); } } + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (is_sb_gb_io(ctx, ci)) { + // If something is connecto the GLOBAL OUTPUT, create the fake 'matching' SB_GB + std::unique_ptr gb = + create_padin_gbuf(ctx, ci, id_GLOBAL_BUFFER_OUTPUT, "$gbuf_" + ci->name.str(ctx) + "_io"); + new_cells.push_back(std::move(gb)); + + // Make it a normal SB_IO with global marker + ci->type = ctx->id("SB_IO"); + ci->attrs[ctx->id("GLOBAL")] = "1"; + } + } for (auto pcell : packed_cells) { ctx->cells.erase(pcell); } @@ -488,8 +506,7 @@ static bool is_logic_port(BaseCtx *ctx, const PortRef &port) { if (is_clock_port(ctx, port) || is_reset_port(ctx, port) || is_enable_port(ctx, port)) return false; - return !is_sb_io(ctx, port.cell) && - !is_gbuf(ctx, port.cell) && + return !is_sb_io(ctx, port.cell) && !is_sb_gb_io(ctx, port.cell) && !is_gbuf(ctx, port.cell) && !is_sb_pll40(ctx, port.cell); }