From e3519ddfcdfa0e0d3a2942ecf4802c3751db0e17 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 19 Jun 2018 11:12:18 +0200 Subject: ice40: Adding support for tristate IO Signed-off-by: David Shah --- frontend/json/jsonparse.cc | 41 ++++++++++++++++++++++++----------------- ice40/cells.cc | 23 +++++++++++++++++++++-- ice40/cells.h | 2 +- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/frontend/json/jsonparse.cc b/frontend/json/jsonparse.cc index cacc57ea..b3d6f718 100644 --- a/frontend/json/jsonparse.cc +++ b/frontend/json/jsonparse.cc @@ -663,7 +663,11 @@ static void insert_iobuf(Context *ctx, NetInfo *net, PortType type, log_info("processing input port %s\n", name.c_str()); iobuf->type = ctx->id("$nextpnr_ibuf"); iobuf->ports[ctx->id("O")] = PortInfo{ctx->id("O"), net, PORT_OUT}; - + // Special case: input, etc, directly drives inout + if (net->driver.cell != nullptr) { + assert(net->driver.cell->type == ctx->id("$nextpnr_iobuf")); + net = net->driver.cell->ports.at(ctx->id("I")).net; + } assert(net->driver.cell == nullptr); net->driver.port = ctx->id("O"); net->driver.cell = iobuf; @@ -679,20 +683,22 @@ static void insert_iobuf(Context *ctx, NetInfo *net, PortType type, log_info("processing inout port %s\n", name.c_str()); iobuf->type = ctx->id("$nextpnr_iobuf"); iobuf->ports[ctx->id("I")] = PortInfo{ctx->id("I"), nullptr, PORT_IN}; - if (net->driver.cell != NULL) { - // Split the input and output nets for bidir ports - NetInfo *net2 = new NetInfo(); - net2->name = ctx->id("$" + net->name.str(ctx) + "$iobuf_i"); - net2->driver = net->driver; + + // Split the input and output nets for bidir ports + NetInfo *net2 = new NetInfo(); + net2->name = ctx->id("$" + net->name.str(ctx) + "$iobuf_i"); + net2->driver = net->driver; + if (net->driver.cell != nullptr) { net2->driver.cell->ports[net2->driver.port].net = net2; net->driver.cell = nullptr; - ctx->nets[net2->name] = net2; - iobuf->ports[ctx->id("I")].net = net2; - PortRef ref; - ref.cell = iobuf; - ref.port = ctx->id("I"); - net2->users.push_back(ref); } + ctx->nets[net2->name] = net2; + iobuf->ports[ctx->id("I")].net = net2; + PortRef ref; + ref.cell = iobuf; + ref.port = ctx->id("I"); + net2->users.push_back(ref); + iobuf->ports[ctx->id("O")] = PortInfo{ctx->id("O"), net, PORT_OUT}; assert(net->driver.cell == nullptr); net->driver.port = ctx->id("O"); @@ -742,11 +748,12 @@ void json_import(Context *ctx, string modname, JsonNode *node) int netid = bits->data_array.at(i)->data_number; if (netid >= netnames.size()) netnames.resize(netid + 1); - netnames.at(netid) = ctx->id( - basename + - (num_bits == 1 ? "" : std::string("[") + - std::to_string(i) + - std::string("]"))); + netnames.at(netid) = + ctx->id(basename + + (num_bits == 1 ? "" + : std::string("[") + + std::to_string(i) + + std::string("]"))); } } } diff --git a/ice40/cells.cc b/ice40/cells.cc index e0640f0c..d21d5b3b 100644 --- a/ice40/cells.cc +++ b/ice40/cells.cc @@ -25,7 +25,7 @@ NEXTPNR_NAMESPACE_BEGIN void add_port(const Context *ctx, CellInfo *cell, std::string name, - PortType dir) + PortType dir) { IdString id = ctx->id(name); cell->ports[id] = PortInfo{id, nullptr, dir}; @@ -179,7 +179,7 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, replace_port(dff, "Q", lc, "O"); } -void nxio_to_sb(const Context *ctx, CellInfo *nxio, CellInfo *sbio) +void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio) { if (nxio->type == ctx->id("$nextpnr_ibuf")) { sbio->params[ctx->id("PIN_TYPE")] = "1"; @@ -190,9 +190,28 @@ void nxio_to_sb(const Context *ctx, CellInfo *nxio, CellInfo *sbio) } else if (nxio->type == ctx->id("$nextpnr_obuf")) { sbio->params[ctx->id("PIN_TYPE")] = "25"; replace_port(nxio, "I", sbio, "D_OUT_0"); + } else if (nxio->type == ctx->id("$nextpnr_iobuf")) { + // N.B. tristate will be dealt with below + sbio->params[ctx->id("PIN_TYPE")] = "25"; + replace_port(nxio, "I", sbio, "D_OUT_0"); + replace_port(nxio, "O", sbio, "D_IN_0"); } else { assert(false); } + NetInfo *donet = sbio->ports.at(ctx->id("D_OUT_0")).net; + CellInfo *tbuf = + net_driven_by(ctx, donet, [] + (const Context *ctx, const CellInfo *cell) { + return cell->type == ctx->id("$_TBUF_"); + }, + "Y"); + if (tbuf) { + sbio->params[ctx->id("PIN_TYPE")] = "41"; + replace_port(tbuf, "A", sbio, "D_OUT_0"); + replace_port(tbuf, "E", sbio, "OUTPUT_ENABLE"); + ctx->nets.erase(donet->name); + ctx->cells.erase(tbuf->name); + } } bool is_clock_port(const Context *ctx, const PortRef &port) diff --git a/ice40/cells.h b/ice40/cells.h index bd07563e..f1636410 100644 --- a/ice40/cells.h +++ b/ice40/cells.h @@ -96,7 +96,7 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false); // Convert a nextpnr IO buffer to a SB_IO -void nxio_to_sb(const Context *ctx, CellInfo *nxio, CellInfo *sbio); +void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio); // Return true if a net is a global net bool is_global_net(const Context *ctx, const NetInfo *net); -- cgit v1.2.3