186 lines
6.2 KiB
C++
186 lines
6.2 KiB
C++
/*
|
|
* nextpnr -- Next Generation Place and Route
|
|
*
|
|
* Copyright (C) 2018 Claire Xenia Wolf <claire@yosyshq.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_types.h"
|
|
#include "context.h"
|
|
#include "log.h"
|
|
|
|
#include "nextpnr_namespaces.h"
|
|
|
|
NEXTPNR_NAMESPACE_BEGIN
|
|
|
|
void CellInfo::addInput(IdString name)
|
|
{
|
|
ports[name].name = name;
|
|
ports[name].type = PORT_IN;
|
|
}
|
|
void CellInfo::addOutput(IdString name)
|
|
{
|
|
ports[name].name = name;
|
|
ports[name].type = PORT_OUT;
|
|
}
|
|
void CellInfo::addInout(IdString name)
|
|
{
|
|
ports[name].name = name;
|
|
ports[name].type = PORT_INOUT;
|
|
}
|
|
|
|
void CellInfo::setParam(IdString name, Property value) { params[name] = value; }
|
|
void CellInfo::unsetParam(IdString name) { params.erase(name); }
|
|
void CellInfo::setAttr(IdString name, Property value) { attrs[name] = value; }
|
|
void CellInfo::unsetAttr(IdString name) { attrs.erase(name); }
|
|
|
|
bool CellInfo::testRegion(BelId bel) const
|
|
{
|
|
return region == nullptr || !region->constr_bels || region->bels.count(bel);
|
|
}
|
|
|
|
void CellInfo::connectPort(IdString port_name, NetInfo *net)
|
|
{
|
|
if (net == nullptr)
|
|
return;
|
|
PortInfo &port = ports.at(port_name);
|
|
NPNR_ASSERT(port.net == nullptr);
|
|
port.net = net;
|
|
if (port.type == PORT_OUT) {
|
|
NPNR_ASSERT(net->driver.cell == nullptr);
|
|
net->driver.cell = this;
|
|
net->driver.port = port_name;
|
|
} else if (port.type == PORT_IN || port.type == PORT_INOUT) {
|
|
PortRef user;
|
|
user.cell = this;
|
|
user.port = port_name;
|
|
net->users.push_back(user);
|
|
} else {
|
|
NPNR_ASSERT_FALSE("invalid port type for connect_port");
|
|
}
|
|
}
|
|
|
|
void CellInfo::disconnectPort(IdString port_name)
|
|
{
|
|
if (!ports.count(port_name))
|
|
return;
|
|
PortInfo &port = ports.at(port_name);
|
|
if (port.net != nullptr) {
|
|
port.net->users.erase(std::remove_if(port.net->users.begin(), port.net->users.end(),
|
|
[this, port_name](const PortRef &user) {
|
|
return user.cell == this && user.port == port_name;
|
|
}),
|
|
port.net->users.end());
|
|
if (port.net->driver.cell == this && port.net->driver.port == port_name)
|
|
port.net->driver.cell = nullptr;
|
|
port.net = nullptr;
|
|
}
|
|
}
|
|
|
|
void CellInfo::connectPorts(IdString port, CellInfo *other, IdString other_port)
|
|
{
|
|
PortInfo &port1 = ports.at(port);
|
|
if (port1.net == nullptr) {
|
|
// No net on port1; need to create one
|
|
NetInfo *p1net = ctx->createNet(ctx->id(name.str(ctx) + "$conn$" + port.str(ctx)));
|
|
connectPort(port, p1net);
|
|
}
|
|
other->connectPort(other_port, port1.net);
|
|
}
|
|
|
|
void CellInfo::movePortTo(IdString port, CellInfo *other, IdString other_port)
|
|
{
|
|
if (!ports.count(port))
|
|
return;
|
|
PortInfo &old = ports.at(port);
|
|
|
|
// Create port on the replacement cell if it doesn't already exist
|
|
if (!other->ports.count(other_port)) {
|
|
other->ports[other_port].name = other_port;
|
|
other->ports[other_port].type = old.type;
|
|
}
|
|
|
|
PortInfo &rep = other->ports.at(other_port);
|
|
NPNR_ASSERT(old.type == rep.type);
|
|
|
|
rep.net = old.net;
|
|
old.net = nullptr;
|
|
if (rep.type == PORT_OUT) {
|
|
if (rep.net != nullptr) {
|
|
rep.net->driver.cell = other;
|
|
rep.net->driver.port = other_port;
|
|
}
|
|
} else if (rep.type == PORT_IN) {
|
|
if (rep.net != nullptr) {
|
|
for (PortRef &load : rep.net->users) {
|
|
if (load.cell == this && load.port == port) {
|
|
load.cell = other;
|
|
load.port = other_port;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
NPNR_ASSERT(false);
|
|
}
|
|
}
|
|
|
|
void CellInfo::renamePort(IdString old_name, IdString new_name)
|
|
{
|
|
if (!ports.count(old_name))
|
|
return;
|
|
PortInfo pi = ports.at(old_name);
|
|
if (pi.net != nullptr) {
|
|
if (pi.net->driver.cell == this && pi.net->driver.port == old_name)
|
|
pi.net->driver.port = new_name;
|
|
for (auto &usr : pi.net->users)
|
|
if (usr.cell == this && usr.port == old_name)
|
|
usr.port = new_name;
|
|
}
|
|
ports.erase(old_name);
|
|
pi.name = new_name;
|
|
ports[new_name] = pi;
|
|
}
|
|
|
|
void CellInfo::movePortBusTo(IdString old_name, int old_offset, bool old_brackets, CellInfo *new_cell,
|
|
IdString new_name, int new_offset, bool new_brackets, int width)
|
|
{
|
|
for (int i = 0; i < width; i++) {
|
|
IdString old_port = ctx->id(stringf(old_brackets ? "%s[%d]" : "%s%d", old_name.c_str(ctx), i + old_offset));
|
|
IdString new_port = ctx->id(stringf(new_brackets ? "%s[%d]" : "%s%d", new_name.c_str(ctx), i + new_offset));
|
|
movePortTo(old_port, new_cell, new_port);
|
|
}
|
|
}
|
|
|
|
void CellInfo::copyPortTo(IdString port, CellInfo *other, IdString other_port)
|
|
{
|
|
if (!ports.count(port))
|
|
return;
|
|
other->ports[other_port].name = other_port;
|
|
other->ports[other_port].type = ports.at(port).type;
|
|
other->connectPort(other_port, ports.at(port).net);
|
|
}
|
|
|
|
void CellInfo::copyPortBusTo(IdString old_name, int old_offset, bool old_brackets, CellInfo *new_cell,
|
|
IdString new_name, int new_offset, bool new_brackets, int width)
|
|
{
|
|
for (int i = 0; i < width; i++) {
|
|
IdString old_port = ctx->id(stringf(old_brackets ? "%s[%d]" : "%s%d", old_name.c_str(ctx), i + old_offset));
|
|
IdString new_port = ctx->id(stringf(new_brackets ? "%s[%d]" : "%s%d", new_name.c_str(ctx), i + new_offset));
|
|
copyPortTo(old_port, new_cell, new_port);
|
|
}
|
|
}
|
|
|
|
NEXTPNR_NAMESPACE_END
|