From 19f5d24b7933e2812b0b3278c7b6be5d6afe40bd Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 18 Dec 2024 08:56:54 +0100 Subject: [PATCH] Restructure code --- himbaechel/uarch/gatemate/bitstream.cc | 151 ++++++++++++++++ himbaechel/uarch/gatemate/constids.inc | 8 + himbaechel/uarch/gatemate/gatemate.cc | 234 +------------------------ himbaechel/uarch/gatemate/gatemate.h | 4 +- himbaechel/uarch/gatemate/gfx.cc | 54 ++++++ himbaechel/uarch/gatemate/pack.cc | 141 +++++++++++++++ himbaechel/uarch/gatemate/pack.h | 40 +++++ 7 files changed, 397 insertions(+), 235 deletions(-) create mode 100644 himbaechel/uarch/gatemate/bitstream.cc create mode 100644 himbaechel/uarch/gatemate/gfx.cc create mode 100644 himbaechel/uarch/gatemate/pack.cc create mode 100644 himbaechel/uarch/gatemate/pack.h diff --git a/himbaechel/uarch/gatemate/bitstream.cc b/himbaechel/uarch/gatemate/bitstream.cc new file mode 100644 index 00000000..a80b643a --- /dev/null +++ b/himbaechel/uarch/gatemate/bitstream.cc @@ -0,0 +1,151 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2024 The Project Peppercorn Authors. + * + * 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 + +#include "config.h" +#include "gatemate.h" + +#define HIMBAECHEL_CONSTIDS "uarch/gatemate/constids.inc" +#include "himbaechel_constids.h" + +NEXTPNR_NAMESPACE_BEGIN + +namespace { + +struct BitstreamBackend +{ + Context *ctx; + GateMateImpl *uarch; + const std::string &device; + std::ostream &out; + + BitstreamBackend(Context *ctx, GateMateImpl *uarch, const std::string &device, std::ostream &out) + : ctx(ctx), uarch(uarch), device(device), out(out) {}; + + void get_bitstream_tile(int x, int y, int &b_x, int &b_y) + { + // Edge blocks are bit bigger + if (x == -2) + x++; + if (x == 163) + x--; + if (y == -2) + y++; + if (y == 131) + y--; + b_x = (x + 1) / 2; + b_y = (y + 1) / 2; + } + + std::vector int_to_bitvector(int val, int size) + { + std::vector bv; + for (int i = 0; i < size; i++) { + bv.push_back((val & (1 << i)) != 0); + } + return bv; + } + + std::vector str_to_bitvector(std::string str, int size) + { + std::vector bv; + bv.resize(size, 0); + for (int i = 0; i < int(str.size()); i++) { + char c = str.at((str.size() - i) - 1); + NPNR_ASSERT(c == '0' || c == '1'); + bv.at(i) = (c == '1'); + } + return bv; + } + + CfgLoc getConfigLoc(Context *ctx, int tile) + { + int x0, y0; + int bx, by; + tile_xy(ctx->chip_info, tile, x0, y0); + get_bitstream_tile(x0 - 2, y0 - 2, bx, by); + CfgLoc loc; + loc.die = 0; + loc.x = bx; + loc.y = by; + return loc; + } + + void write_bitstream() + { + ChipConfig cc; + cc.chip_name = device; + cc.configs[0].add_word("GPIO.BANK_E1", int_to_bitvector(1, 1)); + cc.configs[0].add_word("GPIO.BANK_E2", int_to_bitvector(1, 1)); + cc.configs[0].add_word("GPIO.BANK_N1", int_to_bitvector(1, 1)); + cc.configs[0].add_word("GPIO.BANK_N2", int_to_bitvector(1, 1)); + cc.configs[0].add_word("GPIO.BANK_S1", int_to_bitvector(1, 1)); + cc.configs[0].add_word("GPIO.BANK_S2", int_to_bitvector(1, 1)); + cc.configs[0].add_word("GPIO.BANK_W1", int_to_bitvector(1, 1)); + cc.configs[0].add_word("GPIO.BANK_W2", int_to_bitvector(1, 1)); + for (auto &cell : ctx->cells) { + switch (cell.second->type.index) { + case id_GPIO.index: { + CfgLoc loc = getConfigLoc(ctx, cell.second.get()->bel.tile); + cc.tiles[loc].add_word( + "GPIO.INIT", + str_to_bitvector(str_or_default(cell.second.get()->params, ctx->id("INIT"), ""), 72)); + break; + } + default: + break; + } + } + + for (auto &net : ctx->nets) { + NetInfo *ni = net.second.get(); + if (ni->wires.empty()) + continue; + std::set nets; + for (auto &w : ni->wires) { + if (w.second.pip != PipId()) { + PipId pip = w.second.pip; + const auto extra_data = *reinterpret_cast( + chip_pip_info(ctx->chip_info, pip).extra_data.get()); + if (extra_data.name != 0) { + IdString name = IdString(extra_data.name); + CfgLoc loc = getConfigLoc(ctx, pip.tile); + cc.tiles[loc].add_word(name.c_str(ctx), int_to_bitvector(extra_data.value, extra_data.bits)); + } + } + } + } + out << cc; + } +}; + +} // namespace + +void GateMateImpl::write_bitstream(const std::string &device, const std::string &filename) +{ + std::ofstream out(filename); + if (!out) + log_error("failed to open file %s for writing (%s)\n", filename.c_str(), strerror(errno)); + + BitstreamBackend be(ctx, this, device, out); + be.write_bitstream(); +} + +NEXTPNR_NAMESPACE_END diff --git a/himbaechel/uarch/gatemate/constids.inc b/himbaechel/uarch/gatemate/constids.inc index 8c1ecc92..43431bfe 100644 --- a/himbaechel/uarch/gatemate/constids.inc +++ b/himbaechel/uarch/gatemate/constids.inc @@ -36,6 +36,14 @@ X(GPIO) X(CC_IBUF) X(CC_OBUF) +X(CC_TOBUF) +X(CC_IOBUF) +X(CC_LVDS_IBUF) +X(CC_LVDS_OBUF) +X(CC_LVDS_TOBUF) +X(CC_LVDS_IOBUF) +X(CC_IDDR) +X(CC_ODDR) X(I) X(O) X(DI) diff --git a/himbaechel/uarch/gatemate/gatemate.cc b/himbaechel/uarch/gatemate/gatemate.cc index 3f21311a..356222d6 100644 --- a/himbaechel/uarch/gatemate/gatemate.cc +++ b/himbaechel/uarch/gatemate/gatemate.cc @@ -17,25 +17,12 @@ * */ -#include -#include "extra_data.h" -#include "himbaechel_api.h" -#include "log.h" -#include "nextpnr.h" -#include "util.h" - -#include "himbaechel_helpers.h" - -#include "config.h" #include "gatemate.h" #define GEN_INIT_CONSTIDS #define HIMBAECHEL_CONSTIDS "uarch/gatemate/constids.inc" -#define HIMBAECHEL_GFXIDS "uarch/gatemate/gfxids.inc" -#define HIMBAECHEL_UARCH gatemate #include "himbaechel_constids.h" -#include "himbaechel_gfxids.h" NEXTPNR_NAMESPACE_BEGIN @@ -50,132 +37,7 @@ void GateMateImpl::init_database(Arch *arch) arch->set_speed_grade("DEFAULT"); } -void GateMateImpl::init(Context *ctx) -{ - h.init(ctx); - HimbaechelAPI::init(ctx); -} - -void GateMateImpl::drawBel(std::vector &g, GraphicElement::style_t style, IdString bel_type, Loc loc) -{ - GraphicElement el; - el.type = GraphicElement::TYPE_BOX; - el.style = style; - switch (bel_type.index) { - case id_CPE.index: - el.x1 = loc.x + 0.70; - el.x2 = el.x1 + 0.20; - el.y1 = loc.y + 0.55; - el.y2 = el.y1 + 0.40; - g.push_back(el); - break; - case id_GPIO.index: - el.x1 = loc.x + 0.20; - el.x2 = el.x1 + 0.60; - el.y1 = loc.y + 0.20; - el.y2 = el.y1 + 0.60; - g.push_back(el); - break; - } -} - -void GateMateImpl::pack() -{ - const ArchArgs &args = ctx->args; - if (args.options.count("ccf")) { - parse_ccf(args.options.at("ccf")); - } - // Trim nextpnr IOBs - assume IO buffer insertion has been done in synthesis - for (auto &port : ctx->ports) { - if (!ctx->cells.count(port.first)) - log_error("Port '%s' doesn't seem to have a corresponding top level IO\n", ctx->nameOf(port.first)); - CellInfo *ci = ctx->cells.at(port.first).get(); - - PortRef top_port; - top_port.cell = nullptr; - bool is_npnr_iob = false; - - if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) { - // Might have an input buffer connected to it - is_npnr_iob = true; - NetInfo *o = ci->getPort(id_O); - if (o == nullptr) - ; - else if (o->users.entries() > 1) - log_error("Top level pin '%s' has multiple input buffers\n", ctx->nameOf(port.first)); - else if (o->users.entries() == 1) - top_port = *o->users.begin(); - } - if (ci->type == ctx->id("$nextpnr_obuf") || ci->type == ctx->id("$nextpnr_iobuf")) { - // Might have an output buffer connected to it - is_npnr_iob = true; - NetInfo *i = ci->getPort(id_I); - if (i != nullptr && i->driver.cell != nullptr) { - if (top_port.cell != nullptr) - log_error("Top level pin '%s' has multiple input/output buffers\n", ctx->nameOf(port.first)); - top_port = i->driver; - } - // Edge case of a bidirectional buffer driving an output pin - if (i->users.entries() > 2) { - log_error("Top level pin '%s' has illegal buffer configuration\n", ctx->nameOf(port.first)); - } else if (i->users.entries() == 2) { - if (top_port.cell != nullptr) - log_error("Top level pin '%s' has illegal buffer configuration\n", ctx->nameOf(port.first)); - for (auto &usr : i->users) { - if (usr.cell->type == ctx->id("$nextpnr_obuf") || usr.cell->type == ctx->id("$nextpnr_iobuf")) - continue; - top_port = usr; - break; - } - } - } - if (!is_npnr_iob) - log_error("Port '%s' doesn't seem to have a corresponding top level IO (internal cell type mismatch)\n", - ctx->nameOf(port.first)); - - if (top_port.cell == nullptr) { - log_info("Trimming port '%s' as it is unused.\n", ctx->nameOf(port.first)); - } else { - // Copy attributes to real IO buffer - for (auto &attrs : ci->attrs) - top_port.cell->attrs[attrs.first] = attrs.second; - for (auto ¶ms : ci->params) - top_port.cell->params[params.first] = params.second; - - // Make sure that top level net is set correctly - port.second.net = top_port.cell->ports.at(top_port.port).net; - } - // Now remove the nextpnr-inserted buffer - ci->disconnectPort(id_I); - ci->disconnectPort(id_O); - ctx->cells.erase(port.first); - } - - for (auto &cell : ctx->cells) { - CellInfo &ci = *cell.second; - if (!ci.type.in(id_CC_IBUF, id_CC_OBUF)) - continue; - if (ci.type == id_CC_IBUF) { - ci.renamePort(id_I, id_DI); - ci.renamePort(id_Y, id_IN1); - std::string loc = ci.params.at(ctx->id("LOC")).to_string(); - BelId bel = ctx->get_package_pin_bel(ctx->id(loc)); - ci.params[ctx->id("INIT")] = - Property("000000000000000000000001000000000000000000000000000000000000000001010000"); - ctx->bindBel(bel, &ci, PlaceStrength::STRENGTH_FIXED); - } - if (ci.type == id_CC_OBUF) { - ci.renamePort(id_O, id_DO); - ci.renamePort(id_A, id_OUT2); - ci.params[ctx->id("INIT")] = - Property("000000000000000000000000000000000000000100000000000000010000100100000000"); - std::string loc = ci.params.at(ctx->id("LOC")).to_string(); - BelId bel = ctx->get_package_pin_bel(ctx->id(loc)); - ctx->bindBel(bel, &ci, PlaceStrength::STRENGTH_FIXED); - } - ci.type = id_GPIO; - } -} +void GateMateImpl::init(Context *ctx) { HimbaechelAPI::init(ctx); } delay_t GateMateImpl::estimateDelay(WireId src, WireId dst) const { @@ -186,103 +48,11 @@ delay_t GateMateImpl::estimateDelay(WireId src, WireId dst) const return 100 * (std::abs(dx - sx) / 4 + std::abs(dy - sy) / 4 + 2); } -void get_bitstream_tile(int x, int y, int &b_x, int &b_y) -{ - // Edge blocks are bit bigger - if (x == -2) - x++; - if (x == 163) - x--; - if (y == -2) - y++; - if (y == 131) - y--; - b_x = (x + 1) / 2; - b_y = (y + 1) / 2; -} - -std::vector int_to_bitvector(int val, int size) -{ - std::vector bv; - for (int i = 0; i < size; i++) { - bv.push_back((val & (1 << i)) != 0); - } - return bv; -} - -std::vector str_to_bitvector(std::string str, int size) -{ - std::vector bv; - bv.resize(size, 0); - for (int i = 0; i < int(str.size()); i++) { - char c = str.at((str.size() - i) - 1); - NPNR_ASSERT(c == '0' || c == '1'); - bv.at(i) = (c == '1'); - } - return bv; -} - -CfgLoc getConfigLoc(Context *ctx, int tile) -{ - int x0, y0; - int bx, by; - tile_xy(ctx->chip_info, tile, x0, y0); - get_bitstream_tile(x0 - 2, y0 - 2, bx, by); - CfgLoc loc; - loc.die = 0; - loc.x = bx; - loc.y = by; - return loc; -} - void GateMateImpl::postRoute() { const ArchArgs &args = ctx->args; if (args.options.count("out")) { - ChipConfig cc; - cc.chip_name = args.device; - cc.configs[0].add_word("GPIO.BANK_E1", int_to_bitvector(1, 1)); - cc.configs[0].add_word("GPIO.BANK_E2", int_to_bitvector(1, 1)); - cc.configs[0].add_word("GPIO.BANK_N1", int_to_bitvector(1, 1)); - cc.configs[0].add_word("GPIO.BANK_N2", int_to_bitvector(1, 1)); - cc.configs[0].add_word("GPIO.BANK_S1", int_to_bitvector(1, 1)); - cc.configs[0].add_word("GPIO.BANK_S2", int_to_bitvector(1, 1)); - cc.configs[0].add_word("GPIO.BANK_W1", int_to_bitvector(1, 1)); - cc.configs[0].add_word("GPIO.BANK_W2", int_to_bitvector(1, 1)); - for (auto &cell : ctx->cells) { - switch (cell.second->type.index) { - case id_GPIO.index: { - CfgLoc loc = getConfigLoc(ctx, cell.second.get()->bel.tile); - cc.tiles[loc].add_word( - "GPIO.INIT", - str_to_bitvector(str_or_default(cell.second.get()->params, ctx->id("INIT"), ""), 72)); - break; - } - default: - break; - } - } - - for (auto &net : ctx->nets) { - NetInfo *ni = net.second.get(); - if (ni->wires.empty()) - continue; - std::set nets; - for (auto &w : ni->wires) { - if (w.second.pip != PipId()) { - PipId pip = w.second.pip; - const auto extra_data = *reinterpret_cast( - chip_pip_info(ctx->chip_info, pip).extra_data.get()); - if (extra_data.name != 0) { - IdString name = IdString(extra_data.name); - CfgLoc loc = getConfigLoc(ctx, pip.tile); - cc.tiles[loc].add_word(name.c_str(ctx), int_to_bitvector(extra_data.value, extra_data.bits)); - } - } - } - } - std::ofstream out_config(args.options.at("out")); - out_config << cc; + write_bitstream(args.device, args.options.at("out")); } } diff --git a/himbaechel/uarch/gatemate/gatemate.h b/himbaechel/uarch/gatemate/gatemate.h index 9a7a892b..9da903e6 100644 --- a/himbaechel/uarch/gatemate/gatemate.h +++ b/himbaechel/uarch/gatemate/gatemate.h @@ -45,10 +45,8 @@ struct GateMateImpl : HimbaechelAPI void drawBel(std::vector &g, GraphicElement::style_t style, IdString bel_type, Loc loc) override; + void write_bitstream(const std::string &device, const std::string &filename); void parse_ccf(const std::string &filename); - - private: - HimbaechelHelpers h; }; NEXTPNR_NAMESPACE_END diff --git a/himbaechel/uarch/gatemate/gfx.cc b/himbaechel/uarch/gatemate/gfx.cc new file mode 100644 index 00000000..21ed304b --- /dev/null +++ b/himbaechel/uarch/gatemate/gfx.cc @@ -0,0 +1,54 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2024 The Project Peppercorn Authors. + * + * 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 "gatemate.h" + +#define HIMBAECHEL_CONSTIDS "uarch/gatemate/constids.inc" +#define HIMBAECHEL_GFXIDS "uarch/gatemate/gfxids.inc" +#define HIMBAECHEL_UARCH gatemate + +#include "himbaechel_constids.h" +#include "himbaechel_gfxids.h" + +NEXTPNR_NAMESPACE_BEGIN + +void GateMateImpl::drawBel(std::vector &g, GraphicElement::style_t style, IdString bel_type, Loc loc) +{ + GraphicElement el; + el.type = GraphicElement::TYPE_BOX; + el.style = style; + switch (bel_type.index) { + case id_CPE.index: + el.x1 = loc.x + 0.70; + el.x2 = el.x1 + 0.20; + el.y1 = loc.y + 0.55; + el.y2 = el.y1 + 0.40; + g.push_back(el); + break; + case id_GPIO.index: + el.x1 = loc.x + 0.20; + el.x2 = el.x1 + 0.60; + el.y1 = loc.y + 0.20; + el.y2 = el.y1 + 0.60; + g.push_back(el); + break; + } +} + +NEXTPNR_NAMESPACE_END \ No newline at end of file diff --git a/himbaechel/uarch/gatemate/pack.cc b/himbaechel/uarch/gatemate/pack.cc new file mode 100644 index 00000000..9cc100d3 --- /dev/null +++ b/himbaechel/uarch/gatemate/pack.cc @@ -0,0 +1,141 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2024 The Project Peppercorn Authors. + * + * 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 "pack.h" + +#define HIMBAECHEL_CONSTIDS "uarch/gatemate/constids.inc" +#include "himbaechel_constids.h" + +NEXTPNR_NAMESPACE_BEGIN + +void GateMatePacker::pack_io() +{ + // Trim nextpnr IOBs - assume IO buffer insertion has been done in synthesis + for (auto &port : ctx->ports) { + if (!ctx->cells.count(port.first)) + log_error("Port '%s' doesn't seem to have a corresponding top level IO\n", ctx->nameOf(port.first)); + CellInfo *ci = ctx->cells.at(port.first).get(); + + PortRef top_port; + top_port.cell = nullptr; + bool is_npnr_iob = false; + + if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) { + // Might have an input buffer connected to it + is_npnr_iob = true; + NetInfo *o = ci->getPort(id_O); + if (o == nullptr) + ; + else if (o->users.entries() > 1) + log_error("Top level pin '%s' has multiple input buffers\n", ctx->nameOf(port.first)); + else if (o->users.entries() == 1) + top_port = *o->users.begin(); + } + if (ci->type == ctx->id("$nextpnr_obuf") || ci->type == ctx->id("$nextpnr_iobuf")) { + // Might have an output buffer connected to it + is_npnr_iob = true; + NetInfo *i = ci->getPort(id_I); + if (i != nullptr && i->driver.cell != nullptr) { + if (top_port.cell != nullptr) + log_error("Top level pin '%s' has multiple input/output buffers\n", ctx->nameOf(port.first)); + top_port = i->driver; + } + // Edge case of a bidirectional buffer driving an output pin + if (i->users.entries() > 2) { + log_error("Top level pin '%s' has illegal buffer configuration\n", ctx->nameOf(port.first)); + } else if (i->users.entries() == 2) { + if (top_port.cell != nullptr) + log_error("Top level pin '%s' has illegal buffer configuration\n", ctx->nameOf(port.first)); + for (auto &usr : i->users) { + if (usr.cell->type == ctx->id("$nextpnr_obuf") || usr.cell->type == ctx->id("$nextpnr_iobuf")) + continue; + top_port = usr; + break; + } + } + } + if (!is_npnr_iob) + log_error("Port '%s' doesn't seem to have a corresponding top level IO (internal cell type mismatch)\n", + ctx->nameOf(port.first)); + + if (top_port.cell == nullptr) { + log_info("Trimming port '%s' as it is unused.\n", ctx->nameOf(port.first)); + } else { + // Copy attributes to real IO buffer + for (auto &attrs : ci->attrs) + top_port.cell->attrs[attrs.first] = attrs.second; + for (auto ¶ms : ci->params) + top_port.cell->params[params.first] = params.second; + + // Make sure that top level net is set correctly + port.second.net = top_port.cell->ports.at(top_port.port).net; + } + // Now remove the nextpnr-inserted buffer + ci->disconnectPort(id_I); + ci->disconnectPort(id_O); + ctx->cells.erase(port.first); + } + + for (auto &cell : ctx->cells) { + CellInfo &ci = *cell.second; + if (!ci.type.in(id_CC_IBUF, id_CC_OBUF)) + continue; + std::string loc; + if (ci.params.count(ctx->id("LOC")) == 0) { + log_warning("IO signal name '%s' is not defined in CCF file and will be auto-placed.\n", ctx->nameOf(&ci)); + } else { + loc = ci.params.at(ctx->id("LOC")).to_string(); + } + + if (ci.type == id_CC_IBUF) { + ci.renamePort(id_I, id_DI); + ci.renamePort(id_Y, id_IN1); + ci.params[ctx->id("INIT")] = + Property("000000000000000000000001000000000000000000000000000000000000000001010000"); + } + if (ci.type == id_CC_OBUF) { + ci.renamePort(id_O, id_DO); + ci.renamePort(id_A, id_OUT2); + ci.params[ctx->id("INIT")] = + Property("000000000000000000000000000000000000000100000000000000010000100100000000"); + } + if (!loc.empty()) { + BelId bel = ctx->get_package_pin_bel(ctx->id(loc)); + if (bel == BelId()) + log_error("Unable to constrain IO '%s', device does not have a pin named '%s'\n", ci.name.c_str(ctx), + loc.c_str()); + log_info(" Constraining '%s' to pad '%s'\n", ci.name.c_str(ctx), loc.c_str()); + + ctx->bindBel(bel, &ci, PlaceStrength::STRENGTH_FIXED); + } + ci.type = id_GPIO; + } +} +void GateMateImpl::pack() +{ + const ArchArgs &args = ctx->args; + if (args.options.count("ccf")) { + parse_ccf(args.options.at("ccf")); + } + + GateMatePacker packer(ctx, this); + packer.pack_io(); +} + +NEXTPNR_NAMESPACE_END diff --git a/himbaechel/uarch/gatemate/pack.h b/himbaechel/uarch/gatemate/pack.h new file mode 100644 index 00000000..219484b8 --- /dev/null +++ b/himbaechel/uarch/gatemate/pack.h @@ -0,0 +1,40 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2024 The Project Peppercorn Authors. + * + * 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. + * + */ + +#ifndef GATEMATE_PACK_H +#define GATEMATE_PACK_H + +#include "gatemate.h" + +NEXTPNR_NAMESPACE_BEGIN + +struct GateMatePacker +{ + GateMatePacker(Context *ctx, GateMateImpl *uarch) : ctx(ctx), uarch(uarch) { h.init(ctx); }; + + void pack_io(); + + Context *ctx; + GateMateImpl *uarch; + + HimbaechelHelpers h; +}; + +NEXTPNR_NAMESPACE_END +#endif