aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml3
-rw-r--r--common/command.cc2
-rw-r--r--common/design_utils.cc4
-rw-r--r--common/nextpnr.h15
-rw-r--r--docs/archapi.md8
-rw-r--r--docs/netlist.md1
-rw-r--r--ecp5/arch.h2
-rw-r--r--fpga_interchange/arch.cc18
-rw-r--r--fpga_interchange/arch.h8
-rw-r--r--fpga_interchange/family.cmake9
-rw-r--r--fpga_interchange/main.cc22
-rw-r--r--fpga_interchange/xdc.cc152
-rw-r--r--fpga_interchange/xdc.h33
-rw-r--r--frontend/frontend_base.h44
-rw-r--r--frontend/json_frontend.cc2
-rw-r--r--generic/arch.cc5
-rw-r--r--generic/arch.h4
-rw-r--r--generic/arch_pybindings.cc7
-rw-r--r--generic/examples/simple.py4
-rw-r--r--ice40/arch.h2
-rw-r--r--nexus/arch.h2
m---------tests0
22 files changed, 306 insertions, 41 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 0c2d8b78..f7181fd3 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -5,12 +5,13 @@ task:
memory: 20
dockerfile: .cirrus/Dockerfile.ubuntu20.04
- build_script: mkdir build && cd build && cmake .. -DARCH=all+alpha -DOXIDE_INSTALL_PREFIX=$HOME/.cargo -DBUILD_TESTS=on -DBUILD_GUI=on && make -j3
submodule_script: git submodule sync --recursive && git submodule update --init --recursive
+ build_script: mkdir build && cd build && cmake .. -DARCH=all+alpha -DOXIDE_INSTALL_PREFIX=$HOME/.cargo -DBUILD_TESTS=on -DBUILD_GUI=on && make -j3
test_generic_script: cd build && ./nextpnr-generic-test
test_ice40_script: cd build && ./nextpnr-ice40-test
smoketest_ice40_script: export NEXTPNR=$(pwd)/build/nextpnr-ice40 && cd ice40/smoketest/attosoc && ./smoketest.sh
test_ecp5_script: cd build && ./nextpnr-ecp5-test
+ test_fpga_interchange_script: cd build && ./nextpnr-fpga_interchange-test
smoketest_generic_script: export NEXTPNR=$(pwd)/build/nextpnr-generic && cd generic/examples && ./simple.sh && ./simtest.sh
regressiontest_ice40_script: make -j $(nproc) -C tests/ice40/regressions NPNR=$(pwd)/build/nextpnr-ice40
regressiontest_ecp5_script: make -j $(nproc) -C tests/ecp5/regressions NPNR=$(pwd)/build/nextpnr-ecp5
diff --git a/common/command.cc b/common/command.cc
index 23572e02..d3e8af8d 100644
--- a/common/command.cc
+++ b/common/command.cc
@@ -331,7 +331,7 @@ int CommandHandler::executeMain(std::unique_ptr<Context> ctx)
execute_python_file(filename.c_str());
} else
#endif
- if (vm.count("json")) {
+ if (ctx->design_loaded) {
bool do_pack = vm.count("pack-only") != 0 || vm.count("no-pack") == 0;
bool do_place = vm.count("pack-only") == 0 && vm.count("no-place") == 0;
bool do_route = vm.count("pack-only") == 0 && vm.count("no-route") == 0;
diff --git a/common/design_utils.cc b/common/design_utils.cc
index 16cc2710..b81449b7 100644
--- a/common/design_utils.cc
+++ b/common/design_utils.cc
@@ -71,7 +71,9 @@ void print_utilisation(const Context *ctx)
}
std::map<IdString, int> available_types;
for (auto bel : ctx->getBels()) {
- available_types[ctx->getBelType(bel)]++;
+ if (!ctx->getBelHidden(bel)) {
+ available_types[ctx->getBelType(bel)]++;
+ }
}
log_break();
log_info("Device utilisation:\n");
diff --git a/common/nextpnr.h b/common/nextpnr.h
index cb4dbc28..b6ee33fe 100644
--- a/common/nextpnr.h
+++ b/common/nextpnr.h
@@ -833,6 +833,7 @@ struct BaseCtx
// Top-level ports
std::unordered_map<IdString, PortInfo> ports;
+ std::unordered_map<IdString, CellInfo *> port_cells;
// Floorplanning regions
std::unordered_map<IdString, std::unique_ptr<Region>> region;
@@ -842,6 +843,9 @@ struct BaseCtx
Context *as_ctx = nullptr;
+ // Has the frontend loaded a design?
+ bool design_loaded;
+
BaseCtx()
{
idstring_str_to_idx = new std::unordered_map<std::string, int>;
@@ -853,6 +857,8 @@ struct BaseCtx
wildcard.id.index = 0;
wildcard.type = TimingConstraintObject::ANYTHING;
constraintObjects.push_back(wildcard);
+
+ design_loaded = false;
}
virtual ~BaseCtx()
@@ -1089,6 +1095,7 @@ template <typename R> struct ArchAPI : BaseCtx
virtual CellInfo *getBoundBelCell(BelId bel) const = 0;
virtual CellInfo *getConflictingBelCell(BelId bel) const = 0;
virtual IdString getBelType(BelId bel) const = 0;
+ virtual bool getBelHidden(BelId bel) const = 0;
virtual typename R::BelAttrsRangeT getBelAttrs(BelId bel) const = 0;
virtual WireId getBelPinWire(BelId bel, IdString pin) const = 0;
virtual PortType getBelPinType(BelId bel, IdString pin) const = 0;
@@ -1204,7 +1211,7 @@ template <typename R> struct BaseArch : ArchAPI<R>
// Basic config
virtual IdString archId() const override { return this->id(STRINGIFY(ARCHNAME)); }
- virtual IdString archArgsToId(typename R::ArchArgsT args) const { return IdString(); }
+ virtual IdString archArgsToId(typename R::ArchArgsT args) const override { return IdString(); }
virtual int getTilePipDimZ(int x, int y) const override { return 1; }
virtual char getNameDelimiter() const override { return ' '; }
@@ -1231,6 +1238,8 @@ template <typename R> struct BaseArch : ArchAPI<R>
this->refreshUiBel(bel);
}
+ virtual bool getBelHidden(BelId bel) const override { return false; }
+
virtual bool getBelGlobalBuf(BelId bel) const override { return false; }
virtual bool checkBelAvail(BelId bel) const override { return getBoundBelCell(bel) == nullptr; };
virtual CellInfo *getBoundBelCell(BelId bel) const override
@@ -1298,7 +1307,7 @@ template <typename R> struct BaseArch : ArchAPI<R>
virtual NetInfo *getConflictingWireNet(WireId wire) const override { return getBoundWireNet(wire); }
// Pip methods
- virtual IdString getPipType(PipId pip) const { return IdString(); }
+ virtual IdString getPipType(PipId pip) const override { return IdString(); }
virtual typename R::PipAttrsRangeT getPipAttrs(PipId) const override
{
return empty_if_possible<typename R::PipAttrsRangeT>();
@@ -1375,7 +1384,7 @@ template <typename R> struct BaseArch : ArchAPI<R>
// Decal methods
virtual typename R::DecalGfxRangeT getDecalGraphics(DecalId decal) const override
{
- NPNR_ASSERT_FALSE("unreachable");
+ return empty_if_possible<typename R::DecalGfxRangeT>();
};
virtual DecalXY getBelDecal(BelId bel) const override { return DecalXY(); }
virtual DecalXY getWireDecal(WireId wire) const override { return DecalXY(); }
diff --git a/docs/archapi.md b/docs/archapi.md
index 2a38502c..0f0e6181 100644
--- a/docs/archapi.md
+++ b/docs/archapi.md
@@ -226,6 +226,12 @@ Return a list of all bels on the device.
Return the type of a given bel.
+### bool getBelHidden(BelId bel) const
+
+Should this bel be hidden from utilities?
+
+*BaseArch default: returns false*
+
### BelAttrsRangeT getBelAttrs(BelId bel) const
Return the attributes for that bel. Bel attributes are only informal. They are displayed by the GUI but are otherwise
@@ -574,7 +580,7 @@ Return the graphic elements that make up a decal.
The same decal must always produce the same list. If the graphics for
a design element changes, that element must return another decal.
-*BaseArch default: asserts false as unreachable due to there being no decals*
+*BaseArch default: returns default-constructed range*
### DecalXY getBelDecal(BelId bel) const
diff --git a/docs/netlist.md b/docs/netlist.md
index 763f7d40..2e989a33 100644
--- a/docs/netlist.md
+++ b/docs/netlist.md
@@ -52,6 +52,7 @@ Relevant fields from a netlist point of view are:
- `nets` is a map from net name to a `unique_ptr<NetInfo>` containing net data
- `net_aliases` maps every alias for a net to its canonical name (i.e. index into `nets`) - net aliases often occur when a net has a name both inside a submodule and higher level module
- `ports` is a list of top level ports, primarily used during JSON export (e.g. to produce a useful post-PnR simulation model). Unlike other ports, top level ports are _not_ added to the driver or users of any connected net. In this sense, nets connected to top-level ports are _dangling_. However, top level ports _can_ still see their connected net as part of their `PortInfo`.
+ - `port_cells` is a map of top level port cells. This is a subset of the `cells` maps containing only ports.
Context also has a method `check()` that ensures all of the contracts met above are satisfied. It is strongly suggested to run this after any pass that may modify the netlist.
diff --git a/ecp5/arch.h b/ecp5/arch.h
index de8b225e..d5edd88e 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -601,7 +601,7 @@ struct Arch : BaseArch<ArchRanges>
return range;
}
- std::vector<IdString> getBelPins(BelId bel) const;
+ std::vector<IdString> getBelPins(BelId bel) const override;
// -------------------------------------------------
diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc
index 583813f0..1abf6f30 100644
--- a/fpga_interchange/arch.cc
+++ b/fpga_interchange/arch.cc
@@ -33,6 +33,7 @@
#include "router2.h"
#include "timing.h"
#include "util.h"
+#include "xdc.h"
NEXTPNR_NAMESPACE_BEGIN
@@ -558,6 +559,23 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
return info;
}
+// -----------------------------------------------------------------------
+
+void Arch::read_logical_netlist(const std::string &filename) {}
+void Arch::write_physical_netlist(const std::string &filename) const {}
+
+void Arch::parse_xdc(const std::string &filename)
+{
+ TclInterp interp(getCtx());
+ auto result = Tcl_EvalFile(interp.interp, filename.c_str());
+ if (result != TCL_OK) {
+ log_error("Error in %s:%d => %s\n", filename.c_str(), Tcl_GetErrorLine(interp.interp),
+ Tcl_GetStringResult(interp.interp));
+ }
+}
+
+// -----------------------------------------------------------------------
+
#ifdef WITH_HEAP
const std::string Arch::defaultPlacer = "heap";
#else
diff --git a/fpga_interchange/arch.h b/fpga_interchange/arch.h
index e5c7551b..886978f1 100644
--- a/fpga_interchange/arch.h
+++ b/fpga_interchange/arch.h
@@ -650,6 +650,7 @@ struct BelBucketRange
struct ArchArgs
{
std::string chipdb;
+ std::string package;
};
struct ArchRanges
@@ -825,8 +826,7 @@ struct Arch : ArchAPI<ArchRanges>
return false;
}
- // TODO: this needs to become part of the Arch API
- bool getBelHidden(BelId bel) const { return bel_info(chip_info, bel).category != BEL_CATEGORY_LOGIC; }
+ bool getBelHidden(BelId bel) const override { return bel_info(chip_info, bel).category != BEL_CATEGORY_LOGIC; }
IdString getBelType(BelId bel) const override
{
@@ -1305,7 +1305,9 @@ struct Arch : ArchAPI<ArchRanges>
static const std::vector<std::string> availableRouters;
// -------------------------------------------------
- void write_physical_netlist(const std::string &filename) const {}
+ void read_logical_netlist(const std::string &filename);
+ void write_physical_netlist(const std::string &filename) const;
+ void parse_xdc(const std::string &filename);
};
NEXTPNR_NAMESPACE_END
diff --git a/fpga_interchange/family.cmake b/fpga_interchange/family.cmake
index e69de29b..c3fefaba 100644
--- a/fpga_interchange/family.cmake
+++ b/fpga_interchange/family.cmake
@@ -0,0 +1,9 @@
+find_package(TCL)
+if(NOT ${TCL_FOUND})
+ message(FATAL_ERROR "Tcl is required for FPGA interchange Arch.")
+endif()
+
+foreach (target ${family_targets})
+ target_link_libraries(${target} LINK_PUBLIC ${TCL_LIBRARY})
+ include_directories (${TCL_INCLUDE_PATH})
+endforeach()
diff --git a/fpga_interchange/main.cc b/fpga_interchange/main.cc
index 1f98b186..48b07584 100644
--- a/fpga_interchange/main.cc
+++ b/fpga_interchange/main.cc
@@ -49,8 +49,10 @@ po::options_description FpgaInterchangeCommandHandler::getArchOptions()
{
po::options_description specific("Architecture specific options");
specific.add_options()("chipdb", po::value<std::string>(), "name of chip database binary");
- specific.add_options()("xdc", po::value<std::vector<std::string>>(), "XDC-style constraints file");
+ specific.add_options()("xdc", po::value<std::vector<std::string>>(), "XDC-style constraints file to read");
+ specific.add_options()("netlist", po::value<std::string>(), "FPGA interchange logical netlist to read");
specific.add_options()("phys", po::value<std::string>(), "FPGA interchange Physical netlist to write");
+ specific.add_options()("package", po::value<std::string>(), "Package to use");
return specific;
}
@@ -70,7 +72,23 @@ std::unique_ptr<Context> FpgaInterchangeCommandHandler::createContext(std::unord
log_error("chip database binary must be provided\n");
}
chipArgs.chipdb = vm["chipdb"].as<std::string>();
- return std::unique_ptr<Context>(new Context(chipArgs));
+ if (vm.count("package")) {
+ chipArgs.package = vm["package"].as<std::string>();
+ }
+
+ auto ctx = std::unique_ptr<Context>(new Context(chipArgs));
+
+ if (vm.count("netlist")) {
+ ctx->read_logical_netlist(vm["netlist"].as<std::string>());
+ }
+
+ if (vm.count("xdc")) {
+ for (auto &x : vm["xdc"].as<std::vector<std::string>>()) {
+ ctx->parse_xdc(x);
+ }
+ }
+
+ return ctx;
}
void FpgaInterchangeCommandHandler::customAfterLoad(Context *ctx) {}
diff --git a/fpga_interchange/xdc.cc b/fpga_interchange/xdc.cc
new file mode 100644
index 00000000..584a1777
--- /dev/null
+++ b/fpga_interchange/xdc.cc
@@ -0,0 +1,152 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2019 David Shah <david@symbioticeda.com>
+ * Copyright (C) 2021 Symbiflow 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 "xdc.h"
+#include <string>
+#include "log.h"
+#include "nextpnr.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+static int port_set_from_any(Tcl_Interp *interp, Tcl_Obj *objPtr) { return TCL_ERROR; }
+
+static void set_tcl_obj_string(Tcl_Obj *objPtr, const std::string &s)
+{
+ NPNR_ASSERT(objPtr->bytes == nullptr);
+ // Need to have space for the end null byte.
+ objPtr->bytes = Tcl_Alloc(s.size() + 1);
+
+ // Length is length of string, not including the end null byte.
+ objPtr->length = s.size();
+
+ std::copy(s.begin(), s.end(), objPtr->bytes);
+ objPtr->bytes[objPtr->length] = '\0';
+}
+
+static void port_update_string(Tcl_Obj *objPtr)
+{
+ const Context *ctx = static_cast<const Context *>(objPtr->internalRep.twoPtrValue.ptr1);
+ PortInfo *port_info = static_cast<PortInfo *>(objPtr->internalRep.twoPtrValue.ptr2);
+
+ std::string port_name = port_info->name.str(ctx);
+ set_tcl_obj_string(objPtr, port_name);
+}
+
+static void port_dup(Tcl_Obj *srcPtr, Tcl_Obj *dupPtr)
+{
+ dupPtr->internalRep.twoPtrValue = srcPtr->internalRep.twoPtrValue;
+}
+
+static void port_free(Tcl_Obj *objPtr) {}
+
+static void Tcl_SetStringResult(Tcl_Interp *interp, const std::string &s)
+{
+ char *copy = Tcl_Alloc(s.size() + 1);
+ std::copy(s.begin(), s.end(), copy);
+ copy[s.size()] = '\0';
+ Tcl_SetResult(interp, copy, TCL_DYNAMIC);
+}
+
+static Tcl_ObjType port_object = {
+ "port", port_free, port_dup, port_update_string, port_set_from_any,
+};
+
+static int get_ports(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
+{
+ const Context *ctx = static_cast<const Context *>(data);
+ if (objc == 1) {
+ // Return list of all ports.
+ Tcl_SetStringResult(interp, "Unimplemented");
+ return TCL_ERROR;
+ } else if (objc == 2) {
+ const char *arg0 = Tcl_GetString(objv[1]);
+ IdString port_name = ctx->id(arg0);
+
+ auto iter = ctx->ports.find(port_name);
+ if (iter == ctx->ports.end()) {
+ Tcl_SetStringResult(interp, "Could not find port " + port_name.str(ctx));
+ return TCL_ERROR;
+ }
+
+ Tcl_Obj *result = Tcl_NewObj();
+ result->typePtr = &port_object;
+ result->internalRep.twoPtrValue.ptr1 = (void *)(ctx);
+ result->internalRep.twoPtrValue.ptr2 = (void *)(&iter->second);
+
+ result->bytes = nullptr;
+ port_update_string(result);
+
+ Tcl_SetObjResult(interp, result);
+ return TCL_OK;
+ } else {
+ return TCL_ERROR;
+ }
+}
+
+static int set_property(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
+{
+ // set_property <property> <value> <object>
+ if (objc != 4) {
+ Tcl_SetStringResult(interp, "Only simple 'set_property <property> <value> <object>' is supported");
+ return TCL_ERROR;
+ }
+
+ const char *property = Tcl_GetString(objv[1]);
+ const char *value = Tcl_GetString(objv[2]);
+ const Tcl_Obj *object = objv[3];
+
+ if (object->typePtr != &port_object) {
+ Tcl_SetStringResult(interp, "Only port objects are handled right now!");
+ return TCL_ERROR;
+ }
+
+ const Context *ctx = static_cast<const Context *>(object->internalRep.twoPtrValue.ptr1);
+ PortInfo *port_info = static_cast<PortInfo *>(object->internalRep.twoPtrValue.ptr2);
+ NPNR_ASSERT(port_info->net != nullptr);
+ CellInfo *cell = ctx->port_cells.at(port_info->name);
+
+ cell->attrs[ctx->id(property)] = Property(value);
+
+ return TCL_OK;
+}
+
+TclInterp::TclInterp(Context *ctx)
+{
+ interp = Tcl_CreateInterp();
+ NPNR_ASSERT(Tcl_Init(interp) == TCL_OK);
+
+ Tcl_RegisterObjType(&port_object);
+
+ NPNR_ASSERT(Tcl_Eval(interp, "rename unknown _original_unknown") == TCL_OK);
+ NPNR_ASSERT(Tcl_Eval(interp, "proc unknown args {\n"
+ " set result [scan [lindex $args 0] \"%d\" value]\n"
+ " if { $result == 1 && [llength $args] == 1 } {\n"
+ " return \\[$value\\]\n"
+ " } else {\n"
+ " uplevel 1 [list _original_unknown {*}$args]\n"
+ " }\n"
+ "}") == TCL_OK);
+ Tcl_CreateObjCommand(interp, "get_ports", get_ports, ctx, nullptr);
+ Tcl_CreateObjCommand(interp, "set_property", set_property, ctx, nullptr);
+}
+
+TclInterp::~TclInterp() { Tcl_DeleteInterp(interp); }
+
+NEXTPNR_NAMESPACE_END
diff --git a/fpga_interchange/xdc.h b/fpga_interchange/xdc.h
new file mode 100644
index 00000000..c6b80870
--- /dev/null
+++ b/fpga_interchange/xdc.h
@@ -0,0 +1,33 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2021 Symbiflow 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 <tcl.h>
+#include "nextpnr.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+struct TclInterp
+{
+ TclInterp(Context *ctx);
+ ~TclInterp();
+
+ Tcl_Interp *interp;
+};
+
+NEXTPNR_NAMESPACE_END
diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h
index e262c943..d39a8304 100644
--- a/frontend/frontend_base.h
+++ b/frontend/frontend_base.h
@@ -123,7 +123,7 @@ struct ModuleInfo
template <typename FrontendType> struct GenericFrontend
{
- GenericFrontend(Context *ctx, const FrontendType &impl) : ctx(ctx), impl(impl) {}
+ GenericFrontend(Context *ctx, const FrontendType &impl, bool split_io) : ctx(ctx), impl(impl), split_io(split_io) {}
void operator()()
{
// Find which module is top
@@ -135,10 +135,13 @@ template <typename FrontendType> struct GenericFrontend
ctx->top_module = top;
// Do the actual import, starting from the top level module
import_module(m, top.str(ctx), top.str(ctx), mod_refs.at(top));
+
+ ctx->design_loaded = true;
}
Context *ctx;
const FrontendType &impl;
+ const bool split_io;
using mod_dat_t = typename FrontendType::ModuleDataType;
using mod_port_dat_t = typename FrontendType::ModulePortDataType;
using cell_dat_t = typename FrontendType::CellDataType;
@@ -146,7 +149,7 @@ template <typename FrontendType> struct GenericFrontend
using bitvector_t = typename FrontendType::BitVectorDataType;
std::unordered_map<IdString, ModuleInfo> mods;
- std::unordered_map<IdString, const mod_dat_t &> mod_refs;
+ std::unordered_map<IdString, const mod_dat_t> mod_refs;
IdString top;
// Process the list of modules and determine
@@ -583,22 +586,28 @@ template <typename FrontendType> struct GenericFrontend
connect_port(ctx, net, iobuf, ctx->id("I"));
} else if (dir == PORT_INOUT) {
iobuf->type = ctx->id("$nextpnr_iobuf");
- iobuf->addInput(ctx->id("I"));
- iobuf->addOutput(ctx->id("O"));
- // Need to bifurcate the net to avoid multiple drivers and split
- // the input/output parts of an inout
- // Create a new net connecting only the current net's driver and the IOBUF input
- // Then use the IOBUF output to drive all of the current net's users
- NetInfo *split_iobuf_i = ctx->createNet(unique_name("", "$" + name + "$iobuf_i", true));
- auto drv = net->driver;
- if (drv.cell != nullptr) {
- disconnect_port(ctx, drv.cell, drv.port);
- drv.cell->ports[drv.port].net = nullptr;
- connect_port(ctx, split_iobuf_i, drv.cell, drv.port);
+
+ if (split_io) {
+ iobuf->addInput(ctx->id("I"));
+ iobuf->addOutput(ctx->id("O"));
+ // Need to bifurcate the net to avoid multiple drivers and split
+ // the input/output parts of an inout
+ // Create a new net connecting only the current net's driver and the IOBUF input
+ // Then use the IOBUF output to drive all of the current net's users
+ NetInfo *split_iobuf_i = ctx->createNet(unique_name("", "$" + name + "$iobuf_i", true));
+ auto drv = net->driver;
+ if (drv.cell != nullptr) {
+ disconnect_port(ctx, drv.cell, drv.port);
+ drv.cell->ports[drv.port].net = nullptr;
+ connect_port(ctx, split_iobuf_i, drv.cell, drv.port);
+ }
+ connect_port(ctx, split_iobuf_i, iobuf, ctx->id("I"));
+ NPNR_ASSERT(net->driver.cell == nullptr);
+ connect_port(ctx, net, iobuf, ctx->id("O"));
+ } else {
+ iobuf->addInout(ctx->id("IO"));
+ connect_port(ctx, net, iobuf, ctx->id("IO"));
}
- connect_port(ctx, split_iobuf_i, iobuf, ctx->id("I"));
- NPNR_ASSERT(net->driver.cell == nullptr);
- connect_port(ctx, net, iobuf, ctx->id("O"));
}
PortInfo pinfo;
@@ -606,6 +615,7 @@ template <typename FrontendType> struct GenericFrontend
pinfo.net = net;
pinfo.type = dir;
ctx->ports[pinfo.name] = pinfo;
+ ctx->port_cells[pinfo.name] = iobuf;
return iobuf;
}
diff --git a/frontend/json_frontend.cc b/frontend/json_frontend.cc
index 136786fc..52f7bfdc 100644
--- a/frontend/json_frontend.cc
+++ b/frontend/json_frontend.cc
@@ -197,7 +197,7 @@ bool parse_json(std::istream &in, const std::string &filename, Context *ctx)
log_error("JSON file '%s' doesn't look like a netlist (doesn't contain \"modules\" key)\n",
filename.c_str());
}
- GenericFrontend<JsonFrontendImpl>(ctx, JsonFrontendImpl(root))();
+ GenericFrontend<JsonFrontendImpl>(ctx, JsonFrontendImpl(root), /*split_io=*/true)();
return true;
}
diff --git a/generic/arch.cc b/generic/arch.cc
index c51fbb84..7cd71179 100644
--- a/generic/arch.cc
+++ b/generic/arch.cc
@@ -91,7 +91,7 @@ void Arch::addPip(IdStringList name, IdString type, IdStringList srcWire, IdStri
tilePipDimZ[loc.x][loc.y] = std::max(tilePipDimZ[loc.x][loc.y], loc.z + 1);
}
-void Arch::addBel(IdStringList name, IdString type, Loc loc, bool gb)
+void Arch::addBel(IdStringList name, IdString type, Loc loc, bool gb, bool hidden)
{
NPNR_ASSERT(bels.count(name) == 0);
NPNR_ASSERT(bel_by_loc.count(loc) == 0);
@@ -102,6 +102,7 @@ void Arch::addBel(IdStringList name, IdString type, Loc loc, bool gb)
bi.y = loc.y;
bi.z = loc.z;
bi.gb = gb;
+ bi.hidden = hidden;
bel_ids.push_back(name);
bel_by_loc[loc] = name;
@@ -319,6 +320,8 @@ const std::vector<BelId> &Arch::getBels() const { return bel_ids; }
IdString Arch::getBelType(BelId bel) const { return bels.at(bel).type; }
+bool Arch::getBelHidden(BelId bel) const { return bels.at(bel).hidden; }
+
const std::map<IdString, std::string> &Arch::getBelAttrs(BelId bel) const { return bels.at(bel).attrs; }
WireId Arch::getBelPinWire(BelId bel, IdString pin) const
diff --git a/generic/arch.h b/generic/arch.h
index e7d204ef..2a0c7158 100644
--- a/generic/arch.h
+++ b/generic/arch.h
@@ -77,6 +77,7 @@ struct BelInfo
DecalXY decalxy;
int x, y, z;
bool gb;
+ bool hidden;
};
struct GroupInfo
@@ -178,7 +179,7 @@ struct Arch : ArchAPI<ArchRanges>
void addWire(IdStringList name, IdString type, int x, int y);
void addPip(IdStringList name, IdString type, IdStringList srcWire, IdStringList dstWire, DelayInfo delay, Loc loc);
- void addBel(IdStringList name, IdString type, Loc loc, bool gb);
+ void addBel(IdStringList name, IdString type, Loc loc, bool gb, bool hidden);
void addBelInput(IdStringList bel, IdString name, IdStringList wire);
void addBelOutput(IdStringList bel, IdString name, IdStringList wire);
void addBelInout(IdStringList bel, IdString name, IdStringList wire);
@@ -238,6 +239,7 @@ struct Arch : ArchAPI<ArchRanges>
CellInfo *getConflictingBelCell(BelId bel) const override;
const std::vector<BelId> &getBels() const override;
IdString getBelType(BelId bel) const override;
+ bool getBelHidden(BelId bel) const override;
const std::map<IdString, std::string> &getBelAttrs(BelId bel) const override;
WireId getBelPinWire(BelId bel, IdString pin) const override;
PortType getBelPinType(BelId bel, IdString pin) const override;
diff --git a/generic/arch_pybindings.cc b/generic/arch_pybindings.cc
index 29e8bc53..3dc04206 100644
--- a/generic/arch_pybindings.cc
+++ b/generic/arch_pybindings.cc
@@ -162,10 +162,9 @@ void arch_wrap_python(py::module &m)
pass_through<DelayInfo>, pass_through<Loc>>::def_wrap(ctx_cls, "addPip", "name"_a, "type"_a,
"srcWire"_a, "dstWire"_a, "delay"_a, "loc"_a);
- fn_wrapper_4a_v<Context, decltype(&Context::addBel), &Context::addBel, conv_from_str<IdStringList>,
- conv_from_str<IdString>, pass_through<Loc>, pass_through<bool>>::def_wrap(ctx_cls, "addBel",
- "name"_a, "type"_a,
- "loc"_a, "gb"_a);
+ fn_wrapper_5a_v<Context, decltype(&Context::addBel), &Context::addBel, conv_from_str<IdStringList>,
+ conv_from_str<IdString>, pass_through<Loc>, pass_through<bool>,
+ pass_through<bool>>::def_wrap(ctx_cls, "addBel", "name"_a, "type"_a, "loc"_a, "gb"_a, "hidden"_a);
fn_wrapper_3a_v<Context, decltype(&Context::addBelInput), &Context::addBelInput, conv_from_str<IdStringList>,
conv_from_str<IdString>, conv_from_str<IdStringList>>::def_wrap(ctx_cls, "addBelInput", "bel"_a,
"name"_a, "wire"_a);
diff --git a/generic/examples/simple.py b/generic/examples/simple.py
index 9379b505..4b7f4025 100644
--- a/generic/examples/simple.py
+++ b/generic/examples/simple.py
@@ -20,13 +20,13 @@ for x in range(X):
if x == y:
continue
for z in range(2):
- ctx.addBel(name="X%dY%d_IO%d" % (x, y, z), type="GENERIC_IOB", loc=Loc(x, y, z), gb=False)
+ ctx.addBel(name="X%dY%d_IO%d" % (x, y, z), type="GENERIC_IOB", loc=Loc(x, y, z), gb=False, hidden=False)
ctx.addBelInput(bel="X%dY%d_IO%d" % (x, y, z), name="I", wire="X%dY%dZ%d_I0" % (x, y, z))
ctx.addBelInput(bel="X%dY%d_IO%d" % (x, y, z), name="EN", wire="X%dY%dZ%d_I1" % (x, y, z))
ctx.addBelOutput(bel="X%dY%d_IO%d" % (x, y, z), name="O", wire="X%dY%dZ%d_Q" % (x, y, z))
else:
for z in range(N):
- ctx.addBel(name="X%dY%d_SLICE%d" % (x, y, z), type="GENERIC_SLICE", loc=Loc(x, y, z), gb=False)
+ ctx.addBel(name="X%dY%d_SLICE%d" % (x, y, z), type="GENERIC_SLICE", loc=Loc(x, y, z), gb=False, hidden=False)
ctx.addBelInput(bel="X%dY%d_SLICE%d" % (x, y, z), name="CLK", wire="X%dY%dZ%d_CLK" % (x, y, z))
for k in range(K):
ctx.addBelInput(bel="X%dY%d_SLICE%d" % (x, y, z), name="I[%d]" % k, wire="X%dY%dZ%d_I%d" % (x, y, z, k))
diff --git a/ice40/arch.h b/ice40/arch.h
index 5df072f9..30b5f871 100644
--- a/ice40/arch.h
+++ b/ice40/arch.h
@@ -849,7 +849,7 @@ struct Arch : BaseArch<ArchRanges>
// Assign architecture-specific arguments to nets and cells, which must be
// called between packing or further
// netlist modifications, and validity checks
- void assignArchInfo();
+ void assignArchInfo() override;
void assignCellInfo(CellInfo *cell);
// -------------------------------------------------
diff --git a/nexus/arch.h b/nexus/arch.h
index d81605af..963b5b2f 100644
--- a/nexus/arch.h
+++ b/nexus/arch.h
@@ -1118,7 +1118,7 @@ struct Arch : BaseArch<ArchRanges>
WireId getPipSrcWire(PipId pip) const override { return canonical_wire(pip.tile, pip_data(pip).from_wire); }
- WireId getPipDstWire(PipId pip) const { return canonical_wire(pip.tile, pip_data(pip).to_wire); }
+ WireId getPipDstWire(PipId pip) const override { return canonical_wire(pip.tile, pip_data(pip).to_wire); }
DelayInfo getPipDelay(PipId pip) const override
{
diff --git a/tests b/tests
-Subproject 8f93e7e0f897b1b5da469919c9a43ba28b623b2
+Subproject 31648368460b9e216479ce7c38e6fed883c380c