diff options
author | gatecat <gatecat@ds0.me> | 2021-02-12 18:22:06 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-12 18:22:06 +0000 |
commit | cede6825859217e15a0d41cd4cc51b6129902aad (patch) | |
tree | 00e3ffdbe4116b1c6ca6ba44f3f8115c7abad16b | |
parent | c956cae8244c094783edc7101fd0ca542c24e55b (diff) | |
parent | e28dedbbe3eb8743d9351634dc7e44a1576c06c4 (diff) | |
download | nextpnr-cede6825859217e15a0d41cd4cc51b6129902aad.tar.gz nextpnr-cede6825859217e15a0d41cd4cc51b6129902aad.tar.bz2 nextpnr-cede6825859217e15a0d41cd4cc51b6129902aad.zip |
Merge pull request #579 from litghost/add_control_for_split_io
Add control to whether GenericFrontend splits IO ports.
-rw-r--r-- | common/nextpnr.h | 1 | ||||
-rw-r--r-- | docs/netlist.md | 1 | ||||
-rw-r--r-- | frontend/frontend_base.h | 42 | ||||
-rw-r--r-- | frontend/json_frontend.cc | 2 |
4 files changed, 28 insertions, 18 deletions
diff --git a/common/nextpnr.h b/common/nextpnr.h index 8d6ab4cc..811500ab 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; 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/frontend/frontend_base.h b/frontend/frontend_base.h index 4f7d22ec..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 @@ -141,6 +141,7 @@ template <typename FrontendType> struct GenericFrontend 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; @@ -148,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 @@ -585,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; @@ -608,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; } |