diff options
Diffstat (limited to 'ecp5/lpf.cc')
-rw-r--r-- | ecp5/lpf.cc | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/ecp5/lpf.cc b/ecp5/lpf.cc new file mode 100644 index 00000000..c8e61414 --- /dev/null +++ b/ecp5/lpf.cc @@ -0,0 +1,103 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 David Shah <david@symbioticeda.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 <sstream> +#include "log.h" +#include "log.h" + +NEXTPNR_NAMESPACE_BEGIN + +bool Arch::applyLPF(std::string filename, std::istream &in) +{ + auto isempty = [] (const std::string &str) {return std::all_of(str.begin(), str.end(), [](char c){return isblank(c);});}; + auto strip_quotes = [] (const std::string &str) {if (str.at(0) == '"') { + NPNR_ASSERT(str.back() == '"'); + return str.substr(1, str.size() - 2); + } else { + return str; + }}; + + try { + if (!in) + log_error("failed to open LPF file\n"); + std::string line; + std::string linebuf; + while (std::getline(in, line)) { + size_t cstart = line.find('#'); + if (cstart != std::string::npos) + line = line.substr(0, cstart); + if (isempty(line)) + continue; + linebuf += line; + // Look for a command up to a semicolon + size_t scpos = linebuf.find(';'); + while (scpos != std::string::npos) { + std::string command = linebuf.substr(0, scpos); + // Split command into words + std::stringstream ss(line); + std::vector<std::string> words; + std::string tmp; + while (ss >> tmp) + words.push_back(tmp); + if (words.size() >= 0) { + std::string verb = words.at(0); + if(verb == "BLOCK" || verb == "SYSCONFIG" || verb == "FREQUENCY") { + log_warning(" ignoring unsupported LPF command '%s'\n", command.c_str()); + } else if (verb == "LOCATE") { + NPNR_ASSERT(words.at(1) == "COMP"); + std::string cell = strip_quotes(words.at(2)); + NPNR_ASSERT(words.at(1) == "SITE"); + auto fnd_cell = cells.find(id(cell)); + if (fnd_cell == cells.end()) { + log_warning("unmatched LPF 'LOCATE COMP' '%s'\n", cell.c_str()); + } else { + fnd_cell->second->attrs[id("LOC")] = strip_quotes(words.at(3)); + } + } else if (verb == "IOBUF") { + NPNR_ASSERT(words.at(1) == "PORT"); + std::string cell = strip_quotes(words.at(2)); + auto fnd_cell = cells.find(id(cell)); + if (fnd_cell == cells.end()) { + log_warning("unmatched LPF 'IOBUF PORT' '%s'\n", cell.c_str()); + } else { + for (size_t i = 3; i < words.size(); i++) { + std::string setting = words.at(i); + size_t eqpos = setting.find('='); + NPNR_ASSERT(eqpos != std::string::npos); + std::string key = setting.substr(0, eqpos), value = setting.substr(eqpos + 1); + fnd_cell->second->attrs[id(key)] = value; + } + } + } + } + + linebuf = linebuf.substr(scpos+1); + scpos = linebuf.find(';'); + } + } + if (!isempty(linebuf)) + log_error("unexpected end of LPF file\n"); + settings.emplace(id("input/lpf"), filename); + return true; + } catch (log_execution_error_exception) { + return false; + } +} + +NEXTPNR_NAMESPACE_END |