From 47ea599e564d00290af11753d002bd17fd5b5cf4 Mon Sep 17 00:00:00 2001 From: Adrien Prost-Boucle Date: Tue, 1 Oct 2024 10:04:49 +0200 Subject: [PATCH 1/6] BaseCtx : Fix crash in getNetByAlias() --- common/kernel/basectx.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/kernel/basectx.h b/common/kernel/basectx.h index c8791a2b96..7ff1822829 100644 --- a/common/kernel/basectx.h +++ b/common/kernel/basectx.h @@ -213,7 +213,9 @@ struct BaseCtx NetInfo *getNetByAlias(IdString alias) const { - return nets.count(alias) ? nets.at(alias).get() : nets.at(net_aliases.at(alias)).get(); + if(nets.count(alias) > 0) return nets.at(alias).get(); + if(net_aliases.count(alias) == 0) return nullptr; + return nets.at(net_aliases.at(alias)).get(); } // Intended to simplify Python API From 98094672e0062410e3f8de8498f40bc246f30987 Mon Sep 17 00:00:00 2001 From: Adrien Prost-Boucle Date: Tue, 1 Oct 2024 11:11:21 +0200 Subject: [PATCH 2/6] Himbaechel Xilinx : More warning messages about unsupported things in XDC file --- himbaechel/uarch/xilinx/xdc.cc | 70 ++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/himbaechel/uarch/xilinx/xdc.cc b/himbaechel/uarch/xilinx/xdc.cc index e6d76b599a..1a16b9bdc9 100644 --- a/himbaechel/uarch/xilinx/xdc.cc +++ b/himbaechel/uarch/xilinx/xdc.cc @@ -39,9 +39,11 @@ void XilinxImpl::parse_xdc(const std::string &filename) std::ifstream in(filename); if (!in) log_error("failed to open XDC file '%s'\n", filename.c_str()); + log_info("Parsing XDC file...\n"); std::string line; std::string linebuf; int lineno = 0; + unsigned num_errors = 0; auto isempty = [](const std::string &str) { return std::all_of(str.begin(), str.end(), [](char c) { return std::isspace(c); }); @@ -109,8 +111,10 @@ void XilinxImpl::parse_xdc(const std::string &filename) auto get_nets = [&](std::string str) { std::vector tgt_nets; - if (str.empty() || str.front() != '[') - log_error("failed to parse target (on line %d)\n", lineno); + if (str.empty()) + return tgt_nets; + if (str.front() != '[' || str.back() != ']') + log_error("failed to parse target '%s' (on line %d)\n", str.c_str(), lineno); str = str.substr(1, str.size() - 2); auto split = split_to_args(str, false); if (split.size() < 1) @@ -141,12 +145,18 @@ void XilinxImpl::parse_xdc(const std::string &filename) std::string &cmd = arguments.front(); if (cmd == "set_property") { std::vector> arg_pairs; - if (arguments.size() != 4) - log_error("expected four arguments to 'set_property' (on line %d)\n", lineno); + if (arguments.size() != 4) { + log_nonfatal_error("expected at four arguments to 'set_property' (on line %d)\n", lineno); + num_errors++; + goto nextline; + } else if (arguments.at(1) == "-dict") { std::vector dict_args = split_to_args(strip_quotes(arguments.at(2)), false); - if ((dict_args.size() % 2) != 0) - log_error("expected an even number of argument for dictionary (on line %d)\n", lineno); + if ((dict_args.size() % 2) != 0) { + log_nonfatal_error("expected an even number of argument for dictionary (on line %d)\n", lineno); + num_errors++; + goto nextline; + } arg_pairs.reserve(dict_args.size() / 2); for (int cursor = 0; cursor + 1 < int(dict_args.size()); cursor += 2) { arg_pairs.emplace_back(std::move(dict_args.at(cursor)), std::move(dict_args.at(cursor + 1))); @@ -154,8 +164,11 @@ void XilinxImpl::parse_xdc(const std::string &filename) } else { arg_pairs.emplace_back(std::move(arguments.at(1)), std::move(arguments.at(2))); } - if (arg_pairs.size() == 1 && arg_pairs.front().first == "INTERNAL_VREF") // get_iobanks not supported + // Warning : ug835 has lowercase example, so probably supporting lowercase too is needed + if (arg_pairs.size() == 1 && arg_pairs.front().first == "INTERNAL_VREF") { // get_iobanks not supported + log_warning("INTERNAL_VREF isn't supported, ignoring (on line %d)\n", lineno); continue; + } if (arguments.at(3).size() > 2 && arguments.at(3) == "[current_design]") { log_warning("[current_design] isn't supported, ignoring (on line %d)\n", lineno); continue; @@ -170,32 +183,57 @@ void XilinxImpl::parse_xdc(const std::string &filename) int cursor = 1; for (cursor = 1; cursor < int(arguments.size()); cursor++) { std::string opt = arguments.at(cursor); - if (opt == "-add") - ; - else if (opt == "-name" || opt == "-waveform") + if (opt == "-add") { + log_warning("ignoring unsupported XDC option '%s' (on line %d)\n", opt.c_str(), lineno); + } + else if (opt == "-name" || opt == "-waveform") { + log_warning("ignoring unsupported XDC option '%s' (on line %d)\n", opt.c_str(), lineno); cursor++; + } else if (opt == "-period") { cursor++; period = std::stod(arguments.at(cursor)); got_period = true; - } else + } + else break; } - if (!got_period) - log_error("found create_clock without period (on line %d)", lineno); + if (!got_period) { + log_nonfatal_error("found create_clock without period (on line %d)\n", lineno); + num_errors++; + goto nextline; + } + if (cursor >= int(arguments.size())) { + log_warning("found create_clock without designated nets (on line %d)\n", lineno); + goto nextline; + } std::vector dest = get_nets(arguments.at(cursor)); for (auto n : dest) { + if (ctx->debug) + log_info("applying clock period constraint on net '%s' (on line %d)\n", n->name.c_str(ctx), lineno); + if (n->clkconstr.get() != nullptr) { + log_nonfatal_error("found multiple clock constraints on net '%s' (on line %d)\n", n->name.c_str(ctx), lineno); + num_errors++; + } n->clkconstr = std::unique_ptr(new ClockConstraint); n->clkconstr->period = DelayPair(ctx->getDelayFromNS(period)); n->clkconstr->high = DelayPair(ctx->getDelayFromNS(period / 2)); n->clkconstr->low = DelayPair(ctx->getDelayFromNS(period / 2)); } } else { - log_info("ignoring unsupported XDC command '%s' (on line %d)\n", cmd.c_str(), lineno); + log_warning("ignoring unsupported XDC command '%s' (on line %d)\n", cmd.c_str(), lineno); } + + nextline: + ; // Phony statement to have something legal after the label + } + if (!isempty(linebuf)) { + log_nonfatal_error("unexpected end of XDC file\n"); + num_errors++; + } + if (num_errors > 0) { + log_error("Stopping the program after %u errors found in XDC file\n", num_errors); } - if (!isempty(linebuf)) - log_error("unexpected end of XDC file\n"); } NEXTPNR_NAMESPACE_END From a26b6de415b5bb5757f7aaa505c9394576dbaa6d Mon Sep 17 00:00:00 2001 From: Adrien Prost-Boucle Date: Tue, 1 Oct 2024 11:19:03 +0200 Subject: [PATCH 3/6] Himbaechel Xilinx : Support multiple nets per command --- himbaechel/uarch/xilinx/xdc.cc | 40 ++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/himbaechel/uarch/xilinx/xdc.cc b/himbaechel/uarch/xilinx/xdc.cc index 1a16b9bdc9..eaa2c513ce 100644 --- a/himbaechel/uarch/xilinx/xdc.cc +++ b/himbaechel/uarch/xilinx/xdc.cc @@ -143,10 +143,11 @@ void XilinxImpl::parse_xdc(const std::string &filename) if (arguments.empty()) continue; std::string &cmd = arguments.front(); + if (cmd == "set_property") { std::vector> arg_pairs; - if (arguments.size() != 4) { - log_nonfatal_error("expected at four arguments to 'set_property' (on line %d)\n", lineno); + if (arguments.size() < 4) { + log_nonfatal_error("expected at least four arguments to 'set_property' (on line %d)\n", lineno); num_errors++; goto nextline; } @@ -173,10 +174,26 @@ void XilinxImpl::parse_xdc(const std::string &filename) log_warning("[current_design] isn't supported, ignoring (on line %d)\n", lineno); continue; } - std::vector dest = get_cells(arguments.at(3)); - for (auto c : dest) - for (const auto &pair : arg_pairs) - c->attrs[ctx->id(pair.first)] = std::string(pair.second); + // All remaining arguments are supposed to designate cells + std::vector dest; + for (int cursor = 3; cursor < int(arguments.size()); cursor++) { + std::vector dest_loc = get_cells(arguments.at(cursor)); + if (dest_loc.empty()) + log_warning("found set_property with no cells matching '%s' (on line %d)\n", arguments.at(cursor).c_str(), lineno); + dest.insert(dest.end(), dest_loc.begin(), dest_loc.end()); + } + for (auto c : dest) { + for (const auto &pair : arg_pairs) { + IdString id_prop = ctx->id(pair.first); + if (ctx->debug) + log_info("applying property '%s' = '%s' to cell '%s' (on line %d)\n", pair.first.c_str(), pair.second.c_str(), c->name.c_str(ctx), lineno); + if(c->attrs.find(id_prop) != c->attrs.end()) { + log_nonfatal_error("found multiple properties '%s' for cell '%s' (on line %d)\n", pair.first.c_str(), c->name.c_str(ctx), lineno); + num_errors++; + } + c->attrs[id_prop] = std::string(pair.second); + } + } } else if (cmd == "create_clock") { double period = 0; bool got_period = false; @@ -203,11 +220,16 @@ void XilinxImpl::parse_xdc(const std::string &filename) num_errors++; goto nextline; } - if (cursor >= int(arguments.size())) { + // All remaining arguments are supposed to designate ports/nets + std::vector dest; + if (cursor >= int(arguments.size())) log_warning("found create_clock without designated nets (on line %d)\n", lineno); - goto nextline; + for ( ; cursor < (int)arguments.size(); cursor++) { + std::vector dest_loc = get_nets(arguments.at(cursor)); + if (dest_loc.empty()) + log_warning("found create_clock with no nets matching '%s' (on line %d)\n", arguments.at(cursor).c_str(), lineno); + dest.insert(dest.end(), dest_loc.begin(), dest_loc.end()); } - std::vector dest = get_nets(arguments.at(cursor)); for (auto n : dest) { if (ctx->debug) log_info("applying clock period constraint on net '%s' (on line %d)\n", n->name.c_str(ctx), lineno); From e65438eaab3e9140115206b63357fc680b80a0cd Mon Sep 17 00:00:00 2001 From: Adrien Prost-Boucle Date: Tue, 1 Oct 2024 11:20:57 +0200 Subject: [PATCH 4/6] Himbaechel Xilinx : Support get_nets with braces around net name in XDC commands --- himbaechel/uarch/xilinx/xdc.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/himbaechel/uarch/xilinx/xdc.cc b/himbaechel/uarch/xilinx/xdc.cc index eaa2c513ce..8ae2d1ac7f 100644 --- a/himbaechel/uarch/xilinx/xdc.cc +++ b/himbaechel/uarch/xilinx/xdc.cc @@ -123,7 +123,10 @@ void XilinxImpl::parse_xdc(const std::string &filename) log_error("targets other than 'get_ports' or 'get_nets' are not supported (on line %d)\n", lineno); if (split.size() < 2) log_error("failed to parse target (on line %d)\n", lineno); - IdString netname = ctx->id(split.at(1)); + str = strip_quotes(split.at(1)); + if (str.empty()) + return tgt_nets; + IdString netname = ctx->id(str); NetInfo *maybe_net = ctx->getNetByAlias(netname); if (maybe_net != nullptr) tgt_nets.push_back(maybe_net); From 0aa8323ac68267cc6c857d9dbe8b52ff3fb07230 Mon Sep 17 00:00:00 2001 From: Adrien Prost-Boucle Date: Tue, 1 Oct 2024 11:23:33 +0200 Subject: [PATCH 5/6] Himbaechel Xilinx : XDC commands : Also search nets with lowercase for better interoperability with other synthesis tools and RTL languages --- himbaechel/uarch/xilinx/xdc.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/himbaechel/uarch/xilinx/xdc.cc b/himbaechel/uarch/xilinx/xdc.cc index 8ae2d1ac7f..b0f41922a0 100644 --- a/himbaechel/uarch/xilinx/xdc.cc +++ b/himbaechel/uarch/xilinx/xdc.cc @@ -128,6 +128,14 @@ void XilinxImpl::parse_xdc(const std::string &filename) return tgt_nets; IdString netname = ctx->id(str); NetInfo *maybe_net = ctx->getNetByAlias(netname); + if (maybe_net != nullptr) { + tgt_nets.push_back(maybe_net); + return tgt_nets; + } + // Also test the lowercase variant, for better interoperability with synthesis tools + boost::algorithm::to_lower(str); + netname = ctx->id(str); + maybe_net = ctx->getNetByAlias(netname); if (maybe_net != nullptr) tgt_nets.push_back(maybe_net); return tgt_nets; From 90c057ff5d6141738ab2b76b72f3e261c89b8888 Mon Sep 17 00:00:00 2001 From: Adrien Prost-Boucle Date: Tue, 1 Oct 2024 14:20:19 +0200 Subject: [PATCH 6/6] clang-format on basectx.h --- common/kernel/basectx.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/common/kernel/basectx.h b/common/kernel/basectx.h index 7ff1822829..3f021e82cc 100644 --- a/common/kernel/basectx.h +++ b/common/kernel/basectx.h @@ -213,8 +213,10 @@ struct BaseCtx NetInfo *getNetByAlias(IdString alias) const { - if(nets.count(alias) > 0) return nets.at(alias).get(); - if(net_aliases.count(alias) == 0) return nullptr; + if (nets.count(alias) > 0) + return nets.at(alias).get(); + if (net_aliases.count(alias) == 0) + return nullptr; return nets.at(net_aliases.at(alias)).get(); }