From 547e254a9bcd846232f54512a834c1af561a155e Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 5 Nov 2025 12:12:30 +0100 Subject: [PATCH] libparse: parse expressions in filterlib --- passes/techmap/dfflibmap.cc | 4 +- passes/techmap/libparse.cc | 120 +++++++++++++++++++++--------------- passes/techmap/libparse.h | 10 +-- 3 files changed, 79 insertions(+), 55 deletions(-) diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index 6d55d1b43..e8fc6fc12 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -127,7 +127,7 @@ static bool parse_next_state(const LibertyAst *cell, const LibertyAst *attr, std return false; } - auto pin_names = pool{}; + auto pin_names = std::unordered_set{}; tree.get_pin_names(pin_names); // 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(pin_names.begin(), pin_names.end()); int lut = 0; for (int n = 0; n < 8; n++) { - auto values = dict{}; + auto values = std::unordered_map{}; 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(ff_output, (n & 4) == 4)); diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index cf1854c87..50bf2aca6 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -26,8 +26,20 @@ #include #include -#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" +void warn(std::string str) { + Yosys::log_formatted_warning("", str); +} #endif using namespace Yosys; @@ -162,13 +174,15 @@ void LibertyAst::dump(FILE *f, sieve &blacklist, sieve &whitelist, std::string i fprintf(f, " ;\n"); } -#ifndef FILTERLIB - // binary operators excluding ' ' -bool LibertyExpression::is_nice_binop(char c) { +bool LibertyExpression::char_is_nice_binop(char 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 LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) { if (s.empty()) @@ -191,7 +205,9 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) { s.next(); lhs = parse(s); 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; } s.next(); @@ -200,7 +216,9 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) { lhs.kind = Kind::NOT; lhs.children.push_back(parse(s, 7)); } 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; } @@ -246,7 +264,7 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) { s.next(); 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 // and we just discard it as meaningless whitespace continue; @@ -286,7 +304,7 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) { return lhs; } -void LibertyExpression::get_pin_names(pool& names) { +void LibertyExpression::get_pin_names(std::unordered_set& names) { if (kind == Kind::PIN) { names.insert(name); } else { @@ -295,7 +313,7 @@ void LibertyExpression::get_pin_names(pool& names) { } } -bool LibertyExpression::eval(dict& values) { +bool LibertyExpression::eval(std::unordered_map& values) { bool result = false; switch (kind) { case Kind::AND: @@ -324,7 +342,7 @@ bool LibertyExpression::eval(dict& values) { return false; } -std::string LibertyExpression::str(int indent) +std::string LibertyExpression::sexpr_str(int indent) { std::string prefix; switch (kind) { @@ -355,14 +373,53 @@ std::string LibertyExpression::str(int indent) if (!first) { prefix += "\n" + std::string(indent + add_indent, ' '); } - prefix += child.str(indent + add_indent); + prefix += child.sexpr_str(indent + add_indent); first = false; } 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) { @@ -764,43 +821,8 @@ const LibertyAst *find_non_null(const LibertyAst *node, const char *name) 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")) { - char c_left = pos > 0 ? str[pos-1] : ' '; - 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 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; + auto helper = LibertyExpression::Lexer(str); + return LibertyExpression::parse(helper).vlog_str(); } void event2vl(const LibertyAst *ast, std::string &edge, std::string &expr) diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index 91f06a46c..f1138567d 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -91,11 +91,13 @@ namespace Yosys LibertyExpression() : kind(Kind::EMPTY) {} static LibertyExpression parse(Lexer &s, int min_prio = 0); - void get_pin_names(pool& names); - bool eval(dict& values); - std::string str(int indent = 0); + void get_pin_names(std::unordered_set& names); + bool eval(std::unordered_map& values); + std::string sexpr_str(int indent = 0); + std::string vlog_str(); private: - static bool is_nice_binop(char c); + static bool char_is_nice_binop(char c); + bool is_binop(); }; class LibertyInputStream {