From a3e9b4aea93373ab38896de8a29cbc056e98b6b2 Mon Sep 17 00:00:00 2001 From: Ganesh Gore Date: Fri, 27 Sep 2019 13:58:48 -0600 Subject: [PATCH 01/10] Added mINI/lib - INI Read write to project --- libs/CMakeLists.txt | 2 + libs/external/CMakeLists.txt | 1 + libs/external/libini/CMakeLists.txt | 12 + libs/external/libini/src/ini.h | 755 ++++++++++++++++++++++++++++ vpr7_x2p/vpr/CMakeLists.txt | 14 +- 5 files changed, 778 insertions(+), 6 deletions(-) create mode 100644 libs/external/CMakeLists.txt create mode 100644 libs/external/libini/CMakeLists.txt create mode 100755 libs/external/libini/src/ini.h diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index aed5d49c0..990d003d2 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -2,6 +2,8 @@ #add_subdirectory(libarchfpga) add_subdirectory(libvtrutil) add_subdirectory(liblog) +add_subdirectory(external) +#add_subdirectory(external) #add_subdirectory(libpugiutil) #add_subdirectory(libeasygl) #add_subdirectory(librtlnumber) diff --git a/libs/external/CMakeLists.txt b/libs/external/CMakeLists.txt new file mode 100644 index 000000000..dc4be51bd --- /dev/null +++ b/libs/external/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(libini) \ No newline at end of file diff --git a/libs/external/libini/CMakeLists.txt b/libs/external/libini/CMakeLists.txt new file mode 100644 index 000000000..2730c6325 --- /dev/null +++ b/libs/external/libini/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(libini) + +file(GLOB_RECURSE LIB_HEADERS src/*.h) +files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS) + +#Create the library +add_library(libini STATIC + ${LIB_HEADERS}) +target_include_directories(libini PUBLIC ${LIB_INCLUDE_DIRS}) +set_target_properties(libini PROPERTIES PREFIX "" LINKER_LANGUAGE CXX) \ No newline at end of file diff --git a/libs/external/libini/src/ini.h b/libs/external/libini/src/ini.h new file mode 100755 index 000000000..cb323192f --- /dev/null +++ b/libs/external/libini/src/ini.h @@ -0,0 +1,755 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Danijel Durakovic + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +/////////////////////////////////////////////////////////////////////////////// +// +// /mINI/ v0.9.7 +// An INI file reader and writer for the modern age. +// +/////////////////////////////////////////////////////////////////////////////// +// +// A tiny utility library for manipulating INI files with a straightforward +// API and a minimal footprint. It conforms to the (somewhat) standard INI +// format - sections and keys are case insensitive and all leading and +// trailing whitespace is ignored. Comments are lines that begin with a +// semicolon. Trailing comments are allowed on section lines. +// +// Files are read on demand, upon which data is kept in memory and the file +// is closed. This utility supports lazy writing, which only writes changes +// and updates to a file and preserves custom formatting and comments. A lazy +// write invoked by a write() call will read the output file, find what +// changes have been made and update the file accordingly. If you only need to +// generate files, use generate() instead. Section and key order is preserved +// on read, write and insert. +// +/////////////////////////////////////////////////////////////////////////////// +// +// /* BASIC USAGE EXAMPLE: */ +// +// /* read from file */ +// mINI::INIFile file("myfile.ini"); +// mINI::INIStructure ini; +// file.read(ini); +// +// /* read value; gets a reference to actual value in the structure. +// if key or section don't exist, a new empty value will be created */ +// std::string& value = ini["section"]["key"]; +// +// /* read value safely; gets a copy of value in the structure. +// does not alter the structure */ +// std::string value = ini.get("section").get("key"); +// +// /* set or update values */ +// ini["section"]["key"] = "value"; +// +// /* set multiple values */ +// ini["section2"].set({ +// {"key1", "value1"}, +// {"key2", "value2"} +// }); +// +// /* write updates back to file, preserving comments and formatting */ +// file.write(ini); +// +// /* or generate a file (overwrites the original) */ +// file.generate(ini); +// +/////////////////////////////////////////////////////////////////////////////// +// +// Long live the INI file!!! +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MINI_INI_H_ +#define MINI_INI_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mINI +{ +namespace INIStringUtil +{ +const std::string whitespaceDelimiters = " \t\n\r\f\v"; +inline void trim(std::string &str) +{ + str.erase(str.find_last_not_of(whitespaceDelimiters) + 1); + str.erase(0, str.find_first_not_of(whitespaceDelimiters)); +} +#ifndef MINI_CASE_SENSITIVE +inline void toLower(std::string &str) +{ + std::transform(str.begin(), str.end(), str.begin(), ::tolower); +} +#endif +inline void replace(std::string &str, std::string const &a, std::string const &b) +{ + if (!a.empty()) + { + std::size_t pos = 0; + while ((pos = str.find(a, pos)) != std::string::npos) + { + str.replace(pos, a.size(), b); + pos += b.size(); + } + } +} +#ifdef _WIN32 +const std::string endl = "\r\n"; +#else +const std::string endl = "\n"; +#endif +}; // namespace INIStringUtil + +template +class INIMap +{ +private: + using T_DataIndexMap = std::unordered_map; + using T_DataItem = std::pair; + using T_DataContainer = std::vector; + using T_MultiArgs = typename std::vector>; + + T_DataIndexMap dataIndexMap; + T_DataContainer data; + + inline std::size_t setEmpty(std::string &key) + { + std::size_t index = data.size(); + dataIndexMap[key] = index; + data.emplace_back(key, T()); + return index; + } + +public: + using const_iterator = typename T_DataContainer::const_iterator; + + INIMap() {} + + INIMap(INIMap const &other) + { + std::size_t data_size = other.data.size(); + for (std::size_t i = 0; i < data_size; ++i) + { + auto const &key = other.data[i].first; + auto const &obj = other.data[i].second; + data.emplace_back(key, obj); + } + dataIndexMap = T_DataIndexMap(other.dataIndexMap); + } + + T &operator[](std::string key) + { + INIStringUtil::trim(key); +#ifndef MINI_CASE_SENSITIVE + INIStringUtil::toLower(key); +#endif + auto it = dataIndexMap.find(key); + bool hasIt = (it != dataIndexMap.end()); + std::size_t index = (hasIt) ? it->second : setEmpty(key); + return data[index].second; + } + T get(std::string key) const + { + INIStringUtil::trim(key); +#ifndef MINI_CASE_SENSITIVE + INIStringUtil::toLower(key); +#endif + auto it = dataIndexMap.find(key); + if (it == dataIndexMap.end()) + { + return T(); + } + return T(data[it->second].second); + } + bool has(std::string key) const + { + INIStringUtil::trim(key); +#ifndef MINI_CASE_SENSITIVE + INIStringUtil::toLower(key); +#endif + return (dataIndexMap.count(key) == 1); + } + void set(std::string key, T obj) + { + INIStringUtil::trim(key); +#ifndef MINI_CASE_SENSITIVE + INIStringUtil::toLower(key); +#endif + auto it = dataIndexMap.find(key); + if (it != dataIndexMap.end()) + { + data[it->second].second = obj; + } + else + { + dataIndexMap[key] = data.size(); + data.emplace_back(key, obj); + } + } + void set(T_MultiArgs const &multiArgs) + { + for (auto const &it : multiArgs) + { + auto const &key = it.first; + auto const &obj = it.second; + set(key, obj); + } + } + bool remove(std::string key) + { + INIStringUtil::trim(key); +#ifndef MINI_CASE_SENSITIVE + INIStringUtil::toLower(key); +#endif + auto it = dataIndexMap.find(key); + if (it != dataIndexMap.end()) + { + std::size_t index = it->second; + data.erase(data.begin() + index); + dataIndexMap.erase(it); + for (auto &it2 : dataIndexMap) + { + auto &vi = it2.second; + if (vi > index) + { + vi--; + } + } + return true; + } + return false; + } + void clear() + { + data.clear(); + dataIndexMap.clear(); + } + std::size_t size() const + { + return data.size(); + } + const_iterator begin() const { return data.begin(); } + const_iterator end() const { return data.end(); } +}; + +using INIStructure = INIMap>; + +namespace INIParser +{ +using T_ParseValues = std::pair; + +enum class PDataType : char +{ + PDATA_NONE, + PDATA_COMMENT, + PDATA_SECTION, + PDATA_KEYVALUE, + PDATA_UNKNOWN +}; + +inline PDataType parseLine(std::string line, T_ParseValues &parseData) +{ + parseData.first.clear(); + parseData.second.clear(); + INIStringUtil::trim(line); + if (line.empty()) + { + return PDataType::PDATA_NONE; + } + char firstCharacter = line[0]; + if (firstCharacter == ';') + { + return PDataType::PDATA_COMMENT; + } + if (firstCharacter == '[') + { + auto commentAt = line.find_first_of(';'); + if (commentAt != std::string::npos) + { + line = line.substr(0, commentAt); + } + auto closingBracketAt = line.find_last_of(']'); + if (closingBracketAt != std::string::npos) + { + auto section = line.substr(1, closingBracketAt - 1); + INIStringUtil::trim(section); + parseData.first = section; + return PDataType::PDATA_SECTION; + } + } + auto lineNorm = line; + INIStringUtil::replace(lineNorm, "\\=", " "); + auto equalsAt = lineNorm.find_first_of('='); + if (equalsAt != std::string::npos) + { + auto key = line.substr(0, equalsAt); + INIStringUtil::trim(key); + INIStringUtil::replace(key, "\\=", "="); + auto value = line.substr(equalsAt + 1); + INIStringUtil::trim(value); + parseData.first = key; + parseData.second = value; + return PDataType::PDATA_KEYVALUE; + } + return PDataType::PDATA_UNKNOWN; +} +}; // namespace INIParser + +class INIReader +{ +public: + using T_LineData = std::vector; + using T_LineDataPtr = std::shared_ptr; + +private: + std::ifstream fileReadStream; + T_LineDataPtr lineData; + + T_LineData readFile() + { + std::string fileContents; + fileReadStream.seekg(0, std::ios::end); + fileContents.resize(fileReadStream.tellg()); + fileReadStream.seekg(0, std::ios::beg); + std::size_t fileSize = fileContents.size(); + fileReadStream.read(&fileContents[0], fileSize); + fileReadStream.close(); + T_LineData output; + if (fileSize == 0) + { + return output; + } + std::string buffer; + buffer.reserve(50); + for (std::size_t i = 0; i < fileSize; ++i) + { + char &c = fileContents[i]; + if (c == '\n') + { + output.emplace_back(buffer); + buffer.clear(); + continue; + } + if (c != '\0' && c != '\r') + { + buffer += c; + } + } + output.emplace_back(buffer); + return output; + } + +public: + INIReader(std::string const &filename, bool keepLineData = false) + { + fileReadStream.open(filename, std::ios::in | std::ios::binary); + if (keepLineData) + { + lineData = std::make_shared(); + } + } + ~INIReader() {} + + bool operator>>(INIStructure &data) + { + if (!fileReadStream.is_open()) + { + return false; + } + T_LineData fileLines = readFile(); + std::string section; + bool inSection = false; + INIParser::T_ParseValues parseData; + for (auto const &line : fileLines) + { + auto parseResult = INIParser::parseLine(line, parseData); + if (parseResult == INIParser::PDataType::PDATA_SECTION) + { + inSection = true; + data[section = parseData.first]; + } + else if (inSection && parseResult == INIParser::PDataType::PDATA_KEYVALUE) + { + auto const &key = parseData.first; + auto const &value = parseData.second; + data[section][key] = value; + } + if (lineData && parseResult != INIParser::PDataType::PDATA_UNKNOWN) + { + if (parseResult == INIParser::PDataType::PDATA_KEYVALUE && !inSection) + { + continue; + } + lineData->emplace_back(line); + } + } + return true; + } + T_LineDataPtr getLines() + { + return lineData; + } +}; + +class INIGenerator +{ +private: + std::ofstream fileWriteStream; + +public: + bool prettyPrint = false; + + INIGenerator(std::string const &filename) + { + fileWriteStream.open(filename, std::ios::out | std::ios::binary); + } + ~INIGenerator() {} + + bool operator<<(INIStructure const &data) + { + if (!fileWriteStream.is_open()) + { + return false; + } + if (!data.size()) + { + return true; + } + auto it = data.begin(); + for (;;) + { + auto const §ion = it->first; + auto const &collection = it->second; + fileWriteStream + << "[" + << section + << "]"; + if (collection.size()) + { + fileWriteStream << INIStringUtil::endl; + auto it2 = collection.begin(); + for (;;) + { + auto key = it2->first; + INIStringUtil::replace(key, "=", "\\="); + auto value = it2->second; + INIStringUtil::trim(value); + fileWriteStream + << key + << ((prettyPrint) ? " = " : "=") + << value; + if (++it2 == collection.end()) + { + break; + } + fileWriteStream << INIStringUtil::endl; + } + } + if (++it == data.end()) + { + break; + } + fileWriteStream << INIStringUtil::endl; + if (prettyPrint) + { + fileWriteStream << INIStringUtil::endl; + } + } + return true; + } +}; + +class INIWriter +{ +private: + using T_LineData = std::vector; + using T_LineDataPtr = std::shared_ptr; + + std::string filename; + + T_LineData getLazyOutput(T_LineDataPtr const &lineData, INIStructure &data, INIStructure &original) + { + T_LineData output; + INIParser::T_ParseValues parseData; + std::string sectionCurrent; + bool parsingSection = false; + bool continueToNextSection = false; + bool discardNextEmpty = false; + bool writeNewKeys = false; + std::size_t lastKeyLine = 0; + for (auto line = lineData->begin(); line != lineData->end(); ++line) + { + if (!writeNewKeys) + { + auto parseResult = INIParser::parseLine(*line, parseData); + if (parseResult == INIParser::PDataType::PDATA_SECTION) + { + if (parsingSection) + { + writeNewKeys = true; + parsingSection = false; + --line; + continue; + } + sectionCurrent = parseData.first; + if (data.has(sectionCurrent)) + { + parsingSection = true; + continueToNextSection = false; + discardNextEmpty = false; + output.emplace_back(*line); + lastKeyLine = output.size(); + } + else + { + continueToNextSection = true; + discardNextEmpty = true; + continue; + } + } + else if (parseResult == INIParser::PDataType::PDATA_KEYVALUE) + { + if (continueToNextSection) + { + continue; + } + if (data.has(sectionCurrent)) + { + auto &collection = data[sectionCurrent]; + auto const &key = parseData.first; + auto const &value = parseData.second; + if (collection.has(key)) + { + auto outputValue = collection[key]; + if (value == outputValue) + { + output.emplace_back(*line); + } + else + { + INIStringUtil::trim(outputValue); + auto lineNorm = *line; + INIStringUtil::replace(lineNorm, "\\=", " "); + auto equalsAt = lineNorm.find_first_of('='); + auto valueAt = lineNorm.find_first_not_of( + INIStringUtil::whitespaceDelimiters, + equalsAt + 1); + std::string outputLine = line->substr(0, valueAt); + if (prettyPrint && equalsAt + 1 == valueAt) + { + outputLine += " "; + } + outputLine += outputValue; + output.emplace_back(outputLine); + } + lastKeyLine = output.size(); + } + } + } + else + { + if (discardNextEmpty && line->empty()) + { + discardNextEmpty = false; + } + else if (parseResult != INIParser::PDataType::PDATA_UNKNOWN) + { + output.emplace_back(*line); + } + } + } + if (writeNewKeys || std::next(line) == lineData->end()) + { + T_LineData linesToAdd; + if (data.has(sectionCurrent) && original.has(sectionCurrent)) + { + auto const &collection = data[sectionCurrent]; + auto const &collectionOriginal = original[sectionCurrent]; + for (auto const &it : collection) + { + auto key = it.first; + if (collectionOriginal.has(key)) + { + continue; + } + auto value = it.second; + INIStringUtil::replace(key, "=", "\\="); + INIStringUtil::trim(value); + linesToAdd.emplace_back( + key + ((prettyPrint) ? " = " : "=") + value); + } + } + if (!linesToAdd.empty()) + { + output.insert( + output.begin() + lastKeyLine, + linesToAdd.begin(), + linesToAdd.end()); + } + if (writeNewKeys) + { + writeNewKeys = false; + --line; + } + } + } + for (auto const &it : data) + { + auto const §ion = it.first; + if (original.has(section)) + { + continue; + } + if (prettyPrint && output.size() > 0 && !output.back().empty()) + { + output.emplace_back(); + } + output.emplace_back("[" + section + "]"); + auto const &collection = it.second; + for (auto const &it2 : collection) + { + auto key = it2.first; + auto value = it2.second; + INIStringUtil::replace(key, "=", "\\="); + INIStringUtil::trim(value); + output.emplace_back( + key + ((prettyPrint) ? " = " : "=") + value); + } + } + return output; + } + +public: + bool prettyPrint = false; + + INIWriter(std::string const &filename) + : filename(filename) + { + } + ~INIWriter() {} + + bool operator<<(INIStructure &data) + { + struct stat buf; + bool fileExists = (stat(filename.c_str(), &buf) == 0); + if (!fileExists) + { + INIGenerator generator(filename); + generator.prettyPrint = prettyPrint; + return generator << data; + } + INIStructure originalData; + T_LineDataPtr lineData; + bool readSuccess = false; + { + INIReader reader(filename, true); + if ((readSuccess = reader >> originalData)) + { + lineData = reader.getLines(); + } + } + if (!readSuccess) + { + return false; + } + T_LineData output = getLazyOutput(lineData, data, originalData); + std::ofstream fileWriteStream(filename, std::ios::out | std::ios::binary); + if (fileWriteStream.is_open()) + { + if (output.size()) + { + auto line = output.begin(); + for (;;) + { + fileWriteStream << *line; + if (++line == output.end()) + { + break; + } + fileWriteStream << INIStringUtil::endl; + } + } + return true; + } + return false; + } +}; + +class INIFile +{ +private: + std::string filename; + +public: + INIFile(std::string const &filename) + : filename(filename) + { + } + + ~INIFile() {} + + bool read(INIStructure &data) const + { + if (data.size()) + { + data.clear(); + } + if (filename.empty()) + { + return false; + } + INIReader reader(filename); + return reader >> data; + } + bool generate(INIStructure const &data, bool pretty = false) const + { + if (filename.empty()) + { + return false; + } + INIGenerator generator(filename); + generator.prettyPrint = pretty; + return generator << data; + } + bool write(INIStructure &data, bool pretty = false) const + { + if (filename.empty()) + { + return false; + } + INIWriter writer(filename); + writer.prettyPrint = pretty; + return writer << data; + } +}; +} // namespace mINI + +#endif // MINI_INI_H_ diff --git a/vpr7_x2p/vpr/CMakeLists.txt b/vpr7_x2p/vpr/CMakeLists.txt index 4d97fcf0d..0fa11717e 100644 --- a/vpr7_x2p/vpr/CMakeLists.txt +++ b/vpr7_x2p/vpr/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.8.12) if (${CMAKE_VERSION} VERSION_GREATER "3.8") #For cmake >= 3.9 INTERPROCEDURAL_OPTIMIZATION behaviour we need to explicitly #set the cmake policy version number - cmake_policy(VERSION 3.9) + cmake_policy(VERSION 3.9) # If we are using verison < 3.9 then setting INTERPROCEDURAL_OPTIMIZATION # has no effect unless an Intel compiler is used @@ -29,13 +29,13 @@ else () endif() if (NOT ENABLE_VPR_GRAPHIC_CXX_FLAG) - # Add a flag to notify compiler not to consider graphic-related source codes + # Add a flag to notify compiler not to consider graphic-related source codes set (DISABLE_GRAPHIC_FLAGS "-DNO_GRAPHICS") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DISABLE_GRAPHIC_FLAGS}") message(STATUS "Add flags to disable graphics in VPR compilation: ${DISABLE_GRAPHIC_FLAGS}") endif() -# We need readline to compile +# We need readline to compile find_package(Readline REQUIRED) #Collect the source files @@ -65,12 +65,14 @@ if (ENABLE_VPR_GRAPHIC_CXX_FLAG) libarchfpga X11 libvtrutil - readline) -else () + readline + libini) +else () target_link_libraries(libvpr libarchfpga libvtrutil - readline) + readline + libini) endif() #Create the executables From 438b592a8a92d1e0c0ebdb8a106c62957b9f80fc Mon Sep 17 00:00:00 2001 From: Ganesh Gore Date: Fri, 27 Sep 2019 14:00:27 -0600 Subject: [PATCH 02/10] Appended VPR to genereate INI File --- .../verilog/verilog_formality_autodeck.c | 316 +++++++++++------- 1 file changed, 187 insertions(+), 129 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c index 0be59a137..33f587a75 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c @@ -10,6 +10,8 @@ #include #include #include +#define MINI_CASE_SENSITIVE +#include "ini.h" /* Include vpr structs*/ #include "util.h" @@ -39,82 +41,81 @@ #include "verilog_routing.h" #include "verilog_tcl_utils.h" -static void searching_used_latch(FILE *fp, t_pb *pb, int pb_index, char *chomped_circuit_name, char *inst_name) -{ +mINI::INIStructure ini; + +static void searching_used_latch(FILE *fp, t_pb * pb, int pb_index, char* chomped_circuit_name, char* inst_name){ int i, j; - // char* tmp = NULL; + char WriteBuffer[200]; + char INI_lbl[100]; +// char* tmp = NULL; const t_pb_type *pb_type; t_mode *mode; - t_pb_graph_node *node; - // char* index = NULL; + t_pb_graph_node * node; +// char* index = NULL; pb_type = pb->pb_graph_node->pb_type; node = pb->pb_graph_node->physical_pb_graph_node; mode = &pb_type->modes[pb->mode]; - // tmp = (char*) my_malloc(sizeof(1 + (strlen(ff_hierarchy) + 1 + strlen(my_strcat(pb_type->name, index))))); - // tmp = ff_hierarchy; - // index = my_strcat("_", my_strcat(my_itoa(pb_index), "_")); +// tmp = (char*) my_malloc(sizeof(1 + (strlen(ff_hierarchy) + 1 + strlen(my_strcat(pb_type->name, index))))); +// tmp = ff_hierarchy; +// index = my_strcat("_", my_strcat(my_itoa(pb_index), "_")); - if (pb_type->num_modes > 0) - { - for (i = 0; i < mode->num_pb_type_children; i++) - { - for (j = 0; j < mode->pb_type_children[i].num_pb; j++) - { - // if(strcmp(pb_type->name, mode->name) != 0) - // tmp = my_strcat(tmp, my_strcat("/", my_strcat(pb_type->name, index))); - if (pb->child_pbs[i][j].name != NULL) + if (pb_type->num_modes > 0) { + for (i = 0; i < mode->num_pb_type_children; i++) { + for (j = 0; j < mode->pb_type_children[i].num_pb; j++) { +// if(strcmp(pb_type->name, mode->name) != 0) +// tmp = my_strcat(tmp, my_strcat("/", my_strcat(pb_type->name, index))); + if(pb->child_pbs[i][j].name != NULL) searching_used_latch(fp, &pb->child_pbs[i][j], j, chomped_circuit_name, inst_name); } } - } - else if ((pb_type->class_type == LATCH_CLASS) && (pb->name)) - { - // tmp = my_strcat(tmp, my_strcat("/", my_strcat(pb_type->physical_pb_type_name, my_strcat(index, "/dff_0_")))); + } else if((pb_type->class_type == LATCH_CLASS) && (pb->name)){ +// tmp = my_strcat(tmp, my_strcat("/", my_strcat(pb_type->physical_pb_type_name, my_strcat(index, "/dff_0_")))); fprintf(fp, "set_user_match r:/WORK/%s/%s_reg i:/WORK/%s/%sdff_0 -type cell -noninverted\n", chomped_circuit_name, - pb->name, - inst_name, - gen_verilog_one_pb_graph_node_full_name_in_hierarchy(node)); + pb->name, + inst_name, + gen_verilog_one_pb_graph_node_full_name_in_hierarchy(node) ); + sprintf(WriteBuffer, "%s/%sdff_0 ", + inst_name, gen_verilog_one_pb_graph_node_full_name_in_hierarchy(node)); + + sprintf(INI_lbl, "%s_reg", pb->name); + ini["REGISTER_MATCH"][INI_lbl] = WriteBuffer; } //free(tmp); //Looks like is the cause of a double free, once free executated next iteration as no value in tmp return; } -static void clb_iteration(FILE *fp, char *chomped_circuit_name, int h) -{ - t_pb *pb; - char *inst_name = NULL; +static void clb_iteration(FILE *fp, char* chomped_circuit_name, int h){ + t_pb* pb; + char* inst_name = NULL; const t_pb_type *pb_type; t_mode *mode; int i, j, x_pos, y_pos; - char *grid_x = NULL; - char *grid_y = NULL; + char* grid_x = NULL; + char* grid_y = NULL; x_pos = block[h].x; y_pos = block[h].y; - pb = (t_pb *)block[h].pb; + pb = (t_pb*) block[h].pb; pb_type = pb->pb_graph_node->pb_type; mode = &pb_type->modes[pb->mode]; - grid_x = my_strcat("_", my_strcat(my_itoa(x_pos), "_")); + grid_x = my_strcat("_", my_strcat(my_itoa(x_pos), "_")); grid_y = my_strcat("_", my_strcat(my_itoa(y_pos), "_")); - if (strcmp(pb_type->name, FILL_TYPE->name) == 0) - { - inst_name = my_strcat(chomped_circuit_name, my_strcat(formal_verification_top_postfix, my_strcat("/", my_strcat(formal_verification_top_module_uut_name, my_strcat("/grid", my_strcat(grid_x, my_strcat(grid_y, "/"))))))); - if (pb_type->num_modes > 0) - { - for (i = 0; i < mode->num_pb_type_children; i++) - { + + if (strcmp(pb_type->name, FILL_TYPE->name) == 0) { + inst_name = my_strcat(chomped_circuit_name, my_strcat(formal_verification_top_postfix, my_strcat("/", my_strcat(formal_verification_top_module_uut_name, my_strcat("/grid",my_strcat(grid_x, my_strcat(grid_y, "/" ))))))); + if (pb_type->num_modes > 0) { + for (i = 0; i < mode->num_pb_type_children; i++) { inst_name = my_strcat(inst_name, my_strcat("grid_", my_strcat(pb_type->name, my_strcat("_", my_strcat(my_itoa(i), "_"))))); - for (j = 0; j < mode->pb_type_children[i].num_pb; j++) - { + for (j = 0; j < mode->pb_type_children[i].num_pb; j++) { /* If child pb is not used but routing is used, I must print things differently */ - if ((pb->child_pbs[i] != NULL) && (pb->child_pbs[i][j].name != NULL)) - { + if ((pb->child_pbs[i] != NULL) + && (pb->child_pbs[i][j].name != NULL)) { searching_used_latch(fp, &pb->child_pbs[i][j], j, chomped_circuit_name, inst_name); } } @@ -124,14 +125,29 @@ static void clb_iteration(FILE *fp, char *chomped_circuit_name, int h) return; } -static void formality_include_user_defined_verilog_netlists(FILE *fp, - t_spice spice) -{ +static void match_registers(FILE *fp, char* chomped_circuit_name) { + int h; + + for(h = 0; h < copy_nb_clusters; h++) + clb_iteration(fp, chomped_circuit_name, h); +/* for(h = 0; h < copy_nb_clusters; h++){ + free_cb(copy_clb[h].pb); + free(copy_clb[h].name); + free(copy_clb[h].nets); + free(copy_clb[h].pb); + }*/ +// free(copy_clb); +// free(block); + return; +} + +static +void formality_include_user_defined_verilog_netlists(FILE* fp, + t_spice spice) { int i; /* A valid file handler*/ - if (NULL == fp) - { + if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid File Handler!\n", __FILE__, __LINE__); @@ -139,16 +155,12 @@ static void formality_include_user_defined_verilog_netlists(FILE *fp, } /* Include user-defined sub-circuit netlist */ - for (i = 0; i < spice.num_include_netlist; i++) - { - if (0 == spice.include_netlists[i].included) - { + for (i = 0; i < spice.num_include_netlist; i++) { + if (0 == spice.include_netlists[i].included) { assert(NULL != spice.include_netlists[i].path); - fprintf(fp, "%s \n", spice.include_netlists[i].path); + fprintf(fp, "%s ", spice.include_netlists[i].path); spice.include_netlists[i].included = 1; - } - else - { + } else { assert(1 == spice.include_netlists[i].included); } } @@ -156,102 +168,148 @@ static void formality_include_user_defined_verilog_netlists(FILE *fp, return; } -void write_formality_script(t_syn_verilog_opts fpga_verilog_opts, - char *fm_dir_formatted, - char *src_dir_formatted, - char *chomped_circuit_name, - t_spice spice) -{ - int iblock, h; - char *formScriptfp = NULL; - char *benchmark_path = NULL; - char *original_output_name = NULL; - /* int output_length; */ - /* int pos; */ - FILE *fp = NULL; +void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, + char* fm_dir_formatted, + char* src_dir_formatted, + char* chomped_circuit_name, + t_spice spice){ + int iblock, i, FileCounter=0; + char* formality_script_file_name = NULL; + char* benchmark_path = NULL; + char* original_output_name = NULL; + char WriteBuffer[200]; + char INI_lbl[20]; +/* int output_length; */ +/* int pos; */ + FILE* fp = NULL; - if (TRUE == fpga_verilog_opts.print_autocheck_top_testbench) - { + if(TRUE == fpga_verilog_opts.print_autocheck_top_testbench) benchmark_path = fpga_verilog_opts.reference_verilog_benchmark_file; - } else - { benchmark_path = "Insert verilog benchmark path"; - } - formScriptfp = my_strcat(fm_dir_formatted, - my_strcat(chomped_circuit_name, - formality_script_name_postfix)); - fp = fopen(formScriptfp, "w"); - if (NULL == fp) - { - vpr_printf(TIO_MESSAGE_ERROR, - "(FILE:%s,LINE[%d])Failure in create formality script %s", - __FILE__, __LINE__, formScriptfp); - exit(1); - } + formality_script_file_name = my_strcat(fm_dir_formatted, my_strcat(chomped_circuit_name, formality_script_name_postfix)); + fp = fopen(formality_script_file_name, "w"); + if (NULL == fp) { + vpr_printf(TIO_MESSAGE_ERROR, + "(FILE:%s,LINE[%d])Failure in create formality script %s", + __FILE__, __LINE__, formality_script_file_name); + exit(1); + } /* Load Verilog benchmark as reference */ - fprintf(fp, "%s\n\n", benchmark_path); + fprintf(fp, "read_verilog -container r -libname WORK -05 { %s }\n", benchmark_path); + ini["BENCHMARK_INFO"]["benchmark_netlist "] = benchmark_path; /* Set reference top */ - fprintf(fp, "%s\n\n", chomped_circuit_name); + fprintf(fp, "set_top r:/WORK/%s\n", chomped_circuit_name); + ini["BENCHMARK_INFO"]["src_top_module "] = chomped_circuit_name; /* Load generated verilog as implemnetation */ - fprintf(fp, "%s%s%s\n", src_dir_formatted, chomped_circuit_name, + fprintf(fp, "read_verilog -container i -libname WORK -05 { "); + fprintf(fp, "%s%s%s ", src_dir_formatted, + chomped_circuit_name, + verilog_top_postfix); + sprintf(WriteBuffer, "%s%s%s", src_dir_formatted, chomped_circuit_name, verilog_top_postfix); + sprintf(INI_lbl, "impl_netlist_%02d",FileCounter++); + ini["FPGA_INFO"][INI_lbl] = WriteBuffer; - fprintf(fp, "%s%s%s\n", src_dir_formatted, - chomped_circuit_name, - formal_verification_verilog_file_postfix); + fprintf(fp, "%s%s%s ", src_dir_formatted, + chomped_circuit_name, + formal_verification_verilog_file_postfix); + sprintf(WriteBuffer, "%s%s%s\n", src_dir_formatted, + chomped_circuit_name, formal_verification_verilog_file_postfix); + sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++); + ini["FPGA_INFO"][INI_lbl] = WriteBuffer; init_include_user_defined_verilog_netlists(spice); - formality_include_user_defined_verilog_netlists(fp, spice); - fprintf(fp, "%s%s%s\n", src_dir_formatted, - default_rr_dir_name, - routing_verilog_file_name); - fprintf(fp, "%s%s%s\n", src_dir_formatted, - default_lb_dir_name, - logic_block_verilog_file_name); - fprintf(fp, "%s%s%s\n", src_dir_formatted, - default_submodule_dir_name, - submodule_verilog_file_name); - fprintf(fp, "\n"); + // formality_include_user_defined_verilog_netlists(fp, spice); - /* Set implementation top */ - fprintf(fp, "%s\n", my_strcat(chomped_circuit_name, formal_verification_top_postfix)); - /* Run matching */ - fprintf(fp, "\n"); - /* Add manual matching for the outputs */ - for (iblock = 0; iblock < num_logical_blocks; iblock++) - { - original_output_name = NULL; - if (iopad_verilog_model == logical_block[iblock].mapped_spice_model) - { - /* Make sure We find the correct logical block !*/ - assert((VPACK_INPAD == logical_block[iblock].type) || (VPACK_OUTPAD == logical_block[iblock].type)); - if (VPACK_OUTPAD == logical_block[iblock].type) - { - /* output_length = strlen(logical_block[iblock].name); */ - original_output_name = logical_block[iblock].name + 4; - /* printf("%s", original_output_name); */ - // fprintf(fp, "set_user_match r:/WORK/%s/%s i:/WORK/%s/%s[0] -type port -noninverted\n", - fprintf(fp, "/WORK/%s/%s /WORK/%s/%s[0]\n", - chomped_circuit_name, - original_output_name, - my_strcat(chomped_circuit_name, formal_verification_top_postfix), - my_strcat(logical_block[iblock].name, formal_verification_top_module_port_postfix)); - } + /* Include user-defined sub-circuit netlist */ + for (i = 0; i < spice.num_include_netlist; i++) { + if (0 == spice.include_netlists[i].included) { + assert(NULL != spice.include_netlists[i].path); + fprintf(fp, "%s ", spice.include_netlists[i].path); + sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++); + ini["FPGA_INFO"][INI_lbl] = spice.include_netlists[i].path; + spice.include_netlists[i].included = 1; + } else { + assert(1 == spice.include_netlists[i].included); } } - for (h = 0; h < copy_nb_clusters; h++) - clb_iteration(fp, chomped_circuit_name, h); + fprintf(fp, "%s%s%s ", src_dir_formatted, + default_rr_dir_name, + routing_verilog_file_name); + sprintf(WriteBuffer, "%s%s%s\n", src_dir_formatted, + default_rr_dir_name, + routing_verilog_file_name); + sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++); + ini["FPGA_INFO"][INI_lbl] = WriteBuffer; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + fprintf(fp, "%s%s%s ", src_dir_formatted, + default_lb_dir_name, + logic_block_verilog_file_name); + sprintf(WriteBuffer, "%s%s%s\n", src_dir_formatted, + default_lb_dir_name, + logic_block_verilog_file_name); + sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++); + ini["FPGA_INFO"][INI_lbl] = WriteBuffer; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + fprintf(fp, "%s%s%s ", src_dir_formatted, + default_submodule_dir_name, + submodule_verilog_file_name); + sprintf(WriteBuffer, "%s%s%s\n", src_dir_formatted, + default_submodule_dir_name, + submodule_verilog_file_name); + sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++); + ini["FPGA_INFO"][INI_lbl] = WriteBuffer; + fprintf(fp, "}\n"); + /* Set implementation top */ + fprintf(fp, "set_top i:/WORK/%s\n", my_strcat(chomped_circuit_name, + formal_verification_top_postfix)); + sprintf(WriteBuffer, "%s", my_strcat(chomped_circuit_name, + formal_verification_top_postfix)); + ini["FPGA_INFO"]["impl_top_module"] = WriteBuffer; + + /* Run matching */ + fprintf(fp, "match\n"); + /* Add manual matching for the outputs */ + for (iblock = 0; iblock < num_logical_blocks; iblock++) { + original_output_name = NULL; + if (iopad_verilog_model == logical_block[iblock].mapped_spice_model) { + /* Make sure We find the correct logical block !*/ + assert((VPACK_INPAD == logical_block[iblock].type) + ||(VPACK_OUTPAD == logical_block[iblock].type)); + if(VPACK_OUTPAD == logical_block[iblock].type){ + /* output_length = strlen(logical_block[iblock].name); */ + original_output_name = logical_block[iblock].name + 4; + /* printf("%s", original_output_name); */ + fprintf(fp, "set_user_match r:/WORK/%s/%s i:/WORK/%s/%s[0] -type port -noninverted\n", + chomped_circuit_name, + original_output_name, + my_strcat(chomped_circuit_name, formal_verification_top_postfix), + my_strcat(logical_block[iblock].name, + formal_verification_top_module_port_postfix)); + + sprintf(WriteBuffer, "%s/%s[0]", + my_strcat(chomped_circuit_name, formal_verification_top_postfix), + my_strcat(logical_block[iblock].name, formal_verification_top_module_port_postfix)); + + sprintf(INI_lbl, "%s", original_output_name); + ini["PORT_MATCHING"][INI_lbl] = WriteBuffer; + } + } + } + match_registers(fp, chomped_circuit_name); /* Run verification */ - fprintf(fp, "\n"); + fprintf(fp, "verify\n"); /* Script END */ fclose(fp); + mINI::INIFile file(my_strcat(formality_script_file_name,".ini")); + file.generate(ini, true); return; } From d269472dafe64817ef4cdca21d4426612b5345e5 Mon Sep 17 00:00:00 2001 From: Ganesh Gore Date: Fri, 27 Sep 2019 14:00:57 -0600 Subject: [PATCH 03/10] Updated formality python script --- openfpga_flow/misc/formality_template.tcl | 20 ++++++ openfpga_flow/misc/modelsim_template.j2 | 8 --- .../{run_modelsim.py => run_formality.py} | 67 ++++++++++++------- 3 files changed, 63 insertions(+), 32 deletions(-) create mode 100644 openfpga_flow/misc/formality_template.tcl delete mode 100644 openfpga_flow/misc/modelsim_template.j2 rename openfpga_flow/scripts/{run_modelsim.py => run_formality.py} (50%) diff --git a/openfpga_flow/misc/formality_template.tcl b/openfpga_flow/misc/formality_template.tcl new file mode 100644 index 000000000..2eb607ae9 --- /dev/null +++ b/openfpga_flow/misc/formality_template.tcl @@ -0,0 +1,20 @@ +# = = = = = = = = = = = = = = = = = = = = = = +# Auto generated using OpenFPGA +# = = = = = = = = = = = = = = = = = = = = = = + +# Benchmark Source Files +read_verilog -container r -libname WORK -05 { ${SOURCE_DESIGN_FILES} } +set_top r:${SOURCE_TOP_MODULE} + +# Benchmark Implementation Files +read_verilog -container i -libname WORK -05 { ${IMPL_DESIGN_FILES} } +set_top i:${IMPL_TOP_DIR} + +match +# Port Mapping +${PORT_MAP_LIST} + +# Register Mapping +${REGISTER_MAP_LIST} + +verify diff --git a/openfpga_flow/misc/modelsim_template.j2 b/openfpga_flow/misc/modelsim_template.j2 deleted file mode 100644 index cfa43d11c..000000000 --- a/openfpga_flow/misc/modelsim_template.j2 +++ /dev/null @@ -1,8 +0,0 @@ -read_verilog -container r -libname WORK -05 { ${SOURCE_DESIGN} } -set_top r:${SOURCE_TOP_DIR} -read_verilog -container i -libname WORK -05 { ${IMPL_DESIGN} } - -set_top i:${IMPL_TOP_DIR} -match -${MATCH_MODUEL_LIST} -verify diff --git a/openfpga_flow/scripts/run_modelsim.py b/openfpga_flow/scripts/run_formality.py similarity index 50% rename from openfpga_flow/scripts/run_modelsim.py rename to openfpga_flow/scripts/run_formality.py index e8dca5cb4..f1d781626 100644 --- a/openfpga_flow/scripts/run_modelsim.py +++ b/openfpga_flow/scripts/run_formality.py @@ -1,10 +1,12 @@ from string import Template import sys import os +import pprint import argparse import subprocess import logging from pprint import pprint +from configparser import ConfigParser # = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = # Configure logging system @@ -13,55 +15,72 @@ logging.basicConfig(level=logging.INFO, stream=sys.stdout, format='%(levelname)s (%(threadName)10s) - %(message)s') logger = logging.getLogger('Modelsim_run_log') +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Parse commandline arguments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = parser = argparse.ArgumentParser() parser.add_argument('files', nargs='+') -parser.add_argument('--modelsim_template', type=str, +parser.add_argument('--formality_template', type=str, help="Modelsim verification template file") parser.add_argument('--run_sim', action="store_true", help="Execute generated script in formality") args = parser.parse_args() - -if not args.modelsim_template: +# Consider default formality script template +if not args.formality_template: task_script_dir = os.path.dirname(os.path.abspath(__file__)) - args.modelsim_template = os.path.join(task_script_dir, os.pardir, - "misc", "modelsim_template.j2") + args.formality_template = os.path.join(task_script_dir, os.pardir, + "misc", "formality_template.tcl") -args.modelsim_template = os.path.abspath(args.modelsim_template) +args.formality_template = os.path.abspath(args.formality_template) def main(): for eachFile in args.files: eachFile = os.path.abspath(eachFile) - directory = os.path.dirname(eachFile) - os.chdir(directory) - with open(eachFile, 'r') as fp: - lines = fp.read().split("\n") - SplitL = [indx for indx, eachL in enumerate(lines) if eachL == ""] - SplitL = list(zip([0] + SplitL[:-1], SplitL)) - for indx, eachSection in enumerate(SplitL): - SplitL[indx] = list(filter(None, lines[slice(*eachSection)])) + pDir = os.path.dirname(eachFile) + os.chdir(pDir) - match_str = "set_user_match r:%s i:%s -type port -noninverted" - lables = {"SOURCE_DESIGN": " ".join(SplitL[0]), - "SOURCE_TOP_DIR": "/WORK/" + " ".join(SplitL[1]), - "IMPL_DESIGN": " ".join(SplitL[2]), - "IMPL_TOP_DIR": "/WORK/" + " ".join(SplitL[3]), - "MATCH_MODUEL_LIST": "\n".join([match_str % tuple(eachPort.split()) for eachPort in SplitL[4]]) - } + config = ConfigParser() + config.read(eachFile) - tmpl = Template(open(args.modelsim_template, encoding='utf-8').read()) - with open("Output.tcl", 'w', encoding='utf-8') as tclout: + port_map = ("set_user_match r:%s/%%s i:/WORK/%%s -type port -noninverted" % ( + "/WORK/" + config["BENCHMARK_INFO"]["src_top_module"] + )) + cell_map = ("set_user_match r:%s/%%s i:/WORK/%%s -type cell -noninverted" % ( + "/WORK/" + config["BENCHMARK_INFO"]["src_top_module"] + )) + + lables = { + "SOURCE_DESIGN_FILES": config["BENCHMARK_INFO"]["benchmark_netlist"], + "SOURCE_TOP_MODULE": "/WORK/" + config["BENCHMARK_INFO"]["src_top_module"], + + "IMPL_DESIGN_FILES": " ".join( + [val for key, val in config["FPGA_INFO"].items() + if "impl_netlist_" in key]), + "IMPL_TOP_DIR": "/WORK/" + config["FPGA_INFO"]["impl_top_module"], + + "PORT_MAP_LIST": "\n".join([port_map % + ele for ele in + config["PORT_MATCHING"].items()]), + "REGISTER_MAP_LIST": "\n".join([cell_map % + ele for ele in + config["REGISTER_MATCH"].items()]), + } + + tmpl = Template(open(args.formality_template, encoding='utf-8').read()) + with open(os.path.join(pDir, "Output.tcl"), 'w', encoding='utf-8') as tclout: tclout.write(tmpl.substitute(lables)) if args.run_sim: formality_run_string = ["formality", "-file", "Output.tcl"] - run_command("Modelsim run", "modelsim_run.log", formality_run_string) + run_command("Formality Run", "formality_run.log", formality_run_string) else: with open("Output.tcl", 'r', encoding='utf-8') as tclout: print(tclout.read()) def run_command(taskname, logfile, command, exit_if_fail=True): + os.chdir(os.pardir) logger.info("Launching %s " % taskname) with open(logfile, 'w+') as output: try: From eaf8ecee86d0c1680e93692edc9f5729077d6be5 Mon Sep 17 00:00:00 2001 From: Ganesh Gore Date: Tue, 15 Oct 2019 16:07:34 -0600 Subject: [PATCH 04/10] added _vpr.txt subscript to vpr log files --- openfpga_flow/scripts/run_fpga_flow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfpga_flow/scripts/run_fpga_flow.py b/openfpga_flow/scripts/run_fpga_flow.py index 6a203e302..75ce54af7 100644 --- a/openfpga_flow/scripts/run_fpga_flow.py +++ b/openfpga_flow/scripts/run_fpga_flow.py @@ -621,7 +621,7 @@ def run_vpr(): min_channel_width = run_standard_vpr( args.top_module+".blif", args.fix_route_chan_width, - args.top_module+"_fr_chan_width.txt") + args.top_module+"_fr_chan_width_vpr.txt") logger.info("Fixed routing channel successfully routed with %d width" % min_channel_width) extract_vpr_stats(args.top_module+"_fr_chan_width.txt") From c034b871bb4c7eb169c00bd0a70df15b1ce04276 Mon Sep 17 00:00:00 2001 From: Ganesh Gore Date: Tue, 15 Oct 2019 16:08:25 -0600 Subject: [PATCH 05/10] Made activity file independent of power option --- openfpga_flow/scripts/run_fpga_flow.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/openfpga_flow/scripts/run_fpga_flow.py b/openfpga_flow/scripts/run_fpga_flow.py index 75ce54af7..2abaee97d 100644 --- a/openfpga_flow/scripts/run_fpga_flow.py +++ b/openfpga_flow/scripts/run_fpga_flow.py @@ -234,10 +234,11 @@ def main(): if (args.fpga_flow == "yosys_vpr"): logger.info('Running "yosys_vpr" Flow') run_yosys_with_abc() + # TODO Make it optional if activity file is provided + run_ace2() + run_pro_blif_3arg() if args.power: - run_ace2() - run_pro_blif_3arg() - run_rewrite_verilog() + run_rewrite_verilog() if (args.fpga_flow == "vpr_blif"): collect_files_for_vpr() # if (args.fpga_flow == "vtr"): @@ -642,13 +643,13 @@ def run_standard_vpr(bench_blif, fixed_chan_width, logfile, route_only=False): "--place_file", args.top_module+"_vpr.place", "--route_file", args.top_module+"_vpr.route", "--full_stats", "--nodisp", + "--activity_file", args.top_module+"_ace_out.act", ] if route_only: command += ["--route"] # Power options if args.power: command += ["--power", - "--activity_file", args.top_module+"_ace_out.act", "--tech_properties", args.power_tech] # packer options if args.vpr_timing_pack_off: @@ -700,7 +701,7 @@ def run_standard_vpr(bench_blif, fixed_chan_width, logfile, route_only=False): command += ["--fpga_spice_testbench_load_extraction", "off"] # FPGA Verilog options - if (args.power and args.vpr_fpga_verilog): + if args.vpr_fpga_verilog: command += ["--fpga_verilog"] if args.vpr_fpga_verilog_dir: command += ["--fpga_verilog_dir", args.vpr_fpga_verilog_dir] From 81180939ca5d3fbdbbf379e8983a4aa997b3591f Mon Sep 17 00:00:00 2001 From: Ganesh Gore Date: Thu, 31 Oct 2019 09:56:57 -0600 Subject: [PATCH 06/10] Bug fix: Missing exit_if_fail flag in fpga_flow script --- openfpga_flow/scripts/run_fpga_flow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfpga_flow/scripts/run_fpga_flow.py b/openfpga_flow/scripts/run_fpga_flow.py index 2abaee97d..110a0f506 100644 --- a/openfpga_flow/scripts/run_fpga_flow.py +++ b/openfpga_flow/scripts/run_fpga_flow.py @@ -836,7 +836,7 @@ def run_rewrite_verilog(): run_command("Yosys", "yosys_output.txt", command) -def run_netlists_verification(): +def run_netlists_verification(exit_if_fail=True): ExecTime["VerificationStart"] = time.time() compiled_file = "compiled_"+args.top_module # include_netlists = args.top_module+"_include_netlists.v" From a0512e40b19d611cb3c8dbd1e56771e55136b2d5 Mon Sep 17 00:00:00 2001 From: Ganesh Gore Date: Fri, 1 Nov 2019 18:20:00 -0600 Subject: [PATCH 07/10] Created intermidiate file for modelsim simulation --- .../verilog/simulation_info_writer.cpp | 85 +++++++++++++++++++ .../fpga_x2p/verilog/simulation_info_writer.h | 13 +++ .../vpr/SRC/fpga_x2p/verilog/verilog_api.c | 16 +++- 3 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp new file mode 100644 index 000000000..520376be0 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp @@ -0,0 +1,85 @@ +/***********************************/ +/* Synthesizable Verilog Dumping */ +/* Xifan TANG, EPFL/LSI */ +/***********************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define MINI_CASE_SENSITIVE +#include "ini.h" + +/* Include vpr structs*/ +#include "util.h" +#include "physical_types.h" +#include "vpr_types.h" +#include "globals.h" +#include "rr_graph.h" +#include "vpr_utils.h" +#include "path_delay.h" +#include "stats.h" + +/* Include FPGA-SPICE utils */ +#include "linkedlist.h" +#include "fpga_x2p_utils.h" +#include "fpga_x2p_globals.h" + +/* Include verilog utils */ +#include "verilog_global.h" +#include "verilog_utils.h" +#include "simulation_info_writer.h" + +// Infile Function +static float get_verilog_modelsim_simulation_time_period(const float &time_unit, + const int &num_prog_clock_cycles, + const float &prog_clock_period, + const int &num_op_clock_cycles, + const float &op_clock_period) +{ + float total_time_period = 0.; + + /* Take into account the prog_reset and reset cycles */ + total_time_period = (num_prog_clock_cycles + 2) * prog_clock_period + num_op_clock_cycles * op_clock_period; + total_time_period = total_time_period / time_unit; + + return total_time_period; +} + +/***** Top-level function *****/ +void print_verilog_simulation_info(const int &num_operating_clock_cycles, + const std::string &verilog_dir_formatted, + const std::string &chomped_circuit_name, + const std::string &src_dir_path, + const size_t &num_program_clock_cycles, + const float &prog_clock_freq, + const float &op_clock_freq) +{ + mINI::INIStructure ini; + // std::map units_map; + // units_map['s']=1; // units_map['ms']=1E-3; // units_map['us']=1E-6; + // units_map['ns']=1E-9; // units_map['ps']=1E-12; // units_map['fs']=1E-15; + + /* Compute simulation time period */ + float simulation_time_period = get_verilog_modelsim_simulation_time_period(1E-3, + num_program_clock_cycles, + 1. / prog_clock_freq, + num_operating_clock_cycles, + 1. / op_clock_freq); + + ini["SIMULATION_DECK"]["PROJECTNAME "] = "ModelSimProject"; + ini["SIMULATION_DECK"]["BENCHMARK "] = chomped_circuit_name; + ini["SIMULATION_DECK"]["TOP_TB"] = chomped_circuit_name + std::string("_top_formal_verification_random_tb"); + ini["SIMULATION_DECK"]["SIMTIME "] = std::to_string(simulation_time_period); + ini["SIMULATION_DECK"]["UNIT "] = "ms"; + ini["SIMULATION_DECK"]["VERILOG_PATH "] = std::string(src_dir_path); + ini["SIMULATION_DECK"]["VERILOG_FILE1"] = std::string(defines_verilog_file_name); + ini["SIMULATION_DECK"]["VERILOG_FILE2"] = std::string(chomped_circuit_name + "_include_netlists.v"); + + mINI::INIFile file("SimulationDeckInfo.ini"); + file.generate(ini, true); +} \ No newline at end of file diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h new file mode 100644 index 000000000..46c178c17 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h @@ -0,0 +1,13 @@ +#ifndef VPR_API_H +#define VPR_API_H + +#include + +void print_verilog_simulation_info(const int &num_operating_clock_cycles, + const std::string &verilog_dir_formatted, + const std::string &chomped_circuit_name, + const std::string &src_dir_path, + const size_t &num_program_clock_cycles, + const float &prog_clock_freq, + const float &op_clock_freq); +#endif \ No newline at end of file diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index bb5af9ac5..998a8f2db 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -62,6 +62,7 @@ #include "verilog_formality_autodeck.h" #include "verilog_sdc_pb_types.h" #include "verilog_include_netlists.h" +#include "simulation_info_writer.h" #include "verilog_api.h" @@ -410,12 +411,12 @@ void vpr_fpga_verilog(ModuleManager& module_manager, dump_verilog_formal_verification_top_netlist(sram_verilog_orgz_info, chomped_circuit_name, std::string(formal_verification_top_netlist_file_path + std::string(".bak")).c_str(), src_dir_path); /* TODO: new function: to be tested */ - print_verilog_preconfig_top_module(module_manager, bitstream_manager, + print_verilog_preconfig_top_module(module_manager, bitstream_manager, Arch.spice->circuit_lib, global_ports, L_logical_blocks, - device_size, L_grids, L_blocks, + device_size, L_grids, L_blocks, std::string(chomped_circuit_name), formal_verification_top_netlist_file_path, - std::string(src_dir_path)); - + std::string(src_dir_path)); + /* Output script for formality */ write_formality_script(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, fm_dir_path, @@ -430,6 +431,13 @@ void vpr_fpga_verilog(ModuleManager& module_manager, print_verilog_random_top_testbench(std::string(chomped_circuit_name), random_top_testbench_file_path, std::string(src_dir_path), L_logical_blocks, vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, Arch.spice->spice_params); + print_verilog_simulation_info(Arch.spice->spice_params.meas_params.sim_num_clock_cycle, + std::string(msim_dir_path), + std::string(chomped_circuit_name), + std::string(src_dir_path), + bitstream_manager.bits().size(), + Arch.spice->spice_params.stimulate_params.prog_clock_freq, + Arch.spice->spice_params.stimulate_params.op_clock_freq); } if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_autocheck_top_testbench) { From 27005d6640f61d9364669ed7d24cef4a901c3d87 Mon Sep 17 00:00:00 2001 From: Ganesh Gore Date: Fri, 1 Nov 2019 18:20:40 -0600 Subject: [PATCH 08/10] Added Modelsim Python Script --- openfpga_flow/misc/modelsim_proc.tcl | 71 ++++++++++++ openfpga_flow/misc/modelsim_runsim.tcl | 37 +++++++ openfpga_flow/scripts/run_modelsim.py | 148 +++++++++++++++++++++++++ 3 files changed, 256 insertions(+) create mode 100644 openfpga_flow/misc/modelsim_proc.tcl create mode 100644 openfpga_flow/misc/modelsim_runsim.tcl create mode 100644 openfpga_flow/scripts/run_modelsim.py diff --git a/openfpga_flow/misc/modelsim_proc.tcl b/openfpga_flow/misc/modelsim_proc.tcl new file mode 100644 index 000000000..cede56af4 --- /dev/null +++ b/openfpga_flow/misc/modelsim_proc.tcl @@ -0,0 +1,71 @@ +proc create_project {projectname project_path} { + #Switch to the modelsim folder to create the project + set libname $projectname + set initfile /uusoc/facility/cad_tools/Mentor/modelsim10.7b/modeltech/modelsim.ini + project new $project_path/$projectname $projectname $libname $initfile 0 +} + +proc create_project_with_close {projectname modelsim_path} { + #Get the current project name + set project_env [project env] + if {$project_env eq ""} { + #If string empty (no project) + create_project $projectname $modelsim_path + } else { + #If string not empty (a project is loaded so clsoe it first) + project close + create_project $projectname $modelsim_path + } + } + +proc add_files_project {verilog_files} { + #Get the length of the list + set listlength [llength $verilog_files] + #Add the verilog files one by one + for {set x 0} {$x<$listlength} {incr x} { + project addfile [lindex $verilog_files $x] + } +} + +proc add_waves {top_tb} { + add wave -position insertpoint sim:/$top_tb/* +} +proc runsim {simtime unit} { + run $simtime $unit +} +#Top procedure to create enw project +proc top_create_new_project {projectname verilog_files modelsim_path simtime unit top_tb} { + #Create the project + create_project_with_close $projectname $modelsim_path + #Add the verilog files + add_files_project $verilog_files + #Compile all the files + set myFiles [project filenames] + foreach x $myFiles { + vlog +define+ENABLE_TIMING +define+ENABLE_SIGNAL_INITIALIZATION $x + } + #Start the simulation + vsim $projectname.$top_tb -voptargs=+acc + #Add the waves + add_waves top_tb + #run the simulation + runsim $simtime $unit + #Fit the window view + wave zoom full +} +#Top proc to recompile files and re run the simulation +proc top_rerun_sim {simtime unit top_tb} { + #Save actual format + set myLoc [pwd] + write format wave -window .main_pane.wave.interior.cs.body.pw.wf $myLoc/relaunch.do + quit -sim + #Compile updated verilog files + set myFiles [project filenames] + foreach x $myFiles { + vlog +define+ENABLE_TIMING +define+ENABLE_SIGNAL_INITIALIZATION $x + } + set projectname K4n4_test_fpga_msim + vsim $projectname.$top_tb -voptargs=+acc -do relaunch.do + #run the simulation + run $simtime $unit +} diff --git a/openfpga_flow/misc/modelsim_runsim.tcl b/openfpga_flow/misc/modelsim_runsim.tcl new file mode 100644 index 000000000..64578d883 --- /dev/null +++ b/openfpga_flow/misc/modelsim_runsim.tcl @@ -0,0 +1,37 @@ + +echo "==========================" +pwd +echo "==========================" + +set projectname ${PROJECTNAME} +set benchmark ${BENCHMARK} +set top_tb ${TOP_TB} +#in ms +set simtime ${SIMTIME} +set unit ${UNIT} + +#Path were both tcl script are located +set verilog_path ${VERILOG_PATH} +set project_path "${MODELSIM_PROJ_DIR}/msim_projects/" + +#Path were the verilog files are located +set verilog_path ${VERILOG_PATH} + +set verilog_files [list \ + ${VERILOG_PATH}${VERILOG_FILE1} \ + ${VERILOG_PATH}${VERILOG_FILE2} \ + ${VERILOG_PATH}fpga_defines.v + ] + +#Source the tcl script +source ${MODELSIM_PROJ_DIR}/${BENCHMARK}_autocheck_proc.tcl + +#Execute the top level procedure + +try { + top_create_new_project $$projectname $$verilog_files $$project_path $$simtime $$unit $$top_tb +} finally { + quit +} + +#Relaunch simulation diff --git a/openfpga_flow/scripts/run_modelsim.py b/openfpga_flow/scripts/run_modelsim.py new file mode 100644 index 000000000..0ddbe118c --- /dev/null +++ b/openfpga_flow/scripts/run_modelsim.py @@ -0,0 +1,148 @@ +from string import Template +import sys +import os +import pprint +import argparse +import subprocess +import logging +from pprint import pprint +from configparser import ConfigParser + +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Configure logging system +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +logging.basicConfig(level=logging.INFO, stream=sys.stdout, + format='%(levelname)s (%(threadName)10s) - %(message)s') +logger = logging.getLogger('Modelsim_run_log') + +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Parse commandline arguments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +parser = argparse.ArgumentParser() +parser.add_argument('files', nargs='+', + help="Pass SimulationDeckInfo generated by OpenFPGA flow") +parser.add_argument('--modelsim_proc_tmpl', type=str, + help="Modelsim proc template file") +parser.add_argument('--modelsim_runsim_tmpl', type=str, + help="Modelsim runsim template file") +parser.add_argument('--run_sim', action="store_true", + help="Execute generated script in formality") +parser.add_argument('--modelsim_proj_dir', + help="Provide modelsim project directory") +parser.add_argument('--modelsim_proj_name', + help="Provide modelsim project name") +parser.add_argument('--modelsim_ini', type=str, + default="/uusoc/facility/cad_tools/Mentor/modelsim10.7b/modeltech/modelsim.ini", + help="Skip any confirmation") +parser.add_argument('--skip_prompt', action='store_true', + help='Skip any confirmation') +args = parser.parse_args() + +# Consider default formality script template +task_script_dir = os.path.dirname(os.path.abspath(__file__)) +if not args.modelsim_proc_tmpl: + args.modelsim_proc_tmpl = os.path.join(task_script_dir, os.pardir, + "misc", "modelsim_proc.tcl") +if not args.modelsim_runsim_tmpl: + args.modelsim_runsim_tmpl = os.path.join(task_script_dir, os.pardir, + "misc", "modelsim_runsim.tcl") + +args.modelsim_proc_tmpl = os.path.abspath(args.modelsim_proc_tmpl) +args.modelsim_runsim_tmpl = os.path.abspath(args.modelsim_runsim_tmpl) + + +def main(): + for eachFile in args.files: + eachFile = os.path.abspath(eachFile) + pDir = os.path.dirname(eachFile) + os.chdir(pDir) + + config = ConfigParser() + config.read(eachFile) + config = config["SIMULATION_DECK"] + + # Resolve project Modelsim project path + if not args.modelsim_proj_dir: + args.modelsim_run_dir = os.path.dirname(os.path.abspath(eachFile)) + args.modelsim_proj_dir = os.path.join( + args.modelsim_run_dir, "MMSIM2") + logger.info(f"Modelsim project dir not provide " + + f"using default {args.modelsim_proj_dir} directory") + if not args.skip_prompt: + input("Press Enter to continue, Ctrl+C to abort") + args.modelsim_proj_dir = os.path.abspath(args.modelsim_proj_dir) + config["MODELSIM_PROJ_DIR"] = args.modelsim_proj_dir + if not os.path.exists(args.modelsim_proj_dir): + os.makedirs(args.modelsim_proj_dir) + + # Resolve Modelsim Project name + if not args.modelsim_proj_name: + args.modelsim_proj_name = config["BENCHMARK"] + "_MMSIM" + logger.info(f"Modelsim project name not provide " + + f"using default {args.modelsim_proj_name} directory") + + if not args.skip_prompt: + input("Press Enter to continue, Ctrl+C to abort") + config["MODELSIM_PROJ_NAME"] = args.modelsim_proj_name + config["MODELSIM_INI"] = args.modelsim_ini + + # Modify the variables in config file here + config["TOP_TB"] = os.path.splitext(config["TOP_TB"])[0] + # pass + + # Write final template file + # Write runsim file + tmpl = Template(open(args.modelsim_runsim_tmpl, + encoding='utf-8').read()) + runsim_filename = os.path.join(args.modelsim_proj_dir, + "%s_runsim.tcl" % config['BENCHMARK']) + logger.info(f"Creating tcl script at : {runsim_filename}") + with open(runsim_filename, 'w', encoding='utf-8') as tclout: + tclout.write(tmpl.substitute(config)) + + # Write proc file + proc_filename = os.path.join(args.modelsim_proj_dir, + "%s_autocheck_proc.tcl" % config['BENCHMARK']) + logger.info(f"Creating tcl script at : {proc_filename}") + with open(proc_filename, 'w', encoding='utf-8') as tclout: + tclout.write(open(args.modelsim_proc_tmpl, + encoding='utf-8').read()) + + # Execute modelsim + if args.run_sim: + os.chdir(args.modelsim_run_dir) + print(args.modelsim_run_dir) + modelsim_run_cmd = ["vsim", "-c", "-do", runsim_filename] + run_command("ModelSim Run", "modelsim_run.log", + modelsim_run_cmd) + else: + logger.info("Created runsim and proc files") + logger.info(f"runsim_filename {runsim_filename}") + logger.info(f"proc_filename {proc_filename}") + + +def run_command(taskname, logfile, command, exit_if_fail=True): + # os.chdir(os.pardir) + logger.info("Launching %s " % taskname) + with open(logfile, 'w+') as output: + try: + output.write(os.getcwd() + "\n") + output.write(" ".join(command)+"\n") + process = subprocess.run(command, + check=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True) + output.write(process.stdout) + if process.returncode: + logger.error("%s run failed with returncode %d" % + (taskname, process.returncode)) + except (Exception, subprocess.CalledProcessError) as e: + logger.exception("failed to execute %s" % taskname) + return None + logger.info("%s is written in file %s" % (taskname, logfile)) + return process.stdout + + +if __name__ == "__main__": + main() From 595d2d3070b3cd8a2868385efc3a38cb31aabdaf Mon Sep 17 00:00:00 2001 From: Ganesh Gore Date: Fri, 1 Nov 2019 18:21:26 -0600 Subject: [PATCH 09/10] Simple argument shuffle --- openfpga_flow/scripts/run_fpga_flow.py | 3 ++- openfpga_flow/scripts/run_fpga_task.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/openfpga_flow/scripts/run_fpga_flow.py b/openfpga_flow/scripts/run_fpga_flow.py index 110a0f506..83850ffe4 100644 --- a/openfpga_flow/scripts/run_fpga_flow.py +++ b/openfpga_flow/scripts/run_fpga_flow.py @@ -711,7 +711,8 @@ def run_standard_vpr(bench_blif, fixed_chan_width, logfile, route_only=False): command += ["--fpga_verilog_print_input_blif_testbench"] if args.vpr_fpga_verilog_print_autocheck_top_testbench: command += ["--fpga_verilog_print_autocheck_top_testbench", - args.top_module+"_output_verilog.v"] + # args.vpr_fpga_verilog_print_autocheck_top_testbench] + os.path.join(args.run_dir, args.top_module+"_output_verilog.v")] if args.vpr_fpga_verilog_include_timing: command += ["--fpga_verilog_include_timing"] if args.vpr_fpga_verilog_explicit_mapping: diff --git a/openfpga_flow/scripts/run_fpga_task.py b/openfpga_flow/scripts/run_fpga_task.py index a46c99e79..061ef1248 100644 --- a/openfpga_flow/scripts/run_fpga_task.py +++ b/openfpga_flow/scripts/run_fpga_task.py @@ -367,7 +367,7 @@ def create_run_command(curr_job_dir, archfile, benchmark_obj, param, task_conf): if task_gc.getboolean("verilog_output"): command += ["--vpr_fpga_verilog"] - command += ["--vpr_fpga_verilog_dir", "."] + command += ["--vpr_fpga_verilog_dir", curr_job_dir] command += ["--vpr_fpga_x2p_rename_illegal_port"] # Add other paramters to pass From 370a5ed40875c47831fb65a869d2ce4473b012d0 Mon Sep 17 00:00:00 2001 From: Ganesh Gore Date: Fri, 1 Nov 2019 18:22:40 -0600 Subject: [PATCH 10/10] Bug Fix: shifter ff.v include path to tcl script --- openfpga_flow/VerilogNetlists/ff.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfpga_flow/VerilogNetlists/ff.v b/openfpga_flow/VerilogNetlists/ff.v index 7e902c73a..bd556f936 100644 --- a/openfpga_flow/VerilogNetlists/ff.v +++ b/openfpga_flow/VerilogNetlists/ff.v @@ -5,7 +5,7 @@ // Coder : Xifan TANG //----------------------------------------------------- //------ Include defines: preproc flags ----- -`include "./SRC/fpga_defines.v" +// `include "./SRC/fpga_defines.v" module static_dff ( /* Global ports go first */ input set, // set input