Merge branch 'master' of gitlab.com:SymbioticEDA/nextpnr
This commit is contained in:
commit
8067ed9af0
@ -31,15 +31,15 @@ void add_port(const Context *ctx, CellInfo *cell, std::string name,
|
|||||||
cell->ports[id] = PortInfo{id, nullptr, dir};
|
cell->ports[id] = PortInfo{id, nullptr, dir};
|
||||||
}
|
}
|
||||||
|
|
||||||
CellInfo *create_ice_cell(Context *ctx, IdString type, IdString name)
|
CellInfo *create_ice_cell(Context *ctx, IdString type, std::string name)
|
||||||
{
|
{
|
||||||
static int auto_idx = 0;
|
static int auto_idx = 0;
|
||||||
CellInfo *new_cell = new CellInfo();
|
CellInfo *new_cell = new CellInfo();
|
||||||
if (name == IdString()) {
|
if (name.empty()) {
|
||||||
new_cell->name = IdString("$nextpnr_" + type.str() + "_" +
|
new_cell->name = IdString(ctx, "$nextpnr_" + type.str() + "_" +
|
||||||
std::to_string(auto_idx++));
|
std::to_string(auto_idx++));
|
||||||
} else {
|
} else {
|
||||||
new_cell->name = name;
|
new_cell->name = ctx->id(name);
|
||||||
}
|
}
|
||||||
new_cell->type = type;
|
new_cell->type = type;
|
||||||
if (type == ctx->id("ICESTORM_LC")) {
|
if (type == ctx->id("ICESTORM_LC")) {
|
||||||
@ -251,7 +251,7 @@ bool is_enable_port(const Context *ctx, const PortRef &port)
|
|||||||
|
|
||||||
bool is_global_net(const Context *ctx, const NetInfo *net)
|
bool is_global_net(const Context *ctx, const NetInfo *net)
|
||||||
{
|
{
|
||||||
return bool(net_driven_by(ctx, net, is_gbuf, "GLOBAL_BUFFER_OUTPUT"));
|
return bool(net_driven_by(ctx, net, is_gbuf, ctx->id("GLOBAL_BUFFER_OUTPUT")));
|
||||||
}
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -28,7 +28,7 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||||||
// Create a standard iCE40 cell and return it
|
// Create a standard iCE40 cell and return it
|
||||||
// Name will be automatically assigned if not specified
|
// Name will be automatically assigned if not specified
|
||||||
CellInfo *create_ice_cell(Context *ctx, IdString type,
|
CellInfo *create_ice_cell(Context *ctx, IdString type,
|
||||||
IdString name = IdString());
|
std::string name = "");
|
||||||
|
|
||||||
// Return true if a cell is a LUT
|
// Return true if a cell is a LUT
|
||||||
inline bool is_lut(const Context *ctx, const CellInfo *cell)
|
inline bool is_lut(const Context *ctx, const CellInfo *cell)
|
||||||
|
@ -36,26 +36,26 @@ static void pack_lut_lutffs(Context *ctx)
|
|||||||
std::vector<CellInfo *> new_cells;
|
std::vector<CellInfo *> new_cells;
|
||||||
for (auto cell : ctx->cells) {
|
for (auto cell : ctx->cells) {
|
||||||
CellInfo *ci = cell.second;
|
CellInfo *ci = cell.second;
|
||||||
log_info("cell '%s' is of type '%s'\n", ci->name.c_str(),
|
log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx),
|
||||||
ci->type.c_str());
|
ci->type.c_str(ctx));
|
||||||
if (is_lut(ctx, ci)) {
|
if (is_lut(ctx, ci)) {
|
||||||
CellInfo *packed =
|
CellInfo *packed =
|
||||||
create_ice_cell(ctx, "ICESTORM_LC", ci->name.str() + "_LC");
|
create_ice_cell(ctx, "ICESTORM_LC", ci->name.str(ctx) + "_LC");
|
||||||
std::copy(ci->attrs.begin(), ci->attrs.end(),
|
std::copy(ci->attrs.begin(), ci->attrs.end(),
|
||||||
std::inserter(packed->attrs, packed->attrs.begin()));
|
std::inserter(packed->attrs, packed->attrs.begin()));
|
||||||
packed_cells.insert(ci->name);
|
packed_cells.insert(ci->name);
|
||||||
new_cells.push_back(packed);
|
new_cells.push_back(packed);
|
||||||
log_info("packed cell %s into %s\n", ci->name.c_str(),
|
log_info("packed cell %s into %s\n", ci->name.c_str(ctx),
|
||||||
packed->name.c_str());
|
packed->name.c_str(ctx));
|
||||||
// See if we can pack into a DFF
|
// See if we can pack into a DFF
|
||||||
// TODO: LUT cascade
|
// TODO: LUT cascade
|
||||||
NetInfo *o = ci->ports.at("O").net;
|
NetInfo *o = ci->ports.at(ctx->id("O")).net;
|
||||||
CellInfo *dff = net_only_drives(ctx, o, is_ff, "D", true);
|
CellInfo *dff = net_only_drives(ctx, o, is_ff, "D", true);
|
||||||
auto lut_bel = ci->attrs.find("BEL");
|
auto lut_bel = ci->attrs.find(ctx->id("BEL"));
|
||||||
bool packed_dff = false;
|
bool packed_dff = false;
|
||||||
if (dff) {
|
if (dff) {
|
||||||
log_info("found attached dff %s\n", dff->name.c_str());
|
log_info("found attached dff %s\n", dff->name.c_str(ctx));
|
||||||
auto dff_bel = dff->attrs.find("BEL");
|
auto dff_bel = dff->attrs.find(ctx->id("BEL"));
|
||||||
if (lut_bel != ci->attrs.end() && dff_bel != dff->attrs.end() &&
|
if (lut_bel != ci->attrs.end() && dff_bel != dff->attrs.end() &&
|
||||||
lut_bel->second != dff_bel->second) {
|
lut_bel->second != dff_bel->second) {
|
||||||
// Locations don't match, can't pack
|
// Locations don't match, can't pack
|
||||||
@ -64,10 +64,10 @@ static void pack_lut_lutffs(Context *ctx)
|
|||||||
dff_to_lc(ctx, dff, packed, false);
|
dff_to_lc(ctx, dff, packed, false);
|
||||||
ctx->nets.erase(o->name);
|
ctx->nets.erase(o->name);
|
||||||
if (dff_bel != dff->attrs.end())
|
if (dff_bel != dff->attrs.end())
|
||||||
packed->attrs["BEL"] = dff_bel->second;
|
packed->attrs[ctx->id("BEL")] = dff_bel->second;
|
||||||
packed_cells.insert(dff->name);
|
packed_cells.insert(dff->name);
|
||||||
log_info("packed cell %s into %s\n", dff->name.c_str(),
|
log_info("packed cell %s into %s\n", dff->name.c_str(ctx),
|
||||||
packed->name.c_str());
|
packed->name.c_str(ctx));
|
||||||
packed_dff = true;
|
packed_dff = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,11 +96,11 @@ static void pack_nonlut_ffs(Context *ctx)
|
|||||||
CellInfo *ci = cell.second;
|
CellInfo *ci = cell.second;
|
||||||
if (is_ff(ctx, ci)) {
|
if (is_ff(ctx, ci)) {
|
||||||
CellInfo *packed = create_ice_cell(ctx, "ICESTORM_LC",
|
CellInfo *packed = create_ice_cell(ctx, "ICESTORM_LC",
|
||||||
ci->name.str() + "_DFFLC");
|
ci->name.str(ctx) + "_DFFLC");
|
||||||
std::copy(ci->attrs.begin(), ci->attrs.end(),
|
std::copy(ci->attrs.begin(), ci->attrs.end(),
|
||||||
std::inserter(packed->attrs, packed->attrs.begin()));
|
std::inserter(packed->attrs, packed->attrs.begin()));
|
||||||
log_info("packed cell %s into %s\n", ci->name.c_str(),
|
log_info("packed cell %s into %s\n", ci->name.c_str(ctx),
|
||||||
packed->name.c_str());
|
packed->name.c_str(ctx));
|
||||||
packed_cells.insert(ci->name);
|
packed_cells.insert(ci->name);
|
||||||
new_cells.push_back(packed);
|
new_cells.push_back(packed);
|
||||||
dff_to_lc(ctx, ci, packed, true);
|
dff_to_lc(ctx, ci, packed, true);
|
||||||
@ -126,18 +126,18 @@ static void pack_ram(Context *ctx)
|
|||||||
CellInfo *ci = cell.second;
|
CellInfo *ci = cell.second;
|
||||||
if (is_ram(ctx, ci)) {
|
if (is_ram(ctx, ci)) {
|
||||||
CellInfo *packed = create_ice_cell(ctx, "ICESTORM_RAM",
|
CellInfo *packed = create_ice_cell(ctx, "ICESTORM_RAM",
|
||||||
ci->name.str() + "_RAM");
|
ci->name.str(ctx) + "_RAM");
|
||||||
packed_cells.insert(ci->name);
|
packed_cells.insert(ci->name);
|
||||||
new_cells.push_back(packed);
|
new_cells.push_back(packed);
|
||||||
for (auto param : ci->params)
|
for (auto param : ci->params)
|
||||||
packed->params[param.first] = param.second;
|
packed->params[param.first] = param.second;
|
||||||
packed->params["NEG_CLK_W"] =
|
packed->params["NEG_CLK_W"] =
|
||||||
std::to_string(ci->type == "SB_RAM40_4KNW" ||
|
std::to_string(ci->type == ctx->id("SB_RAM40_4KNW") ||
|
||||||
ci->type == "SB_RAM40_4KNRNW");
|
ci->type == ctx->id("SB_RAM40_4KNRNW"));
|
||||||
packed->params["NEG_CLK_R"] =
|
packed->params["NEG_CLK_R"] =
|
||||||
std::to_string(ci->type == "SB_RAM40_4KNR" ||
|
std::to_string(ci->type == ctx->id("SB_RAM40_4KNR") ||
|
||||||
ci->type == "SB_RAM40_4KNRNW");
|
ci->type == ctx->id("SB_RAM40_4KNRNW"));
|
||||||
packed->type = "ICESTORM_RAM";
|
packed->type = ctx->id("ICESTORM_RAM");
|
||||||
for (auto port : ci->ports) {
|
for (auto port : ci->ports) {
|
||||||
PortInfo &pi = port.second;
|
PortInfo &pi = port.second;
|
||||||
std::string newname = pi.name;
|
std::string newname = pi.name;
|
||||||
@ -168,8 +168,8 @@ static void set_net_constant(const Context *ctx, NetInfo *orig,
|
|||||||
for (auto user : orig->users) {
|
for (auto user : orig->users) {
|
||||||
if (user.cell != nullptr) {
|
if (user.cell != nullptr) {
|
||||||
CellInfo *uc = user.cell;
|
CellInfo *uc = user.cell;
|
||||||
log_info("%s user %s\n", orig->name.c_str(), uc->name.c_str());
|
log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx));
|
||||||
if (is_lut(ctx, uc) && (user.port.str().at(0) == 'I') &&
|
if (is_lut(ctx, uc) && (user.port.str(ctx).at(0) == 'I') &&
|
||||||
!constval) {
|
!constval) {
|
||||||
uc->ports[user.port].net = nullptr;
|
uc->ports[user.port].net = nullptr;
|
||||||
} else {
|
} else {
|
||||||
@ -187,30 +187,30 @@ static void pack_constants(Context *ctx)
|
|||||||
log_info("Packing constants..\n");
|
log_info("Packing constants..\n");
|
||||||
|
|
||||||
CellInfo *gnd_cell = create_ice_cell(ctx, "ICESTORM_LC", "$PACKER_GND");
|
CellInfo *gnd_cell = create_ice_cell(ctx, "ICESTORM_LC", "$PACKER_GND");
|
||||||
gnd_cell->params["LUT_INIT"] = "0";
|
gnd_cell->params[ctx->id("LUT_INIT")] = "0";
|
||||||
NetInfo *gnd_net = new NetInfo;
|
NetInfo *gnd_net = new NetInfo;
|
||||||
gnd_net->name = "$PACKER_GND_NET";
|
gnd_net->name = "$PACKER_GND_NET";
|
||||||
gnd_net->driver.cell = gnd_cell;
|
gnd_net->driver.cell = gnd_cell;
|
||||||
gnd_net->driver.port = "O";
|
gnd_net->driver.port = ctx->id("O");
|
||||||
|
|
||||||
CellInfo *vcc_cell = create_ice_cell(ctx, "ICESTORM_LC", "$PACKER_VCC");
|
CellInfo *vcc_cell = create_ice_cell(ctx, "ICESTORM_LC", "$PACKER_VCC");
|
||||||
vcc_cell->params["LUT_INIT"] = "1";
|
vcc_cell->params[ctx->id("LUT_INIT")] = "1";
|
||||||
NetInfo *vcc_net = new NetInfo;
|
NetInfo *vcc_net = new NetInfo;
|
||||||
vcc_net->name = "$PACKER_VCC_NET";
|
vcc_net->name = ctx->id("$PACKER_VCC_NET");
|
||||||
vcc_net->driver.cell = vcc_cell;
|
vcc_net->driver.cell = vcc_cell;
|
||||||
vcc_net->driver.port = "O";
|
vcc_net->driver.port = ctx->id("O");
|
||||||
|
|
||||||
std::vector<IdString> dead_nets;
|
std::vector<IdString> dead_nets;
|
||||||
|
|
||||||
for (auto net : ctx->nets) {
|
for (auto net : ctx->nets) {
|
||||||
NetInfo *ni = net.second;
|
NetInfo *ni = net.second;
|
||||||
if (ni->driver.cell != nullptr && ni->driver.cell->type == "GND") {
|
if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) {
|
||||||
set_net_constant(ctx, ni, gnd_net, false);
|
set_net_constant(ctx, ni, gnd_net, false);
|
||||||
ctx->cells[gnd_cell->name] = gnd_cell;
|
ctx->cells[gnd_cell->name] = gnd_cell;
|
||||||
ctx->nets[gnd_net->name] = gnd_net;
|
ctx->nets[gnd_net->name] = gnd_net;
|
||||||
dead_nets.push_back(net.first);
|
dead_nets.push_back(net.first);
|
||||||
} else if (ni->driver.cell != nullptr &&
|
} else if (ni->driver.cell != nullptr &&
|
||||||
ni->driver.cell->type == "VCC") {
|
ni->driver.cell->type == ctx->id("VCC")) {
|
||||||
set_net_constant(ctx, ni, vcc_net, true);
|
set_net_constant(ctx, ni, vcc_net, true);
|
||||||
ctx->cells[vcc_cell->name] = vcc_cell;
|
ctx->cells[vcc_cell->name] = vcc_cell;
|
||||||
ctx->nets[vcc_net->name] = vcc_net;
|
ctx->nets[vcc_net->name] = vcc_net;
|
||||||
@ -222,10 +222,10 @@ static void pack_constants(Context *ctx)
|
|||||||
ctx->nets.erase(dn);
|
ctx->nets.erase(dn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_nextpnr_iob(CellInfo *cell)
|
static bool is_nextpnr_iob(Context *ctx, CellInfo *cell)
|
||||||
{
|
{
|
||||||
return cell->type == "$nextpnr_ibuf" || cell->type == "$nextpnr_obuf" ||
|
return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") ||
|
||||||
cell->type == "$nextpnr_iobuf";
|
cell->type == ctx->id("$nextpnr_iobuf");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pack IO buffers
|
// Pack IO buffers
|
||||||
@ -238,13 +238,13 @@ static void pack_io(Context *ctx)
|
|||||||
|
|
||||||
for (auto cell : ctx->cells) {
|
for (auto cell : ctx->cells) {
|
||||||
CellInfo *ci = cell.second;
|
CellInfo *ci = cell.second;
|
||||||
if (is_nextpnr_iob(ci)) {
|
if (is_nextpnr_iob(ctx, ci)) {
|
||||||
CellInfo *sb = nullptr;
|
CellInfo *sb = nullptr;
|
||||||
if (ci->type == "$nextpnr_ibuf" || ci->type == "$nextpnr_iobuf") {
|
if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) {
|
||||||
sb = net_only_drives(ctx, ci->ports.at("O").net, is_sb_io,
|
sb = net_only_drives(ctx, ci->ports.at("O").net, is_sb_io,
|
||||||
"PACKAGE_PIN", true, ci);
|
"PACKAGE_PIN", true, ci);
|
||||||
|
|
||||||
} else if (ci->type == "$nextpnr_obuf") {
|
} else if (ci->type == ctx->id("$nextpnr_obuf")) {
|
||||||
sb = net_only_drives(ctx, ci->ports.at("I").net, is_sb_io,
|
sb = net_only_drives(ctx, ci->ports.at("I").net, is_sb_io,
|
||||||
"PACKAGE_PIN", true, ci);
|
"PACKAGE_PIN", true, ci);
|
||||||
}
|
}
|
||||||
@ -252,8 +252,8 @@ static void pack_io(Context *ctx)
|
|||||||
// Trivial case, SB_IO used. Just destroy the net and the
|
// Trivial case, SB_IO used. Just destroy the net and the
|
||||||
// iobuf
|
// iobuf
|
||||||
log_info("%s feeds SB_IO %s, removing %s %s.\n",
|
log_info("%s feeds SB_IO %s, removing %s %s.\n",
|
||||||
ci->name.c_str(), sb->name.c_str(), ci->type.c_str(),
|
ci->name.c_str(ctx), sb->name.c_str(ctx), ci->type.c_str(ctx),
|
||||||
ci->name.c_str());
|
ci->name.c_str(ctx));
|
||||||
NetInfo *net = sb->ports.at("PACKAGE_PIN").net;
|
NetInfo *net = sb->ports.at("PACKAGE_PIN").net;
|
||||||
if (net != nullptr) {
|
if (net != nullptr) {
|
||||||
ctx->nets.erase(net->name);
|
ctx->nets.erase(net->name);
|
||||||
@ -281,22 +281,22 @@ static void pack_io(Context *ctx)
|
|||||||
static void insert_global(Context *ctx, NetInfo *net, bool is_reset,
|
static void insert_global(Context *ctx, NetInfo *net, bool is_reset,
|
||||||
bool is_cen)
|
bool is_cen)
|
||||||
{
|
{
|
||||||
std::string glb_name = net->name.str() + std::string("_$glb_") +
|
std::string glb_name = net->name.str(ctx) + std::string("_$glb_") +
|
||||||
(is_reset ? "sr" : (is_cen ? "ce" : "clk"));
|
(is_reset ? "sr" : (is_cen ? "ce" : "clk"));
|
||||||
CellInfo *gb = create_ice_cell(ctx, "SB_GB", "$gbuf_" + glb_name);
|
CellInfo *gb = create_ice_cell(ctx, "SB_GB", "$gbuf_" + glb_name);
|
||||||
gb->ports["USER_SIGNAL_TO_GLOBAL_BUFFER"].net = net;
|
gb->ports[ctx->id("USER_SIGNAL_TO_GLOBAL_BUFFER")].net = net;
|
||||||
PortRef pr;
|
PortRef pr;
|
||||||
pr.cell = gb;
|
pr.cell = gb;
|
||||||
pr.port = "USER_SIGNAL_TO_GLOBAL_BUFFER";
|
pr.port = ctx->id("USER_SIGNAL_TO_GLOBAL_BUFFER");
|
||||||
net->users.push_back(pr);
|
net->users.push_back(pr);
|
||||||
|
|
||||||
pr.cell = gb;
|
pr.cell = gb;
|
||||||
pr.port = "GLOBAL_BUFFER_OUTPUT";
|
pr.port = ctx->id("GLOBAL_BUFFER_OUTPUT");
|
||||||
NetInfo *glbnet = new NetInfo();
|
NetInfo *glbnet = new NetInfo();
|
||||||
glbnet->name = glb_name;
|
glbnet->name = ctx->id(glb_name);
|
||||||
glbnet->driver = pr;
|
glbnet->driver = pr;
|
||||||
ctx->nets[glbnet->name] = glbnet;
|
ctx->nets[glbnet->name] = glbnet;
|
||||||
gb->ports["GLOBAL_BUFFER_OUTPUT"].net = glbnet;
|
gb->ports[ctx->id("GLOBAL_BUFFER_OUTPUT")].net = glbnet;
|
||||||
std::vector<PortRef> keep_users;
|
std::vector<PortRef> keep_users;
|
||||||
for (auto user : net->users) {
|
for (auto user : net->users) {
|
||||||
if (is_clock_port(ctx, user) ||
|
if (is_clock_port(ctx, user) ||
|
||||||
|
Loading…
Reference in New Issue
Block a user