add verilog parser; update db

This commit is contained in:
bunchgrape 2025-05-02 13:21:19 +08:00
parent 396789ae3e
commit 5a4e5cf8f2
16 changed files with 1389 additions and 7 deletions

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -42,4 +42,5 @@ class PowerNet;
class EdgeTypes;
class GCellGrid;
class BsRouteInfo;
class VerilogParser;
} // namespace db

View File

@ -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) {

View File

@ -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; }

View File

@ -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) {}

View File

@ -113,6 +113,7 @@ public:
int gpdb_id = -1;
int parentCellPinId = -1;
bool is_connected = false;
string name = "";
PinSTA* staInfo = nullptr;

View 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;
}
}

View File

@ -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) {

View 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

View 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

View 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();
}
%%

View 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();
}

View 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

View File

@ -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;