3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-10-10 09:48:06 +00:00

Merge pull request #5339 from rocallahan/fast-rtlil-parser

Rewrite the RTLIL parser for efficiency
This commit is contained in:
Emil J 2025-10-08 14:52:37 +02:00 committed by GitHub
commit a80462f27f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 807 additions and 794 deletions

View file

@ -63,6 +63,10 @@ significant bit first. Bits may be any of:
- ``m``: A marked bit (internal use only) - ``m``: A marked bit (internal use only)
- ``-``: A don't care value - ``-``: A don't care value
When the bit representation has fewer bits than the width, it is padded to the width with
the most significant explicit bit, or ``0`` if the most significant explicit bit is ``1``,
or ``x`` if there are no explicit bits.
An *integer* is simply a signed integer value in decimal format. **Warning:** An *integer* is simply a signed integer value in decimal format. **Warning:**
Integer constants are limited to 32 bits. That is, they may only be in the range Integer constants are limited to 32 bits. That is, they may only be in the range
:math:`[-2147483648, 2147483648)`. Integers outside this range will result in an :math:`[-2147483648, 2147483648)`. Integers outside this range will result in an
@ -133,6 +137,7 @@ wires, memories, cells, processes, and connections.
<module> ::= <attr-stmt>* <module-stmt> <module-body> <module-end-stmt> <module> ::= <attr-stmt>* <module-stmt> <module-body> <module-end-stmt>
<module-stmt> ::= module <id> <eol> <module-stmt> ::= module <id> <eol>
<module-body> ::= (<param-stmt> <module-body> ::= (<param-stmt>
| <conn-stmt>
| <wire> | <wire>
| <memory> | <memory>
| <cell> | <cell>
@ -170,6 +175,11 @@ See :ref:`sec:rtlil_sigspec` for an overview of signal specifications.
| <sigspec> [ <integer> (:<integer>)? ] | <sigspec> [ <integer> (:<integer>)? ]
| { <sigspec>* } | { <sigspec>* }
When a ``<wire-id>`` is specified, the wire must have been previously declared.
When a signal slice is specified, the left-hand integer must be greather than or
equal to the right-hand integer.
Connections Connections
^^^^^^^^^^^ ^^^^^^^^^^^
@ -268,7 +278,7 @@ may have zero or more attributes.
.. code:: BNF .. code:: BNF
<switch> ::= <switch-stmt> <case>* <switch-end-stmt> <switch> ::= <switch-stmt> <case>* <switch-end-stmt>
<switch-stmt> := <attr-stmt>* switch <sigspec> <eol> <switch-stmt> ::= <attr-stmt>* switch <sigspec> <eol>
<case> ::= <attr-stmt>* <case-stmt> <case-body> <case> ::= <attr-stmt>* <case-stmt> <case-body>
<case-stmt> ::= case <compare>? <eol> <case-stmt> ::= case <compare>? <eol>
<compare> ::= <sigspec> (, <sigspec>)* <compare> ::= <sigspec> (, <sigspec>)*
@ -295,3 +305,4 @@ be:
| sync always <eol> | sync always <eol>
<sync-type> ::= low | high | posedge | negedge | edge <sync-type> ::= low | high | posedge | negedge | edge
<update-stmt> ::= update <dest-sigspec> <src-sigspec> <eol> <update-stmt> ::= update <dest-sigspec> <src-sigspec> <eol>
| <attr-stmt>* memwr <id> <sigspec> <sigspec> <sigspec> <constant> <eol>

View file

@ -1,19 +1 @@
GENFILES += frontends/rtlil/rtlil_parser.tab.cc
GENFILES += frontends/rtlil/rtlil_parser.tab.hh
GENFILES += frontends/rtlil/rtlil_parser.output
GENFILES += frontends/rtlil/rtlil_lexer.cc
frontends/rtlil/rtlil_parser.tab.cc: frontends/rtlil/rtlil_parser.y
$(Q) mkdir -p $(dir $@)
$(P) $(BISON) -o $@ -d -r all -b frontends/rtlil/rtlil_parser $<
frontends/rtlil/rtlil_parser.tab.hh: frontends/rtlil/rtlil_parser.tab.cc
frontends/rtlil/rtlil_lexer.cc: frontends/rtlil/rtlil_lexer.l
$(Q) mkdir -p $(dir $@)
$(P) flex -o frontends/rtlil/rtlil_lexer.cc $<
OBJS += frontends/rtlil/rtlil_parser.tab.o frontends/rtlil/rtlil_lexer.o
OBJS += frontends/rtlil/rtlil_frontend.o OBJS += frontends/rtlil/rtlil_frontend.o

View file

@ -17,27 +17,768 @@
* *
* --- * ---
* *
* A very simple and straightforward frontend for the RTLIL text * A handwritten recursive-descent parser for the RTLIL text representation.
* representation.
* *
*/ */
#include "rtlil_frontend.h"
#include "kernel/register.h" #include "kernel/register.h"
#include "kernel/log.h" #include "kernel/log.h"
#include "kernel/utils.h"
void rtlil_frontend_yyerror(char const *s) #include <charconv>
{ #include <deque>
YOSYS_NAMESPACE_PREFIX log_error("Parser error in line %d: %s\n", rtlil_frontend_yyget_lineno(), s); #include <optional>
}
void rtlil_frontend_yywarning(char const *s)
{
YOSYS_NAMESPACE_PREFIX log_warning("In line %d: %s\n", rtlil_frontend_yyget_lineno(), s);
}
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
struct RTLILFrontendWorker {
// Forbid constants of more than 1 Gb.
// This will help us not explode on malicious RTLIL.
static constexpr int MAX_CONST_WIDTH = 1024 * 1024 * 1024;
std::istream *f = nullptr;
RTLIL::Design *design;
bool flag_nooverwrite = false;
bool flag_overwrite = false;
bool flag_lib = false;
int line_num;
std::string line_buf;
// Substring of line_buf. Always newline-terminated, thus never empty.
std::string_view line;
RTLIL::Module *current_module;
dict<RTLIL::IdString, RTLIL::Const> attrbuf;
std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack;
std::vector<RTLIL::CaseRule*> case_stack;
template <typename... Args>
[[noreturn]]
void error(FmtString<TypeIdentity<Args>...> fmt, const Args &... args)
{
log_error("Parser error in line %d: %s\n", line_num, fmt.format(args...));
}
template <typename... Args>
void warning(FmtString<TypeIdentity<Args>...> fmt, const Args &... args)
{
log_warning("In line %d: %s\n", line_num, fmt.format(args...));
}
// May return an empty line if the stream is not good().
void advance_to_next_nonempty_line()
{
if (!f->good()) {
line = "\n";
return;
}
while (true) {
std::getline(*f, line_buf);
line_num++;
if (line_buf.empty() || line_buf[line_buf.size() - 1] != '\n')
line_buf += '\n';
line = line_buf;
consume_whitespace_and_comments();
if (line[0] != '\n' || !f->good())
break;
}
}
void consume_whitespace_and_comments()
{
while (true) {
switch (line[0]) {
case ' ':
case '\t':
line = line.substr(1);
break;
case '#':
line = "\n";
return;
default:
return;
}
}
}
bool try_parse_keyword(std::string_view keyword)
{
int keyword_size = keyword.size();
if (keyword != line.substr(0, keyword_size))
return false;
// This index is safe because `line` is always newline-terminated
// and `keyword` never contains a newline.
char ch = line[keyword_size];
if (ch >= 'a' && ch <= 'z')
return false;
line = line.substr(keyword_size);
consume_whitespace_and_comments();
return true;
}
std::string error_token()
{
std::string result;
for (char ch : line) {
if (ch == '\n' || ch == ' ' || ch == '\t')
break;
result += ch;
}
return result;
}
void expect_keyword(std::string_view keyword)
{
if (!try_parse_keyword(keyword))
error("Expected token `%s', got `%s'.", keyword, error_token());
}
bool try_parse_char(char ch)
{
if (line[0] != ch)
return false;
line = line.substr(1);
consume_whitespace_and_comments();
return true;
}
void expect_char(char ch)
{
if (!try_parse_char(ch))
error("Expected `%c', got `%s'.", ch, error_token());
}
bool try_parse_eol()
{
if (line[0] != '\n')
return false;
advance_to_next_nonempty_line();
return true;
}
void expect_eol()
{
if (!try_parse_eol())
error("Expected EOL, got `%s'.", error_token());
}
std::optional<RTLIL::IdString> try_parse_id()
{
char ch = line[0];
if (ch != '\\' && ch != '$')
return std::nullopt;
int idx = 1;
while (true) {
ch = line[idx];
if (ch <= ' ' && (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'))
break;
++idx;
}
IdString result(line.substr(0, idx));
line = line.substr(idx);
consume_whitespace_and_comments();
return result;
}
RTLIL::IdString parse_id()
{
std::optional<RTLIL::IdString> id = try_parse_id();
if (!id.has_value())
error("Expected ID, got `%s'.", error_token());
return std::move(*id);
}
long long parse_integer()
{
long long result = parse_integer_alone();
consume_whitespace_and_comments();
return result;
}
long long parse_integer_alone()
{
int idx = 0;
if (line[idx] == '-')
++idx;
while (true) {
char ch = line[idx];
if (ch < '0' || ch > '9')
break;
++idx;
}
long long result;
if (std::from_chars(line.data(), line.data() + idx, result, 10).ec != std::errc{})
error("Invalid integer `%s'.", error_token());
line = line.substr(idx);
return result;
}
std::string parse_string()
{
if (line[0] != '\"')
error("Expected string, got `%s'.", error_token());
std::string str;
int idx = 1;
while (true) {
int start_idx = idx;
char ch;
while (true) {
ch = line[idx];
if (ch == '"' || ch == '\n' || ch == '\\' || ch == 0)
break;
++idx;
}
str.append(line.data() + start_idx, line.data() + idx);
++idx;
if (ch == '"')
break;
if (ch == 0)
error("Null byte in string literal: `%s'.", line);
if (ch == '\n')
error("Unterminated string literal: `%s'.", line);
ch = line[idx++];
if (ch == 'n') {
ch = '\n';
} else if (ch == 't') {
ch = '\t';
} else if (ch >= '0' && ch <= '7') {
int v = ch - '0';
char next_ch = line[idx + 1];
if (next_ch >= '0' && next_ch <= '7') {
++idx;
v = v*8 + (next_ch - '0');
next_ch = line[idx + 1];
if (next_ch >= '0' && next_ch <= '7') {
++idx;
v = v*8 + (next_ch - '0');
}
}
ch = v;
}
str += ch;
}
line = line.substr(idx);
consume_whitespace_and_comments();
return str;
}
RTLIL::Const parse_const()
{
if (line[0] == '"')
return RTLIL::Const(parse_string());
bool negative_value = line[0] == '-';
long long width = parse_integer_alone();
// Can't test value<0 here because we need to stop parsing after '-0'
if (negative_value || line[0] != '\'') {
if (width < INT_MIN || width > INT_MAX)
error("Integer %lld out of range before `%s'.", width, error_token());
consume_whitespace_and_comments();
return RTLIL::Const(width);
}
int idx = 1;
bool is_signed = line[1] == 's';
if (is_signed)
++idx;
std::vector<RTLIL::State> bits;
if (width > MAX_CONST_WIDTH)
error("Constant width %lld out of range before `%s`.", width, error_token());
bits.reserve(width);
while (true) {
RTLIL::State bit;
switch (line[idx]) {
case '0': bit = RTLIL::S0; break;
case '1': bit = RTLIL::S1; break;
case 'x': bit = RTLIL::Sx; break;
case 'z': bit = RTLIL::Sz; break;
case 'm': bit = RTLIL::Sm; break;
case '-': bit = RTLIL::Sa; break;
default: goto done;
}
bits.push_back(bit);
++idx;
}
done:
std::reverse(bits.begin(), bits.end());
if (GetSize(bits) > width)
bits.resize(width);
else if (GetSize(bits) < width) {
RTLIL::State extbit = RTLIL::Sx;
if (!bits.empty()) {
extbit = bits.back();
if (extbit == RTLIL::S1)
extbit = RTLIL::S0;
}
bits.resize(width, extbit);
}
RTLIL::Const val(std::move(bits));
if (is_signed)
val.flags |= RTLIL::CONST_FLAG_SIGNED;
line = line.substr(idx);
consume_whitespace_and_comments();
return val;
}
RTLIL::SigSpec parse_sigspec()
{
if (try_parse_char('{')) {
std::vector<SigSpec> parts;
while (!try_parse_char('}'))
parts.push_back(parse_sigspec());
RTLIL::SigSpec sig;
for (auto it = parts.rbegin(); it != parts.rend(); ++it)
sig.append(std::move(*it));
return sig;
}
RTLIL::SigSpec sig;
// We could add a special path for parsing IdStrings that must already exist,
// as here.
// We don't need to addref/release in this case.
std::optional<RTLIL::IdString> id = try_parse_id();
if (id.has_value()) {
RTLIL::Wire *wire = current_module->wire(*id);
if (wire == nullptr)
error("Wire `%s' not found.", *id);
sig = RTLIL::SigSpec(wire);
} else {
sig = RTLIL::SigSpec(parse_const());
}
while (try_parse_char('[')) {
int left = parse_integer();
if (left >= sig.size() || left < 0)
error("bit index %d out of range", left);
if (try_parse_char(':')) {
int right = parse_integer();
if (right < 0)
error("bit index %d out of range", right);
if (left < right)
error("invalid slice [%d:%d]", left, right);
sig = sig.extract(right, left-right+1);
} else {
sig = sig.extract(left);
}
expect_char(']');
}
return sig;
}
void parse_module()
{
RTLIL::IdString module_name = parse_id();
expect_eol();
bool delete_current_module = false;
if (design->has(module_name)) {
RTLIL::Module *existing_mod = design->module(module_name);
if (!flag_overwrite && (flag_lib || (attrbuf.count(ID::blackbox) && attrbuf.at(ID::blackbox).as_bool()))) {
log("Ignoring blackbox re-definition of module %s.\n", module_name);
delete_current_module = true;
} else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute(ID::blackbox)) {
error("RTLIL error: redefinition of module %s.", module_name);
} else if (flag_nooverwrite) {
log("Ignoring re-definition of module %s.\n", module_name);
delete_current_module = true;
} else {
log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", module_name);
design->remove(existing_mod);
}
}
current_module = new RTLIL::Module;
current_module->name = std::move(module_name);
current_module->attributes = std::move(attrbuf);
if (!delete_current_module)
design->add(current_module);
while (true)
{
if (try_parse_keyword("attribute")) {
parse_attribute();
continue;
}
if (try_parse_keyword("parameter")) {
parse_parameter();
continue;
}
if (try_parse_keyword("connect")) {
parse_connect();
continue;
}
if (try_parse_keyword("wire")) {
parse_wire();
continue;
}
if (try_parse_keyword("cell")) {
parse_cell();
continue;
}
if (try_parse_keyword("memory")) {
parse_memory();
continue;
}
if (try_parse_keyword("process")) {
parse_process();
continue;
}
if (try_parse_keyword("end")) {
expect_eol();
break;
}
error("Unexpected token in module body: %s", error_token());
}
if (attrbuf.size() != 0)
error("dangling attribute");
current_module->fixup_ports();
if (delete_current_module)
delete current_module;
else if (flag_lib)
current_module->makeblackbox();
current_module = nullptr;
}
void parse_attribute()
{
RTLIL::IdString id = parse_id();
RTLIL::Const c = parse_const();
attrbuf.insert({std::move(id), std::move(c)});
expect_eol();
}
void parse_parameter()
{
RTLIL::IdString id = parse_id();
current_module->avail_parameters(id);
if (try_parse_eol())
return;
RTLIL::Const c = parse_const();
current_module->parameter_default_values.insert({std::move(id), std::move(c)});
expect_eol();
}
void parse_wire()
{
RTLIL::Wire *wire;
int width = 1;
int start_offset = 0;
int port_id = 0;
bool port_input = false;
bool port_output = false;
bool upto = false;
bool is_signed = false;
while (true)
{
std::optional<RTLIL::IdString> id = try_parse_id();
if (id.has_value()) {
if (current_module->wire(*id) != nullptr)
error("RTLIL error: redefinition of wire %s.", *id);
wire = current_module->addWire(std::move(*id));
break;
}
if (try_parse_keyword("width"))
width = parse_integer();
else if (try_parse_keyword("upto"))
upto = true;
else if (try_parse_keyword("signed"))
is_signed = true;
else if (try_parse_keyword("offset"))
start_offset = parse_integer();
else if (try_parse_keyword("input")) {
port_id = parse_integer();
port_input = true;
} else if (try_parse_keyword("output")) {
port_id = parse_integer();
port_output = true;
} else if (try_parse_keyword("inout")) {
port_id = parse_integer();
port_input = true;
port_output = true;
} else if (try_parse_eol())
error("Missing wire ID");
else
error("Unexpected wire option: %s", error_token());
}
wire->attributes = std::move(attrbuf);
wire->width = width;
wire->upto = upto;
wire->start_offset = start_offset;
wire->is_signed = is_signed;
wire->port_id = port_id;
wire->port_input = port_input;
wire->port_output = port_output;
expect_eol();
}
void parse_memory()
{
RTLIL::Memory *memory = new RTLIL::Memory;
memory->attributes = std::move(attrbuf);
int width = 1;
int start_offset = 0;
int size = 0;
while (true)
{
std::optional<RTLIL::IdString> id = try_parse_id();
if (id.has_value()) {
if (current_module->memories.count(*id) != 0)
error("RTLIL error: redefinition of memory %s.", *id);
memory->name = std::move(*id);
break;
}
if (try_parse_keyword("width"))
width = parse_integer();
else if (try_parse_keyword("size"))
size = parse_integer();
else if (try_parse_keyword("offset"))
start_offset = parse_integer();
else if (try_parse_eol())
error("Missing memory ID");
else
error("Unexpected memory option: %s", error_token());
}
memory->width = width;
memory->start_offset = start_offset;
memory->size = size;
current_module->memories.insert({memory->name, memory});
expect_eol();
}
void parse_cell()
{
RTLIL::IdString cell_type = parse_id();
RTLIL::IdString cell_name = parse_id();
expect_eol();
if (current_module->cell(cell_name) != nullptr)
error("RTLIL error: redefinition of cell %s.", cell_name);
RTLIL::Cell *cell = current_module->addCell(cell_name, cell_type);
cell->attributes = std::move(attrbuf);
while (true)
{
if (try_parse_keyword("parameter")) {
bool is_signed = false;
bool is_real = false;
if (try_parse_keyword("signed")) {
is_signed = true;
} else if (try_parse_keyword("real")) {
is_real = true;
}
RTLIL::IdString param_name = parse_id();
RTLIL::Const val = parse_const();
if (is_signed)
val.flags |= RTLIL::CONST_FLAG_SIGNED;
if (is_real)
val.flags |= RTLIL::CONST_FLAG_REAL;
cell->parameters.insert({std::move(param_name), std::move(val)});
expect_eol();
} else if (try_parse_keyword("connect")) {
RTLIL::IdString port_name = parse_id();
if (cell->hasPort(port_name))
error("RTLIL error: redefinition of cell port %s.", port_name);
cell->setPort(std::move(port_name), parse_sigspec());
expect_eol();
} else if (try_parse_keyword("end")) {
expect_eol();
break;
} else {
error("Unexpected token in cell body: %s", error_token());
}
}
}
void parse_connect()
{
if (attrbuf.size() != 0)
error("dangling attribute");
RTLIL::SigSpec s1 = parse_sigspec();
RTLIL::SigSpec s2 = parse_sigspec();
current_module->connect(std::move(s1), std::move(s2));
expect_eol();
}
void parse_case_body(RTLIL::CaseRule *current_case)
{
while (true)
{
if (try_parse_keyword("attribute"))
parse_attribute();
else if (try_parse_keyword("switch"))
parse_switch();
else if (try_parse_keyword("assign")) {
if (attrbuf.size() != 0)
error("dangling attribute");
// See https://github.com/YosysHQ/yosys/pull/4765 for discussion on this
// warning
if (!switch_stack.back()->empty())
warning("case rule assign statements after switch statements may cause unexpected behaviour. "
"The assign statement is reordered to come before all switch statements.");
RTLIL::SigSpec s1 = parse_sigspec();
RTLIL::SigSpec s2 = parse_sigspec();
current_case->actions.push_back(RTLIL::SigSig(std::move(s1), std::move(s2)));
expect_eol();
} else
return;
}
}
void parse_switch()
{
RTLIL::SwitchRule *rule = new RTLIL::SwitchRule;
rule->signal = parse_sigspec();
rule->attributes = std::move(attrbuf);
switch_stack.back()->push_back(rule);
expect_eol();
while (true) {
if (try_parse_keyword("attribute")) {
parse_attribute();
continue;
}
if (try_parse_keyword("end")) {
expect_eol();
break;
}
expect_keyword("case");
RTLIL::CaseRule *case_rule = new RTLIL::CaseRule;
case_rule->attributes = std::move(attrbuf);
rule->cases.push_back(case_rule);
switch_stack.push_back(&case_rule->switches);
case_stack.push_back(case_rule);
if (!try_parse_eol()) {
while (true) {
case_rule->compare.push_back(parse_sigspec());
if (try_parse_eol())
break;
expect_char(',');
}
}
parse_case_body(case_rule);
switch_stack.pop_back();
case_stack.pop_back();
}
}
void parse_process()
{
RTLIL::IdString proc_name = parse_id();
expect_eol();
if (current_module->processes.count(proc_name) != 0)
error("RTLIL error: redefinition of process %s.", proc_name);
RTLIL::Process *proc = current_module->addProcess(std::move(proc_name));
proc->attributes = std::move(attrbuf);
switch_stack.clear();
switch_stack.push_back(&proc->root_case.switches);
case_stack.clear();
case_stack.push_back(&proc->root_case);
parse_case_body(&proc->root_case);
while (try_parse_keyword("sync"))
{
RTLIL::SyncRule *rule = new RTLIL::SyncRule;
if (try_parse_keyword("low")) rule->type = RTLIL::ST0;
else if (try_parse_keyword("high")) rule->type = RTLIL::ST1;
else if (try_parse_keyword("posedge")) rule->type = RTLIL::STp;
else if (try_parse_keyword("negedge")) rule->type = RTLIL::STn;
else if (try_parse_keyword("edge")) rule->type = RTLIL::STe;
else if (try_parse_keyword("always")) rule->type = RTLIL::STa;
else if (try_parse_keyword("global")) rule->type = RTLIL::STg;
else if (try_parse_keyword("init")) rule->type = RTLIL::STi;
else error("Unexpected sync type: %s", error_token());
if (rule->type != RTLIL::STa && rule->type != RTLIL::STg && rule->type != RTLIL::STi)
rule->signal = parse_sigspec();
proc->syncs.push_back(rule);
expect_eol();
bool attributes_in_update_list = false;
while (true)
{
if (try_parse_keyword("update")) {
RTLIL::SigSpec s1 = parse_sigspec();
RTLIL::SigSpec s2 = parse_sigspec();
rule->actions.push_back(RTLIL::SigSig(std::move(s1), std::move(s2)));
expect_eol();
continue;
}
if (try_parse_keyword("attribute")) {
attributes_in_update_list = true;
parse_attribute();
continue;
}
if (!try_parse_keyword("memwr"))
break;
RTLIL::MemWriteAction act;
act.attributes = std::move(attrbuf);
act.memid = parse_id();
act.address = parse_sigspec();
act.data = parse_sigspec();
act.enable = parse_sigspec();
act.priority_mask = parse_const();
rule->mem_write_actions.push_back(std::move(act));
expect_eol();
}
// The old parser allowed dangling attributes before a "sync" to carry through
// the "sync", so we will too, for now.
if (attributes_in_update_list && attrbuf.size() > 0)
error("dangling attribute");
}
expect_keyword("end");
expect_eol();
}
RTLILFrontendWorker(RTLIL::Design *design) : design(design) {}
void parse(std::istream *f)
{
this->f = f;
line_num = 0;
advance_to_next_nonempty_line();
while (f->good())
{
if (try_parse_keyword("attribute")) {
parse_attribute();
continue;
}
if (try_parse_keyword("module")) {
parse_module();
continue;
}
if (try_parse_keyword("autoidx")) {
autoidx = std::max<int>(autoidx, parse_integer());
expect_eol();
continue;
}
error("Unexpected token: %s", error_token());
}
if (attrbuf.size() != 0)
error("dangling attribute");
}
};
struct RTLILFrontend : public Frontend { struct RTLILFrontend : public Frontend {
RTLILFrontend() : Frontend("rtlil", "read modules from RTLIL file") { } RTLILFrontend() : Frontend("rtlil", "read modules from RTLIL file") { }
void help() override void help() override
@ -63,9 +804,7 @@ struct RTLILFrontend : public Frontend {
} }
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
{ {
RTLIL_FRONTEND::flag_nooverwrite = false; RTLILFrontendWorker worker(design);
RTLIL_FRONTEND::flag_overwrite = false;
RTLIL_FRONTEND::flag_lib = false;
log_header(design, "Executing RTLIL frontend.\n"); log_header(design, "Executing RTLIL frontend.\n");
@ -73,17 +812,17 @@ struct RTLILFrontend : public Frontend {
for (argidx = 1; argidx < args.size(); argidx++) { for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx]; std::string arg = args[argidx];
if (arg == "-nooverwrite") { if (arg == "-nooverwrite") {
RTLIL_FRONTEND::flag_nooverwrite = true; worker.flag_nooverwrite = true;
RTLIL_FRONTEND::flag_overwrite = false; worker.flag_overwrite = false;
continue; continue;
} }
if (arg == "-overwrite") { if (arg == "-overwrite") {
RTLIL_FRONTEND::flag_nooverwrite = false; worker.flag_nooverwrite = false;
RTLIL_FRONTEND::flag_overwrite = true; worker.flag_overwrite = true;
continue; continue;
} }
if (arg == "-lib") { if (arg == "-lib") {
RTLIL_FRONTEND::flag_lib = true; worker.flag_lib = true;
continue; continue;
} }
break; break;
@ -92,14 +831,8 @@ struct RTLILFrontend : public Frontend {
log("Input filename: %s\n", filename); log("Input filename: %s\n", filename);
RTLIL_FRONTEND::lexin = f; worker.parse(f);
RTLIL_FRONTEND::current_design = design;
rtlil_frontend_yydebug = false;
rtlil_frontend_yyrestart(NULL);
rtlil_frontend_yyparse();
rtlil_frontend_yylex_destroy();
} }
} RTLILFrontend; } RTLILFrontend;
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END

View file

@ -1,52 +0,0 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* ---
*
* A very simple and straightforward frontend for the RTLIL text
* representation.
*
*/
#ifndef RTLIL_FRONTEND_H
#define RTLIL_FRONTEND_H
#include "kernel/yosys.h"
YOSYS_NAMESPACE_BEGIN
namespace RTLIL_FRONTEND {
extern std::istream *lexin;
extern RTLIL::Design *current_design;
extern bool flag_nooverwrite;
extern bool flag_overwrite;
extern bool flag_lib;
}
YOSYS_NAMESPACE_END
extern int rtlil_frontend_yydebug;
int rtlil_frontend_yylex(void);
void rtlil_frontend_yyerror(char const *s);
void rtlil_frontend_yywarning(char const *s);
void rtlil_frontend_yyrestart(FILE *f);
int rtlil_frontend_yyparse(void);
int rtlil_frontend_yylex_destroy(void);
int rtlil_frontend_yyget_lineno(void);
#endif

View file

@ -1,150 +0,0 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* ---
*
* A very simple and straightforward frontend for the RTLIL text
* representation.
*
*/
%{
#ifdef __clang__
// bison generates code using the 'register' storage class specifier
#pragma clang diagnostic ignored "-Wdeprecated-register"
#endif
#include <cstdlib>
#include "frontends/rtlil/rtlil_frontend.h"
#include "rtlil_parser.tab.hh"
USING_YOSYS_NAMESPACE
#define YY_INPUT(buf,result,max_size) \
result = readsome(*RTLIL_FRONTEND::lexin, buf, max_size)
%}
%option yylineno
%option noyywrap
%option nounput
%option prefix="rtlil_frontend_yy"
%x STRING
%%
"autoidx" { return TOK_AUTOIDX; }
"module" { return TOK_MODULE; }
"attribute" { return TOK_ATTRIBUTE; }
"parameter" { return TOK_PARAMETER; }
"signed" { return TOK_SIGNED; }
"real" { return TOK_REAL; }
"wire" { return TOK_WIRE; }
"memory" { return TOK_MEMORY; }
"width" { return TOK_WIDTH; }
"upto" { return TOK_UPTO; }
"offset" { return TOK_OFFSET; }
"size" { return TOK_SIZE; }
"input" { return TOK_INPUT; }
"output" { return TOK_OUTPUT; }
"inout" { return TOK_INOUT; }
"cell" { return TOK_CELL; }
"connect" { return TOK_CONNECT; }
"switch" { return TOK_SWITCH; }
"case" { return TOK_CASE; }
"assign" { return TOK_ASSIGN; }
"sync" { return TOK_SYNC; }
"low" { return TOK_LOW; }
"high" { return TOK_HIGH; }
"posedge" { return TOK_POSEDGE; }
"negedge" { return TOK_NEGEDGE; }
"edge" { return TOK_EDGE; }
"always" { return TOK_ALWAYS; }
"global" { return TOK_GLOBAL; }
"init" { return TOK_INIT; }
"update" { return TOK_UPDATE; }
"memwr" { return TOK_MEMWR; }
"process" { return TOK_PROCESS; }
"end" { return TOK_END; }
[a-z]+ { return TOK_INVALID; }
"\\"[^ \t\r\n]+ { rtlil_frontend_yylval.string = strdup(yytext); return TOK_ID; }
"$"[^ \t\r\n]+ { rtlil_frontend_yylval.string = strdup(yytext); return TOK_ID; }
[0-9]+'s?[01xzm-]* { rtlil_frontend_yylval.string = strdup(yytext); return TOK_VALUE; }
-?[0-9]+ {
char *end = nullptr;
errno = 0;
long value = strtol(yytext, &end, 10);
log_assert(end == yytext + strlen(yytext));
if (errno == ERANGE)
return TOK_INVALID; // literal out of range of long
if (value < INT_MIN || value > INT_MAX)
return TOK_INVALID; // literal out of range of int (relevant mostly for LP64 platforms)
rtlil_frontend_yylval.integer = value;
return TOK_INT;
}
\" { BEGIN(STRING); }
<STRING>\\. { yymore(); }
<STRING>\" {
BEGIN(0);
char *yystr = strdup(yytext);
yystr[strlen(yytext) - 1] = 0;
int i = 0, j = 0;
while (yystr[i]) {
if (yystr[i] == '\\' && yystr[i + 1]) {
i++;
if (yystr[i] == 'n')
yystr[i] = '\n';
else if (yystr[i] == 't')
yystr[i] = '\t';
else if ('0' <= yystr[i] && yystr[i] <= '7') {
yystr[i] = yystr[i] - '0';
if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') {
yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0';
i++;
}
if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') {
yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0';
i++;
}
}
}
yystr[j++] = yystr[i++];
}
yystr[j] = 0;
rtlil_frontend_yylval.string = yystr;
return TOK_STRING;
}
<STRING>. { yymore(); }
"#"[^\n]* /* ignore comments */
[ \t] /* ignore non-newline whitespaces */
[\r\n]+ { return TOK_EOL; }
. { return *yytext; }
%%
// this is a hack to avoid the 'yyinput defined but not used' error msgs
void *rtlil_frontend_avoid_input_warnings() {
return (void*)&yyinput;
}

View file

@ -1,525 +0,0 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* ---
*
* A very simple and straightforward frontend for the RTLIL text
* representation.
*
*/
%require "3.0"
%{
#include <list>
#include "frontends/rtlil/rtlil_frontend.h"
YOSYS_NAMESPACE_BEGIN
namespace RTLIL_FRONTEND {
std::istream *lexin;
RTLIL::Design *current_design;
RTLIL::Module *current_module;
RTLIL::Wire *current_wire;
RTLIL::Memory *current_memory;
RTLIL::Cell *current_cell;
RTLIL::Process *current_process;
std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack;
std::vector<RTLIL::CaseRule*> case_stack;
dict<RTLIL::IdString, RTLIL::Const> attrbuf;
bool flag_nooverwrite, flag_overwrite, flag_lib;
bool delete_current_module;
}
using namespace RTLIL_FRONTEND;
YOSYS_NAMESPACE_END
USING_YOSYS_NAMESPACE
%}
%define api.prefix {rtlil_frontend_yy}
/* The union is defined in the header, so we need to provide all the
* includes it requires
*/
%code requires {
#include <string>
#include <vector>
#include "frontends/rtlil/rtlil_frontend.h"
}
%union {
char *string;
int integer;
YOSYS_NAMESPACE_PREFIX RTLIL::Const *data;
YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec *sigspec;
std::vector<YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec> *rsigspec;
}
%token <string> TOK_ID TOK_VALUE TOK_STRING
%token <integer> TOK_INT
%token TOK_AUTOIDX TOK_MODULE TOK_WIRE TOK_WIDTH TOK_INPUT TOK_OUTPUT TOK_INOUT
%token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC
%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT
%token TOK_UPDATE TOK_MEMWR TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET
%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO
%type <rsigspec> sigspec_list_reversed
%type <sigspec> sigspec sigspec_list
%type <integer> sync_type
%type <data> constant
%expect 0
%debug
%%
input:
optional_eol {
attrbuf.clear();
} design {
if (attrbuf.size() != 0)
rtlil_frontend_yyerror("dangling attribute");
};
EOL:
optional_eol TOK_EOL;
optional_eol:
optional_eol TOK_EOL | /* empty */;
design:
design module |
design attr_stmt |
design autoidx_stmt |
/* empty */;
module:
TOK_MODULE TOK_ID EOL {
delete_current_module = false;
if (current_design->has($2)) {
RTLIL::Module *existing_mod = current_design->module($2);
if (!flag_overwrite && (flag_lib || (attrbuf.count(ID::blackbox) && attrbuf.at(ID::blackbox).as_bool()))) {
log("Ignoring blackbox re-definition of module %s.\n", $2);
delete_current_module = true;
} else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute(ID::blackbox)) {
rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of module %s.", $2).c_str());
} else if (flag_nooverwrite) {
log("Ignoring re-definition of module %s.\n", $2);
delete_current_module = true;
} else {
log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", $2);
current_design->remove(existing_mod);
}
}
current_module = new RTLIL::Module;
current_module->name = $2;
current_module->attributes = attrbuf;
if (!delete_current_module)
current_design->add(current_module);
attrbuf.clear();
free($2);
} module_body TOK_END {
if (attrbuf.size() != 0)
rtlil_frontend_yyerror("dangling attribute");
current_module->fixup_ports();
if (delete_current_module)
delete current_module;
else if (flag_lib)
current_module->makeblackbox();
current_module = nullptr;
} EOL;
module_body:
module_body module_stmt |
/* empty */;
module_stmt:
param_stmt | param_defval_stmt | attr_stmt | wire_stmt | memory_stmt | cell_stmt | proc_stmt | conn_stmt;
param_stmt:
TOK_PARAMETER TOK_ID EOL {
current_module->avail_parameters($2);
free($2);
};
param_defval_stmt:
TOK_PARAMETER TOK_ID constant EOL {
current_module->avail_parameters($2);
current_module->parameter_default_values[$2] = *$3;
delete $3;
free($2);
};
attr_stmt:
TOK_ATTRIBUTE TOK_ID constant EOL {
attrbuf[$2] = *$3;
delete $3;
free($2);
};
autoidx_stmt:
TOK_AUTOIDX TOK_INT EOL {
autoidx = max(autoidx, $2);
};
wire_stmt:
TOK_WIRE {
current_wire = current_module->addWire("$__rtlil_frontend_tmp__");
current_wire->attributes = attrbuf;
attrbuf.clear();
} wire_options TOK_ID EOL {
if (current_module->wire($4) != nullptr)
rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of wire %s.", $4).c_str());
current_module->rename(current_wire, $4);
free($4);
};
wire_options:
wire_options TOK_WIDTH TOK_INT {
current_wire->width = $3;
} |
wire_options TOK_WIDTH TOK_INVALID {
rtlil_frontend_yyerror("RTLIL error: invalid wire width");
} |
wire_options TOK_UPTO {
current_wire->upto = true;
} |
wire_options TOK_SIGNED {
current_wire->is_signed = true;
} |
wire_options TOK_OFFSET TOK_INT {
current_wire->start_offset = $3;
} |
wire_options TOK_INPUT TOK_INT {
current_wire->port_id = $3;
current_wire->port_input = true;
current_wire->port_output = false;
} |
wire_options TOK_OUTPUT TOK_INT {
current_wire->port_id = $3;
current_wire->port_input = false;
current_wire->port_output = true;
} |
wire_options TOK_INOUT TOK_INT {
current_wire->port_id = $3;
current_wire->port_input = true;
current_wire->port_output = true;
} |
/* empty */;
memory_stmt:
TOK_MEMORY {
current_memory = new RTLIL::Memory;
current_memory->attributes = attrbuf;
attrbuf.clear();
} memory_options TOK_ID EOL {
if (current_module->memories.count($4) != 0)
rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of memory %s.", $4).c_str());
current_memory->name = $4;
current_module->memories[$4] = current_memory;
free($4);
};
memory_options:
memory_options TOK_WIDTH TOK_INT {
current_memory->width = $3;
} |
memory_options TOK_SIZE TOK_INT {
current_memory->size = $3;
} |
memory_options TOK_OFFSET TOK_INT {
current_memory->start_offset = $3;
} |
/* empty */;
cell_stmt:
TOK_CELL TOK_ID TOK_ID EOL {
if (current_module->cell($3) != nullptr)
rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of cell %s.", $3).c_str());
current_cell = current_module->addCell($3, $2);
current_cell->attributes = attrbuf;
attrbuf.clear();
free($2);
free($3);
} cell_body TOK_END EOL;
cell_body:
cell_body TOK_PARAMETER TOK_ID constant EOL {
current_cell->parameters[$3] = *$4;
free($3);
delete $4;
} |
cell_body TOK_PARAMETER TOK_SIGNED TOK_ID constant EOL {
current_cell->parameters[$4] = *$5;
current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_SIGNED;
free($4);
delete $5;
} |
cell_body TOK_PARAMETER TOK_REAL TOK_ID constant EOL {
current_cell->parameters[$4] = *$5;
current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_REAL;
free($4);
delete $5;
} |
cell_body TOK_CONNECT TOK_ID sigspec EOL {
if (current_cell->hasPort($3))
rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of cell port %s.", $3).c_str());
current_cell->setPort($3, *$4);
delete $4;
free($3);
} |
/* empty */;
proc_stmt:
TOK_PROCESS TOK_ID EOL {
if (current_module->processes.count($2) != 0)
rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of process %s.", $2).c_str());
current_process = current_module->addProcess($2);
current_process->attributes = attrbuf;
switch_stack.clear();
switch_stack.push_back(&current_process->root_case.switches);
case_stack.clear();
case_stack.push_back(&current_process->root_case);
attrbuf.clear();
free($2);
} case_body sync_list TOK_END EOL;
switch_stmt:
TOK_SWITCH sigspec EOL {
RTLIL::SwitchRule *rule = new RTLIL::SwitchRule;
rule->signal = *$2;
rule->attributes = attrbuf;
switch_stack.back()->push_back(rule);
attrbuf.clear();
delete $2;
} attr_list switch_body TOK_END EOL;
attr_list:
/* empty */ |
attr_list attr_stmt;
switch_body:
switch_body TOK_CASE {
RTLIL::CaseRule *rule = new RTLIL::CaseRule;
rule->attributes = attrbuf;
switch_stack.back()->back()->cases.push_back(rule);
switch_stack.push_back(&rule->switches);
case_stack.push_back(rule);
attrbuf.clear();
} compare_list EOL case_body {
switch_stack.pop_back();
case_stack.pop_back();
} |
/* empty */;
compare_list:
sigspec {
case_stack.back()->compare.push_back(*$1);
delete $1;
} |
compare_list ',' sigspec {
case_stack.back()->compare.push_back(*$3);
delete $3;
} |
/* empty */;
case_body:
case_body attr_stmt |
case_body switch_stmt |
case_body assign_stmt |
/* empty */;
assign_stmt:
TOK_ASSIGN sigspec sigspec EOL {
if (attrbuf.size() != 0)
rtlil_frontend_yyerror("dangling attribute");
// See https://github.com/YosysHQ/yosys/pull/4765 for discussion on this
// warning
if (!switch_stack.back()->empty()) {
rtlil_frontend_yywarning(
"case rule assign statements after switch statements may cause unexpected behaviour. "
"The assign statement is reordered to come before all switch statements."
);
}
case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3));
delete $2;
delete $3;
};
sync_list:
sync_list TOK_SYNC sync_type sigspec EOL {
RTLIL::SyncRule *rule = new RTLIL::SyncRule;
rule->type = RTLIL::SyncType($3);
rule->signal = *$4;
current_process->syncs.push_back(rule);
delete $4;
} update_list |
sync_list TOK_SYNC TOK_ALWAYS EOL {
RTLIL::SyncRule *rule = new RTLIL::SyncRule;
rule->type = RTLIL::SyncType::STa;
rule->signal = RTLIL::SigSpec();
current_process->syncs.push_back(rule);
} update_list |
sync_list TOK_SYNC TOK_GLOBAL EOL {
RTLIL::SyncRule *rule = new RTLIL::SyncRule;
rule->type = RTLIL::SyncType::STg;
rule->signal = RTLIL::SigSpec();
current_process->syncs.push_back(rule);
} update_list |
sync_list TOK_SYNC TOK_INIT EOL {
RTLIL::SyncRule *rule = new RTLIL::SyncRule;
rule->type = RTLIL::SyncType::STi;
rule->signal = RTLIL::SigSpec();
current_process->syncs.push_back(rule);
} update_list |
/* empty */;
sync_type:
TOK_LOW { $$ = RTLIL::ST0; } |
TOK_HIGH { $$ = RTLIL::ST1; } |
TOK_POSEDGE { $$ = RTLIL::STp; } |
TOK_NEGEDGE { $$ = RTLIL::STn; } |
TOK_EDGE { $$ = RTLIL::STe; };
update_list:
update_list TOK_UPDATE sigspec sigspec EOL {
current_process->syncs.back()->actions.push_back(RTLIL::SigSig(*$3, *$4));
delete $3;
delete $4;
} |
update_list attr_list TOK_MEMWR TOK_ID sigspec sigspec sigspec constant EOL {
RTLIL::MemWriteAction act;
act.attributes = attrbuf;
act.memid = $4;
act.address = *$5;
act.data = *$6;
act.enable = *$7;
act.priority_mask = *$8;
current_process->syncs.back()->mem_write_actions.push_back(std::move(act));
attrbuf.clear();
free($4);
delete $5;
delete $6;
delete $7;
delete $8;
} |
/* empty */;
constant:
TOK_VALUE {
char *ep;
int width = strtol($1, &ep, 10);
bool is_signed = false;
if (*ep == '\'') {
ep++;
}
if (*ep == 's') {
is_signed = true;
ep++;
}
std::list<RTLIL::State> bits;
while (*ep != 0) {
RTLIL::State bit = RTLIL::Sx;
switch (*ep) {
case '0': bit = RTLIL::S0; break;
case '1': bit = RTLIL::S1; break;
case 'x': bit = RTLIL::Sx; break;
case 'z': bit = RTLIL::Sz; break;
case '-': bit = RTLIL::Sa; break;
case 'm': bit = RTLIL::Sm; break;
}
bits.push_front(bit);
ep++;
}
if (bits.size() == 0)
bits.push_back(RTLIL::Sx);
while ((int)bits.size() < width) {
RTLIL::State bit = bits.back();
if (bit == RTLIL::S1)
bit = RTLIL::S0;
bits.push_back(bit);
}
while ((int)bits.size() > width)
bits.pop_back();
RTLIL::Const::Builder builder(bits.size());
for (RTLIL::State bit : bits)
builder.push_back(bit);
$$ = new RTLIL::Const(builder.build());
if (is_signed) {
$$->flags |= RTLIL::CONST_FLAG_SIGNED;
}
free($1);
} |
TOK_INT {
$$ = new RTLIL::Const($1);
} |
TOK_STRING {
$$ = new RTLIL::Const($1);
free($1);
};
sigspec:
constant {
$$ = new RTLIL::SigSpec(*$1);
delete $1;
} |
TOK_ID {
if (current_module->wire($1) == nullptr)
rtlil_frontend_yyerror(stringf("RTLIL error: wire %s not found", $1).c_str());
$$ = new RTLIL::SigSpec(current_module->wire($1));
free($1);
} |
sigspec '[' TOK_INT ']' {
if ($3 >= $1->size() || $3 < 0)
rtlil_frontend_yyerror("bit index out of range");
$$ = new RTLIL::SigSpec($1->extract($3));
delete $1;
} |
sigspec '[' TOK_INT ':' TOK_INT ']' {
if ($3 >= $1->size() || $3 < 0 || $3 < $5)
rtlil_frontend_yyerror("invalid slice");
$$ = new RTLIL::SigSpec($1->extract($5, $3 - $5 + 1));
delete $1;
} |
'{' sigspec_list '}' {
$$ = $2;
};
sigspec_list_reversed:
sigspec_list_reversed sigspec {
$$->push_back(*$2);
delete $2;
} |
/* empty */ {
$$ = new std::vector<RTLIL::SigSpec>;
};
sigspec_list: sigspec_list_reversed {
$$ = new RTLIL::SigSpec;
for (auto it = $1->rbegin(); it != $1->rend(); it++)
$$->append(*it);
delete $1;
};
conn_stmt:
TOK_CONNECT sigspec sigspec EOL {
if (attrbuf.size() != 0)
rtlil_frontend_yyerror("dangling attribute");
current_module->connect(*$2, *$3);
delete $2;
delete $3;
};

View file

@ -264,10 +264,10 @@ std::string& Const::get_str() {
return *get_if_str(); return *get_if_str();
} }
RTLIL::Const::Const(const std::string &str) RTLIL::Const::Const(std::string str)
{ {
flags = RTLIL::CONST_FLAG_STRING; flags = RTLIL::CONST_FLAG_STRING;
new ((void*)&str_) std::string(str); new ((void*)&str_) std::string(std::move(str));
tag = backing_tag::string; tag = backing_tag::string;
} }
@ -3050,7 +3050,7 @@ void RTLIL::Module::fixup_ports()
RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, int width) RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, int width)
{ {
RTLIL::Wire *wire = new RTLIL::Wire; RTLIL::Wire *wire = new RTLIL::Wire;
wire->name = name; wire->name = std::move(name);
wire->width = width; wire->width = width;
add(wire); add(wire);
return wire; return wire;
@ -3058,7 +3058,7 @@ RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, int width)
RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, const RTLIL::Wire *other) RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, const RTLIL::Wire *other)
{ {
RTLIL::Wire *wire = addWire(name); RTLIL::Wire *wire = addWire(std::move(name));
wire->width = other->width; wire->width = other->width;
wire->start_offset = other->start_offset; wire->start_offset = other->start_offset;
wire->port_id = other->port_id; wire->port_id = other->port_id;
@ -3073,7 +3073,7 @@ RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, const RTLIL::Wire *oth
RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, RTLIL::IdString type) RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, RTLIL::IdString type)
{ {
RTLIL::Cell *cell = new RTLIL::Cell; RTLIL::Cell *cell = new RTLIL::Cell;
cell->name = name; cell->name = std::move(name);
cell->type = type; cell->type = type;
add(cell); add(cell);
return cell; return cell;
@ -3081,7 +3081,7 @@ RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, RTLIL::IdString type)
RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *other) RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *other)
{ {
RTLIL::Cell *cell = addCell(name, other->type); RTLIL::Cell *cell = addCell(std::move(name), other->type);
cell->connections_ = other->connections_; cell->connections_ = other->connections_;
cell->parameters = other->parameters; cell->parameters = other->parameters;
cell->attributes = other->attributes; cell->attributes = other->attributes;
@ -3091,7 +3091,7 @@ RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *oth
RTLIL::Memory *RTLIL::Module::addMemory(RTLIL::IdString name, const RTLIL::Memory *other) RTLIL::Memory *RTLIL::Module::addMemory(RTLIL::IdString name, const RTLIL::Memory *other)
{ {
RTLIL::Memory *mem = new RTLIL::Memory; RTLIL::Memory *mem = new RTLIL::Memory;
mem->name = name; mem->name = std::move(name);
mem->width = other->width; mem->width = other->width;
mem->start_offset = other->start_offset; mem->start_offset = other->start_offset;
mem->size = other->size; mem->size = other->size;
@ -3103,7 +3103,7 @@ RTLIL::Memory *RTLIL::Module::addMemory(RTLIL::IdString name, const RTLIL::Memor
RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name) RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name)
{ {
RTLIL::Process *proc = new RTLIL::Process; RTLIL::Process *proc = new RTLIL::Process;
proc->name = name; proc->name = std::move(name);
add(proc); add(proc);
return proc; return proc;
} }
@ -3111,7 +3111,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name)
RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Process *other) RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Process *other)
{ {
RTLIL::Process *proc = other->clone(); RTLIL::Process *proc = other->clone();
proc->name = name; proc->name = std::move(name);
add(proc); add(proc);
return proc; return proc;
} }

View file

@ -209,10 +209,15 @@ struct RTLIL::IdString
} }
static int get_reference(const char *p) static int get_reference(const char *p)
{
return get_reference(std::string_view(p));
}
static int get_reference(std::string_view p)
{ {
log_assert(destruct_guard_ok); log_assert(destruct_guard_ok);
auto it = global_id_index_.find((char*)p); auto it = global_id_index_.find(p);
if (it != global_id_index_.end()) { if (it != global_id_index_.end()) {
#ifndef YOSYS_NO_IDS_REFCNT #ifndef YOSYS_NO_IDS_REFCNT
global_refcount_storage_.at(it->second)++; global_refcount_storage_.at(it->second)++;
@ -226,14 +231,13 @@ struct RTLIL::IdString
ensure_prepopulated(); ensure_prepopulated();
if (!p[0]) if (p.empty())
return 0; return 0;
log_assert(p[0] == '$' || p[0] == '\\'); log_assert(p[0] == '$' || p[0] == '\\');
log_assert(p[1] != 0); for (char ch : p)
for (const char *c = p; *c; c++) if ((unsigned)ch <= (unsigned)' ')
if ((unsigned)*c <= (unsigned)' ') log_error("Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\n", ch, std::string(p).c_str());
log_error("Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\n", *c, p);
#ifndef YOSYS_NO_IDS_REFCNT #ifndef YOSYS_NO_IDS_REFCNT
if (global_free_idx_list_.empty()) { if (global_free_idx_list_.empty()) {
@ -245,8 +249,11 @@ struct RTLIL::IdString
int idx = global_free_idx_list_.back(); int idx = global_free_idx_list_.back();
global_free_idx_list_.pop_back(); global_free_idx_list_.pop_back();
global_id_storage_.at(idx) = strdup(p); char* buf = static_cast<char*>(malloc(p.size() + 1));
global_id_index_[global_id_storage_.at(idx)] = idx; memcpy(buf, p.data(), p.size());
buf[p.size()] = 0;
global_id_storage_.at(idx) = buf;
global_id_index_.insert(it, {std::string_view(buf, p.size()), idx});
global_refcount_storage_.at(idx)++; global_refcount_storage_.at(idx)++;
#else #else
int idx = global_id_storage_.size(); int idx = global_id_storage_.size();
@ -255,7 +262,7 @@ struct RTLIL::IdString
#endif #endif
if (yosys_xtrace) { if (yosys_xtrace) {
log("#X# New IdString '%s' with index %d.\n", p, idx); log("#X# New IdString '%s' with index %d.\n", global_id_storage_.at(idx), idx);
log_backtrace("-X- ", yosys_xtrace-1); log_backtrace("-X- ", yosys_xtrace-1);
} }
@ -322,7 +329,8 @@ struct RTLIL::IdString
inline IdString(const char *str) : index_(get_reference(str)) { } inline IdString(const char *str) : index_(get_reference(str)) { }
inline IdString(const IdString &str) : index_(get_reference(str.index_)) { } inline IdString(const IdString &str) : index_(get_reference(str.index_)) { }
inline IdString(IdString &&str) : index_(str.index_) { str.index_ = 0; } inline IdString(IdString &&str) : index_(str.index_) { str.index_ = 0; }
inline IdString(const std::string &str) : index_(get_reference(str.c_str())) { } inline IdString(const std::string &str) : index_(get_reference(std::string_view(str))) { }
inline IdString(std::string_view str) : index_(get_reference(str)) { }
inline IdString(StaticId id) : index_(static_cast<short>(id)) {} inline IdString(StaticId id) : index_(static_cast<short>(id)) {}
inline ~IdString() { put_reference(index_); } inline ~IdString() { put_reference(index_); }
@ -331,6 +339,12 @@ struct RTLIL::IdString
index_ = get_reference(rhs.index_); index_ = get_reference(rhs.index_);
} }
inline void operator=(IdString &&rhs) {
put_reference(index_);
index_ = rhs.index_;
rhs.index_ = 0;
}
inline void operator=(const char *rhs) { inline void operator=(const char *rhs) {
IdString id(rhs); IdString id(rhs);
*this = id; *this = id;
@ -859,7 +873,7 @@ private:
public: public:
Const() : flags(RTLIL::CONST_FLAG_NONE), tag(backing_tag::bits), bits_(std::vector<RTLIL::State>()) {} Const() : flags(RTLIL::CONST_FLAG_NONE), tag(backing_tag::bits), bits_(std::vector<RTLIL::State>()) {}
Const(const std::string &str); Const(std::string str);
Const(long long val); // default width is 32 Const(long long val); // default width is 32
Const(long long val, int width); Const(long long val, int width);
Const(RTLIL::State bit, int width = 1); Const(RTLIL::State bit, int width = 1);