From e7f8ca5ea627680fa90947010b91779e1c686aec Mon Sep 17 00:00:00 2001 From: Rowan Goemans Date: Thu, 26 Sep 2024 18:26:03 +0200 Subject: [PATCH] sdc: add_false_path to PathConstraint logic --- common/kernel/sdc.cc | 120 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 96 insertions(+), 24 deletions(-) diff --git a/common/kernel/sdc.cc b/common/kernel/sdc.cc index 214acc2f..bc93da9b 100644 --- a/common/kernel/sdc.cc +++ b/common/kernel/sdc.cc @@ -28,6 +28,22 @@ 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 { enum EntityType @@ -59,6 +75,23 @@ struct SdcEntity 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 { if (type == ENTITY_PIN) { @@ -251,6 +284,60 @@ struct SDCParser 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 &arguments) { std::vector nets; @@ -318,7 +405,7 @@ struct SDCParser if (pos == std::string::npos) 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))); - 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()); pins.pop_back(); } @@ -369,8 +456,8 @@ struct SDCParser SdcValue cmd_set_false_path(const std::vector &arguments) { - NetInfo *from = nullptr; - NetInfo *to = nullptr; + PathConstraint ct; + ct.exception = FalsePath{}; for (int i = 1; i < int(arguments.size()); i++) { auto &arg = arguments.at(i); @@ -396,32 +483,17 @@ struct SDCParser auto &ety = val.list.at(0); - NetInfo *net = nullptr; - 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; - } + sdc_into_path_constraint(ety, is_from, ct); } } - if (from == nullptr) { - log_error("-from is required for set_false_path (line %d)\n", lineno); - } else if (to == nullptr) { - log_error("-to is required for set_false_path (line %d)\n", lineno); + if (ct.from.empty()) { + log_error("query specified in -from did not find any pins or ports (line %d)\n", lineno); + } else if (ct.to.empty()) { + 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), - to->name.c_str(ctx)); + ctx->path_constraints.emplace_back(ct); return std::string{}; }