diff --git a/libopenfpga/libpcf/src/io/pcf.cpp b/libopenfpga/libpcf/src/io/pcf.cpp new file mode 100644 index 000000000..e4e60aca7 --- /dev/null +++ b/libopenfpga/libpcf/src/io/pcf.cpp @@ -0,0 +1,90 @@ +/* (C) 2018 - genBTC, All Rights Reserved */ +/* November 17, 2018 */ + +#include +#include +#include +#include +#include +#include +#include +#include "main.h" + +#define TEST_PRINT_PCFREAD_CHECK 0 + +std::vector parsePCF(const char* pcffile) { + std::vector v; + std::ifstream input(pcffile); // open the file + std::string line; // iterate each line + while (std::getline(input, line)) { // getline returns the stream by reference, so this handles EOF + std::stringstream ss(line); // create a stringstream out of each line + PCFlayout PCF_node; // start a new node + while (ss) { // while the stream is good + std::string word; // get first word + if (ss >> word) { // if first word is set_io + if (word.find("set_io") == 0) { + ss >> PCF_node.pinName >> PCF_node.pinNum; + if (PCF_node.pinNum != "") + PCF_node.pinNumInt = std::stoi(PCF_node.pinNum); + //strip out the [ ] + auto loc = PCF_node.pinName.find('['); + if (loc != std::string::npos) { + PCF_node.pinNameBit = std::stoi(PCF_node.pinName.substr(loc + 1, PCF_node.pinName.find(']') - 1)); + PCF_node.pinNameBase = PCF_node.pinName; //copy the full string, then + PCF_node.pinNameBase.erase(loc); //remove the [bitfield] part + } + //no break statement, means keep checking (next iteration, for comments) + } + else if (word[0] == '#') { // if it's a comment + int commentpos = line.find("#"); + //if its not at the beginning of the line, store it + if (commentpos != 0) + PCF_node.comment = line.substr(commentpos); + break; //or ignore the full line comment and move on + } + else { + std::cerr << "Unresolved Symbol: '" << word << "'\n"; // report unexpected data + break; //and move onto next line. without this, it will accept more following values on this line + } + } + } + if (PCF_node.pinName == "") continue; + v.push_back(PCF_node); + } + return v; +} + + +void printParsedPCFcheck(std::vector &pcfnodes) +{ + //visually prints PCF input data we just read into the vector - to check validity, as a Unit Test + if (TEST_PRINT_PCFREAD_CHECK) { + std::cout << "Printing Parsed PCF:\n"; + for (auto node : pcfnodes) { + if (node.pinName.length() != 0) + std::cout << "set_io" << " " << node.pinName << " " << node.pinNum << " " << node.comment << std::endl; + } + std::cout << "\n"; + } +} + + +bool hasDuplicatePinErrorsMap(std::vector &v1, std::map &pcfMap) { + bool hasdupes{ false }; int dupes_found = 0; + + for (auto vi : v1) { + //Check map for duplicate + if (pcfMap.find(vi.pinNumInt) != pcfMap.end()) { + hasdupes = true; ++dupes_found; + std::cout << "Duplicate Pin: " << vi.pinNum << " = " << vi.pinName << " <-- Re-definition error.\n"; + std::cout << ">Original Pin: " << pcfMap[vi.pinNumInt].pinNum << " = " << pcfMap[vi.pinNumInt].pinName << "\n"; + continue; + } + pcfMap[vi.pinNumInt] = vi; + if (VERBOSE_V_MODE) + std::cout << "Checking: " << vi.pinNum << " = " << vi.pinName << "\n"; + } + if (hasdupes || dupes_found) + std::cout << "\n" << dupes_found << " Duplicates Found\n"; + return hasdupes; +} diff --git a/libopenfpga/libpcf/src/io/verilog.cpp b/libopenfpga/libpcf/src/io/verilog.cpp new file mode 100644 index 000000000..baec34767 --- /dev/null +++ b/libopenfpga/libpcf/src/io/verilog.cpp @@ -0,0 +1,146 @@ +/* (C) 2018 - genBTC, All Rights Reserved */ +/* November 17, 2018 */ + +#include +#include +#include +#include +#include +#include +#include +#include "main.h" + +#define TEST_PRINT_VERILOG_CHECK 0 +#define TEST_PCFMAP_PIN_COUNT 0 + +std::vector parseVerilog(const char* verilogfile) { + std::vector v; + std::ifstream input(verilogfile); // open the file + std::string line; // iterate each line + while (std::getline(input, line)) { // getline returns the stream by reference, so this handles EOF + std::stringstream ss(line); // create a stringstream out of each line + Veriloglayout VLog_node; // start a new node + while (ss) { // while the stream is good + std::string word; // get first word + if (ss >> word) { // if first word is set_io + if (word.find("input") == 0 || word.find("output") == 0 || word.find("inout") == 0) { + VLog_node.inpout = word; + if (ss >> word) { + if (word.find('[') == 0) { + VLog_node.bitfield = word; + VLog_node.hibit = std::stoi(word.substr(1, word.find(':'))); + VLog_node.lobit = std::stoi(word.substr(word.find(':') + 1, word.size())); + VLog_node.bits = VLog_node.hibit - VLog_node.lobit + 1; + ss >> VLog_node.pinName; + } + else + VLog_node.pinName = word; + //remove the ending comma + auto l = VLog_node.pinName.size() - 1; + if (l == VLog_node.pinName.find(',')) + VLog_node.pinName.erase(l); + } + break; + } + else if (word.find("wire") == 0) //marks a wire block. + break; + else if (word[0] == '#') { // if it's a comment + int commentpos = line.find("#"); + //if its not at the beginning of the line, store it + if (commentpos != 0) + VLog_node.comment = line.substr(commentpos); + break; //or ignore the full line comment and move on + } + else if (word.find("verilog") == 0) //marks the start of the file + break; + else if (word.find("module") == 0) { //marks the start of the module definition + ss >> word; //this is the title of the module + break; + } + else if (word.find(");") == 0) //marks the end of the file + break; + else { + //noisy parser errors + std::cerr << "Error @ line: " << line << "\n"; + std::cerr << "Unresolved Symbol: '" << word << "'\n"; + break; //and move onto next line. without this, it will accept more following values on this line + } + } + } + if (VLog_node.pinName == "") continue; + v.push_back(VLog_node); + } + return v; +} + + +void printParsedVerilogCheck(std::vector &vlognodes) +{ + //visually prints Verilog data we just read into the vector - to check validity, as a Unit Test + if (TEST_PRINT_VERILOG_CHECK) { + std::cout << "Printing parsed Verilog:\n"; + for (auto node : vlognodes) { + if (node.pinName.length() != 0) { + std::cout << node.inpout << ": " << node.pinName; + if (node.bits > 1) + std::cout << " bits: [" << node.bits << "]"; + std::cout << " " << node.comment << std::endl; + } + } + std::cout << "\n"; + } +} + +bool comparePCFtoVerilog(std::vector &v1, std::vector &v2){ + std::map pinBitNumsMap; + //Count up the number of PCF pins with the same name; + for (auto &pNode : v1) { + //make a map of the PCF to find by BaseName and count up the bits + pinBitNumsMap[pNode.pinNameBase]++; //increment seen pin bit count + } + //check output: + if (TEST_PCFMAP_PIN_COUNT) { + std::cout << "\nCount up the number of PCF pins with the same name:\n"; + for (auto pin : pinBitNumsMap) { + //map will be: PIN_NAME , TOTAL_BITS_ACCOUNTED_FOR + std::cout << pin.first << " " << pin.second << "\n"; + } + std::cout << "\n"; + } + std::cout << "Comparing parsed_Verilog with parsed_PCF:\n"; + bool hasMismatches{ false }; int mismatches_found = 0; + //O(n^2)? = meh + for (auto pin : pinBitNumsMap) { + for (auto vNode : v2) { + if (pin.first.find(vNode.pinName) == 0) { + if (pin.second != vNode.bits) { + std::cout << "Verilog @ " << vNode.pinName << " [" << vNode.bits << "]\n"; + std::cout << " NOT EQUAL: \n"; + std::cout << "PCFfile @ " << pin.first << " [" << pin.second << "]\n"; + hasMismatches = true; ++mismatches_found; + break; + } + } + } + } + if (hasMismatches || mismatches_found) + std::cout << "\n" << mismatches_found << " Mis-Matches Found!\n"; + + std::cout << "\nComparing parsed_PCF pin name bit number with parsed_Verilog bit field:\n"; + std::cout << "Finds errors where pin bit name is less than or greater than than the Verilog.v bit-field\n"; + //Finds Bit-Range errors between .PCF and .V + for (auto pNode : v1) { + for (auto vNode : v2) { + if (pNode.pinName.find(vNode.pinName) == 0) { + if (pNode.pinNameBit < vNode.lobit) { + std::cout << "Error: " << pNode.pinName << " @ .PCF = " << pNode.pinNameBit << " < " << vNode.lobit << " @ .V \n"; + } + else if (pNode.pinNameBit > vNode.hibit) { + std::cout << "Error: " << pNode.pinName << " @ .PCF = " << pNode.pinNameBit << " > " << vNode.hibit << " @ .V \n"; + } + } + } + } + + return hasMismatches; +} \ No newline at end of file