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:
commit
a80462f27f
8 changed files with 807 additions and 794 deletions
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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(¤t_process->root_case.switches);
|
|
||||||
case_stack.clear();
|
|
||||||
case_stack.push_back(¤t_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;
|
|
||||||
};
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue