diff --git a/himbaechel/uarch/xilinx/xdc.cc b/himbaechel/uarch/xilinx/xdc.cc index e6d76b59..1a16b9bd 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