aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Shah <davey1576@gmail.com>2018-06-19 11:12:18 +0200
committerDavid Shah <davey1576@gmail.com>2018-06-19 11:12:18 +0200
commite3519ddfcdfa0e0d3a2942ecf4802c3751db0e17 (patch)
tree08ad8d84423d97eb2976d244867e41a6b4bb2825
parentec2792764a3d7df9f9382400d4ba52f416462fa4 (diff)
downloadnextpnr-e3519ddfcdfa0e0d3a2942ecf4802c3751db0e17.tar.gz
nextpnr-e3519ddfcdfa0e0d3a2942ecf4802c3751db0e17.tar.bz2
nextpnr-e3519ddfcdfa0e0d3a2942ecf4802c3751db0e17.zip
ice40: Adding support for tristate IO
Signed-off-by: David Shah <davey1576@gmail.com>
-rw-r--r--frontend/json/jsonparse.cc41
-rw-r--r--ice40/cells.cc23
-rw-r--r--ice40/cells.h2
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);