nextpnr/leuctra/pack.cc

289 lines
9.8 KiB
C++
Raw Normal View History

2019-02-19 23:40:20 +08:00
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "nextpnr.h"
2019-04-16 18:59:09 +08:00
#include "cells.h"
2019-04-02 08:20:35 +08:00
#include "log.h"
2019-04-16 18:59:09 +08:00
#include "util.h"
2019-02-19 23:40:20 +08:00
NEXTPNR_NAMESPACE_BEGIN
2019-04-02 08:20:35 +08:00
static bool is_nextpnr_iob(Context *ctx, CellInfo *cell)
{
return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") ||
cell->type == ctx->id("$nextpnr_iobuf");
}
2019-04-16 18:59:09 +08:00
static bool is_iob(Context *ctx, CellInfo *cell)
{
return cell->type == ctx->id("IOB");
}
2019-04-02 08:20:35 +08:00
class LeuctraPacker
{
public:
LeuctraPacker(Context *ctx) : ctx(ctx){};
private:
// Process the contents of packed_cells and new_cells
void flush_cells()
{
for (auto pcell : packed_cells) {
ctx->cells.erase(pcell);
}
for (auto &ncell : new_cells) {
ctx->cells[ncell->name] = std::move(ncell);
}
packed_cells.clear();
new_cells.clear();
}
// Remove nextpnr iob cells, insert Xilinx primitives instead.
void pack_iob()
{
2019-04-16 18:59:09 +08:00
log_info("Packing IOBs...\n");
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
if (is_nextpnr_iob(ctx, ci)) {
CellInfo *iob = nullptr;
std::unique_ptr<CellInfo> io_cell =
create_leuctra_cell(ctx, ctx->id("IOB"), ci->name.str(ctx) + "$iob");
nxio_to_iob(ctx, ci, io_cell.get(), new_cells, packed_cells);
new_cells.push_back(std::move(io_cell));
iob = new_cells.back().get();
packed_cells.insert(ci->name);
if (iob != nullptr) {
for (const auto &attr : ci->attrs)
iob->attrs[attr.first] = attr.second;
auto loc_attr = iob->attrs.find(ctx->id("LOC"));
if (loc_attr != iob->attrs.end()) {
std::string pin = loc_attr->second;
BelId pinBel = ctx->getPackagePinBel(pin);
if (pinBel == BelId()) {
log_error("IO pin '%s' constrained to pin '%s', which does not exist for package '%s'.\n",
iob->name.c_str(ctx), pin.c_str(), ctx->args.package.c_str());
} else {
log_info("pin '%s' constrained to Bel '%s'.\n", iob->name.c_str(ctx),
ctx->getBelName(pinBel).c_str(ctx));
}
iob->attrs[ctx->id("BEL")] = ctx->getBelName(pinBel).str(ctx);
}
}
}
}
flush_cells();
}
// Ensure ilogic/ologic cell for every IOB that needs one.
void pack_iologic()
{
log_info("Packing ILOGICs/OLOGICs...\n");
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
if (is_iob(ctx, ci)) {
NetInfo *net_i = ci->ports.at(ctx->id("I")).net;
if (net_i != nullptr) {
// Insert ILOGIC.
std::unique_ptr<CellInfo> ilogic =
create_leuctra_cell(ctx, ctx->id("ILOGIC2"), ci->name.str(ctx) + "$ilogic");
insert_ilogic_pass(ctx, ci, ilogic.get());
new_cells.push_back(std::move(ilogic));
}
NetInfo *net_o = ci->ports.at(ctx->id("O")).net;
if (net_o != nullptr) {
// Insert OLOGIC.
std::unique_ptr<CellInfo> ologic =
create_leuctra_cell(ctx, ctx->id("OLOGIC2"), ci->name.str(ctx) + "$ologic");
insert_ologic_pass(ctx, ci, ologic.get());
new_cells.push_back(std::move(ologic));
}
auto bel_attr = ci->attrs.find(ctx->id("BEL"));
if (bel_attr != ci->attrs.end()) {
BelId bel = ctx->getBelByName(ctx->id(ci->attrs[ctx->id("BEL")]));
for (auto &child : ci->constr_children) {
BelId child_bel = ctx->getRelatedBel(bel, child->constr_spec);
child->attrs[ctx->id("BEL")] = ctx->getBelName(child_bel).str(ctx);
child->constr_parent = nullptr;
child->constr_spec = -1;
}
ci->constr_children.clear();
}
}
}
flush_cells();
}
// Convert FFs/latches to LEUCTRA_FFs.
void pack_ff()
{
log_info("Packing FFs...\n");
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
if (is_xilinx_ff(ctx, ci)) {
std::unique_ptr<CellInfo> ff_cell =
create_leuctra_cell(ctx, ctx->id("LEUCTRA_FF"), ci->name.str(ctx) + "$ff");
convert_ff(ctx, ci, ff_cell.get(), new_cells, packed_cells);
new_cells.push_back(std::move(ff_cell));
packed_cells.insert(ci->name);
}
}
flush_cells();
}
// Convert FFs/latches to LEUCTRA_FFs.
void pack_lut()
{
log_info("Packing LUTs...\n");
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
if (is_xilinx_lut(ctx, ci)) {
std::unique_ptr<CellInfo> lut_cell =
create_leuctra_cell(ctx, ctx->id("LEUCTRA_LC"), ci->name.str(ctx) + "$lc");
convert_lut(ctx, ci, lut_cell.get(), new_cells, packed_cells);
new_cells.push_back(std::move(lut_cell));
2019-04-02 08:20:35 +08:00
2019-04-16 18:59:09 +08:00
packed_cells.insert(ci->name);
}
}
2019-04-02 08:20:35 +08:00
flush_cells();
}
2019-04-16 18:59:09 +08:00
// Merge a net into a constant net
void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval)
{
orig->driver.cell = nullptr;
for (auto user : orig->users) {
if (user.cell != nullptr) {
CellInfo *uc = user.cell;
if (ctx->verbose)
log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx));
uc->ports[user.port].net = constnet;
constnet->users.push_back(user);
}
}
orig->users.clear();
}
// Pack constants (simple implementation)
void pack_constants()
{
log_info("Packing constants..\n");
std::unique_ptr<CellInfo> gnd_cell = create_leuctra_cell(ctx, ctx->id("LEUCTRA_LC"), "$PACKER_GND");
gnd_cell->params[ctx->id("INIT")] = "0000000000000000000000000000000000000000000000000000000000000000";
std::unique_ptr<NetInfo> gnd_net = std::unique_ptr<NetInfo>(new NetInfo);
gnd_net->name = ctx->id("$PACKER_GND_NET");
gnd_net->driver.cell = gnd_cell.get();
gnd_net->driver.port = ctx->id("O6");
gnd_cell->ports.at(ctx->id("O6")).net = gnd_net.get();
std::unique_ptr<CellInfo> vcc_cell = create_leuctra_cell(ctx, ctx->id("LEUCTRA_LC"), "$PACKER_VCC");
vcc_cell->params[ctx->id("INIT")] = "1111111111111111111111111111111111111111111111111111111111111111";
std::unique_ptr<NetInfo> vcc_net = std::unique_ptr<NetInfo>(new NetInfo);
vcc_net->name = ctx->id("$PACKER_VCC_NET");
vcc_net->driver.cell = vcc_cell.get();
vcc_net->driver.port = ctx->id("O6");
vcc_cell->ports.at(ctx->id("O6")).net = vcc_net.get();
std::vector<IdString> dead_nets;
bool gnd_used = false, vcc_used = false;
for (auto net : sorted(ctx->nets)) {
NetInfo *ni = net.second;
if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) {
IdString drv_cell = ni->driver.cell->name;
set_net_constant(ctx, ni, gnd_net.get(), false);
gnd_used = true;
dead_nets.push_back(net.first);
ctx->cells.erase(drv_cell);
} else if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("VCC")) {
IdString drv_cell = ni->driver.cell->name;
set_net_constant(ctx, ni, vcc_net.get(), true);
vcc_used = true;
dead_nets.push_back(net.first);
ctx->cells.erase(drv_cell);
}
}
if (gnd_used) {
ctx->cells[gnd_cell->name] = std::move(gnd_cell);
ctx->nets[gnd_net->name] = std::move(gnd_net);
}
if (vcc_used) {
ctx->cells[vcc_cell->name] = std::move(vcc_cell);
ctx->nets[vcc_net->name] = std::move(vcc_net);
}
for (auto dn : dead_nets) {
ctx->nets.erase(dn);
}
}
2019-04-02 08:20:35 +08:00
public:
void pack()
{
pack_iob();
2019-04-16 18:59:09 +08:00
pack_iologic();
pack_ff();
pack_lut();
pack_constants();
2019-04-02 08:20:35 +08:00
}
private:
Context *ctx;
std::unordered_set<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells;
};
2019-02-19 23:40:20 +08:00
// Main pack function
bool Arch::pack()
{
2019-04-02 08:20:35 +08:00
Context *ctx = getCtx();
try {
log_break();
LeuctraPacker(ctx).pack();
log_info("Checksum: 0x%08x\n", ctx->checksum());
// XXX
//assignArchInfo();
return true;
} catch (log_execution_error_exception) {
// XXX
//assignArchInfo();
return false;
}
2019-02-19 23:40:20 +08:00
}
NEXTPNR_NAMESPACE_END