mirror of
https://github.com/YosysHQ/yosys
synced 2025-11-08 15:25:08 +00:00
libparse: parse expressions in filterlib
This commit is contained in:
parent
66d8fc5c28
commit
547e254a9b
3 changed files with 79 additions and 55 deletions
|
|
@ -127,7 +127,7 @@ static bool parse_next_state(const LibertyAst *cell, const LibertyAst *attr, std
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pin_names = pool<std::string>{};
|
auto pin_names = std::unordered_set<std::string>{};
|
||||||
tree.get_pin_names(pin_names);
|
tree.get_pin_names(pin_names);
|
||||||
|
|
||||||
// from the `ff` block, we know the flop output signal name for loopback.
|
// from the `ff` block, we know the flop output signal name for loopback.
|
||||||
|
|
@ -156,7 +156,7 @@ static bool parse_next_state(const LibertyAst *cell, const LibertyAst *attr, std
|
||||||
auto pins = std::vector<std::string>(pin_names.begin(), pin_names.end());
|
auto pins = std::vector<std::string>(pin_names.begin(), pin_names.end());
|
||||||
int lut = 0;
|
int lut = 0;
|
||||||
for (int n = 0; n < 8; n++) {
|
for (int n = 0; n < 8; n++) {
|
||||||
auto values = dict<std::string, bool>{};
|
auto values = std::unordered_map<std::string, bool>{};
|
||||||
values.insert(std::make_pair(pins[0], (n & 1) == 1));
|
values.insert(std::make_pair(pins[0], (n & 1) == 1));
|
||||||
values.insert(std::make_pair(pins[1], (n & 2) == 2));
|
values.insert(std::make_pair(pins[1], (n & 2) == 2));
|
||||||
values.insert(std::make_pair(ff_output, (n & 4) == 4));
|
values.insert(std::make_pair(ff_output, (n & 4) == 4));
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,20 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#ifndef FILTERLIB
|
#ifdef FILTERLIB
|
||||||
|
#undef log_assert
|
||||||
|
void log_assert(bool cond) {
|
||||||
|
if (!cond)
|
||||||
|
fprintf(stderr, "Unspecified assertion failed\n");
|
||||||
|
}
|
||||||
|
void warn(std::string str) {
|
||||||
|
std::cerr << str;
|
||||||
|
}
|
||||||
|
#else
|
||||||
#include "kernel/log.h"
|
#include "kernel/log.h"
|
||||||
|
void warn(std::string str) {
|
||||||
|
Yosys::log_formatted_warning("", str);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace Yosys;
|
using namespace Yosys;
|
||||||
|
|
@ -162,13 +174,15 @@ void LibertyAst::dump(FILE *f, sieve &blacklist, sieve &whitelist, std::string i
|
||||||
fprintf(f, " ;\n");
|
fprintf(f, " ;\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef FILTERLIB
|
|
||||||
|
|
||||||
// binary operators excluding ' '
|
// binary operators excluding ' '
|
||||||
bool LibertyExpression::is_nice_binop(char c) {
|
bool LibertyExpression::char_is_nice_binop(char c) {
|
||||||
return c == '*' || c == '&' || c == '^' || c == '+' || c == '|';
|
return c == '*' || c == '&' || c == '^' || c == '+' || c == '|';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LibertyExpression::is_binop() {
|
||||||
|
return kind == AND || kind == OR || kind == XOR;
|
||||||
|
}
|
||||||
|
|
||||||
// https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html
|
// https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html
|
||||||
LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) {
|
LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) {
|
||||||
if (s.empty())
|
if (s.empty())
|
||||||
|
|
@ -191,7 +205,9 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) {
|
||||||
s.next();
|
s.next();
|
||||||
lhs = parse(s);
|
lhs = parse(s);
|
||||||
if (s.peek() != ')') {
|
if (s.peek() != ')') {
|
||||||
log_warning("expected ')' instead of '%c' while parsing Liberty expression '%s'\n", s.peek(), s.full_expr());
|
std::stringstream ss;
|
||||||
|
ss << "expected ')' instead of " << s.peek() << " while parsing Liberty expression '" << s.full_expr() << "'\n";
|
||||||
|
warn(ss.str());
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
s.next();
|
s.next();
|
||||||
|
|
@ -200,7 +216,9 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) {
|
||||||
lhs.kind = Kind::NOT;
|
lhs.kind = Kind::NOT;
|
||||||
lhs.children.push_back(parse(s, 7));
|
lhs.children.push_back(parse(s, 7));
|
||||||
} else {
|
} else {
|
||||||
log_warning("unrecognised character '%c' while parsing Liberty expression '%s'\n", c, s.full_expr());
|
std::stringstream ss;
|
||||||
|
ss << "unrecognised character " << c << " while parsing Liberty expression " << s.full_expr() << "\n";
|
||||||
|
warn(ss.str());
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,7 +264,7 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) {
|
||||||
s.next();
|
s.next();
|
||||||
c = s.peek();
|
c = s.peek();
|
||||||
}
|
}
|
||||||
if (is_nice_binop(c)) {
|
if (char_is_nice_binop(c)) {
|
||||||
// We found a real binop, so this space wasn't an AND
|
// We found a real binop, so this space wasn't an AND
|
||||||
// and we just discard it as meaningless whitespace
|
// and we just discard it as meaningless whitespace
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -286,7 +304,7 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) {
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibertyExpression::get_pin_names(pool<std::string>& names) {
|
void LibertyExpression::get_pin_names(std::unordered_set<std::string>& names) {
|
||||||
if (kind == Kind::PIN) {
|
if (kind == Kind::PIN) {
|
||||||
names.insert(name);
|
names.insert(name);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -295,7 +313,7 @@ void LibertyExpression::get_pin_names(pool<std::string>& names) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LibertyExpression::eval(dict<std::string, bool>& values) {
|
bool LibertyExpression::eval(std::unordered_map<std::string, bool>& values) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case Kind::AND:
|
case Kind::AND:
|
||||||
|
|
@ -324,7 +342,7 @@ bool LibertyExpression::eval(dict<std::string, bool>& values) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string LibertyExpression::str(int indent)
|
std::string LibertyExpression::sexpr_str(int indent)
|
||||||
{
|
{
|
||||||
std::string prefix;
|
std::string prefix;
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
|
|
@ -355,14 +373,53 @@ std::string LibertyExpression::str(int indent)
|
||||||
if (!first) {
|
if (!first) {
|
||||||
prefix += "\n" + std::string(indent + add_indent, ' ');
|
prefix += "\n" + std::string(indent + add_indent, ' ');
|
||||||
}
|
}
|
||||||
prefix += child.str(indent + add_indent);
|
prefix += child.sexpr_str(indent + add_indent);
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
prefix += ")";
|
prefix += ")";
|
||||||
return prefix;
|
return prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
std::string LibertyExpression::vlog_str()
|
||||||
|
{
|
||||||
|
std::string prefix;
|
||||||
|
if (kind != PIN)
|
||||||
|
prefix += "(";
|
||||||
|
if (is_binop()) {
|
||||||
|
log_assert(children.size() == 2);
|
||||||
|
prefix += children[0].vlog_str();
|
||||||
|
switch (kind) {
|
||||||
|
case AND:
|
||||||
|
prefix += "&";
|
||||||
|
break;
|
||||||
|
case OR:
|
||||||
|
prefix += "|";
|
||||||
|
break;
|
||||||
|
case XOR:
|
||||||
|
prefix += "^";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log_assert(false);
|
||||||
|
}
|
||||||
|
prefix += children[1].vlog_str();
|
||||||
|
} else {
|
||||||
|
switch (kind) {
|
||||||
|
case NOT:
|
||||||
|
log_assert(children.size() == 1);
|
||||||
|
prefix += "~";
|
||||||
|
prefix += children[0].vlog_str();
|
||||||
|
break;
|
||||||
|
case PIN:
|
||||||
|
prefix += name;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log_assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (kind != PIN)
|
||||||
|
prefix += ")";
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
int LibertyParser::lexer_inner(std::string &str)
|
int LibertyParser::lexer_inner(std::string &str)
|
||||||
{
|
{
|
||||||
|
|
@ -764,43 +821,8 @@ const LibertyAst *find_non_null(const LibertyAst *node, const char *name)
|
||||||
|
|
||||||
std::string func2vl(std::string str)
|
std::string func2vl(std::string str)
|
||||||
{
|
{
|
||||||
for (size_t pos = str.find_first_of("\" \t"); pos != std::string::npos; pos = str.find_first_of("\" \t")) {
|
auto helper = LibertyExpression::Lexer(str);
|
||||||
char c_left = pos > 0 ? str[pos-1] : ' ';
|
return LibertyExpression::parse(helper).vlog_str();
|
||||||
char c_right = pos+1 < str.size() ? str[pos+1] : ' ';
|
|
||||||
if (std::string("\" \t*+").find(c_left) != std::string::npos)
|
|
||||||
str.erase(pos, 1);
|
|
||||||
else if (std::string("\" \t*+").find(c_right) != std::string::npos)
|
|
||||||
str.erase(pos, 1);
|
|
||||||
else
|
|
||||||
str[pos] = '*';
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<size_t> group_start;
|
|
||||||
for (size_t pos = 0; pos < str.size(); pos++) {
|
|
||||||
if (str[pos] == '(')
|
|
||||||
group_start.push_back(pos);
|
|
||||||
if (str[pos] == ')' && group_start.size() > 0) {
|
|
||||||
if (pos+1 < str.size() && str[pos+1] == '\'') {
|
|
||||||
std::string group = str.substr(group_start.back(), pos-group_start.back()+1);
|
|
||||||
str[group_start.back()] = '~';
|
|
||||||
str.replace(group_start.back()+1, group.size(), group);
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
group_start.pop_back();
|
|
||||||
}
|
|
||||||
if (str[pos] == '\'' && pos > 0) {
|
|
||||||
size_t start = str.find_last_of("()'*+^&| ", pos-1)+1;
|
|
||||||
std::string group = str.substr(start, pos-start);
|
|
||||||
str[start] = '~';
|
|
||||||
str.replace(start+1, group.size(), group);
|
|
||||||
}
|
|
||||||
if (str[pos] == '*')
|
|
||||||
str[pos] = '&';
|
|
||||||
if (str[pos] == '+')
|
|
||||||
str[pos] = '|';
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void event2vl(const LibertyAst *ast, std::string &edge, std::string &expr)
|
void event2vl(const LibertyAst *ast, std::string &edge, std::string &expr)
|
||||||
|
|
|
||||||
|
|
@ -91,11 +91,13 @@ namespace Yosys
|
||||||
LibertyExpression() : kind(Kind::EMPTY) {}
|
LibertyExpression() : kind(Kind::EMPTY) {}
|
||||||
|
|
||||||
static LibertyExpression parse(Lexer &s, int min_prio = 0);
|
static LibertyExpression parse(Lexer &s, int min_prio = 0);
|
||||||
void get_pin_names(pool<std::string>& names);
|
void get_pin_names(std::unordered_set<std::string>& names);
|
||||||
bool eval(dict<std::string, bool>& values);
|
bool eval(std::unordered_map<std::string, bool>& values);
|
||||||
std::string str(int indent = 0);
|
std::string sexpr_str(int indent = 0);
|
||||||
|
std::string vlog_str();
|
||||||
private:
|
private:
|
||||||
static bool is_nice_binop(char c);
|
static bool char_is_nice_binop(char c);
|
||||||
|
bool is_binop();
|
||||||
};
|
};
|
||||||
|
|
||||||
class LibertyInputStream {
|
class LibertyInputStream {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue