Merge pull request #579 from litghost/add_control_for_split_io

Add control to whether GenericFrontend splits IO ports.
This commit is contained in:
gatecat 2021-02-12 18:22:06 +00:00 committed by GitHub
commit cede682585
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 28 additions and 18 deletions

View File

@ -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;

View File

@ -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.

View File

@ -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;
}

View File

@ -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;
}