Added IO cell type preference Signed-off-by: Maciej Kurc <mkurc@antmicro.com>
diff --git a/ql-iob-plugin/pinmap_parser.cc b/ql-iob-plugin/pinmap_parser.cc index 8215ca7..89a8da8 100644 --- a/ql-iob-plugin/pinmap_parser.cc +++ b/ql-iob-plugin/pinmap_parser.cc
@@ -73,6 +73,10 @@ std::string line; std::getline(*a_Stream, line); + if (line.empty()) { + continue; + } + // Parse datafields auto data = getFields(line);
diff --git a/ql-iob-plugin/ql-iob.cc b/ql-iob-plugin/ql-iob.cc index 3129d31..e382cea 100644 --- a/ql-iob-plugin/ql-iob.cc +++ b/ql-iob-plugin/ql-iob.cc
@@ -25,6 +25,7 @@ #include "kernel/rtlil.h" #include <regex> +#include <sstream> USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -37,6 +38,18 @@ struct QuicklogicIob : public Pass { + struct IoCellType { + std::string type; // Cell type + std::string port; // Name of the port that goes to a pad + std::vector<std::string> preferredTypes; // A list of preferred IO cell types + + IoCellType (const std::string& _type, const std::string& _port, const std::vector<std::string> _preferredTypes = std::vector<std::string>()) : + type(_type), + port(_port), + preferredTypes(_preferredTypes) + {} + }; + QuicklogicIob () : Pass("quicklogic_iob", "Map IO buffers to cells that correspond to their assigned locations") { register_in_tcl_interpreter(pass_name); @@ -62,11 +75,15 @@ log(" - <pinmap file>\n"); log(" Path to a pinmap CSV file with package pin map\n"); log("\n"); - log(" - <io cell specs>\n"); - log(" A space-separated list of <io cell type>:<port>. Each\n"); - log(" entry defines a type of IO cell to be affected an its port\n"); + log(" - <io cell specs> (optional)\n"); + log(" A space-separated list of <io cell type>:<port> or of\n"); + log(" <io cell type>:<port>:<preferred type 1>,<preferred type 2>...\n"); + log(" Each entry defines a type of IO cell to be affected an its port\n"); log(" name that should connect to the top-level port of the design.\n"); log("\n"); + log(" The third argument is a comma-separated list of preferred IO cell\n"); + log(" types in order of preference.\n"); + log("\n"); } void execute(std::vector<std::string> a_Args, RTLIL::Design* a_Design) YS_OVERRIDE { @@ -75,20 +92,41 @@ } // A map of IO cell types and their port names that should go to a pad - std::unordered_map<std::string, std::string> ioCellTypes; + std::unordered_map<std::string, IoCellType> ioCellTypes; + // Parse io cell specification if (a_Args.size() > 3) { // FIXME: Are these characters set the only ones that can be in // cell / port name ? - std::regex re("^([\\w$]+):([\\w$]+)$"); + std::regex re1("^([\\w$]+):([\\w$]+)$"); + std::regex re2("^([\\w$]+):([\\w$]+):([\\w,$]+)$"); for (size_t i=3; i<a_Args.size(); ++i) { std::cmatch cm; - if (std::regex_match(a_Args[i].c_str(), cm, re)) { - ioCellTypes.insert(std::make_pair(cm[1].str(), cm[2].str())); + + // No preffered IO cell types + if (std::regex_match(a_Args[i].c_str(), cm, re1)) { + ioCellTypes.emplace(cm[1].str(), IoCellType(cm[1], cm[2])); } + + // With preferred IO cell types + else if (std::regex_match(a_Args[i].c_str(), cm, re2)) { + std::vector<std::string> preferredTypes; + std::stringstream ss(cm[3]); + + while (ss.good()) { + std::string field; + std::getline(ss, field, ','); + + preferredTypes.push_back(field); + } + + ioCellTypes.emplace(cm[1].str(), IoCellType(cm[1], cm[2], preferredTypes)); + } + + // Invalid else { log_cmd_error("Invalid IO cell+port spec: '%s'\n", a_Args[i].c_str()); } @@ -97,10 +135,10 @@ // Use the default IO cells for QuickLogic FPGAs else { - ioCellTypes.insert(std::make_pair("inpad", "P")); - ioCellTypes.insert(std::make_pair("outpad", "P")); - ioCellTypes.insert(std::make_pair("bipad", "P")); - ioCellTypes.insert(std::make_pair("ckpad", "P")); + ioCellTypes.emplace("inpad", IoCellType("inpad", "P", {"BIDIR", "SDIOMUX"})); + ioCellTypes.emplace("outpad", IoCellType("outpad", "P", {"BIDIR", "SDIOMUX"})); + ioCellTypes.emplace("bipad", IoCellType("bipad", "P", {"BIDIR", "SDIOMUX"})); + ioCellTypes.emplace("ckpad", IoCellType("ckpad", "P", {"CLOCK", "BIDIR", "SDIOMUX"})); } // Get the top module of the design @@ -133,18 +171,24 @@ } // Build a map of pad names to entries - std::unordered_map<std::string, const PinmapParser::Entry> pinmapMap; + std::unordered_map<std::string, std::vector<PinmapParser::Entry>> pinmapMap; for (auto& entry : pinmapParser.getEntries()) { if (entry.count("name") != 0) { - pinmapMap.emplace(entry.at("name"), entry); + auto& name = entry.at("name"); + + if (pinmapMap.count(name) == 0) { + pinmapMap[name] = std::vector<PinmapParser::Entry>(); + } + + pinmapMap[name].push_back(entry); } } // Check all IO cells log("Processing cells..."); log("\n"); - log(" type | instance | net | pad | loc | cell \n"); - log(" ------------+----------------------+------------+------------+----------+----------\n"); + log(" type | net | pad | loc | type | instance\n"); + log(" ------------+------------+------------+----------+----------+-----------\n"); for (auto cell : topModule->cells()) { auto ysCellType = RTLIL::unescape_id(cell->type); @@ -153,7 +197,7 @@ continue; } - log(" %-10s | %-20s ", ysCellType.c_str(), cell->name.c_str()); + log(" %-10s ", ysCellType.c_str()); std::string netName; std::string padName; @@ -161,7 +205,8 @@ std::string cellType; // Get connections to the specified port - std::string port = RTLIL::escape_id(ioCellTypes.at(ysCellType)); + const auto& ioCellType = ioCellTypes.at(ysCellType); + const std::string port = RTLIL::escape_id(ioCellType.port); if (cell->connections().count(port)) { // Get the sigspec of the connection @@ -186,8 +231,12 @@ // Check if there is an entry in the pinmap for this pad name if (pinmapMap.count(constraint.padName)) { - // Get the entry - auto entry = pinmapMap.at(constraint.padName); + // Choose a correct entry for the cell + auto entry = choosePinmapEntry( + pinmapMap.at(constraint.padName), + ioCellType + ); + padName = constraint.padName; // Location string @@ -208,11 +257,12 @@ } } - log("| %-10s | %-10s | %-8s | %s\n", + log("| %-10s | %-10s | %-8s | %-8s | %s\n", netName.c_str(), padName.c_str(), locName.c_str(), - cellType.c_str() + cellType.c_str(), + cell->name.c_str() ); // Annotate the cell by setting its parameters @@ -222,6 +272,30 @@ } } + PinmapParser::Entry choosePinmapEntry( + const std::vector<PinmapParser::Entry>& a_Entries, + const IoCellType& a_IoCellType) + { + // No preferred types, pick the first one + if (a_IoCellType.preferredTypes.empty()) { + return a_Entries[0]; + } + + // Loop over preferred types + for (auto& type : a_IoCellType.preferredTypes) { + + // Find an entry for that type. If found then return it. + for (auto& entry : a_Entries) { + if (type == entry.at("type")) { + return entry; + } + } + } + + // No preferred type was found, pick the first one. + return a_Entries[0]; + } + } QuicklogicIob; PRIVATE_NAMESPACE_END