sdc: add_false_path to PathConstraint logic
This commit is contained in:
parent
7f35139b8e
commit
e7f8ca5ea6
@ -28,6 +28,22 @@
|
|||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
bool is_startpoint(Context *ctx, const PortRef &port)
|
||||||
|
{
|
||||||
|
int clkInfoCount;
|
||||||
|
TimingPortClass cls = ctx->getPortTimingClass(port.cell, port.port, clkInfoCount);
|
||||||
|
|
||||||
|
return cls == TMG_STARTPOINT || cls == TMG_REGISTER_OUTPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_endpoint(Context *ctx, const PortRef &port)
|
||||||
|
{
|
||||||
|
int clkInfoCount;
|
||||||
|
TimingPortClass cls = ctx->getPortTimingClass(port.cell, port.port, clkInfoCount);
|
||||||
|
|
||||||
|
return cls == TMG_ENDPOINT || cls == TMG_REGISTER_OUTPUT;
|
||||||
|
}
|
||||||
|
|
||||||
struct SdcEntity
|
struct SdcEntity
|
||||||
{
|
{
|
||||||
enum EntityType
|
enum EntityType
|
||||||
@ -59,6 +75,23 @@ struct SdcEntity
|
|||||||
return &ctx->ports.at(name);
|
return &ctx->ports.at(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PortRef get_pin(Context *ctx) const
|
||||||
|
{
|
||||||
|
if (type != ENTITY_PIN)
|
||||||
|
return PortRef{nullptr, IdString()};
|
||||||
|
|
||||||
|
CellInfo *cell = nullptr;
|
||||||
|
if (ctx->cells.count(name)) {
|
||||||
|
cell = ctx->cells.at(name).get();
|
||||||
|
} else {
|
||||||
|
return PortRef{nullptr, IdString()};
|
||||||
|
}
|
||||||
|
if (!cell->ports.count(pin))
|
||||||
|
return PortRef{nullptr, IdString()};
|
||||||
|
|
||||||
|
return PortRef{cell, pin};
|
||||||
|
}
|
||||||
|
|
||||||
NetInfo *get_net(Context *ctx) const
|
NetInfo *get_net(Context *ctx) const
|
||||||
{
|
{
|
||||||
if (type == ENTITY_PIN) {
|
if (type == ENTITY_PIN) {
|
||||||
@ -251,6 +284,60 @@ struct SDCParser
|
|||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse an argument to -from/to into the path_constraint
|
||||||
|
void sdc_into_path_constraint(const SdcEntity &ety, bool is_from, PathConstraint &ct)
|
||||||
|
{
|
||||||
|
auto &target = is_from ? ct.from : ct.to;
|
||||||
|
auto test_port = is_from ? is_startpoint : is_endpoint;
|
||||||
|
std::string tartget_str = is_from ? "startpoint" : "endpoint";
|
||||||
|
|
||||||
|
if (ety.type == SdcEntity::ENTITY_PIN) {
|
||||||
|
auto port_ref = ety.get_pin(ctx);
|
||||||
|
if (test_port(ctx, port_ref) == false) {
|
||||||
|
log_error("\"%s.%s\" is not a timing %s (line %d)\n", port_ref.cell->name.c_str(ctx),
|
||||||
|
port_ref.port.c_str(ctx), tartget_str.c_str(), lineno);
|
||||||
|
}
|
||||||
|
target.emplace(CellPortKey(port_ref));
|
||||||
|
} else if (ety.type == SdcEntity::ENTITY_NET) {
|
||||||
|
auto net = ety.get_net(ctx);
|
||||||
|
if (is_from) {
|
||||||
|
auto port_ref = net->driver;
|
||||||
|
if (test_port(ctx, port_ref) == false) {
|
||||||
|
log_error("\"%s.%s\" is not a timing %s (line %d)\n", port_ref.cell->name.c_str(ctx),
|
||||||
|
port_ref.port.c_str(ctx), tartget_str.c_str(), lineno);
|
||||||
|
}
|
||||||
|
target.emplace(CellPortKey(port_ref));
|
||||||
|
} else {
|
||||||
|
for (const auto &usr : net->users) {
|
||||||
|
if (test_port(ctx, usr) == false) {
|
||||||
|
log_error("\"%s.%s\" is not a timing %s (line %d)\n", usr.cell->name.c_str(ctx),
|
||||||
|
usr.port.c_str(ctx), tartget_str.c_str(), lineno);
|
||||||
|
}
|
||||||
|
target.emplace(CellPortKey(usr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ety.type == SdcEntity::ENTITY_PORT) {
|
||||||
|
auto ioport_ref = ety.get_port(ctx);
|
||||||
|
auto net = ioport_ref->net;
|
||||||
|
if (is_from) {
|
||||||
|
auto port_ref = net->driver;
|
||||||
|
if (test_port(ctx, port_ref) == false) {
|
||||||
|
log_error("\"%s.%s\" is not a timing %s (line %d)\n", port_ref.cell->name.c_str(ctx),
|
||||||
|
port_ref.port.c_str(ctx), tartget_str.c_str(), lineno);
|
||||||
|
}
|
||||||
|
target.emplace(CellPortKey(port_ref));
|
||||||
|
} else {
|
||||||
|
for (const auto &usr : net->users) {
|
||||||
|
if (test_port(ctx, usr) == false) {
|
||||||
|
log_error("\"%s.%s\" is not a timing %s (line %d)\n", usr.cell->name.c_str(ctx),
|
||||||
|
usr.port.c_str(ctx), tartget_str.c_str(), lineno);
|
||||||
|
}
|
||||||
|
target.emplace(CellPortKey(usr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SdcValue cmd_get_nets(const std::vector<SdcValue> &arguments)
|
SdcValue cmd_get_nets(const std::vector<SdcValue> &arguments)
|
||||||
{
|
{
|
||||||
std::vector<SdcEntity> nets;
|
std::vector<SdcEntity> nets;
|
||||||
@ -318,7 +405,7 @@ struct SDCParser
|
|||||||
if (pos == std::string::npos)
|
if (pos == std::string::npos)
|
||||||
log_error("expected / in cell pin name '%s' (line %d)\n", s.c_str(), lineno);
|
log_error("expected / in cell pin name '%s' (line %d)\n", s.c_str(), lineno);
|
||||||
pins.emplace_back(SdcEntity::ENTITY_PIN, ctx->id(s.substr(0, pos)), ctx->id(s.substr(pos + 1)));
|
pins.emplace_back(SdcEntity::ENTITY_PIN, ctx->id(s.substr(0, pos)), ctx->id(s.substr(pos + 1)));
|
||||||
if (pins.back().get_net(ctx) == nullptr) {
|
if (pins.back().get_pin(ctx).cell == nullptr) {
|
||||||
log_warning("cell pin '%s' not found\n", s.c_str());
|
log_warning("cell pin '%s' not found\n", s.c_str());
|
||||||
pins.pop_back();
|
pins.pop_back();
|
||||||
}
|
}
|
||||||
@ -369,8 +456,8 @@ struct SDCParser
|
|||||||
|
|
||||||
SdcValue cmd_set_false_path(const std::vector<SdcValue> &arguments)
|
SdcValue cmd_set_false_path(const std::vector<SdcValue> &arguments)
|
||||||
{
|
{
|
||||||
NetInfo *from = nullptr;
|
PathConstraint ct;
|
||||||
NetInfo *to = nullptr;
|
ct.exception = FalsePath{};
|
||||||
|
|
||||||
for (int i = 1; i < int(arguments.size()); i++) {
|
for (int i = 1; i < int(arguments.size()); i++) {
|
||||||
auto &arg = arguments.at(i);
|
auto &arg = arguments.at(i);
|
||||||
@ -396,32 +483,17 @@ struct SDCParser
|
|||||||
|
|
||||||
auto &ety = val.list.at(0);
|
auto &ety = val.list.at(0);
|
||||||
|
|
||||||
NetInfo *net = nullptr;
|
sdc_into_path_constraint(ety, is_from, ct);
|
||||||
if (ety.type == SdcEntity::ENTITY_PIN)
|
|
||||||
net = ety.get_net(ctx);
|
|
||||||
else if (ety.type == SdcEntity::ENTITY_NET)
|
|
||||||
net = ctx->nets.at(ety.name).get();
|
|
||||||
else if (ety.type == SdcEntity::ENTITY_PORT)
|
|
||||||
net = ctx->ports.at(ety.name).net;
|
|
||||||
else
|
|
||||||
log_error("set_false_path applies only to nets, cell pins, or IO ports (line %d)\n", lineno);
|
|
||||||
|
|
||||||
if (is_from) {
|
|
||||||
from = net;
|
|
||||||
} else {
|
|
||||||
to = net;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (from == nullptr) {
|
if (ct.from.empty()) {
|
||||||
log_error("-from is required for set_false_path (line %d)\n", lineno);
|
log_error("query specified in -from did not find any pins or ports (line %d)\n", lineno);
|
||||||
} else if (to == nullptr) {
|
} else if (ct.to.empty()) {
|
||||||
log_error("-to is required for set_false_path (line %d)\n", lineno);
|
log_error("query specified in -to did not find any pins or ports (line %d)\n", lineno);
|
||||||
}
|
}
|
||||||
|
|
||||||
log_warning("set_false_path from: %s, to: %s does not do anything(yet).\n", from->name.c_str(ctx),
|
ctx->path_constraints.emplace_back(ct);
|
||||||
to->name.c_str(ctx));
|
|
||||||
|
|
||||||
return std::string{};
|
return std::string{};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user