add verilog parser; update db
This commit is contained in:
parent
396789ae3e
commit
5a4e5cf8f2
@ -1,13 +1,28 @@
|
||||
file(GLOB_RECURSE SRC_FILES_XPLACE_COMMON ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
||||
file(GLOB_RECURSE SRC_FILES_XPLACE_COMMON ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp)
|
||||
find_library(LIBDEF def ${PATH_THIRDPARTY_ROOT}/lefdef/def58/lib)
|
||||
find_library(LIBLEF lef ${PATH_THIRDPARTY_ROOT}/lefdef/lef58/lib)
|
||||
|
||||
add_library(xplace_common SHARED ${SRC_FILES_XPLACE_COMMON})
|
||||
# BISON/FLEX
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/io/verilog)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
find_package(BISON REQUIRED)
|
||||
find_package(FLEX REQUIRED)
|
||||
message(STATUS "BISON_EXECUTABLE=${BISON_EXECUTABLE}")
|
||||
message(STATUS "FLEX_EXECUTABLE=${FLEX_EXECUTABLE}")
|
||||
|
||||
# Verilog scan/parse.
|
||||
bison_target(verilog_parser ${CMAKE_CURRENT_SOURCE_DIR}/io/verilog/verilog_parser.yy ${CMAKE_CURRENT_BINARY_DIR}/verilog_parser.tab.cc)
|
||||
flex_target(verilog_lexer ${CMAKE_CURRENT_SOURCE_DIR}/io/verilog/verilog_lexer.l ${CMAKE_CURRENT_BINARY_DIR}/verilog_lexer.yy.cc)
|
||||
add_flex_bison_dependency(verilog_lexer verilog_parser)
|
||||
|
||||
add_library(xplace_common SHARED ${SRC_FILES_XPLACE_COMMON} ${FLEX_verilog_lexer_OUTPUTS} ${BISON_verilog_parser_OUTPUTS})
|
||||
|
||||
find_package(ZLIB)
|
||||
|
||||
target_include_directories(
|
||||
xplace_common PRIVATE ${PROJECT_SOURCE_DIR}/cpp_to_py ${PATH_THIRDPARTY_ROOT}/lefdef ${TORCH_INCLUDE_DIRS})
|
||||
target_link_libraries(
|
||||
xplace_common PRIVATE torch ${TORCH_PYTHON_LIBRARY} ${LIBDEF} ${LIBLEF})
|
||||
xplace_common PRIVATE torch stdc++fs ${TORCH_PYTHON_LIBRARY} ${LIBDEF} ${LIBLEF} ZLIB::ZLIB)
|
||||
target_compile_options(xplace_common PRIVATE -fPIC)
|
||||
|
||||
install(TARGETS
|
||||
|
||||
@ -18,6 +18,20 @@
|
||||
|
||||
using namespace db;
|
||||
|
||||
string validate_token(string& name) {
|
||||
// remove '\'
|
||||
string::size_type pos = 0;
|
||||
while ((pos = name.find('\\', pos)) != string::npos) {
|
||||
name.erase(pos, 1);
|
||||
}
|
||||
// remove ' '
|
||||
pos = 0;
|
||||
while ((pos = name.find(' ', pos)) != string::npos) {
|
||||
name.erase(pos, 1);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/***** Database *****/
|
||||
Database::Database() {
|
||||
clear();
|
||||
@ -74,8 +88,9 @@ void Database::load() {
|
||||
readConstraints(setting.Constraints);
|
||||
}
|
||||
|
||||
// verilog is unused now
|
||||
if (setting.Verilog != "") {
|
||||
readVerilog(setting.Verilog);
|
||||
readVerilog_yy(setting.Verilog);
|
||||
}
|
||||
|
||||
logger.info("Finish loading rawdb");
|
||||
@ -690,6 +705,7 @@ void Database::setup() {
|
||||
Layer& Database::addLayer(const string& name, const char type) {
|
||||
layers.emplace_back(name, type);
|
||||
Layer& newlayer = layers.back();
|
||||
name_layers.emplace(name, &newlayer);
|
||||
if (layers.size() == 1) {
|
||||
if (type == 'r') {
|
||||
newlayer.rIndex = 0;
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include "DatabaseClass.h"
|
||||
#include "Setting.h"
|
||||
std::string validate_token(std::string& name);
|
||||
|
||||
namespace db {
|
||||
|
||||
@ -37,6 +38,11 @@ public:
|
||||
robin_hood::unordered_map<string, Net*> name_nets;
|
||||
robin_hood::unordered_map<string, IOPin*> name_iopins;
|
||||
robin_hood::unordered_map<string, ViaType*> name_viatypes;
|
||||
robin_hood::unordered_map<string, Layer*> name_layers;
|
||||
bool verilog_read = false;
|
||||
|
||||
string module_name = "";
|
||||
VerilogParser* verilog_parser = nullptr;
|
||||
|
||||
vector<Layer> layers;
|
||||
vector<Site*> lefsites;
|
||||
@ -176,6 +182,7 @@ public:
|
||||
bool writeICCAD2017(const string& inputDef, const string& outputDef);
|
||||
bool writeICCAD2017(const string& outputDef);
|
||||
bool writeComponents(std::ofstream& ofs);
|
||||
bool writeNets(std::ofstream& ofs);
|
||||
bool writeBuffer(std::ofstream& ofs, const string& line);
|
||||
void writeBufferFlush(std::ofstream& ofs);
|
||||
|
||||
@ -190,7 +197,9 @@ public:
|
||||
bool writeBSPl(const std::string& file);
|
||||
|
||||
bool readVerilog(const std::string& file);
|
||||
bool readVerilog_yy(const std::string &file);
|
||||
bool readLiberty(const std::string& file);
|
||||
bool write_verilog(const std::string& file);
|
||||
|
||||
bool readConstraints(const std::string& file);
|
||||
bool readSize(const std::string& file);
|
||||
|
||||
@ -42,4 +42,5 @@ class PowerNet;
|
||||
class EdgeTypes;
|
||||
class GCellGrid;
|
||||
class BsRouteInfo;
|
||||
class VerilogParser;
|
||||
} // namespace db
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include "SNet.h"
|
||||
#include "Via.h"
|
||||
#include "Geometry.h"
|
||||
#include "Pin.h"
|
||||
|
||||
using namespace db;
|
||||
|
||||
@ -121,6 +122,15 @@ void Net::addPin(Pin* pin) {
|
||||
pins.push_back(pin);
|
||||
}
|
||||
|
||||
int Net::getPin(const string& name) {
|
||||
for (int i = 0; i < (int)pins.size(); i++) {
|
||||
if (pins[i]->name == name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/***** PowerNet *****/
|
||||
|
||||
void PowerNet::addRail(SNet* snet, int lx, int hx, int y) {
|
||||
|
||||
@ -75,9 +75,13 @@ public:
|
||||
std::vector<Pin*> pins;
|
||||
const NDR* ndr = nullptr;
|
||||
int gpdb_id = -1;
|
||||
bool is_port = false;
|
||||
// s: signal, c: clk, p: power, g: ground
|
||||
char _type = 's';
|
||||
|
||||
Net(const string& name, const NDR* ndr = nullptr);
|
||||
Net(const Net& net);
|
||||
int getPin(const string& name);
|
||||
|
||||
bool globalRouted() const { return gRouted; }
|
||||
bool detailedRouted() const { return dRouted; }
|
||||
|
||||
@ -47,7 +47,9 @@ void IOPin::getBounds(int& lx, int& ly, int& hx, int& hy, int& rIndex) const {
|
||||
/***** Pin *****/
|
||||
|
||||
Pin::Pin(const PinType* type) : type(type) {}
|
||||
Pin::Pin(Cell* cell, int i) : cell(cell), type(cell->ctype()->pins[i]), parentCellPinId(i) {}
|
||||
Pin::Pin(Cell* cell, int i) : cell(cell), type(cell->ctype()->pins[i]), parentCellPinId(i) {
|
||||
name = cell->name() + ":" + type->name();
|
||||
}
|
||||
Pin::Pin(IOPin* iopin) : iopin(iopin), type(iopin->type) {}
|
||||
Pin::Pin(const Pin& pin) : cell(pin.cell), net(pin.net), type(pin.type) {}
|
||||
|
||||
|
||||
@ -113,6 +113,7 @@ public:
|
||||
int gpdb_id = -1;
|
||||
int parentCellPinId = -1;
|
||||
bool is_connected = false;
|
||||
string name = "";
|
||||
|
||||
PinSTA* staInfo = nullptr;
|
||||
|
||||
|
||||
226
cpp_to_py/common/io/bison_verilog.cpp
Normal file
226
cpp_to_py/common/io/bison_verilog.cpp
Normal file
@ -0,0 +1,226 @@
|
||||
#include <unordered_set>
|
||||
#include <fstream>
|
||||
|
||||
#include "common/db/Cell.h"
|
||||
#include "common/db/Database.h"
|
||||
#include "common/db/Net.h"
|
||||
#include "common/db/Pin.h"
|
||||
#include "verilog/verilog_driver.hpp"
|
||||
namespace db {
|
||||
|
||||
// helper type for the visitor #4
|
||||
template <class... Ts>
|
||||
struct overloaded : Ts... {
|
||||
using Ts::operator()...;
|
||||
};
|
||||
// explicit deduction guide (not needed as of C++20)
|
||||
template <class... Ts>
|
||||
overloaded(Ts...) -> overloaded<Ts...>;
|
||||
|
||||
class VerilogParser : public verilog::ParserVerilogInterface {
|
||||
public:
|
||||
Database &db;
|
||||
bool lef_read = false;
|
||||
bool def_read = false;
|
||||
VerilogParser() = default;
|
||||
VerilogParser(Database *db, bool lef_read, bool def_read) : db(*db), lef_read(lef_read), def_read(def_read) {}
|
||||
virtual ~VerilogParser() {}
|
||||
vector<verilog::Port> ports;
|
||||
|
||||
void add_module(std::string &&name) {
|
||||
std::cout << "Module name = " << name << '\n';
|
||||
db.module_name = name;
|
||||
}
|
||||
|
||||
void add_port(verilog::Port &&port) {
|
||||
ports.push_back(port);
|
||||
auto addIOPin = [&](const std::string &iopinname, const char direction) {
|
||||
IOPin *iopin;
|
||||
if (def_read) {
|
||||
iopin = db.getIOPin(iopinname);
|
||||
if (!iopin) {
|
||||
logger.warning("IO pin is not defined: %s", iopinname.c_str());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
iopin = db.addIOPin(iopinname, iopinname, direction);
|
||||
}
|
||||
|
||||
Pin *pin = iopin->pin;
|
||||
iopin->is_connected = true;
|
||||
Net *net = db.addNet(iopinname);
|
||||
net->is_port = true;
|
||||
|
||||
pin->net = net;
|
||||
pin->is_connected = true;
|
||||
net->addPin(iopin->pin);
|
||||
};
|
||||
for (auto &name : port.names) {
|
||||
if (port.dir == verilog::PortDirection::INPUT || port.dir == verilog::PortDirection::OUTPUT) {
|
||||
char direction = 'x';
|
||||
direction = (port.dir == verilog::PortDirection::INPUT) ? 'o' : 'i';
|
||||
if ((port.beg != -1) && (port.end != -1)) {
|
||||
for (int i = port.beg; i >= port.end; i--) {
|
||||
// INPUT to the chip, output from external
|
||||
// OUTPUT to the chip, input to external
|
||||
std::string iopinname(name + "[" + std::to_string(i) + "]");
|
||||
addIOPin(iopinname, direction);
|
||||
}
|
||||
} else {
|
||||
std::string iopinname(name);
|
||||
addIOPin(iopinname, direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_net(verilog::Net &&net) {
|
||||
auto addNet = [&](const std::string &netName) { db.addNet(netName); };
|
||||
for (auto &name : net.names) {
|
||||
if ((net.beg != -1) && (net.end != -1)) {
|
||||
for (int i = net.beg; i >= net.end; i--) {
|
||||
std::string netName(name + "[" + std::to_string(i) + "]");
|
||||
netName = validate_token(netName);
|
||||
addNet(netName);
|
||||
}
|
||||
} else {
|
||||
std::string netName(name);
|
||||
netName = validate_token(netName);
|
||||
addNet(netName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_assignment(verilog::Assignment &&ast) {
|
||||
// std::cout << "Assignment: " << ast << '\n';
|
||||
// TODO:
|
||||
}
|
||||
|
||||
void add_instance(verilog::Instance &&inst) {
|
||||
// remove '\' in the head
|
||||
string cellName(inst.inst_name);
|
||||
cellName = validate_token(cellName);
|
||||
Cell *cell;
|
||||
if (def_read) {
|
||||
cell = db.getCell(cellName);
|
||||
if (!cell) {
|
||||
logger.error("Cell is not defined: %s", cellName.c_str());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// // TODO:
|
||||
// string macroName(inst.module_name);
|
||||
// CellType *celltype = db.getCellType(macroName);
|
||||
// if (!celltype) {
|
||||
// celltype = db.addCellType(macroName, db.celltypes.size());
|
||||
// for (auto [cellpin_name, cellpin] : db.cell_libs_[0]->cell(macroName)->cellpins) {
|
||||
// char direction = 'x';
|
||||
// char type = 's';
|
||||
// switch (*cellpin.direction) {
|
||||
// case gt::CellPortDirection::input:
|
||||
// direction = 'i';
|
||||
// break;
|
||||
// case gt::CellPortDirection::output:
|
||||
// direction = 'o';
|
||||
// break;
|
||||
// case gt::CellPortDirection::inout:
|
||||
// if (cellpin_name != "VDD" && cellpin_name != "vdd" && cellpin_name != "VSS" && cellpin_name != "vss") {
|
||||
// logger.warning("unknown pin %s.%s direction: %s", macroName.c_str(), cellpin_name.c_str(), "INOUT");
|
||||
// }
|
||||
// break;
|
||||
// default:
|
||||
// logger.error("unknown pin %s.%s direction: %s", macroName.c_str(), cellpin_name.c_str(), "UNKNOWN");
|
||||
// break;
|
||||
// }
|
||||
// PinType* pintype = celltype->addPin(cellpin_name, direction, type);
|
||||
// }
|
||||
// }
|
||||
|
||||
// cell = db.addCell(cellName, celltype);
|
||||
}
|
||||
for (size_t i = 0; i < inst.pin_names.size(); i++) {
|
||||
if (inst.net_names[i].size() > 1) logger.error("Bus net name is not supported\n");
|
||||
// define std::string and NetBit visit methods
|
||||
std::string pin_name =
|
||||
std::visit(overloaded{
|
||||
[](std::string &v) { return v; },
|
||||
[](verilog::NetBit &v) { return v.name + '[' + std::to_string(v.bit) + ']'; },
|
||||
[](verilog::NetRange &v) { return v.name + '[' + std::to_string(v.beg) + ':' + std::to_string(v.end) + ']'; },
|
||||
[](verilog::Constant &v) { return v.value; },
|
||||
},
|
||||
inst.pin_names[i]);
|
||||
// printf("gate:pin %s:%s\n", cellName.c_str(), pin_name.c_str());
|
||||
|
||||
std::string net_name =
|
||||
std::visit(overloaded{
|
||||
[](std::string &v) { return v; },
|
||||
[](verilog::NetBit &v) { return v.name + '[' + std::to_string(v.bit) + ']'; },
|
||||
[](verilog::NetRange &v) { return v.name + '[' + std::to_string(v.beg) + ':' + std::to_string(v.end) + ']'; },
|
||||
[](verilog::Constant &v) { return v.value; },
|
||||
},
|
||||
inst.net_names[i][0]);
|
||||
|
||||
std::string pinName(pin_name);
|
||||
std::string netName(net_name);
|
||||
netName = validate_token(netName);
|
||||
Net *net = db.getNet(netName);
|
||||
if (!net) logger.error("Net is not defined: %s", netName.c_str());
|
||||
Pin *pin;
|
||||
if (def_read) {
|
||||
pin = cell->pin(pinName);
|
||||
if (!pin) logger.error("Pin is not defined: %s", pinName.c_str());
|
||||
} else {
|
||||
pin = cell->pin(pinName);
|
||||
if (!pin) logger.error("Pin is not defined: %s", pinName.c_str());
|
||||
}
|
||||
pin->net = net;
|
||||
net->addPin(pin);
|
||||
pin->is_connected = true;
|
||||
}
|
||||
cell->is_connected = true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void removeDuplicates(std::vector<T> &vec) {
|
||||
std::unordered_set<T> uniqueElements;
|
||||
vec.erase(std::remove_if(vec.begin(), vec.end(), [&uniqueElements](const T &element) { return !uniqueElements.insert(element).second; }),
|
||||
vec.end());
|
||||
}
|
||||
|
||||
bool Database::readVerilog_yy(const std::string &file) {
|
||||
verilog_parser = new VerilogParser(this, lef_read, def_read);
|
||||
verilog_parser->read(file);
|
||||
|
||||
// remove empty nets
|
||||
for (int i = 0; i < (int)nets.size(); i++) {
|
||||
if (nets[i]->pins.size() == 0) {
|
||||
nets.erase(nets.begin() + i);
|
||||
logger.warning("Empty net %s", nets[i]->name.c_str());
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
// remove duplicates in net pins
|
||||
for (auto &net : nets) {
|
||||
auto &pins = net->pins;
|
||||
removeDuplicates(net->pins);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
string tokenize_name(const string& name) {
|
||||
// if '[' or ']' in the name, add '\' in the front
|
||||
string new_name;
|
||||
for (auto &c : name) {
|
||||
if (c == '[' || c == ']' || c == '$' || c == '.') {
|
||||
new_name += '\\';
|
||||
break;
|
||||
}
|
||||
}
|
||||
new_name += name;
|
||||
return new_name;
|
||||
}
|
||||
|
||||
}
|
||||
@ -393,6 +393,18 @@ bool Database::readDEFPG(const std::string& file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
string expand_name(const std::string& name) {
|
||||
// add '\' before '[' or ']'
|
||||
std::string result;
|
||||
for (char c : name) {
|
||||
if (c == '[' || c == ']') {
|
||||
result.push_back('\\');
|
||||
}
|
||||
result.push_back(c);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Database::writeComponents(std::ofstream& ofs) {
|
||||
int nCells = cells.size();
|
||||
ofs << "COMPONENTS " << nCells << " ;" << std::endl;
|
||||
@ -437,6 +449,40 @@ bool Database::writeComponents(std::ofstream& ofs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Database::writeNets(std::ofstream& ofs) {
|
||||
int nNets = nets.size();
|
||||
ofs << "NETS " << nNets << " ;" << std::endl;
|
||||
for (int i = 0; i < nNets; i++) {
|
||||
Net* net = nets[i];
|
||||
std::ofstream& oss = ofs;
|
||||
|
||||
oss << " - " << expand_name(net->name) << " \n";
|
||||
for (Pin* pin : net->pins) {
|
||||
if (pin->iopin)
|
||||
oss << " ( PIN "
|
||||
<< " " << pin->type->name() << " )";
|
||||
else
|
||||
oss << " ( " << expand_name(pin->cell->name()) << " " << pin->type->name() << " )";
|
||||
}
|
||||
|
||||
const char use(net->_type);
|
||||
if (use == 'p') {
|
||||
oss << " + USE POWER ;\n";
|
||||
} else if (use == 'g') {
|
||||
oss << " + USE GROUND ;\n";
|
||||
} else if (use == 's') {
|
||||
oss << " + USE SIGNAL ;\n";
|
||||
} else if (use == 'c') {
|
||||
oss << " + USE CLOCK ;\n";
|
||||
} else {
|
||||
oss << ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
ofs << "END NETS\n\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Database::writeICCAD2017(const string& inputDef, const string& outputDef) {
|
||||
std::ifstream ifs(inputDef.c_str());
|
||||
if (!ifs.good()) {
|
||||
@ -781,6 +827,15 @@ int readLefLayer(lefrCallbackType_e c, lefiLayer* leflayer, lefiUserData ud) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (db->name_layers.find(name) != db->name_layers.end()) {
|
||||
logger.warning("layer type re-defined: %s", name.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (type != 'r' && type != 'c') {
|
||||
logger.warning("unsupported layer type: %s", name.c_str());
|
||||
return 0;
|
||||
}
|
||||
Layer& layer = db->addLayer(name, type);
|
||||
|
||||
switch (type) {
|
||||
@ -1502,7 +1557,10 @@ int readDefComponentStart(defrCallbackType_e c, int num, defiUserData ud) {
|
||||
int readDefComponent(defrCallbackType_e c, defiComponent* co, defiUserData ud) {
|
||||
Database* db = (Database*)ud;
|
||||
CellType* celltype = db->getCellType(co->name());
|
||||
Cell* cell = db->addCell(co->id(), celltype);
|
||||
|
||||
string cellName(co->id());
|
||||
cellName = validate_token(cellName);
|
||||
Cell* cell = db->addCell(cellName, celltype);
|
||||
|
||||
if (co->isUnplaced()) {
|
||||
cell->fixed(false);
|
||||
@ -1787,7 +1845,29 @@ int readDefNet(defrCallbackType_e c, defiNet* dnet, defiUserData ud) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Net* net = db->addNet(dnet->name(), ndr);
|
||||
string netName(dnet->name());
|
||||
netName = validate_token(netName);
|
||||
// exclude VDD and VSS TODO:
|
||||
if (netName == "VDD" || netName == "VSS") {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Net* net = db->addNet(netName, ndr);
|
||||
|
||||
if (dnet->hasUse()) {
|
||||
const string use(dnet->use());
|
||||
if (use == "POWER") {
|
||||
net->_type = 'p';
|
||||
} else if (use == "GROUND") {
|
||||
net->_type = 'g';
|
||||
} else if (use == "SIGNAL") {
|
||||
net->_type = 's';
|
||||
} else if (use == "CLOCK") {
|
||||
net->_type = 'c';
|
||||
} else {
|
||||
logger.error("unknown use: %s", use.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i != (unsigned)dnet->numConnections(); ++i) {
|
||||
Pin* pin = nullptr;
|
||||
@ -1805,6 +1885,7 @@ int readDefNet(defrCallbackType_e c, defiNet* dnet, defiUserData ud) {
|
||||
iopin->is_connected = true;
|
||||
} else {
|
||||
string cellname(dnet->instance(i));
|
||||
cellname = validate_token(cellname);
|
||||
string pinname(dnet->pin(i));
|
||||
Cell* cell = db->getCell(cellname);
|
||||
if (!cell) {
|
||||
|
||||
254
cpp_to_py/common/io/verilog/verilog_data.hpp
Normal file
254
cpp_to_py/common/io/verilog/verilog_data.hpp
Normal file
@ -0,0 +1,254 @@
|
||||
#ifndef DATA_VERILOG_HPP_
|
||||
#define DATA_VERILOG_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <variant>
|
||||
#include <experimental/filesystem>
|
||||
|
||||
|
||||
namespace verilog {
|
||||
|
||||
enum class ConstantType {
|
||||
NONE,
|
||||
INTEGER,
|
||||
BINARY,
|
||||
OCTAL,
|
||||
DECIMAL,
|
||||
HEX,
|
||||
REAL,
|
||||
EXP
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const ConstantType& t) {
|
||||
switch(t) {
|
||||
case ConstantType::NONE: os << "NONE"; break;
|
||||
case ConstantType::INTEGER: os << "INTEGER"; break;
|
||||
case ConstantType::BINARY: os << "BINARY"; break;
|
||||
case ConstantType::OCTAL: os << "OCTAL"; break;
|
||||
case ConstantType::DECIMAL: os << "DECIMAL"; break;
|
||||
case ConstantType::HEX: os << "HEX"; break;
|
||||
case ConstantType::REAL: os << "REAL"; break;
|
||||
case ConstantType::EXP: os << "EXP"; break;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
struct Constant {
|
||||
Constant() = default; // Need this default constructor for return token
|
||||
Constant(std::string&& v, ConstantType t) : value(std::move(v)), type(t) {}
|
||||
std::string value;
|
||||
ConstantType type {ConstantType::NONE};
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Constant& c) {
|
||||
std::cout << " constant value: " << c.value << " type: " << c.type;
|
||||
return os;
|
||||
}
|
||||
|
||||
enum class PortDirection {
|
||||
INPUT,
|
||||
OUTPUT,
|
||||
INOUT
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const PortDirection& dir) {
|
||||
switch(dir){
|
||||
case PortDirection::INPUT: os << "INPUT"; break;
|
||||
case PortDirection::OUTPUT: os << "OUTPUT"; break;
|
||||
case PortDirection::INOUT: os << "INOUT"; break;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
enum class ConnectionType {
|
||||
NONE,
|
||||
WIRE,
|
||||
REG
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const ConnectionType& ct) {
|
||||
switch(ct){
|
||||
case ConnectionType::NONE: os << "NONE"; break;
|
||||
case ConnectionType::WIRE: os << "WIRE"; break;
|
||||
case ConnectionType::REG: os << "REG"; break;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
struct Port {
|
||||
std::vector<std::string> names;
|
||||
int beg {-1};
|
||||
int end {-1};
|
||||
PortDirection dir;
|
||||
ConnectionType type {ConnectionType::NONE};
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Port& port) {
|
||||
os << "beg: " << port.beg << " end: " << port.end << '\n';
|
||||
os << "Dir: " << port.dir << " type: " << port.type << '\n';
|
||||
for(const auto& n: port.names){
|
||||
os << n << '\n';
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
enum class NetType {
|
||||
NONE,
|
||||
REG,
|
||||
WIRE,
|
||||
WAND,
|
||||
WOR,
|
||||
TRI,
|
||||
TRIOR,
|
||||
TRIAND,
|
||||
SUPPLY0,
|
||||
SUPPLY1
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const NetType& t) {
|
||||
switch(t){
|
||||
case NetType::NONE: os << "NONE"; break;
|
||||
case NetType::REG: os << "REG"; break;
|
||||
case NetType::WIRE: os << "WIRE"; break;
|
||||
case NetType::WAND: os << "WAND"; break;
|
||||
case NetType::WOR: os << "WOR"; break;
|
||||
case NetType::TRI: os << "TRI"; break;
|
||||
case NetType::TRIAND: os << "TRIAND"; break;
|
||||
case NetType::TRIOR: os << "TRIOR"; break;
|
||||
case NetType::SUPPLY0: os << "SUPPLY0"; break;
|
||||
case NetType::SUPPLY1: os << "SUPPLY1"; break;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
struct Net {
|
||||
std::vector<std::string> names;
|
||||
int beg {-1};
|
||||
int end {-1};
|
||||
NetType type {NetType::NONE};
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Net& net) {
|
||||
os << "beg: " << net.beg << " end: " << net.end << '\n';
|
||||
os << "type: " << net.type << '\n';
|
||||
for(const auto& n: net.names){
|
||||
os << n << '\n';
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
struct NetBit {
|
||||
NetBit(std::string&& n, int b): name(std::move(n)), bit(b) {}
|
||||
std::string name;
|
||||
int bit {-1};
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const NetBit& n) {
|
||||
os << n.name << '[' << n.bit << "] ";
|
||||
return os;
|
||||
}
|
||||
|
||||
struct NetRange {
|
||||
NetRange(std::string&& n, int b, int e): name(std::move(n)), beg(b), end(e) {}
|
||||
std::string name;
|
||||
int beg {-1};
|
||||
int end {-1};
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const NetRange& n) {
|
||||
os << n.name << '[' << n.beg << ':' << n.end << "] ";
|
||||
return os;
|
||||
}
|
||||
|
||||
struct Assignment {
|
||||
// Left hand side can be: a wire, a bit in a wire, a part of a wire
|
||||
std::vector<std::variant<std::string, NetBit, NetRange>> lhs;
|
||||
|
||||
// Right hand side can be: a wire, a bit in a wire, a part of a wire, a constant
|
||||
std::vector<std::variant<std::string, NetBit, NetRange, Constant>> rhs;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Assignment& ast) {
|
||||
os << "LHS: ";
|
||||
for(const auto& l: ast.lhs){
|
||||
switch(l.index()){
|
||||
case 0: os << std::get<0>(l) << ' '; break;
|
||||
case 1: os << std::get<1>(l).name << '/' << std::get<1>(l).bit << ' ';
|
||||
break;
|
||||
case 2: os << std::get<2>(l).name << '/' << std::get<2>(l).beg << '/' << std::get<2>(l).end << ' ';
|
||||
break;
|
||||
}
|
||||
}
|
||||
os << '\n';
|
||||
os << "RHS: ";
|
||||
for(const auto& r: ast.rhs){
|
||||
switch(r.index()){
|
||||
case 0: os << std::get<0>(r) << ' '; break;
|
||||
case 1: os << std::get<1>(r).name << '/' << std::get<1>(r).bit << ' ';
|
||||
break;
|
||||
case 2: os << std::get<2>(r).name << '/' << std::get<2>(r).beg << '/' << std::get<2>(r).end << ' ';
|
||||
break;
|
||||
case 3: os << std::get<3>(r) << ' '; break;
|
||||
}
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
using NetConcat = std::variant<std::string, NetBit, NetRange, Constant>;
|
||||
|
||||
struct Instance {
|
||||
std::string module_name;
|
||||
std::string inst_name;
|
||||
|
||||
// pin_names might be empty. e.g. my_module m1(net1, net2);
|
||||
std::vector<std::variant<std::string, NetBit, NetRange>> pin_names;
|
||||
std::vector<std::vector<NetConcat>> net_names;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Instance& inst) {
|
||||
os << inst.module_name << ' ' << inst.inst_name << '(';
|
||||
|
||||
if(!inst.pin_names.empty()){
|
||||
for(size_t i=0; i<inst.pin_names.size(); i++){
|
||||
std::visit([](const auto& name){ std::cout << name << ' '; }, inst.pin_names[i]);
|
||||
std::cout << '(' ;
|
||||
if(inst.net_names[i].size() > 1){
|
||||
std::cout << '{';
|
||||
}
|
||||
for(const auto& v: inst.net_names[i]){
|
||||
std::visit([](const auto& v){ std::cout << v << ' '; }, v);
|
||||
}
|
||||
if(inst.net_names[i].size() > 1){
|
||||
std::cout << '}';
|
||||
}
|
||||
std::cout << ") " ;
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(size_t i=0; i<inst.net_names.size(); i++){
|
||||
if(inst.net_names[i].size() > 1){
|
||||
std::cout << '{';
|
||||
}
|
||||
for(const auto& v: inst.net_names[i]){
|
||||
std::visit([](const auto& v){ std::cout << v << ' '; }, v);
|
||||
}
|
||||
if(inst.net_names[i].size() > 1){
|
||||
std::cout << '}';
|
||||
}
|
||||
std::cout << ',';
|
||||
}
|
||||
}
|
||||
os << ')';
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
54
cpp_to_py/common/io/verilog/verilog_driver.hpp
Normal file
54
cpp_to_py/common/io/verilog/verilog_driver.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
#ifndef PARSER_VERILOG_HPP_
|
||||
#define PARSER_VERILOG_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
#include <variant>
|
||||
#include <unordered_map>
|
||||
#include <filesystem>
|
||||
|
||||
#include "verilog_scanner.hpp"
|
||||
#include "verilog_parser.tab.hh"
|
||||
|
||||
namespace verilog {
|
||||
|
||||
class ParserVerilogInterface {
|
||||
public:
|
||||
virtual ~ParserVerilogInterface(){
|
||||
if(_scanner) delete _scanner;
|
||||
if(_parser) delete _parser;
|
||||
}
|
||||
virtual void add_module(std::string&&) = 0;
|
||||
// port names, begin index, end index, port type (IOB), connection type (wire, reg)
|
||||
virtual void add_port(Port&&) = 0;
|
||||
virtual void add_net(Net&&) = 0;
|
||||
virtual void add_assignment(Assignment&&) = 0;
|
||||
virtual void add_instance(Instance&&) = 0;
|
||||
|
||||
void read(const std::filesystem::path&);
|
||||
|
||||
private:
|
||||
VerilogScanner* _scanner {nullptr};
|
||||
VerilogParser* _parser {nullptr};
|
||||
};
|
||||
|
||||
inline void ParserVerilogInterface::read(const std::filesystem::path& p){
|
||||
if(! std::filesystem::exists(p)){
|
||||
return ;
|
||||
}
|
||||
|
||||
std::ifstream ifs(p);
|
||||
|
||||
if(!_scanner){
|
||||
_scanner = new VerilogScanner(&ifs);
|
||||
}
|
||||
if(!_parser){
|
||||
_parser = new VerilogParser(*_scanner, this);
|
||||
}
|
||||
_parser->parse();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
184
cpp_to_py/common/io/verilog/verilog_lexer.l
Normal file
184
cpp_to_py/common/io/verilog/verilog_lexer.l
Normal file
@ -0,0 +1,184 @@
|
||||
%{
|
||||
/* C++ string header, for string ops below */
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
/* Implementation of yyFlexScanner */
|
||||
#include "verilog_scanner.hpp"
|
||||
#undef YY_DECL
|
||||
#define YY_DECL int verilog::VerilogScanner::yylex(verilog::VerilogParser::semantic_type * const lval, verilog::VerilogParser::location_type *loc )
|
||||
|
||||
/* typedef to make the returns for the tokens shorter */
|
||||
using token = verilog::VerilogParser::token;
|
||||
|
||||
/* define yyterminate as this instead of NULL */
|
||||
#define yyterminate() return( token::END )
|
||||
|
||||
/* msvc2010 requires that we exclude this header file. */
|
||||
#define YY_NO_UNISTD_H
|
||||
|
||||
/* update location on matching */
|
||||
#define YY_USER_ACTION loc->step(); loc->columns(yyleng);
|
||||
%}
|
||||
|
||||
/* Make the generated scanner run in debug mode. */
|
||||
%option debug
|
||||
|
||||
/* Cause the default rule (that unmatched scanner input is echoed to stdout) to be suppressed. */
|
||||
%option nodefault
|
||||
|
||||
/* Inform flex that a derived NAME is implemented as a subclass of yyFlexLexer, so flex will place your actions in the member function foo::yylex() instead of yyFlexLexer::yylex(). */
|
||||
%option yyclass="verilog::VerilogScanner"
|
||||
|
||||
/* Set yywrap always returns 1. yywrap is called when reaching EOF */
|
||||
%option noyywrap
|
||||
|
||||
/* Suppress the warning message yyunput is defined but not used */
|
||||
%option nounput
|
||||
%option never-interactive
|
||||
%option c++
|
||||
|
||||
/* Define inclusive/exclusive states */
|
||||
%x in_comment
|
||||
%x in_attribute
|
||||
|
||||
/* Predefined rules */
|
||||
NEWLINE "\n"|"\r\n"
|
||||
SPACE " "|"\t"|"\f"
|
||||
COMMENT_BEGIN "/*"
|
||||
COMMENT_END "*/"
|
||||
COMMENT_LINE "//".*\n
|
||||
|
||||
ATTRIBUTE_BEGIN "(*"
|
||||
ATTRIBUTE_END "*)"
|
||||
|
||||
/* Name rule http://www.asic-world.com/verilog/syntax1.html */
|
||||
NAME [_a-zA-Z][$_a-zA-Z0-9]*{0,1023}
|
||||
/*
|
||||
Check the escape rule inside character class
|
||||
https://www.regular-expressions.info/charclass.html
|
||||
*/
|
||||
ESCAPED_NAME \\[\\^!"#$%&',()*+\-.a-zA-Z0-9/{|}~[\]_:;<=>?@]+[\t\f ]
|
||||
INTEGER [1-9][0-9]*|0
|
||||
BINARY [+-]?[0-9]*"'"[Bb][01_xXzZ]+
|
||||
OCTAL [+-]?[0-9]*"'"[Oo][0-7_xXzZ]+
|
||||
DECIMAL [+-]?[0-9]*"'"[Dd][0-9_xXzZ]+
|
||||
HEX [+-]?[0-9]*"'"[Hh][0-9a-fA-F_xXzZ]+
|
||||
REAL [-+]?([0-9]*\.[0-9]+|[0-9]+)
|
||||
EXP [-+]?[0-9]+"."?[0-9]*"E"[-+]?[0-9]+
|
||||
|
||||
|
||||
/* Token rule section begins */
|
||||
%%
|
||||
%{ /** Code executed at the beginning of yylex **/
|
||||
yylval = lval;
|
||||
%}
|
||||
|
||||
<*>{SPACE} { /* ignore any space */ }
|
||||
{NEWLINE} { // Update line numbers
|
||||
loc->lines();
|
||||
// return( token::NEWLINE );
|
||||
}
|
||||
|
||||
|
||||
{COMMENT_LINE} { loc->lines(); }
|
||||
|
||||
{COMMENT_BEGIN} { BEGIN(in_comment); }
|
||||
<in_comment><<EOF>> {
|
||||
BEGIN(INITIAL);
|
||||
std::cerr << "Unclosed comment at line " << loc->end.line << " col " << loc->end.column << '\n';
|
||||
yyterminate();
|
||||
}
|
||||
<in_comment>{NEWLINE} { loc->lines(); }
|
||||
<in_comment>. { /* ignore characters in comment */ }
|
||||
<in_comment>{COMMENT_END} { BEGIN(INITIAL); }
|
||||
|
||||
|
||||
{ATTRIBUTE_BEGIN} { BEGIN(in_attribute); }
|
||||
<in_attribute><<EOF>> {
|
||||
BEGIN(INITIAL);
|
||||
std::cerr << "Unclosed attribute at line " << loc->end.line << " col " << loc->end.column << '\n';
|
||||
yyterminate();
|
||||
}
|
||||
<in_attribute>{NEWLINE} { loc->lines(); }
|
||||
<in_attribute>. { /* ignore characters in comment */ }
|
||||
<in_attribute>{ATTRIBUTE_END} { BEGIN(INITIAL); }
|
||||
|
||||
|
||||
":"|"."|"{"|"}"|"["|"]"|","|"*"|";"|"="|"-"|"+"|"|"|"("|")" {
|
||||
return yytext[0];
|
||||
}
|
||||
|
||||
module { return token::MODULE; }
|
||||
endmodule { return token::ENDMODULE; }
|
||||
input { return token::INPUT; }
|
||||
output { return token::OUTPUT; }
|
||||
inout { return token::INOUT; }
|
||||
reg { return token::REG; }
|
||||
wire { return token::WIRE; }
|
||||
wor { return token::WOR; }
|
||||
wand { return token::WAND; }
|
||||
tri { return token::TRI; }
|
||||
trior { return token::TRIOR; }
|
||||
triand { return token::TRIAND; }
|
||||
SUPPLY0 { return token::SUPPLY0; }
|
||||
SUPPLY1 { return token::SUPPLY1; }
|
||||
assign { return token::ASSIGN; }
|
||||
|
||||
|
||||
{ESCAPED_NAME} {
|
||||
yylval->build<std::string>(yytext);
|
||||
return token::ESCAPED_NAME;
|
||||
}
|
||||
|
||||
{NAME} {
|
||||
yylval->build<std::string>( yytext );
|
||||
return token::NAME;
|
||||
}
|
||||
|
||||
{INTEGER} {
|
||||
yylval->build<verilog::Constant>(verilog::Constant(yytext, verilog::ConstantType::INTEGER));
|
||||
return token::INTEGER;
|
||||
}
|
||||
|
||||
{BINARY} {
|
||||
yylval->build<verilog::Constant>(verilog::Constant(yytext, verilog::ConstantType::BINARY));
|
||||
return token::BINARY;
|
||||
}
|
||||
|
||||
{OCTAL} {
|
||||
yylval->build<verilog::Constant>(verilog::Constant(yytext, verilog::ConstantType::OCTAL));
|
||||
return token::OCTAL;
|
||||
}
|
||||
|
||||
{DECIMAL} {
|
||||
yylval->build<verilog::Constant>(verilog::Constant(yytext, verilog::ConstantType::DECIMAL));
|
||||
return token::DECIMAL;
|
||||
}
|
||||
|
||||
{HEX} {
|
||||
yylval->build<verilog::Constant>(verilog::Constant(yytext, verilog::ConstantType::HEX));
|
||||
return token::HEX;
|
||||
}
|
||||
|
||||
{REAL} {
|
||||
verilog::Constant c(yytext, verilog::ConstantType::REAL);
|
||||
return token::REAL;
|
||||
}
|
||||
|
||||
{EXP} {
|
||||
verilog::Constant c(yytext, verilog::ConstantType::EXP);
|
||||
return token::EXP;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
. {
|
||||
/* Last rule catches any unmatched character */
|
||||
std::cerr << "Failed to match : " << yytext << '\n';
|
||||
yyterminate();
|
||||
}
|
||||
%%
|
||||
|
||||
|
||||
484
cpp_to_py/common/io/verilog/verilog_parser.yy
Normal file
484
cpp_to_py/common/io/verilog/verilog_parser.yy
Normal file
@ -0,0 +1,484 @@
|
||||
%skeleton "lalr1.cc"
|
||||
%require "3.0"
|
||||
%debug
|
||||
%defines
|
||||
%define api.namespace {verilog}
|
||||
%define parser_class_name {VerilogParser}
|
||||
|
||||
%define parse.error verbose
|
||||
|
||||
%code requires{
|
||||
#include "verilog_data.hpp"
|
||||
|
||||
namespace verilog {
|
||||
class ParserVerilogInterface;
|
||||
class VerilogScanner;
|
||||
}
|
||||
|
||||
// The following definitions is missing when %locations isn't used
|
||||
# ifndef YY_NULLPTR
|
||||
# if defined __cplusplus && 201103L <= __cplusplus
|
||||
# define YY_NULLPTR nullptr
|
||||
# else
|
||||
# define YY_NULLPTR 0
|
||||
# endif
|
||||
# endif
|
||||
|
||||
}
|
||||
|
||||
%parse-param { VerilogScanner &scanner }
|
||||
%parse-param { ParserVerilogInterface *driver }
|
||||
|
||||
%code {
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <utility>
|
||||
#include <tuple>
|
||||
|
||||
/* include for all driver functions */
|
||||
#include "verilog_driver.hpp"
|
||||
|
||||
#undef yylex
|
||||
#define yylex scanner.yylex
|
||||
}
|
||||
|
||||
%define api.value.type variant
|
||||
%define parse.assert
|
||||
|
||||
|
||||
%left '-' '+'
|
||||
%left '*' '/'
|
||||
%left UMINUS
|
||||
|
||||
%token END 0 "end of file"
|
||||
%token NEWLINE
|
||||
%token UNDEFINED
|
||||
|
||||
/* Valid name (Identifiers) */
|
||||
%token<std::string> NAME
|
||||
%token<std::string> ESCAPED_NAME
|
||||
|
||||
%token<verilog::Constant> INTEGER BINARY OCTAL DECIMAL HEX REAL EXP
|
||||
|
||||
/* Keyword tokens */
|
||||
%token MODULE ENDMODULE INPUT OUTPUT INOUT REG WIRE WAND WOR TRI TRIOR TRIAND SUPPLY0 SUPPLY1 ASSIGN
|
||||
|
||||
|
||||
/* Nonterminal Symbols */
|
||||
%type<std::string> valid_name
|
||||
|
||||
%type<std::pair<verilog::PortDirection, verilog::ConnectionType>> port_type
|
||||
%type<verilog::Port> port_declarations port_decl port_decl_statements
|
||||
|
||||
%type<verilog::NetType> net_type
|
||||
%type<verilog::Net> net_decl_statements net_decl
|
||||
|
||||
%type<verilog::Constant> constant
|
||||
%type<verilog::Assignment> assignment
|
||||
%type<std::vector<std::variant<std::string, verilog::NetBit, verilog::NetRange>>> lhs lhs_concat lhs_exprs lhs_expr
|
||||
%type<std::vector<verilog::NetConcat>> rhs rhs_concat rhs_exprs rhs_expr
|
||||
|
||||
%type<verilog::Instance> instance
|
||||
%type<std::pair<std::vector<std::variant<std::string, NetBit, NetRange>>, std::vector<std::vector<verilog::NetConcat>>>> inst_pins nets_by_name
|
||||
|
||||
%type<std::vector<std::vector<verilog::NetConcat>>> nets_by_position
|
||||
|
||||
%type<std::pair<std::variant<std::string, NetBit, NetRange>, std::vector<verilog::NetConcat>>> net_by_name
|
||||
|
||||
%locations
|
||||
%start design
|
||||
|
||||
%%
|
||||
|
||||
valid_name
|
||||
: NAME { $$ = $1; }
|
||||
| ESCAPED_NAME { $$ = $1; }
|
||||
;
|
||||
|
||||
design
|
||||
: modules;
|
||||
|
||||
modules
|
||||
:
|
||||
| modules module
|
||||
;
|
||||
|
||||
module
|
||||
: MODULE valid_name ';'
|
||||
{
|
||||
driver->add_module(std::move($2));
|
||||
}
|
||||
statements ENDMODULE
|
||||
| MODULE valid_name '(' ')' ';'
|
||||
{
|
||||
driver->add_module(std::move($2));
|
||||
}
|
||||
statements ENDMODULE
|
||||
| MODULE valid_name '(' port_names ')' ';'
|
||||
{
|
||||
driver->add_module(std::move($2));
|
||||
}
|
||||
statements ENDMODULE
|
||||
| MODULE valid_name '('
|
||||
{
|
||||
driver->add_module(std::move($2));
|
||||
}
|
||||
port_declarations ')'
|
||||
{
|
||||
driver->add_port(std::move($5));
|
||||
}
|
||||
';' statements ENDMODULE
|
||||
;
|
||||
|
||||
// port names are ignored as they will be parsed later in declaration
|
||||
port_names
|
||||
: valid_name { }
|
||||
| port_names ',' valid_name { }
|
||||
;
|
||||
|
||||
|
||||
port_type
|
||||
: INPUT { $$ = std::make_pair(verilog::PortDirection::INPUT, verilog::ConnectionType::NONE); }
|
||||
| INPUT WIRE { $$ = std::make_pair(verilog::PortDirection::INPUT, verilog::ConnectionType::WIRE); }
|
||||
| OUTPUT { $$ = std::make_pair(verilog::PortDirection::OUTPUT,verilog::ConnectionType::NONE); }
|
||||
| OUTPUT REG { $$ = std::make_pair(verilog::PortDirection::OUTPUT,verilog::ConnectionType::REG); }
|
||||
| INOUT { $$ = std::make_pair(verilog::PortDirection::INOUT, verilog::ConnectionType::NONE); }
|
||||
| INOUT WIRE { $$ = std::make_pair(verilog::PortDirection::INOUT, verilog::ConnectionType::WIRE); }
|
||||
| INOUT REG { $$ = std::make_pair(verilog::PortDirection::INOUT, verilog::ConnectionType::REG); }
|
||||
;
|
||||
|
||||
// e.g. "input a, b, output c, d" is allowed in port declarations
|
||||
port_declarations
|
||||
: port_decl
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| port_declarations ',' port_decl
|
||||
{
|
||||
driver->add_port(std::move($1));
|
||||
$$ = $3;
|
||||
}
|
||||
| port_declarations ',' valid_name
|
||||
{
|
||||
$1.names.emplace_back(std::move($3));
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
port_decl
|
||||
: port_type valid_name
|
||||
{
|
||||
$$.dir = std::get<0>($1);
|
||||
$$.type = std::get<1>($1);
|
||||
$$.names.emplace_back(std::move($2));
|
||||
}
|
||||
| port_type '[' INTEGER ':' INTEGER ']' valid_name
|
||||
{
|
||||
$$.dir = std::get<0>($1);
|
||||
$$.type = std::get<1>($1);
|
||||
$$.beg = std::stoi($3.value);
|
||||
$$.end = std::stoi($5.value);
|
||||
$$.names.push_back(std::move($7));
|
||||
}
|
||||
;
|
||||
|
||||
statements
|
||||
: // empty
|
||||
| statements statement
|
||||
| statements statement_assign
|
||||
;
|
||||
|
||||
statement
|
||||
: declaration
|
||||
| instance
|
||||
;
|
||||
|
||||
|
||||
declaration
|
||||
: port_decl_statements ';' { driver->add_port(std::move($1)); }
|
||||
| net_decl_statements ';' { driver->add_net(std::move($1)); }
|
||||
;
|
||||
|
||||
// e.g. "input a, b, output c, d" is not allowed in port declaration statements
|
||||
port_decl_statements
|
||||
: port_decl
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| port_decl_statements ',' valid_name
|
||||
{
|
||||
$1.names.emplace_back(std::move($3));
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
net_type
|
||||
: WIRE { $$ = verilog::NetType::WIRE; }
|
||||
| WAND { $$ = verilog::NetType::WAND; }
|
||||
| WOR { $$ = verilog::NetType::WOR; }
|
||||
| TRI { $$ = verilog::NetType::TRI; }
|
||||
| TRIOR { $$ = verilog::NetType::TRIOR; }
|
||||
| TRIAND { $$ = verilog::NetType::TRIAND; }
|
||||
| SUPPLY0 { $$ = verilog::NetType::SUPPLY0; }
|
||||
| SUPPLY1 { $$ = verilog::NetType::SUPPLY1; }
|
||||
;
|
||||
|
||||
net_decl_statements
|
||||
: net_decl
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| net_decl_statements ',' valid_name
|
||||
{
|
||||
$1.names.push_back(std::move($3));
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
net_decl
|
||||
: net_type valid_name
|
||||
{
|
||||
$$.type = $1;
|
||||
$$.names.push_back(std::move($2));
|
||||
}
|
||||
| net_type '[' INTEGER ':' INTEGER ']' valid_name
|
||||
{
|
||||
$$.type = $1;
|
||||
$$.beg = std::stoi($3.value);
|
||||
$$.end = std::stoi($5.value);
|
||||
$$.names.push_back(std::move($7));
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
statement_assign
|
||||
: ASSIGN assignments ';'
|
||||
|
||||
assignments
|
||||
: assignment
|
||||
| assignments ',' assignment
|
||||
;
|
||||
|
||||
assignment
|
||||
: lhs '=' rhs { $$.lhs = $1; $$.rhs = $3; driver->add_assignment(std::move($$)); }
|
||||
;
|
||||
|
||||
|
||||
// Should try to merge lhs & rhs definition
|
||||
lhs
|
||||
: valid_name { $$.push_back(std::move($1)); }
|
||||
| valid_name '[' INTEGER ']'
|
||||
{ $$.emplace_back(verilog::NetBit(std::move($1), std::stoi($3.value))); }
|
||||
| valid_name '[' INTEGER ':' INTEGER ']'
|
||||
{ $$.emplace_back(verilog::NetRange(std::move($1), std::stoi($3.value), std::stoi($5.value))); }
|
||||
| lhs_concat { $$ = $1; }
|
||||
;
|
||||
|
||||
lhs_concat
|
||||
: '{' lhs_exprs '}' { std::move($2.begin(), $2.end(), std::back_inserter($$)); }
|
||||
;
|
||||
|
||||
lhs_exprs
|
||||
: lhs_expr { std::move($1.begin(), $1.end(), std::back_inserter($$)); }
|
||||
| lhs_exprs ',' lhs_expr
|
||||
{
|
||||
std::move($1.begin(), $1.end(), std::back_inserter($$));
|
||||
std::move($3.begin(), $3.end(), std::back_inserter($$));
|
||||
}
|
||||
;
|
||||
|
||||
lhs_expr
|
||||
: valid_name { $$.push_back(std::move($1)); }
|
||||
| valid_name '[' INTEGER ']'
|
||||
{ $$.emplace_back(verilog::NetBit(std::move($1), std::stoi($3.value))); }
|
||||
| valid_name '[' INTEGER ':' INTEGER ']'
|
||||
{ $$.emplace_back(verilog::NetRange(std::move($1), std::stoi($3.value), std::stoi($5.value))); }
|
||||
| lhs_concat
|
||||
{ std::move($1.begin(), $1.end(), std::back_inserter($$)); }
|
||||
;
|
||||
|
||||
|
||||
|
||||
constant
|
||||
: INTEGER { $$=$1; }
|
||||
| BINARY { $$=$1; }
|
||||
| OCTAL { $$=$1; }
|
||||
| DECIMAL { $$=$1; }
|
||||
| HEX { $$=$1; }
|
||||
| REAL { $$=$1; }
|
||||
| EXP { $$=$1; }
|
||||
;
|
||||
|
||||
rhs
|
||||
: valid_name { $$.emplace_back($1); }
|
||||
| valid_name '[' INTEGER ']'
|
||||
{ $$.emplace_back(verilog::NetBit(std::move($1), std::stoi($3.value))); }
|
||||
| valid_name '[' INTEGER ':' INTEGER ']'
|
||||
{ $$.emplace_back(verilog::NetRange(std::move($1), std::stoi($3.value), std::stoi($5.value))); }
|
||||
| constant { $$.push_back(std::move($1)); }
|
||||
| rhs_concat { $$ = $1; }
|
||||
;
|
||||
|
||||
rhs_concat
|
||||
: '{' rhs_exprs '}' { std::move($2.begin(), $2.end(), std::back_inserter($$)); }
|
||||
;
|
||||
|
||||
rhs_exprs
|
||||
: rhs_expr { std::move($1.begin(), $1.end(), std::back_inserter($$)); }
|
||||
| rhs_exprs ',' rhs_expr
|
||||
{
|
||||
std::move($1.begin(), $1.end(), std::back_inserter($$));
|
||||
std::move($3.begin(), $3.end(), std::back_inserter($$));
|
||||
}
|
||||
;
|
||||
|
||||
rhs_expr
|
||||
: valid_name { $$.push_back(std::move($1)); }
|
||||
| valid_name '[' INTEGER ']'
|
||||
{ $$.emplace_back(verilog::NetBit(std::move($1), std::stoi($3.value))); }
|
||||
| valid_name '[' INTEGER ':' INTEGER ']'
|
||||
{ $$.emplace_back(verilog::NetRange(std::move($1), std::stoi($3.value), std::stoi($5.value))); }
|
||||
| constant { $$.push_back(std::move($1)); }
|
||||
| rhs_concat
|
||||
{ std::move($1.begin(), $1.end(), std::back_inserter($$)); }
|
||||
;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
instance
|
||||
: valid_name valid_name '(' inst_pins ')' ';'
|
||||
{
|
||||
std::swap($$.module_name, $1);
|
||||
std::swap($$.inst_name, $2);
|
||||
std::swap($$.pin_names, std::get<0>($4));
|
||||
std::swap($$.net_names, std::get<1>($4));
|
||||
driver->add_instance(std::move($$));
|
||||
}
|
||||
| valid_name parameters valid_name '(' inst_pins ')' ';'
|
||||
{
|
||||
std::swap($$.module_name, $1);
|
||||
std::swap($$.inst_name, $3);
|
||||
std::swap($$.pin_names, std::get<0>($5));
|
||||
std::swap($$.net_names, std::get<1>($5));
|
||||
driver->add_instance(std::move($$));
|
||||
}
|
||||
;
|
||||
|
||||
inst_pins
|
||||
: { } // empty
|
||||
| nets_by_position { std::swap(std::get<1>($$), $1); }
|
||||
| nets_by_name
|
||||
{
|
||||
std::swap(std::get<0>($$), std::get<0>($1));
|
||||
std::swap(std::get<1>($$), std::get<1>($1));
|
||||
}
|
||||
;
|
||||
|
||||
nets_by_position
|
||||
: rhs { $$.emplace_back(std::move($1)); }
|
||||
| nets_by_position ',' rhs
|
||||
{
|
||||
std::move($1.begin(), $1.end(), std::back_inserter($$));
|
||||
$$.push_back(std::move($3));
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
nets_by_name
|
||||
: net_by_name
|
||||
{
|
||||
std::get<0>($$).push_back(std::move(std::get<0>($1)));
|
||||
std::get<1>($$).push_back(std::move(std::get<1>($1)));
|
||||
}
|
||||
| nets_by_name ',' net_by_name
|
||||
{
|
||||
auto &pin_names = std::get<0>($1);
|
||||
auto &net_names = std::get<1>($1);
|
||||
std::move(pin_names.begin(), pin_names.end(), std::back_inserter(std::get<0>($$)));
|
||||
std::move(net_names.begin(), net_names.end(), std::back_inserter(std::get<1>($$)));
|
||||
|
||||
std::get<0>($$).push_back(std::move(std::get<0>($3)));
|
||||
std::get<1>($$).push_back(std::move(std::get<1>($3)));
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
net_by_name
|
||||
: '.' valid_name '(' ')'
|
||||
{ std::get<0>($$) = $2; }
|
||||
| '.' valid_name '(' valid_name ')'
|
||||
{
|
||||
std::get<0>($$) = $2;
|
||||
std::get<1>($$).push_back(std::move($4));
|
||||
}
|
||||
| '.' valid_name '(' valid_name '[' INTEGER ']' ')'
|
||||
{
|
||||
std::get<0>($$) = $2;
|
||||
std::get<1>($$).emplace_back(verilog::NetBit(std::move($4), std::stoi($6.value)));
|
||||
}
|
||||
// The previous two rules are also in rhs. But I don't want to create special rule just for this case
|
||||
| '.' valid_name '(' rhs ')'
|
||||
{
|
||||
std::get<0>($$) = $2;
|
||||
std::get<1>($$) = $4;
|
||||
}
|
||||
// Bus port bit
|
||||
| '.' valid_name '[' INTEGER ']' '(' ')'
|
||||
{
|
||||
std::get<0>($$) = verilog::NetBit(std::move($2), std::stoi($4.value));
|
||||
}
|
||||
| '.' valid_name '[' INTEGER ']' '(' rhs ')'
|
||||
{
|
||||
std::get<0>($$) = verilog::NetBit(std::move($2), std::stoi($4.value));
|
||||
std::get<1>($$) = $7;
|
||||
}
|
||||
// Bus port part
|
||||
| '.' valid_name '[' INTEGER ':' INTEGER ']' '(' ')'
|
||||
{
|
||||
std::get<0>($$) = verilog::NetRange(std::move($2), std::stoi($4.value), std::stoi($6.value));
|
||||
}
|
||||
| '.' valid_name '[' INTEGER ':' INTEGER ']' '(' rhs ')'
|
||||
{
|
||||
std::get<0>($$) = verilog::NetRange(std::move($2), std::stoi($4.value), std::stoi($6.value));
|
||||
std::get<1>($$) = $9;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
// parameters are ignored for now
|
||||
parameters
|
||||
: '#' '(' param_exprs ')'
|
||||
;
|
||||
|
||||
param_exprs
|
||||
: param_expr
|
||||
| param_exprs ',' param_expr
|
||||
;
|
||||
|
||||
param_expr
|
||||
: valid_name
|
||||
| '`' valid_name
|
||||
| constant
|
||||
| '-' param_expr %prec UMINUS
|
||||
| param_expr '+' param_expr
|
||||
| param_expr '-' param_expr
|
||||
| param_expr '*' param_expr
|
||||
| param_expr '/' param_expr
|
||||
| '(' param_expr ')'
|
||||
;
|
||||
|
||||
|
||||
%%
|
||||
|
||||
void verilog::VerilogParser::error(const location_type &l, const std::string &err_message) {
|
||||
std::cerr << "Parser error: " << err_message << '\n'
|
||||
<< " begin at line " << l.begin.line << " col " << l.begin.column << '\n'
|
||||
<< " end at line " << l.end.line << " col " << l.end.column << "\n";
|
||||
std::abort();
|
||||
}
|
||||
|
||||
|
||||
36
cpp_to_py/common/io/verilog/verilog_scanner.hpp
Normal file
36
cpp_to_py/common/io/verilog/verilog_scanner.hpp
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef SCANNER_VERILOG_HPP_
|
||||
#define SCANNER_VERILOG_HPP_
|
||||
|
||||
#if ! defined(yyFlexLexerOnce)
|
||||
#include <FlexLexer.h>
|
||||
#endif
|
||||
|
||||
#include "verilog_parser.tab.hh"
|
||||
#include "location.hh"
|
||||
|
||||
namespace verilog {
|
||||
|
||||
class VerilogScanner : public yyFlexLexer{
|
||||
public:
|
||||
|
||||
VerilogScanner(std::istream *in) : yyFlexLexer(in) {
|
||||
};
|
||||
virtual ~VerilogScanner() {};
|
||||
|
||||
//get rid of override virtual function warning
|
||||
using FlexLexer::yylex;
|
||||
|
||||
virtual
|
||||
int yylex( verilog::VerilogParser::semantic_type * const lval,
|
||||
verilog::VerilogParser::location_type *location );
|
||||
// YY_DECL defined in mc_lexer.l
|
||||
// Method body created by flex in mc_lexer.yy.cc
|
||||
|
||||
private:
|
||||
/* yyval ptr */
|
||||
verilog::VerilogParser::semantic_type *yylval = nullptr;
|
||||
};
|
||||
|
||||
} /* end namespace MC */
|
||||
|
||||
#endif
|
||||
@ -49,6 +49,11 @@ public:
|
||||
bool operator==(const PointT& rhs) const { return x == rhs.x && y == rhs.y; }
|
||||
bool operator!=(const PointT& rhs) const { return !(*this == rhs); }
|
||||
|
||||
bool operator<(const PointT& rhs) const { return (x < rhs.x) || ((x == rhs.x) && (y < rhs.y)); }
|
||||
bool operator>(const PointT& rhs) const { return (x > rhs.x) || ((x == rhs.x) && (y > rhs.y)); }
|
||||
bool operator<=(const PointT& rhs) const { return !(*this > rhs); }
|
||||
bool operator>=(const PointT& rhs) const { return !(*this < rhs); }
|
||||
|
||||
friend inline std::ostream& operator<<(std::ostream& os, const PointT& pt) {
|
||||
os << "(" << pt.x << ", " << pt.y << ")";
|
||||
return os;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user