Merge branch 'ganesh_dev' of https://github.com/LNIS-Projects/OpenFPGA into refactoring
This commit is contained in:
commit
e2b042c61c
|
@ -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)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(libini)
|
|
@ -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)
|
|
@ -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 <string>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <fstream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
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 <typename T>
|
||||
class INIMap
|
||||
{
|
||||
private:
|
||||
using T_DataIndexMap = std::unordered_map<std::string, std::size_t>;
|
||||
using T_DataItem = std::pair<std::string, T>;
|
||||
using T_DataContainer = std::vector<T_DataItem>;
|
||||
using T_MultiArgs = typename std::vector<std::pair<std::string, T>>;
|
||||
|
||||
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<INIMap<std::string>>;
|
||||
|
||||
namespace INIParser
|
||||
{
|
||||
using T_ParseValues = std::pair<std::string, std::string>;
|
||||
|
||||
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<std::string>;
|
||||
using T_LineDataPtr = std::shared_ptr<T_LineData>;
|
||||
|
||||
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<T_LineData>();
|
||||
}
|
||||
}
|
||||
~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<std::string>;
|
||||
using T_LineDataPtr = std::shared_ptr<T_LineData>;
|
||||
|
||||
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_
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,105 @@
|
|||
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='+')
|
||||
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()
|
||||
|
||||
# Consider default formality script template
|
||||
if not args.formality_template:
|
||||
task_script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
args.formality_template = os.path.join(task_script_dir, os.pardir,
|
||||
"misc", "formality_template.tcl")
|
||||
|
||||
args.formality_template = os.path.abspath(args.formality_template)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
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("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:
|
||||
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()
|
|
@ -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"):
|
||||
|
@ -621,7 +622,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")
|
||||
|
@ -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]
|
||||
|
@ -710,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:
|
||||
|
@ -835,7 +837,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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,58 +15,118 @@ 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,
|
||||
help="Modelsim verification template file")
|
||||
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")
|
||||
|
||||
if not args.modelsim_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.modelsim_template = os.path.abspath(args.modelsim_template)
|
||||
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)
|
||||
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)
|
||||
config = config["SIMULATION_DECK"]
|
||||
|
||||
tmpl = Template(open(args.modelsim_template, encoding='utf-8').read())
|
||||
with open("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)
|
||||
else:
|
||||
with open("Output.tcl", 'r', encoding='utf-8') as tclout:
|
||||
print(tclout.read())
|
||||
# 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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/***********************************/
|
||||
/* Synthesizable Verilog Dumping */
|
||||
/* Xifan TANG, EPFL/LSI */
|
||||
/***********************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <map>
|
||||
#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<char, int> 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);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef VPR_API_H
|
||||
#define VPR_API_H
|
||||
|
||||
#include <string>
|
||||
|
||||
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
|
|
@ -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) {
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue