ice40: Adding support for tristate IO

Signed-off-by: David Shah <davey1576@gmail.com>
This commit is contained in:
David Shah 2018-06-19 11:12:18 +02:00
parent ec2792764a
commit e3519ddfcd
3 changed files with 46 additions and 20 deletions

View File

@ -663,7 +663,11 @@ static void insert_iobuf(Context *ctx, NetInfo *net, PortType type,
log_info("processing input port %s\n", name.c_str()); log_info("processing input port %s\n", name.c_str());
iobuf->type = ctx->id("$nextpnr_ibuf"); iobuf->type = ctx->id("$nextpnr_ibuf");
iobuf->ports[ctx->id("O")] = PortInfo{ctx->id("O"), net, PORT_OUT}; 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); assert(net->driver.cell == nullptr);
net->driver.port = ctx->id("O"); net->driver.port = ctx->id("O");
net->driver.cell = iobuf; 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()); log_info("processing inout port %s\n", name.c_str());
iobuf->type = ctx->id("$nextpnr_iobuf"); iobuf->type = ctx->id("$nextpnr_iobuf");
iobuf->ports[ctx->id("I")] = PortInfo{ctx->id("I"), nullptr, PORT_IN}; 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 // Split the input and output nets for bidir ports
NetInfo *net2 = new NetInfo(); NetInfo *net2 = new NetInfo();
net2->name = ctx->id("$" + net->name.str(ctx) + "$iobuf_i"); net2->name = ctx->id("$" + net->name.str(ctx) + "$iobuf_i");
net2->driver = net->driver; net2->driver = net->driver;
if (net->driver.cell != nullptr) {
net2->driver.cell->ports[net2->driver.port].net = net2; net2->driver.cell->ports[net2->driver.port].net = net2;
net->driver.cell = nullptr; net->driver.cell = nullptr;
}
ctx->nets[net2->name] = net2; ctx->nets[net2->name] = net2;
iobuf->ports[ctx->id("I")].net = net2; iobuf->ports[ctx->id("I")].net = net2;
PortRef ref; PortRef ref;
ref.cell = iobuf; ref.cell = iobuf;
ref.port = ctx->id("I"); ref.port = ctx->id("I");
net2->users.push_back(ref); net2->users.push_back(ref);
}
iobuf->ports[ctx->id("O")] = PortInfo{ctx->id("O"), net, PORT_OUT}; iobuf->ports[ctx->id("O")] = PortInfo{ctx->id("O"), net, PORT_OUT};
assert(net->driver.cell == nullptr); assert(net->driver.cell == nullptr);
net->driver.port = ctx->id("O"); net->driver.port = ctx->id("O");
@ -742,9 +748,10 @@ void json_import(Context *ctx, string modname, JsonNode *node)
int netid = bits->data_array.at(i)->data_number; int netid = bits->data_array.at(i)->data_number;
if (netid >= netnames.size()) if (netid >= netnames.size())
netnames.resize(netid + 1); netnames.resize(netid + 1);
netnames.at(netid) = ctx->id( netnames.at(netid) =
basename + ctx->id(basename +
(num_bits == 1 ? "" : std::string("[") + (num_bits == 1 ? ""
: std::string("[") +
std::to_string(i) + std::to_string(i) +
std::string("]"))); std::string("]")));
} }

View File

@ -179,7 +179,7 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc,
replace_port(dff, "Q", lc, "O"); 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")) { if (nxio->type == ctx->id("$nextpnr_ibuf")) {
sbio->params[ctx->id("PIN_TYPE")] = "1"; 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")) { } else if (nxio->type == ctx->id("$nextpnr_obuf")) {
sbio->params[ctx->id("PIN_TYPE")] = "25"; sbio->params[ctx->id("PIN_TYPE")] = "25";
replace_port(nxio, "I", sbio, "D_OUT_0"); 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 { } else {
assert(false); 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) bool is_clock_port(const Context *ctx, const PortRef &port)

View File

@ -96,7 +96,7 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc,
bool pass_thru_lut = false); bool pass_thru_lut = false);
// Convert a nextpnr IO buffer to a SB_IO // 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 // Return true if a net is a global net
bool is_global_net(const Context *ctx, const NetInfo *net); bool is_global_net(const Context *ctx, const NetInfo *net);