3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-08-03 18:00:24 +00:00
This commit is contained in:
Emil J 2025-08-02 14:04:21 +12:00 committed by GitHub
commit 0fd0a9056d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 3694 additions and 3566 deletions

View file

@ -8,7 +8,7 @@ runs:
shell: bash shell: bash
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install gperf build-essential bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev sudo apt-get install gperf build-essential bison flex libfl-dev libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev
- name: Install macOS Dependencies - name: Install macOS Dependencies
if: runner.os == 'macOS' if: runner.os == 'macOS'

View file

@ -27,19 +27,20 @@ jobs:
with: with:
submodules: true submodules: true
persist-credentials: false persist-credentials: false
- run: sudo apt-get install libfl-dev
- name: Build - name: Build
run: make vcxsrc YOSYS_VER=latest run: make vcxsrc YOSYS_VER=latest
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: vcxsrc name: vcxsrc
path: yosys-win32-vcxsrc-latest.zip path: yosys-win32-vcxsrc-latest.zip
vs-build: vs-build:
name: Visual Studio build name: Visual Studio build
runs-on: windows-latest runs-on: windows-latest
needs: [vs-prep, pre_job] needs: [vs-prep, pre_job]
if: needs.pre_job.outputs.should_skip != 'true' if: needs.pre_job.outputs.should_skip != 'true'
steps: steps:
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
name: vcxsrc name: vcxsrc
@ -68,9 +69,20 @@ jobs:
WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz
if ! [ -d ${WASI_SDK} ]; then curl -L ${WASI_SDK_URL} | tar xzf -; fi if ! [ -d ${WASI_SDK} ]; then curl -L ${WASI_SDK_URL} | tar xzf -; fi
FLEX_VER=2.6.4
FLEX=flex-${FLEX_VER}
FLEX_URL=https://github.com/westes/flex/releases/download/v${FLEX_VER}/${FLEX}.tar.gz
if ! [ -d ${FLEX} ]; then curl -L ${FLEX_URL} | tar xzf -; fi
mkdir -p flex-build
(cd flex-build &&
../${FLEX}/configure --prefix=$(pwd)/../flex-prefix &&
make &&
make install)
mkdir -p build mkdir -p build
cat > build/Makefile.conf <<END cat > build/Makefile.conf <<END
export PATH := $(pwd)/${WASI_SDK}/bin:${PATH} export PATH := $(pwd)/${WASI_SDK}/bin:$(pwd)/flex-prefix/bin:${PATH}
WASI_SYSROOT := $(pwd)/${WASI_SDK}/share/wasi-sysroot WASI_SYSROOT := $(pwd)/${WASI_SDK}/share/wasi-sysroot
CONFIG := wasi CONFIG := wasi
@ -80,6 +92,8 @@ jobs:
ENABLE_READLINE := 0 ENABLE_READLINE := 0
ENABLE_PLUGINS := 0 ENABLE_PLUGINS := 0
ENABLE_ZLIB := 0 ENABLE_ZLIB := 0
CXXFLAGS += -I$(pwd)/flex-prefix/include
END END
make -C build -f ../Makefile CXX=clang -j$(nproc) make -C build -f ../Makefile CXX=clang -j$(nproc)

View file

@ -133,8 +133,8 @@ ifeq ($(ENABLE_PYOSYS),1)
CXXFLAGS += -I$(BREW_PREFIX)/boost/include CXXFLAGS += -I$(BREW_PREFIX)/boost/include
LINKFLAGS += -L$(BREW_PREFIX)/boost/lib -L$(BREW_PREFIX)/boost-python3/lib LINKFLAGS += -L$(BREW_PREFIX)/boost/lib -L$(BREW_PREFIX)/boost-python3/lib
endif endif
CXXFLAGS += -I$(BREW_PREFIX)/readline/include CXXFLAGS += -I$(BREW_PREFIX)/readline/include -I$(BREW_PREFIX)/flex/include
LINKFLAGS += -L$(BREW_PREFIX)/readline/lib LINKFLAGS += -L$(BREW_PREFIX)/readline/lib -L$(BREW_PREFIX)/flex/lib
PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH) PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH)
PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk/lib/pkgconfig:$(PKG_CONFIG_PATH) PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk/lib/pkgconfig:$(PKG_CONFIG_PATH)
export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH) export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH)

View file

@ -80,10 +80,10 @@ recommended) and some standard tools such as GNU Flex, GNU Bison, and GNU Make.
TCL, readline and libffi are optional (see ``ENABLE_*`` settings in Makefile). TCL, readline and libffi are optional (see ``ENABLE_*`` settings in Makefile).
Xdot (graphviz) is used by the ``show`` command in yosys to display schematics. Xdot (graphviz) is used by the ``show`` command in yosys to display schematics.
For example on Ubuntu Linux 16.04 LTS the following commands will install all For example on Ubuntu Linux 22.04 LTS the following commands will install all
prerequisites for building yosys: prerequisites for building yosys:
$ sudo apt-get install build-essential clang lld bison flex \ $ sudo apt-get install build-essential clang lld bison flex libfl-dev \
libreadline-dev gawk tcl-dev libffi-dev git \ libreadline-dev gawk tcl-dev libffi-dev git \
graphviz xdot pkg-config python3 libboost-system-dev \ graphviz xdot pkg-config python3 libboost-system-dev \
libboost-python-dev libboost-filesystem-dev zlib1g-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev

View file

@ -47,9 +47,9 @@ be found in :file:`frontends/verilog/verilog_lexer.l` in the Yosys source tree.
The lexer does little more than identifying all keywords and literals recognised The lexer does little more than identifying all keywords and literals recognised
by the Yosys Verilog frontend. by the Yosys Verilog frontend.
The lexer keeps track of the current location in the Verilog source code using The lexer keeps track of the current location in the Verilog source code with
some global variables. These variables are used by the constructor of AST nodes a ``VerilogLexer::out_loc`` and uses it to construct parser-defined
to annotate each node with the source code location it originated from. symbol objects.
Finally the lexer identifies and handles special comments such as "``// synopsys Finally the lexer identifies and handles special comments such as "``// synopsys
translate_off``" and "``// synopsys full_case``". (It is recommended to use translate_off``" and "``// synopsys full_case``". (It is recommended to use
@ -178,21 +178,22 @@ properties:
- | Source code location - | Source code location
| Each ``AST::AstNode`` is automatically annotated with the current source | Each ``AST::AstNode`` is automatically annotated with the current source
code location by the ``AST::AstNode`` constructor. It is stored in the code location by the ``AST::AstNode`` constructor. The ``location`` type
``std::string filename`` and ``int linenum`` member variables. is a manual reimplementation of the bison-provided location type. This
type is defined at ``frontends/verilog/verilog_location.h``.
The ``AST::AstNode`` constructor can be called with up to two child nodes that The ``AST::AstNode`` constructor can be called with up to 4 child nodes. This
are automatically added to the list of child nodes for the new object. This
simplifies the creation of AST nodes for simple expressions a bit. For example simplifies the creation of AST nodes for simple expressions a bit. For example
the bison code for parsing multiplications: the bison code for parsing multiplications:
.. code:: none .. code:: none
:number-lines: :number-lines:
basic_expr '*' attr basic_expr { basic_expr TOK_ASTER attr basic_expr {
$$ = new AstNode(AST_MUL, $1, $4); $$ = std::make_unique<AstNode>(AST_MUL, std::move($1), std::move($4));
append_attr($$, $3); SET_AST_NODE_LOC($$.get(), @1, @4);
} | append_attr($$.get(), $3);
} |
The generated AST data structure is then passed directly to the AST frontend The generated AST data structure is then passed directly to the AST frontend
that performs the actual conversion to RTLIL. that performs the actual conversion to RTLIL.
@ -204,7 +205,7 @@ tree respectively.
Transforming AST to RTLIL Transforming AST to RTLIL
------------------------- -------------------------
The AST Frontend converts a set of modules in AST representation to modules in The AST frontend converts a set of modules in AST representation to modules in
RTLIL representation and adds them to the current design. This is done in two RTLIL representation and adds them to the current design. This is done in two
steps: simplification and RTLIL generation. steps: simplification and RTLIL generation.

View file

@ -38,9 +38,7 @@ using namespace AST_INTERNAL;
// instantiate global variables (public API) // instantiate global variables (public API)
namespace AST { namespace AST {
std::string current_filename; bool sv_mode_but_global_and_used_for_literally_one_condition;
void (*set_line_num)(int) = NULL;
int (*get_line_num)() = NULL;
unsigned long long astnodes = 0; unsigned long long astnodes = 0;
unsigned long long astnode_count() { return astnodes; } unsigned long long astnode_count() { return astnodes; }
} }
@ -192,16 +190,16 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
if (attributes.count(id) == 0) if (attributes.count(id) == 0)
return false; return false;
AstNode *attr = attributes.at(id); AstNode& attr = *(attributes.at(id));
if (attr->type != AST_CONSTANT) if (attr.type != AST_CONSTANT)
attr->input_error("Attribute `%s' with non-constant value!\n", id.c_str()); attr.input_error("Attribute `%s' with non-constant value!\n", id.c_str());
return attr->integer != 0; return attr.integer != 0;
} }
// create new node (AstNode constructor) // create new node (AstNode constructor)
// (the optional child arguments make it easier to create AST trees) // (the optional child arguments make it easier to create AST trees)
AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *child3, AstNode *child4) AstNode::AstNode(AstSrcLocType loc, AstNodeType type, std::unique_ptr<AstNode> child1, std::unique_ptr<AstNode> child2, std::unique_ptr<AstNode> child3, std::unique_ptr<AstNode> child4)
{ {
static unsigned int hashidx_count = 123456789; static unsigned int hashidx_count = 123456789;
hashidx_count = mkhash_xorshift(hashidx_count); hashidx_count = mkhash_xorshift(hashidx_count);
@ -209,7 +207,7 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
astnodes++; astnodes++;
this->type = type; this->type = type;
filename = current_filename; location = loc;
is_input = false; is_input = false;
is_output = false; is_output = false;
is_reg = false; is_reg = false;
@ -239,56 +237,73 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
in_param = false; in_param = false;
if (child1) if (child1)
children.push_back(child1); children.push_back(std::move(child1));
if (child2) if (child2)
children.push_back(child2); children.push_back(std::move(child2));
if (child3) if (child3)
children.push_back(child3); children.push_back(std::move(child3));
if (child4) if (child4)
children.push_back(child4); children.push_back(std::move(child4));
fixup_hierarchy_flags(); fixup_hierarchy_flags();
} }
// create a (deep recursive) copy of a node // create a (deep recursive) copy of a node
AstNode *AstNode::clone() const std::unique_ptr<AstNode> AstNode::clone() const
{ {
AstNode *that = new AstNode; auto that = std::make_unique<AstNode>(this->location, this->type);
*that = *this; cloneInto(*that.get());
for (auto &it : that->children)
it = it->clone();
for (auto &it : that->attributes)
it.second = it.second->clone();
that->set_in_lvalue_flag(false);
that->set_in_param_flag(false);
that->fixup_hierarchy_flags(); // fixup to set flags on cloned children
return that; return that;
} }
// create a (deep recursive) copy of a node use 'other' as target root node // create a (deep recursive) copy of a node use 'other' as target root node
void AstNode::cloneInto(AstNode *other) const void AstNode::cloneInto(AstNode &other) const
{ {
AstNode *tmp = clone(); other.type = type;
tmp->in_lvalue_from_above = other->in_lvalue_from_above; other.str = str;
tmp->in_param_from_above = other->in_param_from_above; other.bits = bits;
other->delete_children(); other.is_input = is_input;
*other = *tmp; other.is_output = is_output;
tmp->children.clear(); other.is_reg = is_reg;
tmp->attributes.clear(); other.is_logic = is_logic;
other->fixup_hierarchy_flags(); other.is_signed = is_signed;
delete tmp; other.is_string = is_string;
other.is_wand = is_wand;
other.is_wor = is_wor;
other.range_valid = range_valid;
other.range_swapped = range_swapped;
other.was_checked = was_checked;
other.is_unsized = is_unsized;
other.is_custom_type = is_custom_type;
other.port_id = port_id,
other.range_left = range_left,
other.range_right = range_right;
other.integer = integer;
other.realvalue = realvalue;
other.is_enum = is_enum;
other.dimensions = dimensions;
other.unpacked_dimensions = unpacked_dimensions;
other.id2ast = id2ast;
other.basic_prep = basic_prep;
other.lookahead = lookahead;
other.location = location;
other.in_lvalue = in_lvalue;
other.in_param = in_param;
// Keep in_lvalue_from_above and in_param_from_above untouched
other.delete_children();
for (auto& child : this->children)
other.children.push_back(child->clone());
for (auto& [key, val] : this->attributes)
other.attributes[key] = (val->clone());
// fixup to set flags on cloned children
other.fixup_hierarchy_flags();
} }
// delete all children in this node // delete all children in this node
void AstNode::delete_children() void AstNode::delete_children()
{ {
for (auto &it : children)
delete it;
children.clear(); children.clear();
for (auto &it : attributes)
delete it.second;
attributes.clear(); attributes.clear();
} }
@ -423,18 +438,18 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
{ {
case AST_MODULE: case AST_MODULE:
fprintf(f, "%s" "module %s(", indent.c_str(), id2vl(str).c_str()); fprintf(f, "%s" "module %s(", indent.c_str(), id2vl(str).c_str());
for (auto child : children) for (const auto& child : children)
if (child->type == AST_WIRE && (child->is_input || child->is_output)) { if (child->type == AST_WIRE && (child->is_input || child->is_output)) {
fprintf(f, "%s%s", first ? "" : ", ", id2vl(child->str).c_str()); fprintf(f, "%s%s", first ? "" : ", ", id2vl(child->str).c_str());
first = false; first = false;
} }
fprintf(f, ");\n"); fprintf(f, ");\n");
for (auto child : children) for (const auto& child : children)
if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || child->type == AST_DEFPARAM) if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || child->type == AST_DEFPARAM)
child->dumpVlog(f, indent + " "); child->dumpVlog(f, indent + " ");
else else
rem_children1.push_back(child); rem_children1.push_back(child.get());
for (auto child : rem_children1) for (auto child : rem_children1)
if (child->type == AST_WIRE || child->type == AST_AUTOWIRE || child->type == AST_MEMORY) if (child->type == AST_WIRE || child->type == AST_AUTOWIRE || child->type == AST_MEMORY)
@ -470,7 +485,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
fprintf(f, "%s" "reg", (is_input || is_output) ? " " : indent.c_str()); fprintf(f, "%s" "reg", (is_input || is_output) ? " " : indent.c_str());
if (is_signed) if (is_signed)
fprintf(f, " signed"); fprintf(f, " signed");
for (auto child : children) { for (const auto& child : children) {
fprintf(f, " "); fprintf(f, " ");
child->dumpVlog(f, ""); child->dumpVlog(f, "");
} }
@ -486,7 +501,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
fprintf(f, "%s" "memory", indent.c_str()); fprintf(f, "%s" "memory", indent.c_str());
if (is_signed) if (is_signed)
fprintf(f, " signed"); fprintf(f, " signed");
for (auto child : children) { for (const auto& child : children) {
fprintf(f, " "); fprintf(f, " ");
child->dumpVlog(f, ""); child->dumpVlog(f, "");
if (first) if (first)
@ -500,7 +515,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
if (0) { case AST_MEMINIT: txt = "@meminit@"; } if (0) { case AST_MEMINIT: txt = "@meminit@"; }
if (0) { case AST_MEMWR: txt = "@memwr@"; } if (0) { case AST_MEMWR: txt = "@memwr@"; }
fprintf(f, "%s%s", indent.c_str(), txt.c_str()); fprintf(f, "%s%s", indent.c_str(), txt.c_str());
for (auto child : children) { for (const auto& child : children) {
fprintf(f, first ? "(" : ", "); fprintf(f, first ? "(" : ", ");
child->dumpVlog(f, ""); child->dumpVlog(f, "");
first = false; first = false;
@ -517,7 +532,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
else else
fprintf(f, "[%d:%d]", range_left, range_right); fprintf(f, "[%d:%d]", range_left, range_right);
} else { } else {
for (auto child : children) { for (const auto& child : children) {
fprintf(f, "%c", first ? '[' : ':'); fprintf(f, "%c", first ? '[' : ':');
child->dumpVlog(f, ""); child->dumpVlog(f, "");
first = false; first = false;
@ -527,13 +542,13 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
break; break;
case AST_MULTIRANGE: case AST_MULTIRANGE:
for (auto child : children) for (const auto& child : children)
child->dumpVlog(f, ""); child->dumpVlog(f, "");
break; break;
case AST_ALWAYS: case AST_ALWAYS:
fprintf(f, "%s" "always @", indent.c_str()); fprintf(f, "%s" "always @", indent.c_str());
for (auto child : children) { for (const auto& child : children) {
if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE) if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
continue; continue;
fprintf(f, first ? "(" : ", "); fprintf(f, first ? "(" : ", ");
@ -541,7 +556,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
first = false; first = false;
} }
fprintf(f, first ? "*\n" : ")\n"); fprintf(f, first ? "*\n" : ")\n");
for (auto child : children) { for (const auto& child : children) {
if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE) if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
child->dumpVlog(f, indent + " "); child->dumpVlog(f, indent + " ");
} }
@ -549,7 +564,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
case AST_INITIAL: case AST_INITIAL:
fprintf(f, "%s" "initial\n", indent.c_str()); fprintf(f, "%s" "initial\n", indent.c_str());
for (auto child : children) { for (const auto& child : children) {
if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE) if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
child->dumpVlog(f, indent + " "); child->dumpVlog(f, indent + " ");
} }
@ -562,7 +577,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
fprintf(f, "posedge "); fprintf(f, "posedge ");
if (type == AST_NEGEDGE) if (type == AST_NEGEDGE)
fprintf(f, "negedge "); fprintf(f, "negedge ");
for (auto child : children) for (const auto& child : children)
child->dumpVlog(f, ""); child->dumpVlog(f, "");
break; break;
@ -574,7 +589,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
else else
fprintf(f, "%s", id2vl(str).c_str()); fprintf(f, "%s", id2vl(str).c_str());
} }
for (auto child : children) for (const auto& child : children)
child->dumpVlog(f, ""); child->dumpVlog(f, "");
break; break;
@ -602,7 +617,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
children[0]->dumpVlog(f, indent); children[0]->dumpVlog(f, indent);
} else { } else {
fprintf(f, "%s" "begin\n", indent.c_str()); fprintf(f, "%s" "begin\n", indent.c_str());
for (auto child : children) for (const auto& child : children)
child->dumpVlog(f, indent + " "); child->dumpVlog(f, indent + " ");
fprintf(f, "%s" "end\n", indent.c_str()); fprintf(f, "%s" "end\n", indent.c_str());
} }
@ -618,7 +633,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
children[0]->dumpVlog(f, ""); children[0]->dumpVlog(f, "");
fprintf(f, ")\n"); fprintf(f, ")\n");
for (size_t i = 1; i < children.size(); i++) { for (size_t i = 1; i < children.size(); i++) {
AstNode *child = children[i]; const auto& child = children[i];
child->dumpVlog(f, indent + " "); child->dumpVlog(f, indent + " ");
} }
fprintf(f, "%s" "endcase\n", indent.c_str()); fprintf(f, "%s" "endcase\n", indent.c_str());
@ -627,7 +642,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
case AST_COND: case AST_COND:
case AST_CONDX: case AST_CONDX:
case AST_CONDZ: case AST_CONDZ:
for (auto child : children) { for (const auto& child : children) {
if (child->type == AST_BLOCK) { if (child->type == AST_BLOCK) {
fprintf(f, ":\n"); fprintf(f, ":\n");
child->dumpVlog(f, indent + " "); child->dumpVlog(f, indent + " ");
@ -663,7 +678,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
case AST_CONCAT: case AST_CONCAT:
fprintf(f, "{"); fprintf(f, "{");
for (int i = GetSize(children)-1; i >= 0; i--) { for (int i = GetSize(children)-1; i >= 0; i--) {
auto child = children[i]; const auto& child = children[i];
if (!first) if (!first)
fprintf(f, ", "); fprintf(f, ", ");
child->dumpVlog(f, ""); child->dumpVlog(f, "");
@ -818,16 +833,16 @@ bool AstNode::contains(const AstNode *other) const
{ {
if (this == other) if (this == other)
return true; return true;
for (auto child : children) for (const auto& child : children)
if (child->contains(other)) if (child->contains(other))
return true; return true;
return false; return false;
} }
// create an AST node for a constant (using a 32 bit int as value) // create an AST node for a constant (using a 32 bit int as value)
AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width) std::unique_ptr<AstNode> AstNode::mkconst_int(AstSrcLocType loc, uint32_t v, bool is_signed, int width)
{ {
AstNode *node = new AstNode(AST_CONSTANT); auto node = std::make_unique<AstNode>(loc, AST_CONSTANT);
node->integer = v; node->integer = v;
node->is_signed = is_signed; node->is_signed = is_signed;
for (int i = 0; i < width; i++) { for (int i = 0; i < width; i++) {
@ -841,9 +856,9 @@ AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width)
} }
// create an AST node for a constant (using a bit vector as value) // create an AST node for a constant (using a bit vector as value)
AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized) std::unique_ptr<AstNode> AstNode::mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized)
{ {
AstNode *node = new AstNode(AST_CONSTANT); auto node = std::make_unique<AstNode>(loc, AST_CONSTANT);
node->is_signed = is_signed; node->is_signed = is_signed;
node->bits = v; node->bits = v;
for (size_t i = 0; i < 32; i++) { for (size_t i = 0; i < 32; i++) {
@ -859,15 +874,15 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
return node; return node;
} }
AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed) std::unique_ptr<AstNode> AstNode::mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed)
{ {
return mkconst_bits(v, is_signed, false); return mkconst_bits(loc, v, is_signed, false);
} }
// create an AST node for a constant (using a string in bit vector form as value) // create an AST node for a constant (using a string in bit vector form as value)
AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v) std::unique_ptr<AstNode> AstNode::mkconst_str(AstSrcLocType loc, const std::vector<RTLIL::State> &v)
{ {
AstNode *node = mkconst_str(RTLIL::Const(v).decode_string()); auto node = mkconst_str(loc, RTLIL::Const(v).decode_string());
while (GetSize(node->bits) < GetSize(v)) while (GetSize(node->bits) < GetSize(v))
node->bits.push_back(RTLIL::State::S0); node->bits.push_back(RTLIL::State::S0);
log_assert(node->bits == v); log_assert(node->bits == v);
@ -875,14 +890,14 @@ AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
} }
// create an AST node for a constant (using a string as value) // create an AST node for a constant (using a string as value)
AstNode *AstNode::mkconst_str(const std::string &str) std::unique_ptr<AstNode> AstNode::mkconst_str(AstSrcLocType loc, const std::string &str)
{ {
AstNode *node; std::unique_ptr<AstNode> node;
// LRM 1364-2005 5.2.3.3 The empty string literal ("") shall be considered // LRM 1364-2005 5.2.3.3 The empty string literal ("") shall be considered
// equivalent to the ASCII NUL ("\0") // equivalent to the ASCII NUL ("\0")
if (str.empty()) { if (str.empty()) {
node = AstNode::mkconst_int(0, false, 8); node = AstNode::mkconst_int(loc, 0, false, 8);
} else { } else {
std::vector<RTLIL::State> data; std::vector<RTLIL::State> data;
data.reserve(str.size() * 8); data.reserve(str.size() * 8);
@ -893,7 +908,7 @@ AstNode *AstNode::mkconst_str(const std::string &str)
ch = ch >> 1; ch = ch >> 1;
} }
} }
node = AstNode::mkconst_bits(data, false); node = AstNode::mkconst_bits(loc, data, false);
} }
node->is_string = true; node->is_string = true;
@ -902,18 +917,19 @@ AstNode *AstNode::mkconst_str(const std::string &str)
} }
// create a temporary register // create a temporary register
AstNode *AstNode::mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed) std::unique_ptr<AstNode> AstNode::mktemp_logic(AstSrcLocType loc, const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed)
{ {
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(range_left, true), mkconst_int(range_right, true))); auto wire_owned = std::make_unique<AstNode>(loc, AST_WIRE, std::make_unique<AstNode>(loc, AST_RANGE, mkconst_int(loc, range_left, true), mkconst_int(loc, range_right, true)));
wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); auto* wire = wire_owned.get();
wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line, autoidx++);
if (nosync) if (nosync)
wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire->set_attribute(ID::nosync, AstNode::mkconst_int(loc, 1, false));
wire->is_signed = is_signed; wire->is_signed = is_signed;
wire->is_logic = true; wire->is_logic = true;
mod->children.push_back(wire); mod->children.push_back(std::move(wire_owned));
while (wire->simplify(true, 1, -1, false)) { } while (wire->simplify(true, 1, -1, false)) { }
AstNode *ident = new AstNode(AST_IDENTIFIER); auto ident = std::make_unique<AstNode>(loc, AST_IDENTIFIER);
ident->str = wire->str; ident->str = wire->str;
ident->id2ast = wire; ident->id2ast = wire;
@ -967,10 +983,9 @@ RTLIL::Const AstNode::asParaConst() const
{ {
if (type == AST_REALVALUE) if (type == AST_REALVALUE)
{ {
AstNode *strnode = AstNode::mkconst_str(stringf("%f", realvalue)); auto strnode = AstNode::mkconst_str(location, stringf("%f", realvalue));
RTLIL::Const val = strnode->asAttrConst(); RTLIL::Const val = strnode->asAttrConst();
val.flags |= RTLIL::CONST_FLAG_REAL; val.flags |= RTLIL::CONST_FLAG_REAL;
delete strnode;
return val; return val;
} }
@ -1070,7 +1085,7 @@ RTLIL::Const AstNode::realAsConst(int width)
std::string AstNode::loc_string() const std::string AstNode::loc_string() const
{ {
return stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column); return stringf("%s:%d.%d-%d.%d", location.begin.filename->c_str(), location.begin.line, location.begin.column, location.end.line, location.end.column);
} }
void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast) void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast)
@ -1078,7 +1093,7 @@ void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast)
obj->attributes[ID::src] = ast->loc_string(); obj->attributes[ID::src] = ast->loc_string();
} }
static bool param_has_no_default(const AstNode *param) { static bool param_has_no_default(const std::unique_ptr<AstNode> &param) {
const auto &children = param->children; const auto &children = param->children;
log_assert(param->type == AST_PARAMETER); log_assert(param->type == AST_PARAMETER);
log_assert(children.size() <= 2); log_assert(children.size() <= 2);
@ -1086,7 +1101,7 @@ static bool param_has_no_default(const AstNode *param) {
(children.size() == 1 && children[0]->type == AST_RANGE); (children.size() == 1 && children[0]->type == AST_RANGE);
} }
static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool defer, AstNode *original_ast = NULL, bool quiet = false) static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool defer, std::unique_ptr<AstNode> original_ast = NULL, bool quiet = false)
{ {
log_assert(current_scope.empty()); log_assert(current_scope.empty());
log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE); log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE);
@ -1100,15 +1115,15 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
AstModule *module = new AstModule; AstModule *module = new AstModule;
current_module = module; current_module = module;
module->ast = NULL; module->ast = nullptr;
module->name = ast->str; module->name = ast->str;
set_src_attr(module, ast); set_src_attr(module, ast);
module->set_bool_attribute(ID::cells_not_processed); module->set_bool_attribute(ID::cells_not_processed);
current_ast_mod = ast; current_ast_mod = ast;
AstNode *ast_before_simplify; std::unique_ptr<AstNode> ast_before_simplify;
if (original_ast != NULL) if (original_ast != NULL)
ast_before_simplify = original_ast; ast_before_simplify = std::move(original_ast);
else else
ast_before_simplify = ast->clone(); ast_before_simplify = ast->clone();
@ -1125,7 +1140,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
if (!defer) if (!defer)
{ {
for (const AstNode *node : ast->children) for (auto& node : ast->children)
if (node->type == AST_PARAMETER && param_has_no_default(node)) if (node->type == AST_PARAMETER && param_has_no_default(node))
node->input_error("Parameter `%s' has no default value and has not been overridden!\n", node->str.c_str()); node->input_error("Parameter `%s' has no default value and has not been overridden!\n", node->str.c_str());
@ -1133,7 +1148,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
if (!blackbox_module && !flag_noblackbox) { if (!blackbox_module && !flag_noblackbox) {
blackbox_module = true; blackbox_module = true;
for (auto child : ast->children) { for (const auto& child : ast->children) {
if (child->type == AST_WIRE && (child->is_input || child->is_output)) if (child->type == AST_WIRE && (child->is_input || child->is_output))
continue; continue;
if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM) if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
@ -1163,36 +1178,33 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
ast->dumpVlog(NULL, " "); ast->dumpVlog(NULL, " ");
log("--- END OF AST DUMP ---\n"); log("--- END OF AST DUMP ---\n");
} }
for (auto &attr: ast->attributes)
log_assert((bool)attr.second.get());
if (flag_nowb && ast->attributes.count(ID::whitebox)) { if (flag_nowb && ast->attributes.count(ID::whitebox)) {
delete ast->attributes.at(ID::whitebox);
ast->attributes.erase(ID::whitebox); ast->attributes.erase(ID::whitebox);
} }
for (auto &attr: ast->attributes)
log_assert((bool)attr.second.get());
if (ast->attributes.count(ID::lib_whitebox)) { if (ast->attributes.count(ID::lib_whitebox)) {
if (!flag_lib || flag_nowb) { if (flag_lib && !flag_nowb) {
delete ast->attributes.at(ID::lib_whitebox); ast->attributes[ID::whitebox] = std::move(
ast->attributes.erase(ID::lib_whitebox); ast->attributes[ID::lib_whitebox]
} else { );
if (ast->attributes.count(ID::whitebox)) {
delete ast->attributes.at(ID::whitebox);
ast->attributes.erase(ID::whitebox);
}
AstNode *n = ast->attributes.at(ID::lib_whitebox);
ast->set_attribute(ID::whitebox, n);
ast->attributes.erase(ID::lib_whitebox);
} }
ast->attributes.erase(ID::lib_whitebox);
} }
for (auto &attr: ast->attributes)
log_assert((bool)attr.second.get());
if (!blackbox_module && ast->attributes.count(ID::blackbox)) { if (!blackbox_module && ast->attributes.count(ID::blackbox)) {
AstNode *n = ast->attributes.at(ID::blackbox); auto& n = ast->attributes.at(ID::blackbox);
if (n->type != AST_CONSTANT) if (n->type != AST_CONSTANT)
ast->input_error("Got blackbox attribute with non-constant value!\n"); ast->input_error("Got blackbox attribute with non-constant value!\n");
blackbox_module = n->asBool(); blackbox_module = n->asBool();
} }
if (blackbox_module && ast->attributes.count(ID::whitebox)) { if (blackbox_module && ast->attributes.count(ID::whitebox)) {
AstNode *n = ast->attributes.at(ID::whitebox); auto& n = ast->attributes.at(ID::whitebox);
if (n->type != AST_CONSTANT) if (n->type != AST_CONSTANT)
ast->input_error("Got whitebox attribute with non-constant value!\n"); ast->input_error("Got whitebox attribute with non-constant value!\n");
blackbox_module = !n->asBool(); blackbox_module = !n->asBool();
@ -1200,62 +1212,59 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
if (ast->attributes.count(ID::noblackbox)) { if (ast->attributes.count(ID::noblackbox)) {
if (blackbox_module) { if (blackbox_module) {
AstNode *n = ast->attributes.at(ID::noblackbox); auto& n = ast->attributes.at(ID::noblackbox);
if (n->type != AST_CONSTANT) if (n->type != AST_CONSTANT)
ast->input_error("Got noblackbox attribute with non-constant value!\n"); ast->input_error("Got noblackbox attribute with non-constant value!\n");
blackbox_module = !n->asBool(); blackbox_module = !n->asBool();
} }
delete ast->attributes.at(ID::noblackbox);
ast->attributes.erase(ID::noblackbox); ast->attributes.erase(ID::noblackbox);
} }
for (auto &attr: ast->attributes)
log_assert((bool)attr.second.get());
if (blackbox_module) if (blackbox_module)
{ {
if (ast->attributes.count(ID::whitebox)) { if (ast->attributes.count(ID::whitebox)) {
delete ast->attributes.at(ID::whitebox);
ast->attributes.erase(ID::whitebox); ast->attributes.erase(ID::whitebox);
} }
if (ast->attributes.count(ID::lib_whitebox)) { if (ast->attributes.count(ID::lib_whitebox)) {
delete ast->attributes.at(ID::lib_whitebox);
ast->attributes.erase(ID::lib_whitebox); ast->attributes.erase(ID::lib_whitebox);
} }
std::vector<AstNode*> new_children; std::vector<std::unique_ptr<AstNode>> new_children;
for (auto child : ast->children) { for (auto& child : ast->children) {
if (child->type == AST_WIRE && (child->is_input || child->is_output)) { if (child->type == AST_WIRE && (child->is_input || child->is_output)) {
new_children.push_back(child); new_children.push_back(std::move(child));
} else if (child->type == AST_PARAMETER) { } else if (child->type == AST_PARAMETER) {
new_children.push_back(child); new_children.push_back(std::move(child));
} else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE && } else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
(child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) { (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) {
new_children.push_back(child); new_children.push_back(std::move(child));
} else {
delete child;
} }
} }
ast->children.swap(new_children); ast->children.swap(new_children);
if (ast->attributes.count(ID::blackbox) == 0) { if (ast->attributes.count(ID::blackbox) == 0) {
ast->set_attribute(ID::blackbox, AstNode::mkconst_int(1, false)); ast->set_attribute(ID::blackbox, AstNode::mkconst_int(ast->location, 1, false));
} }
} }
ignoreThisSignalsInInitial = RTLIL::SigSpec(); ignoreThisSignalsInInitial = RTLIL::SigSpec();
for (auto &attr : ast->attributes) { for (auto &attr : ast->attributes) {
log_assert((bool)attr.second.get());
if (attr.second->type != AST_CONSTANT) if (attr.second->type != AST_CONSTANT)
ast->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str()); ast->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str());
module->attributes[attr.first] = attr.second->asAttrConst(); module->attributes[attr.first] = attr.second->asAttrConst();
} }
for (size_t i = 0; i < ast->children.size(); i++) { for (size_t i = 0; i < ast->children.size(); i++) {
AstNode *node = ast->children[i]; const auto& node = ast->children[i];
if (node->type == AST_WIRE || node->type == AST_MEMORY) if (node->type == AST_WIRE || node->type == AST_MEMORY)
node->genRTLIL(); node->genRTLIL();
} }
for (size_t i = 0; i < ast->children.size(); i++) { for (size_t i = 0; i < ast->children.size(); i++) {
AstNode *node = ast->children[i]; const auto& node = ast->children[i];
if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL) if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL)
node->genRTLIL(); node->genRTLIL();
} }
@ -1263,7 +1272,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
ignoreThisSignalsInInitial.sort_and_unify(); ignoreThisSignalsInInitial.sort_and_unify();
for (size_t i = 0; i < ast->children.size(); i++) { for (size_t i = 0; i < ast->children.size(); i++) {
AstNode *node = ast->children[i]; const auto& node = ast->children[i];
if (node->type == AST_INITIAL) if (node->type == AST_INITIAL)
node->genRTLIL(); node->genRTLIL();
} }
@ -1277,14 +1286,14 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
continue; continue;
module->attributes[attr.first] = attr.second->asAttrConst(); module->attributes[attr.first] = attr.second->asAttrConst();
} }
for (const AstNode *node : ast->children) for (const auto& node : ast->children)
if (node->type == AST_PARAMETER) if (node->type == AST_PARAMETER)
current_module->avail_parameters(node->str); current_module->avail_parameters(node->str);
} }
if (ast->type == AST_INTERFACE) if (ast->type == AST_INTERFACE)
module->set_bool_attribute(ID::is_interface); module->set_bool_attribute(ID::is_interface);
module->ast = ast_before_simplify; module->ast = std::move(ast_before_simplify);
module->nolatches = flag_nolatches; module->nolatches = flag_nolatches;
module->nomeminit = flag_nomeminit; module->nomeminit = flag_nomeminit;
module->nomem2reg = flag_nomem2reg; module->nomem2reg = flag_nomem2reg;
@ -1311,8 +1320,8 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
RTLIL::Module * RTLIL::Module *
AST_INTERNAL::process_and_replace_module(RTLIL::Design *design, AST_INTERNAL::process_and_replace_module(RTLIL::Design *design,
RTLIL::Module *old_module, RTLIL::Module *old_module,
AstNode *new_ast, AST::AstNode *new_ast,
AstNode *original_ast) std::unique_ptr<AstNode> original_ast)
{ {
// The old module will be deleted. Rename and mark for deletion, using // The old module will be deleted. Rename and mark for deletion, using
// a static counter to make sure we get a unique name. // a static counter to make sure we get a unique name.
@ -1335,7 +1344,7 @@ AST_INTERNAL::process_and_replace_module(RTLIL::Design *design,
} }
// Generate RTLIL from AST for the new module and add to the design: // Generate RTLIL from AST for the new module and add to the design:
RTLIL::Module* new_module = process_module(design, new_ast, false, original_ast); RTLIL::Module* new_module = process_module(design, new_ast, false, std::move(original_ast));
if (is_top) if (is_top)
new_module->set_bool_attribute(ID::top); new_module->set_bool_attribute(ID::top);
@ -1347,17 +1356,17 @@ AST_INTERNAL::process_and_replace_module(RTLIL::Design *design,
static void rename_in_package_stmts(AstNode *pkg) static void rename_in_package_stmts(AstNode *pkg)
{ {
std::unordered_set<std::string> idents; std::unordered_set<std::string> idents;
for (AstNode *item : pkg->children) for (auto& item : pkg->children)
idents.insert(item->str); idents.insert(item->str);
std::function<void(AstNode*)> rename = std::function<void(std::unique_ptr<AstNode>&)> rename =
[&rename, &idents, pkg](AstNode *node) { [&rename, &idents, pkg](std::unique_ptr<AstNode>& node) {
for (AstNode *child : node->children) { for (auto& child : node->children) {
if (idents.count(child->str)) if (idents.count(child->str))
child->str = pkg->str + "::" + child->str.substr(1); child->str = pkg->str + "::" + child->str.substr(1);
rename(child); rename(child);
} }
}; };
for (AstNode *item : pkg->children) for (auto& item : pkg->children)
if (item->type == AST_FUNCTION || item->type == AST_TASK) if (item->type == AST_FUNCTION || item->type == AST_TASK)
rename(item); rename(item);
} }
@ -1390,17 +1399,17 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
ast->fixup_hierarchy_flags(true); ast->fixup_hierarchy_flags(true);
log_assert(current_ast->type == AST_DESIGN); log_assert(current_ast->type == AST_DESIGN);
for (AstNode *child : current_ast->children) for (const auto& child : current_ast->children)
{ {
if (child->type == AST_MODULE || child->type == AST_INTERFACE) if (child->type == AST_MODULE || child->type == AST_INTERFACE)
{ {
for (auto n : design->verilog_globals) for (auto& n : design->verilog_globals)
child->children.push_back(n->clone()); child->children.push_back(n->clone());
// append nodes from previous packages using package-qualified names // append nodes from previous packages using package-qualified names
for (auto &n : design->verilog_packages) { for (auto& n : design->verilog_packages) {
for (auto &o : n->children) { for (auto &o : n->children) {
AstNode *cloned_node = o->clone(); auto cloned_node = o->clone();
// log("cloned node %s\n", type2str(cloned_node->type).c_str()); // log("cloned node %s\n", type2str(cloned_node->type).c_str());
if (cloned_node->type == AST_ENUM) { if (cloned_node->type == AST_ENUM) {
for (auto &e : cloned_node->children) { for (auto &e : cloned_node->children) {
@ -1410,7 +1419,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
} else { } else {
cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1); cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1);
} }
child->children.push_back(cloned_node); child->children.push_back(std::move(cloned_node));
} }
} }
@ -1419,7 +1428,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
bool defer_local = defer; bool defer_local = defer;
if (!defer_local) if (!defer_local)
for (const AstNode *node : child->children) for (const auto& node : child->children)
if (node->type == AST_PARAMETER && param_has_no_default(node)) if (node->type == AST_PARAMETER && param_has_no_default(node))
{ {
log("Deferring `%s' because it contains parameter(s) without defaults.\n", child->str.c_str()); log("Deferring `%s' because it contains parameter(s) without defaults.\n", child->str.c_str());
@ -1434,7 +1443,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
if (design->has(child->str)) { if (design->has(child->str)) {
RTLIL::Module *existing_mod = design->module(child->str); RTLIL::Module *existing_mod = design->module(child->str);
if (!nooverwrite && !overwrite && !existing_mod->get_blackbox_attribute()) { if (!nooverwrite && !overwrite && !existing_mod->get_blackbox_attribute()) {
log_file_error(child->filename, child->location.first_line, "Re-definition of module `%s'!\n", child->str.c_str()); log_file_error(*child->location.begin.filename, child->location.begin.line, "Re-definition of module `%s'!\n", child->str.c_str());
} else if (nooverwrite) { } else if (nooverwrite) {
log("Ignoring re-definition of module `%s' at %s.\n", log("Ignoring re-definition of module `%s' at %s.\n",
child->str.c_str(), child->loc_string().c_str()); child->str.c_str(), child->loc_string().c_str());
@ -1447,13 +1456,13 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
} }
} }
process_module(design, child, defer_local); process_module(design, child.get(), defer_local);
current_ast_mod = nullptr; current_ast_mod = nullptr;
} }
else if (child->type == AST_PACKAGE) { else if (child->type == AST_PACKAGE) {
// process enum/other declarations // process enum/other declarations
child->simplify(true, 1, -1, false); child->simplify(true, 1, -1, false);
rename_in_package_stmts(child); rename_in_package_stmts(child.get());
design->verilog_packages.push_back(child->clone()); design->verilog_packages.push_back(child->clone());
current_scope.clear(); current_scope.clear();
} }
@ -1470,16 +1479,9 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
current_scope.clear(); current_scope.clear();
} }
} }
}
// AstModule destructor
AstModule::~AstModule()
{
if (ast != NULL)
delete ast;
} }
// An interface port with modport is specified like this: // An interface port with modport is specified like this:
// <interface_name>.<modport_name> // <interface_name>.<modport_name>
// This function splits the interface_name from the modport_name, and fails if it is not a valid combination // This function splits the interface_name from the modport_name, and fails if it is not a valid combination
@ -1516,7 +1518,7 @@ AstNode * AST::find_modport(AstNode *intf, std::string name)
for (auto &ch : intf->children) for (auto &ch : intf->children)
if (ch->type == AST_MODPORT) if (ch->type == AST_MODPORT)
if (ch->str == name) // Modport found if (ch->str == name) // Modport found
return ch; return ch.get();
return NULL; return NULL;
} }
@ -1524,7 +1526,8 @@ AstNode * AST::find_modport(AstNode *intf, std::string name)
void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport) void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport)
{ {
for (auto w : intfmodule->wires()){ for (auto w : intfmodule->wires()){
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); auto loc = module_ast->location;
auto wire = std::make_unique<AstNode>(loc, AST_WIRE, std::make_unique<AstNode>(loc, AST_RANGE, AstNode::mkconst_int(loc, w->width -1, true), AstNode::mkconst_int(loc, 0, true)));
std::string origname = log_id(w->name); std::string origname = log_id(w->name);
std::string newname = intfname + "." + origname; std::string newname = intfname + "." + origname;
wire->str = newname; wire->str = newname;
@ -1543,16 +1546,13 @@ void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule
} }
} }
if (found_in_modport) { if (found_in_modport) {
module_ast->children.push_back(wire); module_ast->children.push_back(std::move(wire));
}
else { // If not found in modport, do not create port
delete wire;
} }
} }
else { // If no modport, set inout else { // If no modport, set inout
wire->is_input = true; wire->is_input = true;
wire->is_output = true; wire->is_output = true;
module_ast->children.push_back(wire); module_ast->children.push_back(std::move(wire));
} }
} }
} }
@ -1570,7 +1570,7 @@ bool AstModule::reprocess_if_necessary(RTLIL::Design *design)
log("Reprocessing module %s because instantiated module %s has become available.\n", log("Reprocessing module %s because instantiated module %s has become available.\n",
log_id(name), log_id(modname)); log_id(name), log_id(modname));
loadconfig(); loadconfig();
process_and_replace_module(design, this, ast, NULL); process_and_replace_module(design, this, ast.get(), NULL);
return true; return true;
} }
} }
@ -1583,32 +1583,33 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
{ {
loadconfig(); loadconfig();
AstNode *new_ast = ast->clone(); auto new_ast = ast->clone();
auto loc = ast->location;
for (auto &intf : local_interfaces) { for (auto &intf : local_interfaces) {
std::string intfname = intf.first.str(); std::string intfname = intf.first.str();
RTLIL::Module *intfmodule = intf.second; RTLIL::Module *intfmodule = intf.second;
for (auto w : intfmodule->wires()){ for (auto w : intfmodule->wires()){
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); auto wire = std::make_unique<AstNode>(loc, AST_WIRE, std::make_unique<AstNode>(loc, AST_RANGE, AstNode::mkconst_int(loc, w->width -1, true), AstNode::mkconst_int(loc, 0, true)));
std::string newname = log_id(w->name); std::string newname = log_id(w->name);
newname = intfname + "." + newname; newname = intfname + "." + newname;
wire->str = newname; wire->str = newname;
new_ast->children.push_back(wire); new_ast->children.push_back(std::move(wire));
} }
} }
AstNode *ast_before_replacing_interface_ports = new_ast->clone(); auto ast_before_replacing_interface_ports = new_ast->clone();
// Explode all interface ports. Note this will only have an effect on 'top // Explode all interface ports. Note this will only have an effect on 'top
// level' modules. Other sub-modules will have their interface ports // level' modules. Other sub-modules will have their interface ports
// exploded via the derive(..) function // exploded via the derive(..) function
for (size_t i =0; i<new_ast->children.size(); i++) for (size_t i =0; i<new_ast->children.size(); i++)
{ {
AstNode *ch2 = new_ast->children[i]; const auto& ch2 = new_ast->children[i];
if (ch2->type == AST_INTERFACEPORT) { // Is an interface port if (ch2->type == AST_INTERFACEPORT) { // Is an interface port
std::string name_port = ch2->str; // Name of the interface port std::string name_port = ch2->str; // Name of the interface port
if (ch2->children.size() > 0) { if (ch2->children.size() > 0) {
for(size_t j=0; j<ch2->children.size();j++) { for(size_t j=0; j<ch2->children.size();j++) {
AstNode *ch = ch2->children[j]; const auto& ch = ch2->children[j];
if(ch->type == AST_INTERFACEPORTTYPE) { // Found the AST node containing the type of the interface if(ch->type == AST_INTERFACEPORTTYPE) { // Found the AST node containing the type of the interface
std::pair<std::string,std::string> res = split_modport_from_type(ch->str); std::pair<std::string,std::string> res = split_modport_from_type(ch->str);
std::string interface_type = res.first; std::string interface_type = res.first;
@ -1616,11 +1617,11 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
if (design->module(interface_type) != nullptr) { if (design->module(interface_type) != nullptr) {
// Add a cell to the module corresponding to the interface port such that // Add a cell to the module corresponding to the interface port such that
// it can further propagated down if needed: // it can further propagated down if needed:
AstNode *celltype_for_intf = new AstNode(AST_CELLTYPE); auto celltype_for_intf = std::make_unique<AstNode>(loc, AST_CELLTYPE);
celltype_for_intf->str = interface_type; celltype_for_intf->str = interface_type;
AstNode *cell_for_intf = new AstNode(AST_CELL, celltype_for_intf); auto cell_for_intf = std::make_unique<AstNode>(loc, AST_CELL, std::move(celltype_for_intf));
cell_for_intf->str = name_port + "_inst_from_top_dummy"; cell_for_intf->str = name_port + "_inst_from_top_dummy";
new_ast->children.push_back(cell_for_intf); new_ast->children.push_back(std::move(cell_for_intf));
// Get all members of this non-overridden dummy interface instance: // Get all members of this non-overridden dummy interface instance:
RTLIL::Module *intfmodule = design->module(interface_type); // All interfaces should at this point in time (assuming RTLIL::Module *intfmodule = design->module(interface_type); // All interfaces should at this point in time (assuming
@ -1628,9 +1629,9 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
// present in design->modules_ // present in design->modules_
AstModule *ast_module_of_interface = (AstModule*)intfmodule; AstModule *ast_module_of_interface = (AstModule*)intfmodule;
std::string interface_modport_compare_str = "\\" + interface_modport; std::string interface_modport_compare_str = "\\" + interface_modport;
AstNode *modport = find_modport(ast_module_of_interface->ast, interface_modport_compare_str); // modport == NULL if no modport AstNode *modport = find_modport(ast_module_of_interface->ast.get(), interface_modport_compare_str); // modport == NULL if no modport
// Iterate over all wires in the interface and add them to the module: // Iterate over all wires in the interface and add them to the module:
explode_interface_port(new_ast, intfmodule, name_port, modport); explode_interface_port(new_ast.get(), intfmodule, name_port, modport);
} }
break; break;
} }
@ -1642,9 +1643,7 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
// Generate RTLIL from AST for the new module and add to the design, // Generate RTLIL from AST for the new module and add to the design,
// renaming this module to move it out of the way. // renaming this module to move it out of the way.
RTLIL::Module* new_module = RTLIL::Module* new_module =
process_and_replace_module(design, this, new_ast, ast_before_replacing_interface_ports); process_and_replace_module(design, this, new_ast.get(), std::move(ast_before_replacing_interface_ports));
delete new_ast;
// Set the attribute "interfaces_replaced_in_module" so that it does not happen again. // Set the attribute "interfaces_replaced_in_module" so that it does not happen again.
new_module->set_bool_attribute(ID::interfaces_replaced_in_module); new_module->set_bool_attribute(ID::interfaces_replaced_in_module);
@ -1654,7 +1653,7 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
// This method is used to explode the interface when the interface is a port of the module (not instantiated inside) // This method is used to explode the interface when the interface is a port of the module (not instantiated inside)
RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool /*mayfail*/) RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool /*mayfail*/)
{ {
AstNode *new_ast = NULL; std::unique_ptr<AstNode> new_ast = NULL;
std::string modname = derive_common(design, parameters, &new_ast); std::string modname = derive_common(design, parameters, &new_ast);
// Since interfaces themselves may be instantiated with different parameters, // Since interfaces themselves may be instantiated with different parameters,
@ -1690,14 +1689,14 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdStr
if (modports.count(intfname) > 0) { if (modports.count(intfname) > 0) {
std::string interface_modport = modports.at(intfname).str(); std::string interface_modport = modports.at(intfname).str();
AstModule *ast_module_of_interface = (AstModule*)intfmodule; AstModule *ast_module_of_interface = (AstModule*)intfmodule;
AstNode *ast_node_of_interface = ast_module_of_interface->ast; AstNode *ast_node_of_interface = ast_module_of_interface->ast.get();
modport = find_modport(ast_node_of_interface, interface_modport); modport = find_modport(ast_node_of_interface, interface_modport);
} }
// Iterate over all wires in the interface and add them to the module: // Iterate over all wires in the interface and add them to the module:
explode_interface_port(new_ast, intfmodule, intfname, modport); explode_interface_port(new_ast.get(), intfmodule, intfname, modport);
} }
process_module(design, new_ast, false); process_module(design, new_ast.get(), false);
design->module(modname)->check(); design->module(modname)->check();
RTLIL::Module* mod = design->module(modname); RTLIL::Module* mod = design->module(modname);
@ -1734,7 +1733,6 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdStr
log("Found cached RTLIL representation for module `%s'.\n", modname.c_str()); log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
} }
delete new_ast;
return modname; return modname;
} }
@ -1743,18 +1741,17 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdStr
{ {
bool quiet = lib || attributes.count(ID::blackbox) || attributes.count(ID::whitebox); bool quiet = lib || attributes.count(ID::blackbox) || attributes.count(ID::whitebox);
AstNode *new_ast = NULL; std::unique_ptr<AstNode> new_ast = NULL;
std::string modname = derive_common(design, parameters, &new_ast, quiet); std::string modname = derive_common(design, parameters, &new_ast, quiet);
if (!design->has(modname) && new_ast) { if (!design->has(modname) && new_ast) {
new_ast->str = modname; new_ast->str = modname;
process_module(design, new_ast, false, NULL, quiet); process_module(design, new_ast.get(), false, NULL, quiet);
design->module(modname)->check(); design->module(modname)->check();
} else if (!quiet) { } else if (!quiet) {
log("Found cached RTLIL representation for module `%s'.\n", modname.c_str()); log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
} }
delete new_ast;
return modname; return modname;
} }
@ -1784,7 +1781,7 @@ std::string AST::derived_module_name(std::string stripped_name, const std::vecto
} }
// create a new parametric module (when needed) and return the name of the generated module // create a new parametric module (when needed) and return the name of the generated module
std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, AstNode **new_ast_out, bool quiet) std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, std::unique_ptr<AstNode>* new_ast_out, bool quiet)
{ {
std::string stripped_name = name.str(); std::string stripped_name = name.str();
(*new_ast_out) = nullptr; (*new_ast_out) = nullptr;
@ -1794,7 +1791,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
int para_counter = 0; int para_counter = 0;
std::vector<std::pair<RTLIL::IdString, RTLIL::Const>> named_parameters; std::vector<std::pair<RTLIL::IdString, RTLIL::Const>> named_parameters;
for (const auto child : ast->children) { for (const auto& child : ast->children) {
if (child->type != AST_PARAMETER) if (child->type != AST_PARAMETER)
continue; continue;
para_counter++; para_counter++;
@ -1828,12 +1825,13 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
pool<IdString> rewritten; pool<IdString> rewritten;
rewritten.reserve(GetSize(parameters)); rewritten.reserve(GetSize(parameters));
AstNode *new_ast = ast->clone(); auto new_ast = ast->clone();
auto loc = ast->location;
if (!new_ast->attributes.count(ID::hdlname)) if (!new_ast->attributes.count(ID::hdlname))
new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(stripped_name.substr(1))); new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(loc, stripped_name.substr(1)));
para_counter = 0; para_counter = 0;
for (auto child : new_ast->children) { for (auto& child : new_ast->children) {
if (child->type != AST_PARAMETER) if (child->type != AST_PARAMETER)
continue; continue;
para_counter++; para_counter++;
@ -1853,14 +1851,13 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
rewrite_parameter: rewrite_parameter:
if (param_has_no_default(child)) if (param_has_no_default(child))
child->children.insert(child->children.begin(), nullptr); child->children.insert(child->children.begin(), nullptr);
delete child->children.at(0);
if ((it->second.flags & RTLIL::CONST_FLAG_REAL) != 0) { if ((it->second.flags & RTLIL::CONST_FLAG_REAL) != 0) {
child->children[0] = new AstNode(AST_REALVALUE); child->children[0] = std::make_unique<AstNode>(loc, AST_REALVALUE);
child->children[0]->realvalue = std::stod(it->second.decode_string()); child->children[0]->realvalue = std::stod(it->second.decode_string());
} else if ((it->second.flags & RTLIL::CONST_FLAG_STRING) != 0) } else if ((it->second.flags & RTLIL::CONST_FLAG_STRING) != 0)
child->children[0] = AstNode::mkconst_str(it->second.decode_string()); child->children[0] = AstNode::mkconst_str(loc, it->second.decode_string());
else else
child->children[0] = AstNode::mkconst_bits(it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0); child->children[0] = AstNode::mkconst_bits(loc, it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0);
rewritten.insert(it->first); rewritten.insert(it->first);
} }
@ -1868,17 +1865,17 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
for (const auto &param : parameters) { for (const auto &param : parameters) {
if (rewritten.count(param.first)) if (rewritten.count(param.first))
continue; continue;
AstNode *defparam = new AstNode(AST_DEFPARAM, new AstNode(AST_IDENTIFIER)); auto defparam = std::make_unique<AstNode>(loc, AST_DEFPARAM, std::make_unique<AstNode>(loc, AST_IDENTIFIER));
defparam->children[0]->str = param.first.str(); defparam->children[0]->str = param.first.str();
if ((param.second.flags & RTLIL::CONST_FLAG_STRING) != 0) if ((param.second.flags & RTLIL::CONST_FLAG_STRING) != 0)
defparam->children.push_back(AstNode::mkconst_str(param.second.decode_string())); defparam->children.push_back(AstNode::mkconst_str(loc, param.second.decode_string()));
else else
defparam->children.push_back(AstNode::mkconst_bits(param.second.to_bits(), (param.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0)); defparam->children.push_back(AstNode::mkconst_bits(loc, param.second.to_bits(), (param.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0));
new_ast->children.push_back(defparam); new_ast->children.push_back(std::move(defparam));
} }
new_ast->fixup_hierarchy_flags(true); new_ast->fixup_hierarchy_flags(true);
(*new_ast_out) = new_ast; new_ast_out->reset(new_ast.release());
return modname; return modname;
} }
@ -1928,7 +1925,7 @@ void AstNode::input_error(const char *format, ...) const
{ {
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
logv_file_error(filename, location.first_line, format, ap); logv_file_error(*location.begin.filename, location.begin.line, format, ap);
} }
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END

View file

@ -28,6 +28,7 @@
#include "kernel/rtlil.h" #include "kernel/rtlil.h"
#include "kernel/fmt.h" #include "kernel/fmt.h"
#include "frontends/verilog/verilog_location.h"
#include <stdint.h> #include <stdint.h>
#include <set> #include <set>
@ -162,12 +163,7 @@ namespace AST
AST_BIND AST_BIND
}; };
struct AstSrcLocType { using AstSrcLocType = location;
unsigned int first_line, last_line;
unsigned int first_column, last_column;
AstSrcLocType() : first_line(0), last_line(0), first_column(0), last_column(0) {}
AstSrcLocType(int _first_line, int _first_column, int _last_line, int _last_column) : first_line(_first_line), last_line(_last_line), first_column(_first_column), last_column(_last_column) {}
};
// convert an node type to a string (e.g. for debug output) // convert an node type to a string (e.g. for debug output)
std::string type2str(AstNodeType type); std::string type2str(AstNodeType type);
@ -183,10 +179,10 @@ namespace AST
AstNodeType type; AstNodeType type;
// the list of child nodes for this node // the list of child nodes for this node
std::vector<AstNode*> children; std::vector<std::unique_ptr<AstNode>> children;
// the list of attributes assigned to this node // the list of attributes assigned to this node
std::map<RTLIL::IdString, AstNode*> attributes; std::map<RTLIL::IdString, std::unique_ptr<AstNode>> attributes;
bool get_bool_attribute(RTLIL::IdString id); bool get_bool_attribute(RTLIL::IdString id);
// node content - most of it is unused in most node types // node content - most of it is unused in most node types
@ -212,7 +208,7 @@ namespace AST
int unpacked_dimensions; int unpacked_dimensions;
// this is set by simplify and used during RTLIL generation // this is set by simplify and used during RTLIL generation
AstNode *id2ast; AstNode* id2ast;
// this is used by simplify to detect if basic analysis has been performed already on the node // this is used by simplify to detect if basic analysis has been performed already on the node
bool basic_prep; bool basic_prep;
@ -223,7 +219,6 @@ namespace AST
// this is the original sourcecode location that resulted in this AST node // this is the original sourcecode location that resulted in this AST node
// it is automatically set by the constructor using AST::current_filename and // it is automatically set by the constructor using AST::current_filename and
// the AST::get_line_num() callback function. // the AST::get_line_num() callback function.
std::string filename;
AstSrcLocType location; AstSrcLocType location;
// are we embedded in an lvalue, param? // are we embedded in an lvalue, param?
@ -234,9 +229,9 @@ namespace AST
bool in_param_from_above; bool in_param_from_above;
// creating and deleting nodes // creating and deleting nodes
AstNode(AstNodeType type = AST_NONE, AstNode *child1 = nullptr, AstNode *child2 = nullptr, AstNode *child3 = nullptr, AstNode *child4 = nullptr); AstNode(AstSrcLocType loc, AstNodeType type = AST_NONE, std::unique_ptr<AstNode> child1 = nullptr, std::unique_ptr<AstNode> child2 = nullptr, std::unique_ptr<AstNode> child3 = nullptr, std::unique_ptr<AstNode> child4 = nullptr);
AstNode *clone() const; std::unique_ptr<AstNode> clone() const;
void cloneInto(AstNode *other) const; void cloneInto(AstNode &other) const;
void delete_children(); void delete_children();
~AstNode(); ~AstNode();
@ -264,15 +259,16 @@ namespace AST
// simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc. // simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc.
// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL() // it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()
bool simplify(bool const_fold, int stage, int width_hint, bool sign_hint); bool simplify(bool const_fold, int stage, int width_hint, bool sign_hint);
void null_check();
void replace_result_wire_name_in_function(const std::string &from, const std::string &to); void replace_result_wire_name_in_function(const std::string &from, const std::string &to);
AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init); std::unique_ptr<AstNode> readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init);
void expand_genblock(const std::string &prefix); void expand_genblock(const std::string &prefix);
void label_genblks(std::set<std::string>& existing, int &counter); void label_genblks(std::set<std::string>& existing, int &counter);
void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places, void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags); dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block); bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode* async_block);
bool mem2reg_check(pool<AstNode*> &mem2reg_set); bool mem2reg_check(pool<AstNode*> &mem2reg_set);
void mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes); void mem2reg_remove(pool<AstNode*> &mem2reg_set);
void meminfo(int &mem_width, int &mem_size, int &addr_bits); void meminfo(int &mem_width, int &mem_size, int &addr_bits);
bool detect_latch(const std::string &var); bool detect_latch(const std::string &var);
const RTLIL::Module* lookup_cell_module(); const RTLIL::Module* lookup_cell_module();
@ -288,7 +284,7 @@ namespace AST
}; };
bool has_const_only_constructs(); bool has_const_only_constructs();
bool replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall, bool must_succeed); bool replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall, bool must_succeed);
AstNode *eval_const_function(AstNode *fcall, bool must_succeed); std::unique_ptr<AstNode> eval_const_function(AstNode *fcall, bool must_succeed);
bool is_simple_const_expr(); bool is_simple_const_expr();
// helper for parsing format strings // helper for parsing format strings
@ -305,29 +301,30 @@ namespace AST
std::vector<RTLIL::Binding *> genBindings() const; std::vector<RTLIL::Binding *> genBindings() const;
// used by genRTLIL() for detecting expression width and sign // used by genRTLIL() for detecting expression width and sign
void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = NULL); void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = nullptr);
void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = NULL); void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = nullptr);
// create RTLIL code for this AST node // create RTLIL code for this AST node
// for expressions the resulting signal vector is returned // for expressions the resulting signal vector is returned
// all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module // all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module
RTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false); RTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false);
RTLIL::SigSpec genWidthRTLIL(int width, bool sgn, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = NULL); RTLIL::SigSpec genWidthRTLIL(int width, bool sgn, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = nullptr);
// compare AST nodes // compare AST nodes
bool operator==(const AstNode &other) const; bool operator==(const AstNode &other) const;
bool operator!=(const AstNode &other) const; bool operator!=(const AstNode &other) const;
bool contains(const AstNode *other) const; bool contains(const AstNode *other) const;
AstNode operator=(AstNode) = delete;
// helper functions for creating AST nodes for constants // helper functions for creating AST nodes for constants
static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32); static std::unique_ptr<AstNode> mkconst_int(AstSrcLocType loc, uint32_t v, bool is_signed, int width = 32);
static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized); static std::unique_ptr<AstNode> mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized);
static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed); static std::unique_ptr<AstNode> mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed);
static AstNode *mkconst_str(const std::vector<RTLIL::State> &v); static std::unique_ptr<AstNode> mkconst_str(AstSrcLocType loc, const std::vector<RTLIL::State> &v);
static AstNode *mkconst_str(const std::string &str); static std::unique_ptr<AstNode> mkconst_str(AstSrcLocType loc, const std::string &str);
// helper function to create an AST node for a temporary register // helper function to create an AST node for a temporary register
AstNode *mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed); std::unique_ptr<AstNode> mktemp_logic(AstSrcLocType loc, const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed);
// helper function for creating sign-extended const objects // helper function for creating sign-extended const objects
RTLIL::Const bitsAsConst(int width, bool is_signed); RTLIL::Const bitsAsConst(int width, bool is_signed);
@ -356,12 +353,12 @@ namespace AST
// helper to clone the node with some of its subexpressions replaced with zero (this is used // helper to clone the node with some of its subexpressions replaced with zero (this is used
// to evaluate widths of dynamic ranges) // to evaluate widths of dynamic ranges)
AstNode *clone_at_zero(); std::unique_ptr<AstNode> clone_at_zero();
void set_attribute(RTLIL::IdString key, AstNode *node) void set_attribute(RTLIL::IdString key, std::unique_ptr<AstNode> node)
{ {
attributes[key] = node;
node->set_in_param_flag(true); node->set_in_param_flag(true);
attributes[key] = std::move(node);
} }
// helper to set in_lvalue/in_param flags from the hierarchy context (the actual flag // helper to set in_lvalue/in_param flags from the hierarchy context (the actual flag
@ -377,7 +374,7 @@ namespace AST
void fixup_hierarchy_flags(bool force_descend = false); void fixup_hierarchy_flags(bool force_descend = false);
// helpers for indexing // helpers for indexing
AstNode *make_index_range(AstNode *node, bool unpacked_range = false); std::unique_ptr<AstNode> make_index_range(AstNode *node, bool unpacked_range = false);
AstNode *get_struct_member() const; AstNode *get_struct_member() const;
// helper to print errors from simplify/genrtlil code // helper to print errors from simplify/genrtlil code
@ -391,12 +388,11 @@ namespace AST
// parametric modules are supported directly by the AST library // parametric modules are supported directly by the AST library
// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions // therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
struct AstModule : RTLIL::Module { struct AstModule : RTLIL::Module {
AstNode *ast; std::unique_ptr<AstNode> ast;
bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, pwires, autowire; bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, pwires, autowire;
~AstModule() override;
RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, bool mayfail) override; RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, bool mayfail) override;
RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail) override; RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail) override;
std::string derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, AstNode **new_ast_out, bool quiet = false); std::string derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, std::unique_ptr<AstNode>* new_ast_out, bool quiet = false);
void expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces) override; void expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces) override;
bool reprocess_if_necessary(RTLIL::Design *design) override; bool reprocess_if_necessary(RTLIL::Design *design) override;
RTLIL::Module *clone() const override; RTLIL::Module *clone() const override;
@ -406,9 +402,9 @@ namespace AST
// this must be set by the language frontend before parsing the sources // this must be set by the language frontend before parsing the sources
// the AstNode constructor then uses current_filename and get_line_num() // the AstNode constructor then uses current_filename and get_line_num()
// to initialize the filename and linenum properties of new nodes // to initialize the filename and linenum properties of new nodes
extern std::string current_filename; // extern std::string current_filename;
extern void (*set_line_num)(int); // also set by the language frontend to control some AST processing
extern int (*get_line_num)(); extern bool sv_mode_but_global_and_used_for_literally_one_condition;
// for stats // for stats
unsigned long long astnode_count(); unsigned long long astnode_count();
@ -418,7 +414,7 @@ namespace AST
void use_internal_line_num(); void use_internal_line_num();
// call a DPI function // call a DPI function
AstNode *dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args); std::unique_ptr<AstNode> dpi_call(AstSrcLocType loc, const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<std::unique_ptr<AstNode>> &args);
// Helper functions related to handling SystemVerilog interfaces // Helper functions related to handling SystemVerilog interfaces
std::pair<std::string,std::string> split_modport_from_type(std::string name_type); std::pair<std::string,std::string> split_modport_from_type(std::string name_type);
@ -464,7 +460,7 @@ namespace AST_INTERNAL
process_and_replace_module(RTLIL::Design *design, process_and_replace_module(RTLIL::Design *design,
RTLIL::Module *old_module, RTLIL::Module *old_module,
AST::AstNode *new_ast, AST::AstNode *new_ast,
AST::AstNode *original_ast = nullptr); std::unique_ptr<AST::AstNode> original_ast = nullptr);
} }
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END

View file

@ -64,9 +64,9 @@ static ffi_fptr resolve_fn (std::string symbol_name)
log_error("unable to resolve '%s'.\n", symbol_name.c_str()); log_error("unable to resolve '%s'.\n", symbol_name.c_str());
} }
AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args) std::unique_ptr<AST::AstNode> AST::dpi_call(AstSrcLocType loc, const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<std::unique_ptr<AST::AstNode>> &args)
{ {
AST::AstNode *newNode = nullptr; std::unique_ptr<AST::AstNode> newNode = nullptr;
union value { double f64; float f32; int32_t i32; void *ptr; }; union value { double f64; float f32; int32_t i32; void *ptr; };
std::vector<value> value_store(args.size() + 1); std::vector<value> value_store(args.size() + 1);
std::vector<ffi_type *> types(args.size() + 1); std::vector<ffi_type *> types(args.size() + 1);
@ -125,11 +125,11 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values.data()); ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values.data());
if (rtype == "real") { if (rtype == "real") {
newNode = new AstNode(AST_REALVALUE); newNode = std::make_unique<AstNode>(loc, AST_REALVALUE);
newNode->realvalue = value_store[args.size()].f64; newNode->realvalue = value_store[args.size()].f64;
log(" return realvalue: %g\n", newNode->asReal(true)); log(" return realvalue: %g\n", newNode->asReal(true));
} else if (rtype == "shortreal") { } else if (rtype == "shortreal") {
newNode = new AstNode(AST_REALVALUE); newNode = std::make_unique<AstNode>(loc, AST_REALVALUE);
newNode->realvalue = value_store[args.size()].f32; newNode->realvalue = value_store[args.size()].f32;
log(" return realvalue: %g\n", newNode->asReal(true)); log(" return realvalue: %g\n", newNode->asReal(true));
} else if (rtype == "chandle") { } else if (rtype == "chandle") {
@ -137,10 +137,10 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
std::vector<RTLIL::State> bits(64); std::vector<RTLIL::State> bits(64);
for (int i = 0; i < 64; i++) for (int i = 0; i < 64; i++)
bits.at(i) = (rawval & (1ULL << i)) ? RTLIL::State::S1 : RTLIL::State::S0; bits.at(i) = (rawval & (1ULL << i)) ? RTLIL::State::S1 : RTLIL::State::S0;
newNode = AstNode::mkconst_bits(bits, false); newNode = AstNode::mkconst_bits(loc, bits, false);
log(" return chandle: %llx\n", (unsigned long long)newNode->asInt(false)); log(" return chandle: %llx\n", (unsigned long long)newNode->asInt(false));
} else { } else {
newNode = AstNode::mkconst_int(value_store[args.size()].i32, false); newNode = AstNode::mkconst_int(loc, value_store[args.size()].i32, false);
log(" return integer: %lld\n", (long long)newNode->asInt(true)); log(" return integer: %lld\n", (long long)newNode->asInt(true));
} }
@ -153,7 +153,7 @@ YOSYS_NAMESPACE_END
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
AST::AstNode *AST::dpi_call(const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<AstNode*>&) std::unique_ptr<AST::AstNode> AST::dpi_call(AstSrcLocType, const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<std::unique_ptr<AST::AstNode>>&)
{ {
log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str()); log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str());
} }

View file

@ -45,7 +45,7 @@ using namespace AST_INTERNAL;
// helper function for creating RTLIL code for unary operations // helper function for creating RTLIL code for unary operations
static RTLIL::SigSpec uniop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &arg, bool gen_attributes = true) static RTLIL::SigSpec uniop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &arg, bool gen_attributes = true)
{ {
IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++); IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++);
RTLIL::Cell *cell = current_module->addCell(name, type); RTLIL::Cell *cell = current_module->addCell(name, type);
set_src_attr(cell, that); set_src_attr(cell, that);
@ -77,7 +77,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
return; return;
} }
IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++); IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++);
RTLIL::Cell *cell = current_module->addCell(name, ID($pos)); RTLIL::Cell *cell = current_module->addCell(name, ID($pos));
set_src_attr(cell, that); set_src_attr(cell, that);
@ -85,7 +85,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
set_src_attr(wire, that); set_src_attr(wire, that);
wire->is_signed = that->is_signed; wire->is_signed = that->is_signed;
if (that != NULL) if (that != nullptr)
for (auto &attr : that->attributes) { for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT) if (attr.second->type != AST_CONSTANT)
that->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str()); that->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str());
@ -104,7 +104,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
// helper function for creating RTLIL code for binary operations // helper function for creating RTLIL code for binary operations
static RTLIL::SigSpec binop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) static RTLIL::SigSpec binop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
{ {
IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++); IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++);
RTLIL::Cell *cell = current_module->addCell(name, type); RTLIL::Cell *cell = current_module->addCell(name, type);
set_src_attr(cell, that); set_src_attr(cell, that);
@ -138,7 +138,7 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const
log_assert(cond.size() == 1); log_assert(cond.size() == 1);
std::stringstream sstr; std::stringstream sstr;
sstr << "$ternary$" << RTLIL::encode_filename(that->filename) << ":" << that->location.first_line << "$" << (autoidx++); sstr << "$ternary$" << RTLIL::encode_filename(*that->location.begin.filename) << ":" << that->location.begin.line << "$" << (autoidx++);
RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($mux)); RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($mux));
set_src_attr(cell, that); set_src_attr(cell, that);
@ -195,22 +195,22 @@ struct AST_INTERNAL::LookaheadRewriter
if (node->lookahead) { if (node->lookahead) {
log_assert(node->type == AST_IDENTIFIER); log_assert(node->type == AST_IDENTIFIER);
if (!lookaheadids.count(node->str)) { if (!lookaheadids.count(node->str)) {
AstNode *wire = new AstNode(AST_WIRE); auto wire = std::make_unique<AstNode>(node->location, AST_WIRE);
for (auto c : node->id2ast->children) for (auto& c : node->id2ast->children)
wire->children.push_back(c->clone()); wire->children.push_back(c->clone());
wire->fixup_hierarchy_flags(); wire->fixup_hierarchy_flags();
wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++); wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++);
wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire->set_attribute(ID::nosync, AstNode::mkconst_int(node->location, 1, false));
wire->is_logic = true; wire->is_logic = true;
while (wire->simplify(true, 1, -1, false)) { } while (wire->simplify(true, 1, -1, false)) { }
current_ast_mod->children.push_back(wire); lookaheadids[node->str] = make_pair(node->id2ast, wire.get());
lookaheadids[node->str] = make_pair(node->id2ast, wire);
wire->genRTLIL(); wire->genRTLIL();
current_ast_mod->children.push_back(std::move(wire));
} }
} }
for (auto child : node->children) for (auto& child : node->children)
collect_lookaheadids(child); collect_lookaheadids(child.get());
} }
bool has_lookaheadids(AstNode *node) bool has_lookaheadids(AstNode *node)
@ -218,8 +218,8 @@ struct AST_INTERNAL::LookaheadRewriter
if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) != 0) if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) != 0)
return true; return true;
for (auto child : node->children) for (auto& child : node->children)
if (has_lookaheadids(child)) if (has_lookaheadids(child.get()))
return true; return true;
return false; return false;
@ -230,8 +230,8 @@ struct AST_INTERNAL::LookaheadRewriter
if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) == 0) if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) == 0)
return true; return true;
for (auto child : node->children) for (auto& child : node->children)
if (has_nonlookaheadids(child)) if (has_nonlookaheadids(child.get()))
return true; return true;
return false; return false;
@ -241,16 +241,16 @@ struct AST_INTERNAL::LookaheadRewriter
{ {
if (node->type == AST_ASSIGN_LE) if (node->type == AST_ASSIGN_LE)
{ {
if (has_lookaheadids(node->children[0])) if (has_lookaheadids(node->children[0].get()))
{ {
if (has_nonlookaheadids(node->children[0])) if (has_nonlookaheadids(node->children[0].get()))
log_error("incompatible mix of lookahead and non-lookahead IDs in LHS expression.\n"); log_error("incompatible mix of lookahead and non-lookahead IDs in LHS expression.\n");
rewrite_lookaheadids(node->children[0], true); rewrite_lookaheadids(node->children[0].get(), true);
node->type = AST_ASSIGN_EQ; node->type = AST_ASSIGN_EQ;
} }
rewrite_lookaheadids(node->children[1], lhs); rewrite_lookaheadids(node->children[1].get(), lhs);
return; return;
} }
@ -261,21 +261,22 @@ struct AST_INTERNAL::LookaheadRewriter
lhs = false; lhs = false;
} }
for (auto child : node->children) for (auto& child : node->children)
rewrite_lookaheadids(child, lhs); rewrite_lookaheadids(child.get(), lhs);
} }
LookaheadRewriter(AstNode *top) LookaheadRewriter(AstNode *top)
{ {
// top->dumpAst(NULL, "REWRITE-BEFORE> "); // top->dumpAst(nullptr, "REWRITE-BEFORE> ");
// top->dumpVlog(NULL, "REWRITE-BEFORE> "); // top->dumpVlog(nullptr, "REWRITE-BEFORE> ");
AstNode *block = nullptr; AstNode *block = nullptr;
auto loc = top->location;
for (auto c : top->children) for (auto& c : top->children)
if (c->type == AST_BLOCK) { if (c->type == AST_BLOCK) {
log_assert(block == nullptr); log_assert(block == nullptr);
block = c; block = c.get();
} }
log_assert(block != nullptr); log_assert(block != nullptr);
@ -284,25 +285,25 @@ struct AST_INTERNAL::LookaheadRewriter
for (auto it : lookaheadids) for (auto it : lookaheadids)
{ {
AstNode *ref_orig = new AstNode(AST_IDENTIFIER); auto ref_orig = std::make_unique<AstNode>(loc, AST_IDENTIFIER);
ref_orig->str = it.second.first->str; ref_orig->str = it.second.first->str;
ref_orig->id2ast = it.second.first; ref_orig->id2ast = it.second.first;
ref_orig->was_checked = true; ref_orig->was_checked = true;
AstNode *ref_temp = new AstNode(AST_IDENTIFIER); auto ref_temp = std::make_unique<AstNode>(loc, AST_IDENTIFIER);
ref_temp->str = it.second.second->str; ref_temp->str = it.second.second->str;
ref_temp->id2ast = it.second.second; ref_temp->id2ast = it.second.second;
ref_temp->was_checked = true; ref_temp->was_checked = true;
AstNode *init_assign = new AstNode(AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone()); auto init_assign = std::make_unique<AstNode>(loc, AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone());
AstNode *final_assign = new AstNode(AST_ASSIGN_LE, ref_orig, ref_temp); auto final_assign = std::make_unique<AstNode>(loc, AST_ASSIGN_LE, std::move(ref_orig), std::move(ref_temp));
block->children.insert(block->children.begin(), init_assign); block->children.insert(block->children.begin(), std::move(init_assign));
block->children.push_back(final_assign); block->children.push_back(std::move(final_assign));
} }
// top->dumpAst(NULL, "REWRITE-AFTER> "); // top->dumpAst(nullptr, "REWRITE-AFTER> ");
// top->dumpVlog(NULL, "REWRITE-AFTER> "); // top->dumpVlog(nullptr, "REWRITE-AFTER> ");
} }
}; };
@ -310,7 +311,7 @@ struct AST_INTERNAL::LookaheadRewriter
struct AST_INTERNAL::ProcessGenerator struct AST_INTERNAL::ProcessGenerator
{ {
// input and output structures // input and output structures
AstNode *always; std::unique_ptr<AstNode> always;
RTLIL::SigSpec initSyncSignals; RTLIL::SigSpec initSyncSignals;
RTLIL::Process *proc; RTLIL::Process *proc;
RTLIL::SigSpec outputSignals; RTLIL::SigSpec outputSignals;
@ -341,14 +342,14 @@ struct AST_INTERNAL::ProcessGenerator
// The most recently assigned $print or $check cell \PRIORITY. // The most recently assigned $print or $check cell \PRIORITY.
int last_effect_priority; int last_effect_priority;
ProcessGenerator(AstNode *always, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(always), initSyncSignals(initSyncSignalsArg), last_effect_priority(0) ProcessGenerator(std::unique_ptr<AstNode> a, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(std::move(a)), initSyncSignals(initSyncSignalsArg), last_effect_priority(0)
{ {
// rewrite lookahead references // rewrite lookahead references
LookaheadRewriter la_rewriter(always); LookaheadRewriter la_rewriter(always.get());
// generate process and simple root case // generate process and simple root case
proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(always->filename).c_str(), always->location.first_line, autoidx++)); proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(*always->location.begin.filename).c_str(), always->location.begin.line, autoidx++));
set_src_attr(proc, always); set_src_attr(proc, always.get());
for (auto &attr : always->attributes) { for (auto &attr : always->attributes) {
if (attr.second->type != AST_CONSTANT) if (attr.second->type != AST_CONSTANT)
always->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str()); always->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str());
@ -358,13 +359,13 @@ struct AST_INTERNAL::ProcessGenerator
// create initial temporary signal for all output registers // create initial temporary signal for all output registers
RTLIL::SigSpec subst_lvalue_from, subst_lvalue_to; RTLIL::SigSpec subst_lvalue_from, subst_lvalue_to;
collect_lvalues(subst_lvalue_from, always, true, true); collect_lvalues(subst_lvalue_from, always.get(), true, true);
subst_lvalue_to = new_temp_signal(subst_lvalue_from); subst_lvalue_to = new_temp_signal(subst_lvalue_from);
subst_lvalue_map = subst_lvalue_from.to_sigbit_map(subst_lvalue_to); subst_lvalue_map = subst_lvalue_from.to_sigbit_map(subst_lvalue_to);
bool found_global_syncs = false; bool found_global_syncs = false;
bool found_anyedge_syncs = false; bool found_anyedge_syncs = false;
for (auto child : always->children) for (auto& child : always->children)
{ {
if ((child->type == AST_POSEDGE || child->type == AST_NEGEDGE) && GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && if ((child->type == AST_POSEDGE || child->type == AST_NEGEDGE) && GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER &&
child->children.at(0)->id2ast && child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute(ID::gclk)) { child->children.at(0)->id2ast && child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute(ID::gclk)) {
@ -388,7 +389,7 @@ struct AST_INTERNAL::ProcessGenerator
// create syncs for the process // create syncs for the process
bool found_clocked_sync = false; bool found_clocked_sync = false;
for (auto child : always->children) for (auto& child : always->children)
if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) { if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) {
if (GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && child->children.at(0)->id2ast && if (GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && child->children.at(0)->id2ast &&
child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute(ID::gclk)) child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute(ID::gclk))
@ -420,9 +421,9 @@ struct AST_INTERNAL::ProcessGenerator
} }
// process the AST // process the AST
for (auto child : always->children) for (auto& child : always->children)
if (child->type == AST_BLOCK) if (child->type == AST_BLOCK)
processAst(child); processAst(child.get());
for (auto sync: proc->syncs) for (auto sync: proc->syncs)
processMemWrites(sync); processMemWrites(sync);
@ -472,7 +473,7 @@ struct AST_INTERNAL::ProcessGenerator
for (int i = 0; i < GetSize(chunks); i++) for (int i = 0; i < GetSize(chunks); i++)
{ {
RTLIL::SigChunk &chunk = chunks[i]; RTLIL::SigChunk &chunk = chunks[i];
if (chunk.wire == NULL) if (chunk.wire == nullptr)
continue; continue;
std::string wire_name; std::string wire_name;
@ -484,7 +485,7 @@ struct AST_INTERNAL::ProcessGenerator
} while (current_module->wires_.count(wire_name) > 0); } while (current_module->wires_.count(wire_name) > 0);
RTLIL::Wire *wire = current_module->addWire(wire_name, chunk.width); RTLIL::Wire *wire = current_module->addWire(wire_name, chunk.width);
set_src_attr(wire, always); set_src_attr(wire, always.get());
chunk.wire = wire; chunk.wire = wire;
chunk.offset = 0; chunk.offset = 0;
@ -499,10 +500,10 @@ struct AST_INTERNAL::ProcessGenerator
switch (ast->type) switch (ast->type)
{ {
case AST_CASE: case AST_CASE:
for (auto child : ast->children) for (auto& child : ast->children)
if (child != ast->children[0]) { if (child != ast->children[0]) {
log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ); log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ);
collect_lvalues(reg, child, type_eq, type_le, false); collect_lvalues(reg, child.get(), type_eq, type_le, false);
} }
break; break;
@ -511,19 +512,19 @@ struct AST_INTERNAL::ProcessGenerator
case AST_CONDZ: case AST_CONDZ:
case AST_ALWAYS: case AST_ALWAYS:
case AST_INITIAL: case AST_INITIAL:
for (auto child : ast->children) for (auto& child : ast->children)
if (child->type == AST_BLOCK) if (child->type == AST_BLOCK)
collect_lvalues(reg, child, type_eq, type_le, false); collect_lvalues(reg, child.get(), type_eq, type_le, false);
break; break;
case AST_BLOCK: case AST_BLOCK:
for (auto child : ast->children) { for (auto& child : ast->children) {
if (child->type == AST_ASSIGN_EQ && type_eq) if (child->type == AST_ASSIGN_EQ && type_eq)
reg.append(child->children[0]->genRTLIL()); reg.append(child->children[0]->genRTLIL());
if (child->type == AST_ASSIGN_LE && type_le) if (child->type == AST_ASSIGN_LE && type_le)
reg.append(child->children[0]->genRTLIL()); reg.append(child->children[0]->genRTLIL());
if (child->type == AST_CASE || child->type == AST_BLOCK) if (child->type == AST_CASE || child->type == AST_BLOCK)
collect_lvalues(reg, child, type_eq, type_le, false); collect_lvalues(reg, child.get(), type_eq, type_le, false);
} }
break; break;
@ -583,8 +584,8 @@ struct AST_INTERNAL::ProcessGenerator
switch (ast->type) switch (ast->type)
{ {
case AST_BLOCK: case AST_BLOCK:
for (auto child : ast->children) for (auto& child : ast->children)
processAst(child); processAst(child.get());
break; break;
case AST_ASSIGN_EQ: case AST_ASSIGN_EQ:
@ -641,9 +642,9 @@ struct AST_INTERNAL::ProcessGenerator
RTLIL::SigSpec this_case_eq_rvalue = this_case_eq_lvalue; RTLIL::SigSpec this_case_eq_rvalue = this_case_eq_lvalue;
this_case_eq_rvalue.replace(subst_rvalue_map.stdmap()); this_case_eq_rvalue.replace(subst_rvalue_map.stdmap());
RTLIL::CaseRule *default_case = NULL; RTLIL::CaseRule *default_case = nullptr;
RTLIL::CaseRule *last_generated_case = NULL; RTLIL::CaseRule *last_generated_case = nullptr;
for (auto child : ast->children) for (auto& child : ast->children)
{ {
if (child == ast->children[0]) if (child == ast->children[0])
continue; continue;
@ -657,14 +658,14 @@ struct AST_INTERNAL::ProcessGenerator
RTLIL::CaseRule *backup_case = current_case; RTLIL::CaseRule *backup_case = current_case;
current_case = new RTLIL::CaseRule; current_case = new RTLIL::CaseRule;
set_src_attr(current_case, child); set_src_attr(current_case, child.get());
last_generated_case = current_case; last_generated_case = current_case;
addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue); addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);
for (auto node : child->children) { for (auto& node : child->children) {
if (node->type == AST_DEFAULT) if (node->type == AST_DEFAULT)
default_case = current_case; default_case = current_case;
else if (node->type == AST_BLOCK) else if (node->type == AST_BLOCK)
processAst(node); processAst(node.get());
else else
current_case->compare.push_back(node->genWidthRTLIL(width_hint, sign_hint, &subst_rvalue_map.stdmap())); current_case->compare.push_back(node->genWidthRTLIL(width_hint, sign_hint, &subst_rvalue_map.stdmap()));
} }
@ -678,7 +679,7 @@ struct AST_INTERNAL::ProcessGenerator
subst_rvalue_map.restore(); subst_rvalue_map.restore();
} }
if (last_generated_case != NULL && ast->get_bool_attribute(ID::full_case) && default_case == NULL) { if (last_generated_case != nullptr && ast->get_bool_attribute(ID::full_case) && default_case == nullptr) {
#if 0 #if 0
// this is a valid transformation, but as optimization it is premature. // this is a valid transformation, but as optimization it is premature.
// better: add a default case that assigns 'x' to everything, and let later // better: add a default case that assigns 'x' to everything, and let later
@ -690,7 +691,7 @@ struct AST_INTERNAL::ProcessGenerator
sw->cases.push_back(default_case); sw->cases.push_back(default_case);
#endif #endif
} else { } else {
if (default_case == NULL) { if (default_case == nullptr) {
default_case = new RTLIL::CaseRule; default_case = new RTLIL::CaseRule;
addChunkActions(default_case->actions, this_case_eq_ltemp, this_case_eq_rvalue); addChunkActions(default_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);
} }
@ -723,7 +724,7 @@ struct AST_INTERNAL::ProcessGenerator
if (ast->str == "$display" || ast->str == "$displayb" || ast->str == "$displayh" || ast->str == "$displayo" || if (ast->str == "$display" || ast->str == "$displayb" || ast->str == "$displayh" || ast->str == "$displayo" ||
ast->str == "$write" || ast->str == "$writeb" || ast->str == "$writeh" || ast->str == "$writeo") { ast->str == "$write" || ast->str == "$writeb" || ast->str == "$writeh" || ast->str == "$writeo") {
std::stringstream sstr; std::stringstream sstr;
sstr << ast->str << "$" << ast->filename << ":" << ast->location.first_line << "$" << (autoidx++); sstr << ast->str << "$" << ast->location.begin.filename << ":" << ast->location.begin.line << "$" << (autoidx++);
Wire *en = current_module->addWire(sstr.str() + "_EN", 1); Wire *en = current_module->addWire(sstr.str() + "_EN", 1);
set_src_attr(en, ast); set_src_attr(en, ast);
@ -760,14 +761,14 @@ struct AST_INTERNAL::ProcessGenerator
default_base = 16; default_base = 16;
std::vector<VerilogFmtArg> args; std::vector<VerilogFmtArg> args;
for (auto node : ast->children) { for (auto& node : ast->children) {
int width; int width;
bool is_signed; bool is_signed;
node->detectSignWidth(width, is_signed, nullptr); node->detectSignWidth(width, is_signed, nullptr);
VerilogFmtArg arg = {}; VerilogFmtArg arg = {};
arg.filename = node->filename; arg.filename = *node->location.begin.filename;
arg.first_line = node->location.first_line; arg.first_line = node->location.begin.line;
if (node->type == AST_CONSTANT && node->is_string) { if (node->type == AST_CONSTANT && node->is_string) {
arg.type = VerilogFmtArg::STRING; arg.type = VerilogFmtArg::STRING;
arg.str = node->bitsAsConst().decode_string(); arg.str = node->bitsAsConst().decode_string();
@ -793,7 +794,7 @@ struct AST_INTERNAL::ProcessGenerator
fmt.append_literal("\n"); fmt.append_literal("\n");
fmt.emit_rtlil(cell); fmt.emit_rtlil(cell);
} else if (!ast->str.empty()) { } else if (!ast->str.empty()) {
log_file_error(ast->filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str()); log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str());
} }
break; break;
@ -813,7 +814,7 @@ struct AST_INTERNAL::ProcessGenerator
IdString cellname; IdString cellname;
if (ast->str.empty()) if (ast->str.empty())
cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(ast->filename).c_str(), ast->location.first_line, autoidx++); cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(*ast->location.begin.filename).c_str(), ast->location.begin.line, autoidx++);
else else
cellname = ast->str; cellname = ast->str;
check_unique_id(current_module, cellname, ast, "procedural assertion"); check_unique_id(current_module, cellname, ast, "procedural assertion");
@ -843,7 +844,7 @@ struct AST_INTERNAL::ProcessGenerator
set_src_attr(cell, ast); set_src_attr(cell, ast);
for (auto &attr : ast->attributes) { for (auto &attr : ast->attributes) {
if (attr.second->type != AST_CONSTANT) if (attr.second->type != AST_CONSTANT)
log_file_error(ast->filename, ast->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst(); cell->attributes[attr.first] = attr.second->asAttrConst();
} }
cell->setParam(ID::FLAVOR, flavor); cell->setParam(ID::FLAVOR, flavor);
@ -866,8 +867,8 @@ struct AST_INTERNAL::ProcessGenerator
break; break;
default: default:
// ast->dumpAst(NULL, "ast> "); // ast->dumpAst(nullptr, "ast> ");
// current_ast_mod->dumpAst(NULL, "mod> "); // current_ast_mod->dumpAst(nullptr, "mod> ");
log_abort(); log_abort();
} }
} }
@ -876,14 +877,14 @@ struct AST_INTERNAL::ProcessGenerator
{ {
// Maps per-memid AST_MEMWR IDs to indices in the mem_write_actions array. // Maps per-memid AST_MEMWR IDs to indices in the mem_write_actions array.
dict<std::pair<std::string, int>, int> port_map; dict<std::pair<std::string, int>, int> port_map;
for (auto child : always->children) for (auto& child : always->children)
if (child->type == AST_MEMWR) if (child->type == AST_MEMWR)
{ {
std::string memid = child->str; std::string memid = child->str;
int portid = child->children[3]->asInt(false); int portid = child->children[3]->asInt(false);
int cur_idx = GetSize(sync->mem_write_actions); int cur_idx = GetSize(sync->mem_write_actions);
RTLIL::MemWriteAction action; RTLIL::MemWriteAction action;
set_src_attr(&action, child); set_src_attr(&action, child.get());
action.memid = memid; action.memid = memid;
action.address = child->children[0]->genWidthRTLIL(-1, true, &subst_rvalue_map.stdmap()); action.address = child->children[0]->genWidthRTLIL(-1, true, &subst_rvalue_map.stdmap());
action.data = child->children[1]->genWidthRTLIL(current_module->memories[memid]->width, true, &subst_rvalue_map.stdmap()); action.data = child->children[1]->genWidthRTLIL(current_module->memories[memid]->width, true, &subst_rvalue_map.stdmap());
@ -971,11 +972,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
bool sub_sign_hint = true; bool sub_sign_hint = true;
int sub_width_hint = -1; int sub_width_hint = -1;
int this_width = 0; int this_width = 0;
AstNode *range = NULL; AstNode *range = nullptr;
AstNode *id_ast = NULL; AstNode *id_ast = nullptr;
bool local_found_real = false; bool local_found_real = false;
if (found_real == NULL) if (found_real == nullptr)
found_real = &local_found_real; found_real = &local_found_real;
switch (type) switch (type)
@ -1019,22 +1020,22 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
input_error("Failed to detect width for parameter %s!\n", str.c_str()); input_error("Failed to detect width for parameter %s!\n", str.c_str());
} }
if (children.size() != 0) if (children.size() != 0)
range = children[0]; range = children[0].get();
} else if (id_ast->type == AST_WIRE || id_ast->type == AST_AUTOWIRE) { } else if (id_ast->type == AST_WIRE || id_ast->type == AST_AUTOWIRE) {
if (!id_ast->range_valid) { if (!id_ast->range_valid) {
if (id_ast->type == AST_AUTOWIRE) if (id_ast->type == AST_AUTOWIRE)
this_width = 1; this_width = 1;
else { else {
// current_ast_mod->dumpAst(NULL, "mod> "); // current_ast_mod->dumpAst(nullptr, "mod> ");
// log("---\n"); // log("---\n");
// id_ast->dumpAst(NULL, "decl> "); // id_ast->dumpAst(nullptr, "decl> ");
// dumpAst(NULL, "ref> "); // dumpAst(nullptr, "ref> ");
input_error("Failed to detect width of signal access `%s'!\n", str.c_str()); input_error("Failed to detect width of signal access `%s'!\n", str.c_str());
} }
} else { } else {
this_width = id_ast->range_left - id_ast->range_right + 1; this_width = id_ast->range_left - id_ast->range_right + 1;
if (children.size() != 0) if (children.size() != 0)
range = children[0]; range = children[0].get();
} }
} else if (id_ast->type == AST_GENVAR) { } else if (id_ast->type == AST_GENVAR) {
this_width = 32; this_width = 32;
@ -1043,26 +1044,23 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
input_error("Failed to detect width of memory access `%s'!\n", str.c_str()); input_error("Failed to detect width of memory access `%s'!\n", str.c_str());
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1; this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
if (children.size() > 1) if (children.size() > 1)
range = children[1]; range = children[1].get();
} else if (id_ast->type == AST_STRUCT_ITEM || id_ast->type == AST_STRUCT || id_ast->type == AST_UNION) { } else if (id_ast->type == AST_STRUCT_ITEM || id_ast->type == AST_STRUCT || id_ast->type == AST_UNION) {
AstNode *tmp_range = make_index_range(id_ast); auto tmp_range = make_index_range(id_ast);
this_width = tmp_range->range_left - tmp_range->range_right + 1; this_width = tmp_range->range_left - tmp_range->range_right + 1;
delete tmp_range;
} else } else
input_error("Failed to detect width for identifier %s!\n", str.c_str()); input_error("Failed to detect width for identifier %s!\n", str.c_str());
if (range) { if (range) {
if (range->children.size() == 1) if (range->children.size() == 1)
this_width = 1; this_width = 1;
else if (!range->range_valid) { else if (!range->range_valid) {
AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero(); auto left_at_zero_ast = children[0]->children[0]->clone_at_zero();
AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone(); auto right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone();
while (left_at_zero_ast->simplify(true, 1, -1, false)) { } while (left_at_zero_ast->simplify(true, 1, -1, false)) { }
while (right_at_zero_ast->simplify(true, 1, -1, false)) { } while (right_at_zero_ast->simplify(true, 1, -1, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
delete left_at_zero_ast;
delete right_at_zero_ast;
} else } else
this_width = range->range_left - range->range_right + 1; this_width = range->range_left - range->range_right + 1;
sign_hint = false; sign_hint = false;
@ -1106,7 +1104,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
break; break;
case AST_CONCAT: case AST_CONCAT:
for (auto child : children) { for (auto& child : children) {
sub_width_hint = 0; sub_width_hint = 0;
sub_sign_hint = true; sub_sign_hint = true;
child->detectSignWidthWorker(sub_width_hint, sub_sign_hint); child->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
@ -1135,7 +1133,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_BIT_OR: case AST_BIT_OR:
case AST_BIT_XOR: case AST_BIT_XOR:
case AST_BIT_XNOR: case AST_BIT_XNOR:
for (auto child : children) for (auto& child : children)
child->detectSignWidthWorker(width_hint, sign_hint, found_real); child->detectSignWidthWorker(width_hint, sign_hint, found_real);
break; break;
@ -1175,7 +1173,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_MUL: case AST_MUL:
case AST_DIV: case AST_DIV:
case AST_MOD: case AST_MOD:
for (auto child : children) for (auto& child : children)
child->detectSignWidthWorker(width_hint, sign_hint, found_real); child->detectSignWidthWorker(width_hint, sign_hint, found_real);
break; break;
@ -1216,12 +1214,13 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
width_hint = max(width_hint, sub_width_hint); width_hint = max(width_hint, sub_width_hint);
sign_hint &= sub_sign_hint; sign_hint &= sub_sign_hint;
}; };
visit_case_expr(children[0]); visit_case_expr(children[0].get());
for (size_t i = 1; i < children.size(); i++) { for (size_t i = 1; i < children.size(); i++) {
AstNode *child = children[i]; AstNode *child = children[i].get();
for (AstNode *v : child->children) for (auto& v : child->children) {
if (v->type != AST_DEFAULT && v->type != AST_BLOCK) if (v->type != AST_DEFAULT && v->type != AST_BLOCK)
visit_case_expr(v); visit_case_expr(v.get());
}
} }
break; break;
} }
@ -1269,9 +1268,9 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (func->type != AST_FUNCTION) if (func->type != AST_FUNCTION)
input_error("Function call to %s resolved to something that isn't a function!\n", RTLIL::unescape_id(str).c_str()); input_error("Function call to %s resolved to something that isn't a function!\n", RTLIL::unescape_id(str).c_str());
const AstNode *wire = nullptr; const AstNode *wire = nullptr;
for (const AstNode *child : func->children) for (const auto& child : func->children)
if (child->str == func->str) { if (child->str == func->str) {
wire = child; wire = child.get();
break; break;
} }
log_assert(wire && wire->type == AST_WIRE); log_assert(wire && wire->type == AST_WIRE);
@ -1280,10 +1279,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (!wire->children.empty()) if (!wire->children.empty())
{ {
log_assert(wire->children.size() == 1); log_assert(wire->children.size() == 1);
const AstNode *range = wire->children.at(0); const AstNode *range = wire->children.at(0).get();
log_assert(range->type == AST_RANGE && range->children.size() == 2); log_assert(range->type == AST_RANGE && range->children.size() == 2);
AstNode *left = range->children.at(0)->clone(); auto left = range->children.at(0)->clone();
AstNode *right = range->children.at(1)->clone(); auto right = range->children.at(1)->clone();
left->set_in_param_flag(true); left->set_in_param_flag(true);
right->set_in_param_flag(true); right->set_in_param_flag(true);
while (left->simplify(true, 1, -1, false)) { } while (left->simplify(true, 1, -1, false)) { }
@ -1292,8 +1291,6 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
input_error("Function %s has non-constant width!", input_error("Function %s has non-constant width!",
RTLIL::unescape_id(str).c_str()); RTLIL::unescape_id(str).c_str());
result_width = abs(int(left->asInt(true) - right->asInt(true))); result_width = abs(int(left->asInt(true) - right->asInt(true)));
delete left;
delete right;
} }
width_hint = max(width_hint, result_width); width_hint = max(width_hint, result_width);
break; break;
@ -1306,6 +1303,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
for (auto f : log_files) for (auto f : log_files)
current_scope_ast->dumpAst(f, "verilog-ast> "); current_scope_ast->dumpAst(f, "verilog-ast> ");
input_error("Don't know how to detect sign and width for %s node!\n", type2str(type).c_str()); input_error("Don't know how to detect sign and width for %s node!\n", type2str(type).c_str());
} }
if (*found_real) if (*found_real)
@ -1342,8 +1340,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// be instantiated for this type of AST node. // be instantiated for this type of AST node.
IdString type_name; IdString type_name;
current_filename = filename;
switch (type) switch (type)
{ {
// simply ignore this nodes. // simply ignore this nodes.
@ -1508,7 +1504,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
} }
RTLIL::SigSpec sig = realAsConst(width_hint); RTLIL::SigSpec sig = realAsConst(width_hint);
log_file_warning(filename, location.first_line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig)); log_file_warning(*location.begin.filename, location.begin.line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));
return sig; return sig;
} }
@ -1517,11 +1513,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// shifter cell is created and the output signal of this cell is returned // shifter cell is created and the output signal of this cell is returned
case AST_IDENTIFIER: case AST_IDENTIFIER:
{ {
RTLIL::Wire *wire = NULL; RTLIL::Wire *wire = nullptr;
RTLIL::SigChunk chunk; RTLIL::SigChunk chunk;
bool is_interface = false; bool is_interface = false;
AST::AstNode *member_node = NULL; AST::AstNode *member_node = nullptr;
int add_undef_bits_msb = 0; int add_undef_bits_msb = 0;
int add_undef_bits_lsb = 0; int add_undef_bits_lsb = 0;
@ -1540,7 +1536,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (dynamic_cast<RTLIL::Binding*>(current_module)) { if (dynamic_cast<RTLIL::Binding*>(current_module)) {
/* nothing to do here */ /* nothing to do here */
} else if (flag_autowire) } else if (flag_autowire)
log_file_warning(filename, location.first_line, "Identifier `%s' is implicitly declared.\n", str.c_str()); log_file_warning(*location.begin.filename, location.begin.line, "Identifier `%s' is implicitly declared.\n", str.c_str());
else else
input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str());
} }
@ -1608,14 +1604,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
} }
if (!children[0]->range_valid) { if (!children[0]->range_valid) {
AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero(); auto left_at_zero_ast = children[0]->children[0]->clone_at_zero();
AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone(); auto right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone();
while (left_at_zero_ast->simplify(true, 1, -1, false)) { } while (left_at_zero_ast->simplify(true, 1, -1, false)) { }
while (right_at_zero_ast->simplify(true, 1, -1, false)) { } while (right_at_zero_ast->simplify(true, 1, -1, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ? auto fake_ast = std::make_unique<AstNode>(children[0]->location, AST_NONE, clone(), children[0]->children.size() >= 2 ?
children[0]->children[1]->clone() : children[0]->children[0]->clone()); children[0]->children[1]->clone() : children[0]->children[0]->clone());
fake_ast->children[0]->delete_children(); fake_ast->children[0]->delete_children();
if (member_node) if (member_node)
@ -1636,10 +1632,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
} }
if (GetSize(shift_val) >= 32) if (GetSize(shift_val) >= 32)
fake_ast->children[1]->is_signed = true; fake_ast->children[1]->is_signed = true;
RTLIL::SigSpec sig = binop2rtlil(fake_ast, ID($shiftx), width, fake_ast->children[0]->genRTLIL(), shift_val); RTLIL::SigSpec sig = binop2rtlil(fake_ast.get(), ID($shiftx), width, fake_ast->children[0]->genRTLIL(), shift_val);
delete left_at_zero_ast;
delete right_at_zero_ast;
delete fake_ast;
return sig; return sig;
} else { } else {
chunk.width = children[0]->range_left - children[0]->range_right + 1; chunk.width = children[0]->range_left - children[0]->range_right + 1;
@ -1648,10 +1641,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk.offset = source_width - (chunk.offset + chunk.width); chunk.offset = source_width - (chunk.offset + chunk.width);
if (chunk.offset > chunk_left || chunk.offset + chunk.width < chunk_right) { if (chunk.offset > chunk_left || chunk.offset + chunk.width < chunk_right) {
if (chunk.width == 1) if (chunk.width == 1)
log_file_warning(filename, location.first_line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n", log_file_warning(*location.begin.filename, location.begin.line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n",
str.c_str()); str.c_str());
else else
log_file_warning(filename, location.first_line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n", log_file_warning(*location.begin.filename, location.begin.line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n",
children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width); children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width);
chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width); chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);
} else { } else {
@ -1665,10 +1658,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk.offset += add_undef_bits_lsb; chunk.offset += add_undef_bits_lsb;
} }
if (add_undef_bits_lsb) if (add_undef_bits_lsb)
log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", log_file_warning(*location.begin.filename, location.begin.line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n",
children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb); children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb);
if (add_undef_bits_msb) if (add_undef_bits_msb)
log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", log_file_warning(*location.begin.filename, location.begin.line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n",
children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb); children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb);
} }
} }
@ -1942,7 +1935,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_MEMRD: case AST_MEMRD:
{ {
std::stringstream sstr; std::stringstream sstr;
sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++);
RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($memrd)); RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($memrd));
set_src_attr(cell, this); set_src_attr(cell, this);
@ -1980,7 +1973,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_MEMINIT: case AST_MEMINIT:
{ {
std::stringstream sstr; std::stringstream sstr;
sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++);
SigSpec en_sig = children[2]->genRTLIL(); SigSpec en_sig = children[2]->genRTLIL();
@ -2025,7 +2018,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
IdString cellname; IdString cellname;
if (str.empty()) if (str.empty())
cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line, autoidx++);
else else
cellname = str; cellname = str;
check_unique_id(current_module, cellname, this, "procedural assertion"); check_unique_id(current_module, cellname, this, "procedural assertion");
@ -2068,7 +2061,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
new_left.append(left[i]); new_left.append(left[i]);
new_right.append(right[i]); new_right.append(right[i]);
} }
log_file_warning(filename, location.first_line, "Ignoring assignment to constant bits:\n" log_file_warning(*location.begin.filename, location.begin.line, "Ignoring assignment to constant bits:\n"
" old assignment: %s = %s\n new assignment: %s = %s.\n", " old assignment: %s = %s\n new assignment: %s = %s.\n",
log_signal(left), log_signal(right), log_signal(left), log_signal(right),
log_signal(new_left), log_signal(new_right)); log_signal(new_left), log_signal(new_right));
@ -2092,7 +2085,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
cell->set_bool_attribute(ID::module_not_derived); cell->set_bool_attribute(ID::module_not_derived);
for (auto it = children.begin(); it != children.end(); it++) { for (auto it = children.begin(); it != children.end(); it++) {
AstNode *child = *it; AstNode *child = it->get();
if (child->type == AST_CELLTYPE) { if (child->type == AST_CELLTYPE) {
cell->type = child->str; cell->type = child->str;
if (flag_icells && cell->type.begins_with("\\$")) if (flag_icells && cell->type.begins_with("\\$"))
@ -2101,9 +2094,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
} }
if (child->type == AST_PARASET) { if (child->type == AST_PARASET) {
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
const AstNode *value = child->children[0]; const AstNode *value = child->children[0].get();
if (value->type == AST_REALVALUE) if (value->type == AST_REALVALUE)
log_file_warning(filename, location.first_line, "Replacing floating point parameter %s.%s = %f with string.\n", log_file_warning(*location.begin.filename, location.begin.line, "Replacing floating point parameter %s.%s = %f with string.\n",
log_id(cell), log_id(paraname), value->realvalue); log_id(cell), log_id(paraname), value->realvalue);
else if (value->type != AST_CONSTANT) else if (value->type != AST_CONSTANT)
input_error("Parameter %s.%s with non-constant value!\n", input_error("Parameter %s.%s with non-constant value!\n",
@ -2114,7 +2107,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (child->type == AST_ARGUMENT) { if (child->type == AST_ARGUMENT) {
RTLIL::SigSpec sig; RTLIL::SigSpec sig;
if (child->children.size() > 0) { if (child->children.size() > 0) {
AstNode *arg = child->children[0]; AstNode *arg = child->children[0].get();
int local_width_hint = -1; int local_width_hint = -1;
bool local_sign_hint = false; bool local_sign_hint = false;
// don't inadvertently attempt to detect the width of interfaces // don't inadvertently attempt to detect the width of interfaces
@ -2186,30 +2179,28 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// use ProcessGenerator for always blocks // use ProcessGenerator for always blocks
case AST_ALWAYS: { case AST_ALWAYS: {
AstNode *always = this->clone(); auto always = this->clone();
ProcessGenerator generator(always); ProcessGenerator generator(std::move(always));
ignoreThisSignalsInInitial.append(generator.outputSignals); ignoreThisSignalsInInitial.append(generator.outputSignals);
delete always;
} break; } break;
case AST_INITIAL: { case AST_INITIAL: {
AstNode *always = this->clone(); auto always = this->clone();
ProcessGenerator generator(always, ignoreThisSignalsInInitial); ProcessGenerator generator(std::move(always), ignoreThisSignalsInInitial);
delete always;
} break; } break;
case AST_TECALL: { case AST_TECALL: {
int sz = children.size(); int sz = children.size();
if (str == "$info") { if (str == "$info") {
if (sz > 0) if (sz > 0)
log_file_info(filename, location.first_line, "%s.\n", children[0]->str.c_str()); log_file_info(*location.begin.filename, location.begin.line, "%s.\n", children[0]->str.c_str());
else else
log_file_info(filename, location.first_line, "\n"); log_file_info(*location.begin.filename, location.begin.line, "\n");
} else if (str == "$warning") { } else if (str == "$warning") {
if (sz > 0) if (sz > 0)
log_file_warning(filename, location.first_line, "%s.\n", children[0]->str.c_str()); log_file_warning(*location.begin.filename, location.begin.line, "%s.\n", children[0]->str.c_str());
else else
log_file_warning(filename, location.first_line, "\n"); log_file_warning(*location.begin.filename, location.begin.line, "\n");
} else if (str == "$error") { } else if (str == "$error") {
if (sz > 0) if (sz > 0)
input_error("%s.\n", children[0]->str.c_str()); input_error("%s.\n", children[0]->str.c_str());

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,10 @@ frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y
frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc
frontends/verilog/verilog_frontend.o: frontends/verilog/verilog_parser.tab.hh
frontends/verilog/preproc.o: frontends/verilog/verilog_parser.tab.hh
frontends/verilog/verilog_lexer.h: frontends/verilog/verilog_parser.tab.hh
frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l frontends/verilog/verilog_parser.tab.cc frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l frontends/verilog/verilog_parser.tab.cc
$(Q) mkdir -p $(dir $@) $(Q) mkdir -p $(dir $@)
$(P) flex -o frontends/verilog/verilog_lexer.cc $< $(P) flex -o frontends/verilog/verilog_lexer.cc $<
@ -20,5 +24,6 @@ OBJS += frontends/verilog/verilog_parser.tab.o
OBJS += frontends/verilog/verilog_lexer.o OBJS += frontends/verilog/verilog_lexer.o
OBJS += frontends/verilog/preproc.o OBJS += frontends/verilog/preproc.o
OBJS += frontends/verilog/verilog_frontend.o OBJS += frontends/verilog/verilog_frontend.o
OBJS += frontends/verilog/verilog_error.o
OBJS += frontends/verilog/const2ast.o OBJS += frontends/verilog/const2ast.o

View file

@ -42,14 +42,32 @@
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
using namespace AST; using namespace AST;
using namespace VERILOG_FRONTEND;
std::string ConstParser::fmt_maybe_loc(std::string msg) {
std::string s;
s += stringf("%s:%d:", loc.begin.filename->c_str(), loc.begin.line);
s += msg;
return s;
}
void ConstParser::log_maybe_loc_error(std::string msg) {
log_error("%s", fmt_maybe_loc(msg).c_str());
}
void ConstParser::log_maybe_loc_warn(std::string msg) {
log_warning("%s", fmt_maybe_loc(msg).c_str());
}
// divide an arbitrary length decimal number by two and return the rest // divide an arbitrary length decimal number by two and return the rest
static int my_decimal_div_by_two(std::vector<uint8_t> &digits) int ConstParser::my_decimal_div_by_two(std::vector<uint8_t> &digits)
{ {
int carry = 0; int carry = 0;
for (size_t i = 0; i < digits.size(); i++) { for (size_t i = 0; i < digits.size(); i++) {
if (digits[i] >= 10) if (digits[i] >= 10)
log_file_error(current_filename, get_line_num(), "Invalid use of [a-fxz?] in decimal constant.\n"); log_maybe_loc_error("Invalid use of [a-fxz?] in decimal constant.\n");
digits[i] += carry * 10; digits[i] += carry * 10;
carry = digits[i] % 2; carry = digits[i] % 2;
digits[i] /= 2; digits[i] /= 2;
@ -60,7 +78,7 @@ static int my_decimal_div_by_two(std::vector<uint8_t> &digits)
} }
// find the number of significant bits in a binary number (not including the sign bit) // find the number of significant bits in a binary number (not including the sign bit)
static int my_ilog2(int x) int ConstParser::my_ilog2(int x)
{ {
int ret = 0; int ret = 0;
while (x != 0 && x != -1) { while (x != 0 && x != -1) {
@ -71,7 +89,7 @@ static int my_ilog2(int x)
} }
// parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?') // parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?')
static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized) void ConstParser::my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized)
{ {
// all digits in string (MSB at index 0) // all digits in string (MSB at index 0)
std::vector<uint8_t> digits; std::vector<uint8_t> digits;
@ -102,8 +120,8 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
int bits_per_digit = my_ilog2(base-1); int bits_per_digit = my_ilog2(base-1);
for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) { for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) {
if (*it > (base-1) && *it < 0xf0) if (*it > (base-1) && *it < 0xf0)
log_file_error(current_filename, get_line_num(), "Digit larger than %d used in in base-%d constant.\n", log_maybe_loc_error(stringf("Digit larger than %d used in in base-%d constant.\n",
base-1, base); base-1, base));
for (int i = 0; i < bits_per_digit; i++) { for (int i = 0; i < bits_per_digit; i++) {
int bitmask = 1 << i; int bitmask = 1 << i;
if (*it == 0xf0) if (*it == 0xf0)
@ -126,7 +144,7 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
} }
if (is_unsized && (len > len_in_bits)) if (is_unsized && (len > len_in_bits))
log_file_error(current_filename, get_line_num(), "Unsized constant must have width of 1 bit, but have %d bits!\n", len); log_maybe_loc_error(stringf("Unsized constant must have width of 1 bit, but have %d bits!\n", len));
for (len = len - 1; len >= 0; len--) for (len = len - 1; len >= 0; len--)
if (data[len] == State::S1) if (data[len] == State::S1)
@ -140,21 +158,19 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
} }
if (len_in_bits == 0) if (len_in_bits == 0)
log_file_error(current_filename, get_line_num(), "Illegal integer constant size of zero (IEEE 1800-2012, 5.7).\n"); log_maybe_loc_error("Illegal integer constant size of zero (IEEE 1800-2012, 5.7).\n");
if (len > len_in_bits) if (len > len_in_bits)
log_warning("Literal has a width of %d bit, but value requires %d bit. (%s:%d)\n", log_maybe_loc_warn(stringf("Literal has a width of %d bit, but value requires %d bit.\n",
len_in_bits, len, current_filename.c_str(), get_line_num()); len_in_bits, len));
} }
// convert the Verilog code for a constant to an AST node // convert the Verilog code for a constant to an AST node
AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn_z) std::unique_ptr<AstNode> ConstParser::const2ast(std::string code, char case_type, bool warn_z)
{ {
if (warn_z) { if (warn_z) {
AstNode *ret = const2ast(code, case_type); auto ret = const2ast(code, case_type);
if (ret != nullptr && std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end()) if (ret != nullptr && std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n", log_maybe_loc_warn("Yosys has only limited support for tri-state logic at the moment.\n");
current_filename.c_str(), get_line_num());
return ret; return ret;
} }
@ -172,7 +188,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
ch = ch >> 1; ch = ch >> 1;
} }
} }
AstNode *ast = AstNode::mkconst_bits(data, false); auto ast = AstNode::mkconst_bits(loc, data, false);
ast->str = code; ast->str = code;
return ast; return ast;
} }
@ -191,7 +207,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
my_strtobin(data, str, -1, 10, case_type, false); my_strtobin(data, str, -1, 10, case_type, false);
if (data.back() == State::S1) if (data.back() == State::S1)
data.push_back(State::S0); data.push_back(State::S0);
return AstNode::mkconst_bits(data, true); return AstNode::mkconst_bits(loc, data, true);
} }
// unsized constant // unsized constant
@ -239,10 +255,11 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
if (is_signed && data.back() == State::S1) if (is_signed && data.back() == State::S1)
data.push_back(State::S0); data.push_back(State::S0);
} }
return AstNode::mkconst_bits(data, is_signed, is_unsized); return AstNode::mkconst_bits(loc, data, is_signed, is_unsized);
} }
return NULL; return NULL;
} }
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END

View file

@ -34,6 +34,7 @@
#include "preproc.h" #include "preproc.h"
#include "verilog_frontend.h" #include "verilog_frontend.h"
#include "frontends/verilog/verilog_parser.tab.hh"
#include "kernel/log.h" #include "kernel/log.h"
#include <assert.h> #include <assert.h>
#include <stack> #include <stack>
@ -749,7 +750,9 @@ frontend_verilog_preproc(std::istream &f,
std::string filename, std::string filename,
const define_map_t &pre_defines, const define_map_t &pre_defines,
define_map_t &global_defines_cache, define_map_t &global_defines_cache,
const std::list<std::string> &include_dirs) const std::list<std::string> &include_dirs,
ParseState &parse_state,
ParseMode &parse_mode)
{ {
define_map_t defines; define_map_t defines;
defines.merge(pre_defines); defines.merge(pre_defines);
@ -961,11 +964,11 @@ frontend_verilog_preproc(std::istream &f,
} }
if (tok == "`resetall") { if (tok == "`resetall") {
default_nettype_wire = true; parse_state.default_nettype_wire = true;
continue; continue;
} }
if (tok == "`undefineall" && sv_mode) { if (tok == "`undefineall" && parse_mode.sv) {
defines.clear(); defines.clear();
global_defines_cache.clear(); global_defines_cache.clear();
continue; continue;

View file

@ -35,6 +35,11 @@ YOSYS_NAMESPACE_BEGIN
struct define_body_t; struct define_body_t;
struct arg_map_t; struct arg_map_t;
namespace VERILOG_FRONTEND {
struct ParseState;
struct ParseMode;
};
struct define_map_t struct define_map_t
{ {
define_map_t(); define_map_t();
@ -71,7 +76,9 @@ frontend_verilog_preproc(std::istream &f,
std::string filename, std::string filename,
const define_map_t &pre_defines, const define_map_t &pre_defines,
define_map_t &global_defines_cache, define_map_t &global_defines_cache,
const std::list<std::string> &include_dirs); const std::list<std::string> &include_dirs,
VERILOG_FRONTEND::ParseState &parse_state,
VERILOG_FRONTEND::ParseMode &parse_mode);
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END

View file

@ -0,0 +1,52 @@
/*
* 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.
*
* ---
*
*/
#include "kernel/yosys_common.h"
#include "frontends/verilog/verilog_error.h"
#include "frontends/verilog/verilog_location.h"
USING_YOSYS_NAMESPACE
/**
* Legacy behavior is to only track lines. Now we have columns too, but we don't
* report them in errors.
* TODO: report columns, too
*/
[[noreturn]]
static void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap)
{
char buffer[1024];
char *p = buffer;
p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
YOSYS_NAMESPACE_PREFIX log_file_error(filename, begin_line, "%s", buffer);
exit(1);
}
[[noreturn]]
void VERILOG_FRONTEND::err_at_loc(location loc, char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
verr_at(loc.begin.filename ? *(loc.begin.filename) : "UNKNOWN", loc.begin.line, fmt, args);
}

View file

@ -0,0 +1,18 @@
#ifndef VERILOG_ERROR_H
#define VERILOG_ERROR_H
#include "kernel/yosys_common.h"
#include "frontends/ast/ast.h"
#include "frontends/verilog/verilog_location.h"
YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND
{
[[noreturn]]
void err_at_loc(location loc, char const *fmt, ...);
};
YOSYS_NAMESPACE_END
#endif

View file

@ -31,10 +31,14 @@
#endif #endif
#include "verilog_frontend.h" #include "verilog_frontend.h"
#include "verilog_lexer.h"
#include "verilog_error.h"
#include "verilog_location.h"
#include "preproc.h" #include "preproc.h"
#include "kernel/yosys.h" #include "kernel/yosys.h"
#include "libs/sha1/sha1.h" #include "libs/sha1/sha1.h"
#include <stdarg.h> #include <stdarg.h>
#include <list>
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
using namespace VERILOG_FRONTEND; using namespace VERILOG_FRONTEND;
@ -46,13 +50,13 @@ static std::list<std::vector<std::string>> verilog_defaults_stack;
static void error_on_dpi_function(AST::AstNode *node) static void error_on_dpi_function(AST::AstNode *node)
{ {
if (node->type == AST::AST_DPI_FUNCTION) if (node->type == AST::AST_DPI_FUNCTION)
log_file_error(node->filename, node->location.first_line, "Found DPI function %s.\n", node->str.c_str()); err_at_loc(node->location, "Found DPI function %s.\n", node->str.c_str());
for (auto child : node->children) for (auto& child : node->children)
error_on_dpi_function(child); error_on_dpi_function(child.get());
} }
static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std::vector<AST::AstNode *> &package_list) static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std::vector<std::unique_ptr<AST::AstNode>> &package_list)
{ {
// prime the parser's user type lookup table with the package qualified names // prime the parser's user type lookup table with the package qualified names
// of typedefed names in the packages seen so far. // of typedefed names in the packages seen so far.
@ -61,7 +65,7 @@ static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std
for (const auto &node: pkg->children) { for (const auto &node: pkg->children) {
if (node->type == AST::AST_TYPEDEF) { if (node->type == AST::AST_TYPEDEF) {
std::string s = pkg->str + "::" + node->str.substr(1); std::string s = pkg->str + "::" + node->str.substr(1);
user_types[s] = node; user_types[s] = node.get();
} }
} }
} }
@ -250,6 +254,8 @@ struct VerilogFrontend : public Frontend {
bool flag_dump_vlog1 = false; bool flag_dump_vlog1 = false;
bool flag_dump_vlog2 = false; bool flag_dump_vlog2 = false;
bool flag_dump_rtlil = false; bool flag_dump_rtlil = false;
bool flag_debug_lexer = false;
bool flag_debug_parser = false;
bool flag_nolatches = false; bool flag_nolatches = false;
bool flag_nomeminit = false; bool flag_nomeminit = false;
bool flag_nomem2reg = false; bool flag_nomem2reg = false;
@ -266,22 +272,24 @@ struct VerilogFrontend : public Frontend {
bool flag_noblackbox = false; bool flag_noblackbox = false;
bool flag_nowb = false; bool flag_nowb = false;
bool flag_nosynthesis = false; bool flag_nosynthesis = false;
bool flag_yydebug = false;
define_map_t defines_map; define_map_t defines_map;
std::list<std::string> include_dirs; std::list<std::string> include_dirs;
std::list<std::string> attributes; std::list<std::string> attributes;
frontend_verilog_yydebug = false; ParseMode parse_mode = {};
sv_mode = false; ParseState parse_state = {};
formal_mode = false; parse_mode.sv = false;
noassert_mode = false; parse_mode.formal = false;
noassume_mode = false; parse_mode.noassert = false;
norestrict_mode = false; parse_mode.noassume = false;
assume_asserts_mode = false; parse_mode.norestrict = false;
assert_assumes_mode = false; parse_mode.assume_asserts = false;
lib_mode = false; parse_mode.assert_assumes = false;
specify_mode = false; parse_mode.lib = false;
default_nettype_wire = true; parse_mode.specify = false;
parse_state.default_nettype_wire = true;
args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end()); args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end());
@ -289,11 +297,11 @@ struct VerilogFrontend : 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 == "-sv") { if (arg == "-sv") {
sv_mode = true; parse_mode.sv = true;
continue; continue;
} }
if (arg == "-formal") { if (arg == "-formal") {
formal_mode = true; parse_mode.formal = true;
continue; continue;
} }
if (arg == "-nosynthesis") { if (arg == "-nosynthesis") {
@ -301,23 +309,23 @@ struct VerilogFrontend : public Frontend {
continue; continue;
} }
if (arg == "-noassert") { if (arg == "-noassert") {
noassert_mode = true; parse_mode.noassert = true;
continue; continue;
} }
if (arg == "-noassume") { if (arg == "-noassume") {
noassume_mode = true; parse_mode.noassume = true;
continue; continue;
} }
if (arg == "-norestrict") { if (arg == "-norestrict") {
norestrict_mode = true; parse_mode.norestrict = true;
continue; continue;
} }
if (arg == "-assume-asserts") { if (arg == "-assume-asserts") {
assume_asserts_mode = true; parse_mode.assume_asserts = true;
continue; continue;
} }
if (arg == "-assert-assumes") { if (arg == "-assert-assumes") {
assert_assumes_mode = true; parse_mode.assert_assumes = true;
continue; continue;
} }
if (arg == "-nodisplay") { if (arg == "-nodisplay") {
@ -329,7 +337,8 @@ struct VerilogFrontend : public Frontend {
flag_dump_ast2 = true; flag_dump_ast2 = true;
flag_dump_vlog1 = true; flag_dump_vlog1 = true;
flag_dump_vlog2 = true; flag_dump_vlog2 = true;
frontend_verilog_yydebug = true; flag_debug_lexer = true;
flag_debug_parser = true;
continue; continue;
} }
if (arg == "-dump_ast1") { if (arg == "-dump_ast1") {
@ -357,7 +366,9 @@ struct VerilogFrontend : public Frontend {
continue; continue;
} }
if (arg == "-yydebug") { if (arg == "-yydebug") {
frontend_verilog_yydebug = true; flag_yydebug = true;
flag_debug_lexer = true;
flag_debug_parser = true;
continue; continue;
} }
if (arg == "-nolatches") { if (arg == "-nolatches") {
@ -393,7 +404,7 @@ struct VerilogFrontend : public Frontend {
continue; continue;
} }
if (arg == "-lib") { if (arg == "-lib") {
lib_mode = true; parse_mode.lib = true;
defines_map.add("BLACKBOX", ""); defines_map.add("BLACKBOX", "");
continue; continue;
} }
@ -402,7 +413,7 @@ struct VerilogFrontend : public Frontend {
continue; continue;
} }
if (arg == "-specify") { if (arg == "-specify") {
specify_mode = true; parse_mode.specify = true;
continue; continue;
} }
if (arg == "-noopt") { if (arg == "-noopt") {
@ -432,7 +443,7 @@ struct VerilogFrontend : public Frontend {
continue; continue;
} }
if (arg == "-noautowire") { if (arg == "-noautowire") {
default_nettype_wire = false; parse_state.default_nettype_wire = false;
continue; continue;
} }
if (arg == "-setattr" && argidx+1 < args.size()) { if (arg == "-setattr" && argidx+1 < args.size()) {
@ -469,76 +480,82 @@ struct VerilogFrontend : public Frontend {
break; break;
} }
if (formal_mode || !flag_nosynthesis) if (parse_mode.formal || !flag_nosynthesis)
defines_map.add(formal_mode ? "FORMAL" : "SYNTHESIS", "1"); defines_map.add(parse_mode.formal ? "FORMAL" : "SYNTHESIS", "1");
extra_args(f, filename, args, argidx); extra_args(f, filename, args, argidx);
log_header(design, "Executing Verilog-2005 frontend: %s\n", filename.c_str()); log_header(design, "Executing Verilog-2005 frontend: %s\n", filename.c_str());
log("Parsing %s%s input from `%s' to AST representation.\n", log("Parsing %s%s input from `%s' to AST representation.\n",
formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str()); parse_mode.formal ? "formal " : "", parse_mode.sv ? "SystemVerilog" : "Verilog", filename.c_str());
AST::current_filename = filename; AST::sv_mode_but_global_and_used_for_literally_one_condition = parse_mode.sv;
AST::set_line_num = &frontend_verilog_yyset_lineno;
AST::get_line_num = &frontend_verilog_yyget_lineno;
current_ast = new AST::AstNode(AST::AST_DESIGN);
lexin = f;
std::string code_after_preproc; std::string code_after_preproc;
parse_state.lexin = f;
if (!flag_nopp) { if (!flag_nopp) {
code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, *design->verilog_defines, include_dirs); code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, *design->verilog_defines, include_dirs, parse_state, parse_mode);
if (flag_ppdump) if (flag_ppdump)
log("-- Verilog code after preprocessor --\n%s-- END OF DUMP --\n", code_after_preproc.c_str()); log("-- Verilog code after preprocessor --\n%s-- END OF DUMP --\n", code_after_preproc.c_str());
lexin = new std::istringstream(code_after_preproc); parse_state.lexin = new std::istringstream(code_after_preproc);
} }
auto filename_shared = std::make_shared<std::string>(filename);
auto top_loc = location();
top_loc.begin.filename = filename_shared;
parse_state.current_ast = new AST::AstNode(top_loc, AST::AST_DESIGN);
VerilogLexer lexer(&parse_state, &parse_mode, filename_shared);
frontend_verilog_yy::parser parser(&lexer, &parse_state, &parse_mode);
lexer.set_debug(flag_debug_lexer);
parser.set_debug_level(flag_debug_parser ? 1 : 0);
// make package typedefs available to parser // make package typedefs available to parser
add_package_types(pkg_user_types, design->verilog_packages); add_package_types(parse_state.pkg_user_types, design->verilog_packages);
UserTypeMap global_types_map; UserTypeMap global_types_map;
for (auto def : design->verilog_globals) { for (auto& def : design->verilog_globals) {
if (def->type == AST::AST_TYPEDEF) { if (def->type == AST::AST_TYPEDEF) {
global_types_map[def->str] = def; global_types_map[def->str] = def.get();
} }
} }
log_assert(user_type_stack.empty()); log_assert(parse_state.user_type_stack.empty());
// use previous global typedefs as bottom level of user type stack // use previous global typedefs as bottom level of user type stack
user_type_stack.push_back(std::move(global_types_map)); parse_state.user_type_stack.push_back(std::move(global_types_map));
// add a new empty type map to allow overriding existing global definitions // add a new empty type map to allow overriding existing global definitions
user_type_stack.push_back(UserTypeMap()); parse_state.user_type_stack.push_back(UserTypeMap());
frontend_verilog_yyset_lineno(1); if (flag_yydebug) {
frontend_verilog_yyrestart(NULL); lexer.set_debug(true);
frontend_verilog_yyparse(); parser.set_debug_level(1);
frontend_verilog_yylex_destroy(); }
parser.parse();
// frontend_verilog_yyset_lineno(1);
for (auto &child : current_ast->children) { for (auto &child : parse_state.current_ast->children) {
if (child->type == AST::AST_MODULE) if (child->type == AST::AST_MODULE)
for (auto &attr : attributes) for (auto &attr : attributes)
if (child->attributes.count(attr) == 0) if (child->attributes.count(attr) == 0)
child->attributes[attr] = AST::AstNode::mkconst_int(1, false); child->attributes[attr] = AST::AstNode::mkconst_int(top_loc, 1, false);
} }
if (flag_nodpi) if (flag_nodpi)
error_on_dpi_function(current_ast); error_on_dpi_function(parse_state.current_ast);
AST::process(design, current_ast, flag_nodisplay, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, AST::process(design, parse_state.current_ast, flag_nodisplay, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, parse_mode.lib, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, parse_state.default_nettype_wire);
if (!flag_nopp) if (!flag_nopp)
delete lexin; delete parse_state.lexin;
// only the previous and new global type maps remain // only the previous and new global type maps remain
log_assert(user_type_stack.size() == 2); log_assert(parse_state.user_type_stack.size() == 2);
user_type_stack.clear(); parse_state.user_type_stack.clear();
delete current_ast; delete parse_state.current_ast;
current_ast = NULL; parse_state.current_ast = NULL;
log("Successfully finished Verilog frontend.\n"); log("Successfully finished Verilog frontend.\n");
} }
@ -760,18 +777,3 @@ struct VerilogFileList : public Pass {
#endif #endif
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END
// the yyerror function used by bison to report parser errors
void frontend_verilog_yyerror(char const *fmt, ...)
{
va_list ap;
char buffer[1024];
char *p = buffer;
va_start(ap, fmt);
p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
va_end(ap);
p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
YOSYS_NAMESPACE_PREFIX log_file_error(YOSYS_NAMESPACE_PREFIX AST::current_filename, frontend_verilog_yyget_lineno(),
"%s", buffer);
exit(1);
}

View file

@ -31,70 +31,34 @@
#include "kernel/yosys.h" #include "kernel/yosys.h"
#include "frontends/ast/ast.h" #include "frontends/ast/ast.h"
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <list>
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND namespace VERILOG_FRONTEND
{ {
// this variable is set to a new AST_DESIGN node and then filled with the AST by the bison parser /* Ephemeral context class */
extern struct AST::AstNode *current_ast; struct ConstParser {
AST::AstSrcLocType loc;
private:
std::string fmt_maybe_loc(std::string msg);
void log_maybe_loc_error(std::string msg);
void log_maybe_loc_warn(std::string msg);
// divide an arbitrary length decimal number by two and return the rest
int my_decimal_div_by_two(std::vector<uint8_t> &digits);
// find the number of significant bits in a binary number (not including the sign bit)
int my_ilog2(int x);
// parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?')
void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized);
public:
// convert the Verilog code for a constant to an AST node
std::unique_ptr<AST::AstNode> const2ast(std::string code, char case_type = 0, bool warn_z = false);
// this function converts a Verilog constant to an AST_CONSTANT node };
AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false); };
// names of locally typedef'ed types in a stack
typedef std::map<std::string, AST::AstNode*> UserTypeMap;
extern std::vector<UserTypeMap> user_type_stack;
// names of package typedef'ed types
extern dict<std::string, AST::AstNode*> pkg_user_types;
// state of `default_nettype
extern bool default_nettype_wire;
// running in SystemVerilog mode
extern bool sv_mode;
// running in -formal mode
extern bool formal_mode;
// running in -noassert mode
extern bool noassert_mode;
// running in -noassume mode
extern bool noassume_mode;
// running in -norestrict mode
extern bool norestrict_mode;
// running in -assume-asserts mode
extern bool assume_asserts_mode;
// running in -assert-assumes mode
extern bool assert_assumes_mode;
// running in -lib mode
extern bool lib_mode;
// running in -specify mode
extern bool specify_mode;
// lexer input stream
extern std::istream *lexin;
}
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END
// the usual bison/flex stuff
extern int frontend_verilog_yydebug;
void frontend_verilog_yyerror(char const *fmt, ...);
void frontend_verilog_yyrestart(FILE *f);
int frontend_verilog_yyparse(void);
int frontend_verilog_yylex_destroy(void);
int frontend_verilog_yyget_lineno(void);
void frontend_verilog_yyset_lineno (int);
#endif #endif

View file

@ -0,0 +1,48 @@
#ifndef VERILOG_LEXER_H
#define VERILOG_LEXER_H
#include "kernel/yosys.h"
#include "frontends/ast/ast.h"
#include "frontends/verilog/verilog_parser.tab.hh"
#include <string>
#include <memory>
#if ! defined(yyFlexLexerOnce)
#define yyFlexLexer frontend_verilog_yyFlexLexer
#include <FlexLexer.h>
#endif
YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND {
using parser = frontend_verilog_yy::parser;
class VerilogLexer : public frontend_verilog_yyFlexLexer {
ParseState* extra;
ParseMode* mode;
public:
parser::location_type out_loc; // TODO private?
VerilogLexer(ParseState* e, ParseMode* m, std::shared_ptr<string> filename) : frontend_verilog_yyFlexLexer(e->lexin), extra(e), mode(m) {
out_loc.begin.filename = filename;
}
~VerilogLexer() override {}
// autogenerated body due to YY_DECL
parser::symbol_type nextToken();
// get rid of override virtual function warning
using FlexLexer::yylex;
parser::symbol_type terminate() {
return parser::make_FRONTEND_VERILOG_YYEOF(out_loc);
}
private:
std::shared_ptr<std::string> current_filename;
std::vector<std::shared_ptr<std::string>> fn_stack;
std::vector<int> ln_stack;
int LexerInput(char* buf, int max_size) override {
return readsome(*extra->lexin, buf, max_size);
}
};
};
YOSYS_NAMESPACE_END
#endif

View file

@ -32,6 +32,13 @@
* *
*/ */
%option c++
%option yyclass="VerilogLexer"
%option noyywrap
%option nounput
%option yylineno
%option prefix="frontend_verilog_yy"
%{ %{
#ifdef __clang__ #ifdef __clang__
@ -41,78 +48,109 @@
#pragma clang diagnostic ignored "-Wmisleading-indentation" #pragma clang diagnostic ignored "-Wmisleading-indentation"
#endif #endif
#include "kernel/log.h" #include "frontends/verilog/verilog_lexer.h"
#include "frontends/verilog/verilog_frontend.h"
#include "frontends/ast/ast.h" #include "frontends/ast/ast.h"
#include "verilog_parser.tab.hh" #include "frontends/verilog/verilog_location.h"
#include "kernel/log.h"
#include <vector>
#include <memory>
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
using namespace AST; using namespace AST;
using namespace VERILOG_FRONTEND; using namespace VERILOG_FRONTEND;
using parser = frontend_verilog_yy::parser;
#define YYSTYPE FRONTEND_VERILOG_YYSTYPE
#define YYLTYPE FRONTEND_VERILOG_YYLTYPE
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND { #undef YY_DECL
std::vector<std::string> fn_stack; #define YY_DECL parser::symbol_type VerilogLexer::nextToken()
std::vector<int> ln_stack;
YYLTYPE real_location; #undef yyterminate
YYLTYPE old_location; #define yyterminate() return terminate()
}
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END
#define SV_KEYWORD(_tok) \ #define SV_KEYWORD(_tok) \
if (sv_mode) return _tok; \ if (mode->sv) return _tok; \
log("Lexer warning: The SystemVerilog keyword `%s' (at %s:%d) is not "\ log("Lexer warning: The SystemVerilog keyword `%s' (at %s:%d) is not "\
"recognized unless read_verilog is called with -sv!\n", yytext, \ "recognized unless read_verilog is called with -sv!\n", YYText(), \
AST::current_filename.c_str(), frontend_verilog_yyget_lineno()); \ current_filename->c_str(), yylineno); \
yylval->string = new std::string(std::string("\\") + yytext); \ string_t val = std::make_unique<std::string>(std::string("\\") + YYText()); \
return TOK_ID; return parser::make_TOK_ID(std::move(val), out_loc);
#define NON_KEYWORD() \ #define NON_KEYWORD() \
yylval->string = new std::string(std::string("\\") + yytext); \ string_t val = std::make_unique<std::string>(std::string("\\") + YYText()); \
return TOK_ID; return parser::make_TOK_ID(std::move(val), out_loc);
#define YY_INPUT(buf,result,max_size) \
result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size)
#define YY_USER_ACTION \ #define YY_USER_ACTION \
old_location = real_location; \ out_loc.step(); \
real_location.first_line = real_location.last_line; \ for(int i = 0; YYText()[i] != '\0'; ++i){ \
real_location.first_column = real_location.last_column; \ if(YYText()[i] == '\n') { \
for(int i = 0; yytext[i] != '\0'; ++i){ \ out_loc.lines(); \
if(yytext[i] == '\n') { \ } \
real_location.last_line++; \ else { \
real_location.last_column = 1; \ out_loc.columns(); \
} \ } \
else { \ } \
real_location.last_column++; \ out_loc.begin.filename = current_filename; \
} \ out_loc.end.filename = current_filename;
} \
(*yylloc) = real_location;
#define YY_BREAK \ #define YY_BREAK \
(*yylloc) = old_location; \
break; break;
#undef YY_BUF_SIZE #undef YY_BUF_SIZE
#define YY_BUF_SIZE 65536 #define YY_BUF_SIZE 65536
extern int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param); static bool isUserType(ParseState* extra, std::string &s)
static bool isUserType(std::string &s)
{ {
// check current scope then outer scopes for a name // check current scope then outer scopes for a name
for (auto it = user_type_stack.rbegin(); it != user_type_stack.rend(); ++it) { for (auto it = extra->user_type_stack.rbegin(); it != extra->user_type_stack.rend(); ++it) {
if (it->count(s) > 0) { if (it->count(s) > 0) {
return true; return true;
} }
} }
return false; return false;
} }
static bool is_hex_dig(char c, int *val) parser::symbol_type char_tok(char c, parser::location_type loc) {
switch (c) {
case '!': return parser::make_TOK_EXCL(loc);
case '#': return parser::make_TOK_HASH(loc);
case '%': return parser::make_TOK_PERC(loc);
case '&': return parser::make_TOK_AMP(loc);
case '(': return parser::make_TOK_LPAREN(loc);
case ')': return parser::make_TOK_RPAREN(loc);
case '*': return parser::make_TOK_ASTER(loc);
case '+': return parser::make_TOK_PLUS(loc);
case ',': return parser::make_TOK_COMMA(loc);
case '-': return parser::make_TOK_MINUS(loc);
case '.': return parser::make_TOK_DOT(loc);
case '/': return parser::make_TOK_SLASH(loc);
case ':': return parser::make_TOK_COL(loc);
case ';': return parser::make_TOK_SEMICOL(loc);
case '<': return parser::make_TOK_LT(loc);
case '=': return parser::make_TOK_EQ(loc);
case '>': return parser::make_TOK_GT(loc);
case '?': return parser::make_TOK_QUE(loc);
case '@': return parser::make_TOK_AT(loc);
case '[': return parser::make_TOK_LBRA(loc);
case ']': return parser::make_TOK_RBRA(loc);
case '^': return parser::make_TOK_CARET(loc);
case '_': return parser::make_TOK_UNDER(loc);
case '{': return parser::make_TOK_LCURL(loc);
case '|': return parser::make_TOK_PIPE(loc);
case '}': return parser::make_TOK_RCURL(loc);
case '~': return parser::make_TOK_TILDE(loc);
case 'n': return parser::make_TOK_n(loc);
case 'p': return parser::make_TOK_p(loc);
case 'x': return parser::make_TOK_x(loc);
case 'z': return parser::make_TOK_z(loc);
case 0: return parser::make_FRONTEND_VERILOG_YYEOF(loc);
default:
return parser::make_ch_t(c, loc);
}
}
static bool is_hex_dig(char c, int *val, parser::location_type loc)
{ {
if ('0' <= c && c <= '9') { if ('0' <= c && c <= '9') {
*val = c - '0'; *val = c - '0';
@ -124,7 +162,7 @@ static bool is_hex_dig(char c, int *val)
*val = c - 'A' + 0xA; *val = c - 'A' + 0xA;
return true; return true;
} else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') { } else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') {
log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "'%c' not a valid digit in hex escape sequence.\n", c); log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "'%c' not a valid digit in hex escape sequence.\n", c);
*val = 0; // not semantically valid in hex escape... *val = 0; // not semantically valid in hex escape...
return true; // ...but still processed as part of hex token return true; // ...but still processed as part of hex token
} }
@ -132,13 +170,13 @@ static bool is_hex_dig(char c, int *val)
return false; return false;
} }
static bool is_oct_dig(char c, int *val) static bool is_oct_dig(char c, int *val, parser::location_type loc)
{ {
if ('0' <= c && c <= '7') { if ('0' <= c && c <= '7') {
*val = c - '0'; *val = c - '0';
return true; return true;
} else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') { } else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') {
log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "'%c' not a valid digit in octal escape sequence.\n", c); log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "'%c' not a valid digit in octal escape sequence.\n", c);
*val = 0; // not semantically valid in octal escape... *val = 0; // not semantically valid in octal escape...
return true; // ...but still processed as part of octal token return true; // ...but still processed as part of octal token
} }
@ -146,7 +184,7 @@ static bool is_oct_dig(char c, int *val)
return false; return false;
} }
static std::string *process_str(char *str, int len, bool triple) static parser::symbol_type process_str(char *str, int len, bool triple, parser::location_type loc)
{ {
char *in, *out; // Overwrite input buffer: flex manual states "Actions char *in, *out; // Overwrite input buffer: flex manual states "Actions
// are free to modify 'yytext' except for lengthening it". // are free to modify 'yytext' except for lengthening it".
@ -158,7 +196,7 @@ static std::string *process_str(char *str, int len, bool triple)
if (in + 1 < str + len && (in[1] ^ *in) == ('\n' ^ '\r')) if (in + 1 < str + len && (in[1] ^ *in) == ('\n' ^ '\r'))
in++; in++;
if (!triple) if (!triple)
log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "Multi-line string literals should be triple-quoted or escaped.\n"); log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "Multi-line string literals should be triple-quoted or escaped.\n");
*out++ = '\n'; *out++ = '\n';
break; break;
case '\\': case '\\':
@ -186,16 +224,16 @@ static std::string *process_str(char *str, int len, bool triple)
break; break;
case 'x': case 'x':
int val; int val;
if (in + 1 < str + len && is_hex_dig(in[1], &val)) { if (in + 1 < str + len && is_hex_dig(in[1], &val, loc)) {
*out = val; *out = val;
in++; in++;
if (in + 1 < str + len && is_hex_dig(in[1], &val)) { if (in + 1 < str + len && is_hex_dig(in[1], &val, loc)) {
*out = *out * 0x10 + val; *out = *out * 0x10 + val;
in++; in++;
} }
out++; out++;
} else } else
log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "ignoring invalid hex escape.\n"); log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "ignoring invalid hex escape.\n");
break; break;
case '\\': case '\\':
*out++ = '\\'; *out++ = '\\';
@ -213,12 +251,12 @@ static std::string *process_str(char *str, int len, bool triple)
int val; int val;
*out = *in - '0'; *out = *in - '0';
if (in + 1 < str + len && is_oct_dig(in[1], &val)) { if (in + 1 < str + len && is_oct_dig(in[1], &val, loc)) {
*out = *out * 010 + val; *out = *out * 010 + val;
in++; in++;
if (in + 1 < str + len && is_oct_dig(in[1], &val)) { if (in + 1 < str + len && is_oct_dig(in[1], &val, loc)) {
if (*out >= 040) if (*out >= 040)
log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "octal escape exceeds \\377\n"); log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "octal escape exceeds \\377\n");
*out = *out * 010 + val; *out = *out * 010 + val;
in++; in++;
} }
@ -232,18 +270,11 @@ static std::string *process_str(char *str, int len, bool triple)
*out++ = *in; *out++ = *in;
} }
return new std::string(str, out - str); return parser::make_TOK_STRING(std::make_unique<std::string>(str, out - str), loc);
} }
%} %}
%option yylineno
%option noyywrap
%option nounput
%option bison-locations
%option bison-bridge
%option prefix="frontend_verilog_yy"
%x COMMENT %x COMMENT
%x SYNOPSYS_TRANSLATE_OFF %x SYNOPSYS_TRANSLATE_OFF
%x SYNOPSYS_FLAGS %x SYNOPSYS_FLAGS
@ -256,47 +287,46 @@ FIXED_POINT_NUMBER_NO_DEC [0-9][0-9_]*[eE][-+]?[0-9_]+
TIME_SCALE_SUFFIX [munpf]?s TIME_SCALE_SUFFIX [munpf]?s
%% %%
// Initialise comment_caller to something to avoid a "maybe undefined" // Initialise comment_caller to something to avoid a "maybe undefined"
// warning from GCC. // warning from GCC.
int comment_caller = INITIAL; int comment_caller = INITIAL;
<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_push "[^\n]* { <INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_push "[^\n]* {
fn_stack.push_back(current_filename); fn_stack.push_back(current_filename);
ln_stack.push_back(frontend_verilog_yyget_lineno()); ln_stack.push_back(yylineno);
current_filename = yytext+11; std::string filename = YYText()+11;
if (!current_filename.empty() && current_filename.front() == '"') if (!filename.empty() && filename.front() == '"')
current_filename = current_filename.substr(1); filename = filename.substr(1);
if (!current_filename.empty() && current_filename.back() == '"') if (!filename.empty() && filename.back() == '"')
current_filename = current_filename.substr(0, current_filename.size()-1); filename = filename.substr(0, filename.size()-1);
frontend_verilog_yyset_lineno(0); current_filename = std::make_shared<std::string>(filename);
yylloc->first_line = yylloc->last_line = 0; yylineno = (0);
real_location.first_line = real_location.last_line = 0; out_loc.begin.line = out_loc.end.line = 0;
} }
<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_pop"[^\n]*\n { <INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_pop"[^\n]*\n {
current_filename = fn_stack.back(); current_filename = fn_stack.back();
fn_stack.pop_back(); fn_stack.pop_back();
frontend_verilog_yyset_lineno(ln_stack.back()); yylineno = (ln_stack.back());
yylloc->first_line = yylloc->last_line = ln_stack.back(); out_loc.begin.line = out_loc.end.line = ln_stack.back();
real_location.first_line = real_location.last_line = ln_stack.back();
ln_stack.pop_back(); ln_stack.pop_back();
} }
<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`line"[ \t]+[^ \t\r\n]+[ \t]+\"[^ \r\n]+\"[^\r\n]*\n { <INITIAL,SYNOPSYS_TRANSLATE_OFF>"`line"[ \t]+[^ \t\r\n]+[ \t]+\"[^ \r\n]+\"[^\r\n]*\n {
char *p = yytext + 5; const char *p = YYText() + 5;
while (*p == ' ' || *p == '\t') p++; while (*p == ' ' || *p == '\t') p++;
frontend_verilog_yyset_lineno(atoi(p)); yylineno = (atoi(p));
yylloc->first_line = yylloc->last_line = atoi(p); out_loc.begin.line = out_loc.end.line = atoi(p);
real_location.first_line = real_location.last_line = atoi(p);
while (*p && *p != ' ' && *p != '\t') p++; while (*p && *p != ' ' && *p != '\t') p++;
while (*p == ' ' || *p == '\t') p++; while (*p == ' ' || *p == '\t') p++;
char *q = *p ? p + 1 : p; const char *q = *p ? p + 1 : p;
while (*q && *q != '"') q++; while (*q && *q != '"') q++;
current_filename = std::string(p).substr(1, q-p-1); current_filename = std::make_shared<std::string>(std::string(p).substr(1, q-p-1));
} }
"`file_notfound "[^\n]* { "`file_notfound "[^\n]* {
log_error("Can't open include file `%s'!\n", yytext + 15); log_error("Can't open include file `%s'!\n", YYText() + 15);
} }
"`timescale"[ \t]+[^ \t\r\n/]+[ \t]*"/"[ \t]*[^ \t\r\n]* /* ignore timescale directive */ "`timescale"[ \t]+[^ \t\r\n/]+[ \t]*"/"[ \t]*[^ \t\r\n]* /* ignore timescale directive */
@ -305,222 +335,222 @@ TIME_SCALE_SUFFIX [munpf]?s
"`endcelldefine"[^\n]* /* ignore `endcelldefine */ "`endcelldefine"[^\n]* /* ignore `endcelldefine */
"`default_nettype"[ \t]+[^ \t\r\n/]+ { "`default_nettype"[ \t]+[^ \t\r\n/]+ {
char *p = yytext; const char *p = YYText();
while (*p != 0 && *p != ' ' && *p != '\t') p++; while (*p != 0 && *p != ' ' && *p != '\t') p++;
while (*p == ' ' || *p == '\t') p++; while (*p == ' ' || *p == '\t') p++;
if (!strcmp(p, "none")) if (!strcmp(p, "none"))
VERILOG_FRONTEND::default_nettype_wire = false; extra->default_nettype_wire = false;
else if (!strcmp(p, "wire")) else if (!strcmp(p, "wire"))
VERILOG_FRONTEND::default_nettype_wire = true; extra->default_nettype_wire = true;
else else
frontend_verilog_yyerror("Unsupported default nettype: %s", p); err_at_loc(out_loc, "Unsupported default nettype: %s", p);
} }
"`protect"[^\n]* /* ignore `protect*/ "`protect"[^\n]* /* ignore `protect*/
"`endprotect"[^\n]* /* ignore `endprotect*/ "`endprotect"[^\n]* /* ignore `endprotect*/
"`"[a-zA-Z_$][a-zA-Z0-9_$]* { "`"[a-zA-Z_$][a-zA-Z0-9_$]* {
frontend_verilog_yyerror("Unimplemented compiler directive or undefined macro %s.", yytext); err_at_loc(out_loc, "Unimplemented compiler directive or undefined macro %s.", YYText());
} }
"module" { return TOK_MODULE; } "module" { return parser::make_TOK_MODULE(out_loc); }
"endmodule" { return TOK_ENDMODULE; } "endmodule" { return parser::make_TOK_ENDMODULE(out_loc); }
"function" { return TOK_FUNCTION; } "function" { return parser::make_TOK_FUNCTION(out_loc); }
"endfunction" { return TOK_ENDFUNCTION; } "endfunction" { return parser::make_TOK_ENDFUNCTION(out_loc); }
"task" { return TOK_TASK; } "task" { return parser::make_TOK_TASK(out_loc); }
"endtask" { return TOK_ENDTASK; } "endtask" { return parser::make_TOK_ENDTASK(out_loc); }
"specify" { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; } "specify" { return mode->specify ? parser::make_TOK_SPECIFY(out_loc) : parser::make_TOK_IGNORED_SPECIFY(out_loc); }
"endspecify" { return TOK_ENDSPECIFY; } "endspecify" { return parser::make_TOK_ENDSPECIFY(out_loc); }
"specparam" { return TOK_SPECPARAM; } "specparam" { return parser::make_TOK_SPECPARAM(out_loc); }
"package" { SV_KEYWORD(TOK_PACKAGE); } "package" { SV_KEYWORD(parser::make_TOK_PACKAGE(out_loc)); }
"endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); } "endpackage" { SV_KEYWORD(parser::make_TOK_ENDPACKAGE(out_loc)); }
"interface" { SV_KEYWORD(TOK_INTERFACE); } "interface" { SV_KEYWORD(parser::make_TOK_INTERFACE(out_loc)); }
"endinterface" { SV_KEYWORD(TOK_ENDINTERFACE); } "endinterface" { SV_KEYWORD(parser::make_TOK_ENDINTERFACE(out_loc)); }
"modport" { SV_KEYWORD(TOK_MODPORT); } "modport" { SV_KEYWORD(parser::make_TOK_MODPORT(out_loc)); }
"parameter" { return TOK_PARAMETER; } "parameter" { return parser::make_TOK_PARAMETER(out_loc); }
"localparam" { return TOK_LOCALPARAM; } "localparam" { return parser::make_TOK_LOCALPARAM(out_loc); }
"defparam" { return TOK_DEFPARAM; } "defparam" { return parser::make_TOK_DEFPARAM(out_loc); }
"assign" { return TOK_ASSIGN; } "assign" { return parser::make_TOK_ASSIGN(out_loc); }
"always" { return TOK_ALWAYS; } "always" { return parser::make_TOK_ALWAYS(out_loc); }
"initial" { return TOK_INITIAL; } "initial" { return parser::make_TOK_INITIAL(out_loc); }
"begin" { return TOK_BEGIN; } "begin" { return parser::make_TOK_BEGIN(out_loc); }
"end" { return TOK_END; } "end" { return parser::make_TOK_END(out_loc); }
"if" { return TOK_IF; } "if" { return parser::make_TOK_IF(out_loc); }
"else" { return TOK_ELSE; } "else" { return parser::make_TOK_ELSE(out_loc); }
"for" { return TOK_FOR; } "for" { return parser::make_TOK_FOR(out_loc); }
"posedge" { return TOK_POSEDGE; } "posedge" { return parser::make_TOK_POSEDGE(out_loc); }
"negedge" { return TOK_NEGEDGE; } "negedge" { return parser::make_TOK_NEGEDGE(out_loc); }
"or" { return TOK_OR; } "or" { return parser::make_TOK_OR(out_loc); }
"case" { return TOK_CASE; } "case" { return parser::make_TOK_CASE(out_loc); }
"casex" { return TOK_CASEX; } "casex" { return parser::make_TOK_CASEX(out_loc); }
"casez" { return TOK_CASEZ; } "casez" { return parser::make_TOK_CASEZ(out_loc); }
"endcase" { return TOK_ENDCASE; } "endcase" { return parser::make_TOK_ENDCASE(out_loc); }
"default" { return TOK_DEFAULT; } "default" { return parser::make_TOK_DEFAULT(out_loc); }
"generate" { return TOK_GENERATE; } "generate" { return parser::make_TOK_GENERATE(out_loc); }
"endgenerate" { return TOK_ENDGENERATE; } "endgenerate" { return parser::make_TOK_ENDGENERATE(out_loc); }
"while" { return TOK_WHILE; } "while" { return parser::make_TOK_WHILE(out_loc); }
"repeat" { return TOK_REPEAT; } "repeat" { return parser::make_TOK_REPEAT(out_loc); }
"automatic" { return TOK_AUTOMATIC; } "automatic" { return parser::make_TOK_AUTOMATIC(out_loc); }
"unique" { SV_KEYWORD(TOK_UNIQUE); } "unique" { SV_KEYWORD(parser::make_TOK_UNIQUE(out_loc)); }
"unique0" { SV_KEYWORD(TOK_UNIQUE0); } "unique0" { SV_KEYWORD(parser::make_TOK_UNIQUE0(out_loc)); }
"priority" { SV_KEYWORD(TOK_PRIORITY); } "priority" { SV_KEYWORD(parser::make_TOK_PRIORITY(out_loc)); }
"always_comb" { SV_KEYWORD(TOK_ALWAYS_COMB); } "always_comb" { SV_KEYWORD(parser::make_TOK_ALWAYS_COMB(out_loc)); }
"always_ff" { SV_KEYWORD(TOK_ALWAYS_FF); } "always_ff" { SV_KEYWORD(parser::make_TOK_ALWAYS_FF(out_loc)); }
"always_latch" { SV_KEYWORD(TOK_ALWAYS_LATCH); } "always_latch" { SV_KEYWORD(parser::make_TOK_ALWAYS_LATCH(out_loc)); }
/* use special token for labels on assert, assume, cover, and restrict because it's insanley complex /* use special token for labels on assert, assume, cover, and restrict because it's insanley complex
to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some
global state.. its a mess) */ global state.. its a mess) */
[a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] { [a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] {
if (!strcmp(yytext, "default")) if (!strcmp(YYText(), "default"))
return TOK_DEFAULT; return parser::make_TOK_DEFAULT(out_loc);
yylval->string = new std::string(std::string("\\") + yytext); string_t val = std::make_unique<std::string>(std::string("\\") + YYText());
return TOK_SVA_LABEL; return parser::make_TOK_SVA_LABEL(std::move(val), out_loc);
} }
"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); } "assert" { if (mode->formal) return parser::make_TOK_ASSERT(out_loc); SV_KEYWORD(parser::make_TOK_ASSERT(out_loc)); }
"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); } "assume" { if (mode->formal) return parser::make_TOK_ASSUME(out_loc); SV_KEYWORD(parser::make_TOK_ASSUME(out_loc)); }
"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); } "cover" { if (mode->formal) return parser::make_TOK_COVER(out_loc); SV_KEYWORD(parser::make_TOK_COVER(out_loc)); }
"restrict" { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); } "restrict" { if (mode->formal) return parser::make_TOK_RESTRICT(out_loc); SV_KEYWORD(parser::make_TOK_RESTRICT(out_loc)); }
"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); } "property" { if (mode->formal) return parser::make_TOK_PROPERTY(out_loc); SV_KEYWORD(parser::make_TOK_PROPERTY(out_loc)); }
"rand" { if (formal_mode) return TOK_RAND; SV_KEYWORD(TOK_RAND); } "rand" { if (mode->formal) return parser::make_TOK_RAND(out_loc); SV_KEYWORD(parser::make_TOK_RAND(out_loc)); }
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } "const" { if (mode->formal) return parser::make_TOK_CONST(out_loc); SV_KEYWORD(parser::make_TOK_CONST(out_loc)); }
"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); } "checker" { if (mode->formal) return parser::make_TOK_CHECKER(out_loc); SV_KEYWORD(parser::make_TOK_CHECKER(out_loc)); }
"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); } "endchecker" { if (mode->formal) return parser::make_TOK_ENDCHECKER(out_loc); SV_KEYWORD(parser::make_TOK_ENDCHECKER(out_loc)); }
"bind" { if (formal_mode) return TOK_BIND; SV_KEYWORD(TOK_BIND); } "bind" { if (mode->formal) return parser::make_TOK_BIND(out_loc); SV_KEYWORD(parser::make_TOK_BIND(out_loc)); }
"final" { SV_KEYWORD(TOK_FINAL); } "final" { SV_KEYWORD(parser::make_TOK_FINAL(out_loc)); }
"logic" { SV_KEYWORD(TOK_LOGIC); } "logic" { SV_KEYWORD(parser::make_TOK_LOGIC(out_loc)); }
"var" { SV_KEYWORD(TOK_VAR); } "var" { SV_KEYWORD(parser::make_TOK_VAR(out_loc)); }
"bit" { SV_KEYWORD(TOK_LOGIC); } "bit" { SV_KEYWORD(parser::make_TOK_LOGIC(out_loc)); }
"int" { SV_KEYWORD(TOK_INT); } "int" { SV_KEYWORD(parser::make_TOK_INT(out_loc)); }
"byte" { SV_KEYWORD(TOK_BYTE); } "byte" { SV_KEYWORD(parser::make_TOK_BYTE(out_loc)); }
"shortint" { SV_KEYWORD(TOK_SHORTINT); } "shortint" { SV_KEYWORD(parser::make_TOK_SHORTINT(out_loc)); }
"longint" { SV_KEYWORD(TOK_LONGINT); } "longint" { SV_KEYWORD(parser::make_TOK_LONGINT(out_loc)); }
"void" { SV_KEYWORD(TOK_VOID); } "void" { SV_KEYWORD(parser::make_TOK_VOID(out_loc)); }
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } "eventually" { if (mode->formal) return parser::make_TOK_EVENTUALLY(out_loc); SV_KEYWORD(parser::make_TOK_EVENTUALLY(out_loc)); }
"s_eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } "s_eventually" { if (mode->formal) return parser::make_TOK_EVENTUALLY(out_loc); SV_KEYWORD(parser::make_TOK_EVENTUALLY(out_loc)); }
"input" { return TOK_INPUT; } "input" { return parser::make_TOK_INPUT(out_loc); }
"output" { return TOK_OUTPUT; } "output" { return parser::make_TOK_OUTPUT(out_loc); }
"inout" { return TOK_INOUT; } "inout" { return parser::make_TOK_INOUT(out_loc); }
"wire" { return TOK_WIRE; } "wire" { return parser::make_TOK_WIRE(out_loc); }
"tri" { return TOK_WIRE; } "tri" { return parser::make_TOK_WIRE(out_loc); }
"wor" { return TOK_WOR; } "wor" { return parser::make_TOK_WOR(out_loc); }
"trior" { return TOK_WOR; } "trior" { return parser::make_TOK_WOR(out_loc); }
"wand" { return TOK_WAND; } "wand" { return parser::make_TOK_WAND(out_loc); }
"triand" { return TOK_WAND; } "triand" { return parser::make_TOK_WAND(out_loc); }
"reg" { return TOK_REG; } "reg" { return parser::make_TOK_REG(out_loc); }
"integer" { return TOK_INTEGER; } "integer" { return parser::make_TOK_INTEGER(out_loc); }
"signed" { return TOK_SIGNED; } "signed" { return parser::make_TOK_SIGNED(out_loc); }
"unsigned" { SV_KEYWORD(TOK_UNSIGNED); } "unsigned" { SV_KEYWORD(parser::make_TOK_UNSIGNED(out_loc)); }
"genvar" { return TOK_GENVAR; } "genvar" { return parser::make_TOK_GENVAR(out_loc); }
"real" { return TOK_REAL; } "real" { return parser::make_TOK_REAL(out_loc); }
"enum" { SV_KEYWORD(TOK_ENUM); } "enum" { SV_KEYWORD(parser::make_TOK_ENUM(out_loc)); }
"typedef" { SV_KEYWORD(TOK_TYPEDEF); } "typedef" { SV_KEYWORD(parser::make_TOK_TYPEDEF(out_loc)); }
"struct" { SV_KEYWORD(TOK_STRUCT); } "struct" { SV_KEYWORD(parser::make_TOK_STRUCT(out_loc)); }
"union" { SV_KEYWORD(TOK_UNION); } "union" { SV_KEYWORD(parser::make_TOK_UNION(out_loc)); }
"packed" { SV_KEYWORD(TOK_PACKED); } "packed" { SV_KEYWORD(parser::make_TOK_PACKED(out_loc)); }
{UNSIGNED_NUMBER} { {UNSIGNED_NUMBER} {
yylval->string = new std::string(yytext); string_t val = std::make_unique<std::string>(YYText());
return TOK_CONSTVAL; return parser::make_TOK_CONSTVAL(std::move(val), out_loc);
} }
\'[01zxZX] { \'[01zxZX] {
yylval->string = new std::string(yytext); string_t val = std::make_unique<std::string>(YYText());
return TOK_UNBASED_UNSIZED_CONSTVAL; return parser::make_TOK_UNBASED_UNSIZED_CONSTVAL(std::move(val), out_loc);
} }
\'[sS]?[bodhBODH] { \'[sS]?[bodhBODH] {
BEGIN(BASED_CONST); BEGIN(BASED_CONST);
yylval->string = new std::string(yytext); string_t val = std::make_unique<std::string>(YYText());
return TOK_BASE; return parser::make_TOK_BASE(std::move(val), out_loc);
} }
<BASED_CONST>[0-9a-fA-FzxZX?][0-9a-fA-FzxZX?_]* { <BASED_CONST>[0-9a-fA-FzxZX?][0-9a-fA-FzxZX?_]* {
BEGIN(0); BEGIN(0);
yylval->string = new std::string(yytext); string_t val = std::make_unique<std::string>(YYText());
return TOK_BASED_CONSTVAL; return parser::make_TOK_BASED_CONSTVAL(std::move(val), out_loc);
} }
{FIXED_POINT_NUMBER_DEC} { {FIXED_POINT_NUMBER_DEC} {
yylval->string = new std::string(yytext); string_t val = std::make_unique<std::string>(YYText());
return TOK_REALVAL; return parser::make_TOK_REALVAL(std::move(val), out_loc);
} }
{FIXED_POINT_NUMBER_NO_DEC} { {FIXED_POINT_NUMBER_NO_DEC} {
yylval->string = new std::string(yytext); string_t val = std::make_unique<std::string>(YYText());
return TOK_REALVAL; return parser::make_TOK_REALVAL(std::move(val), out_loc);
} }
\"([^\\"]|\\.|\\\n)*\" { yylval->string = process_str(yytext + 1, yyleng - 2, false); return TOK_STRING; } \"([^\\"]|\\.|\\\n)*\" { return process_str(yytext + 1, yyleng - 2, false, out_loc); }
\"{3}(\"{0,2}([^\\"]|\\.|\\\n))*\"{3} { yylval->string = process_str(yytext + 3, yyleng - 6, true); return TOK_STRING; } \"{3}(\"{0,2}([^\\"]|\\.|\\\n))*\"{3} { return process_str(yytext + 3, yyleng - 6, true, out_loc); }
and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 { and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 {
yylval->string = new std::string(yytext); auto val = std::make_unique<std::string>(YYText());
return TOK_PRIMITIVE; return parser::make_TOK_PRIMITIVE(std::move(val), out_loc);
} }
supply0 { return TOK_SUPPLY0; } supply0 { return parser::make_TOK_SUPPLY0(out_loc); }
supply1 { return TOK_SUPPLY1; } supply1 { return parser::make_TOK_SUPPLY1(out_loc); }
"$"(display[bho]?|write[bho]?|strobe|monitor|time|realtime|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) { "$"(display[bho]?|write[bho]?|strobe|monitor|time|realtime|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) {
yylval->string = new std::string(yytext); auto val = std::make_unique<std::string>(YYText());
return TOK_ID; return parser::make_TOK_ID(std::move(val), out_loc);
} }
"$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) { "$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) {
if (!specify_mode) REJECT; if (!mode->specify) REJECT;
yylval->string = new std::string(yytext); auto val = std::make_unique<std::string>(YYText());
return TOK_ID; return parser::make_TOK_ID(std::move(val), out_loc);
} }
"$"(info|warning|error|fatal) { "$"(info|warning|error|fatal) {
yylval->string = new std::string(yytext); auto val = std::make_unique<std::string>(YYText());
return TOK_MSG_TASKS; return parser::make_TOK_MSG_TASKS(std::move(val), out_loc);
} }
"$signed" { return TOK_TO_SIGNED; } "$signed" { return parser::make_TOK_TO_SIGNED(out_loc); }
"$unsigned" { return TOK_TO_UNSIGNED; } "$unsigned" { return parser::make_TOK_TO_UNSIGNED(out_loc); }
[a-zA-Z_][a-zA-Z0-9_]*::[a-zA-Z_$][a-zA-Z0-9_$]* { [a-zA-Z_][a-zA-Z0-9_]*::[a-zA-Z_$][a-zA-Z0-9_$]* {
// package qualifier // package qualifier
auto s = std::string("\\") + yytext; auto s = std::string("\\") + YYText();
if (pkg_user_types.count(s) > 0) { if (extra->pkg_user_types.count(s) > 0) {
// package qualified typedefed name // package qualified typedefed name
yylval->string = new std::string(s); auto val = std::make_unique<std::string>(s);
return TOK_PKG_USER_TYPE; return parser::make_TOK_PKG_USER_TYPE(std::move(val), out_loc);
} }
else { else {
// backup before :: just return first part // backup before :: just return first part
size_t len = strchr(yytext, ':') - yytext; size_t len = strchr(YYText(), ':') - YYText();
yyless(len); yyless(len);
yylval->string = new std::string(std::string("\\") + yytext); auto val = std::make_unique<std::string>(std::string("\\") + YYText());
return TOK_ID; return parser::make_TOK_ID(std::move(val), out_loc);
} }
} }
[a-zA-Z_$][a-zA-Z0-9_$]* { [a-zA-Z_$][a-zA-Z0-9_$]* {
auto s = std::string("\\") + yytext; auto s = std::string("\\") + YYText();
if (isUserType(s)) { if (isUserType(extra, s)) {
// previously typedefed name // previously typedefed name
yylval->string = new std::string(s); auto val = std::make_unique<std::string>(s);
return TOK_USER_TYPE; return parser::make_TOK_USER_TYPE(std::move(val), out_loc);
} }
else { else {
yylval->string = new std::string(std::string("\\") + yytext); auto val = std::make_unique<std::string>(std::string("\\") + YYText());
return TOK_ID; return parser::make_TOK_ID(std::move(val), out_loc);
} }
} }
[a-zA-Z_$][a-zA-Z0-9_$\.]* { [a-zA-Z_$][a-zA-Z0-9_$\.]* {
yylval->string = new std::string(std::string("\\") + yytext); auto val = std::make_unique<std::string>(std::string("\\") + YYText());
return TOK_ID; return parser::make_TOK_ID(std::move(val), out_loc);
} }
"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" { "/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
@ -556,7 +586,7 @@ supply1 { return TOK_SUPPLY1; }
); );
printed_warning = true; printed_warning = true;
} }
return TOK_SYNOPSYS_FULL_CASE; return parser::make_TOK_SYNOPSYS_FULL_CASE(out_loc);
} }
<SYNOPSYS_FLAGS>parallel_case { <SYNOPSYS_FLAGS>parallel_case {
static bool printed_warning = false; static bool printed_warning = false;
@ -570,119 +600,115 @@ supply1 { return TOK_SUPPLY1; }
); );
printed_warning = true; printed_warning = true;
} }
return TOK_SYNOPSYS_PARALLEL_CASE; return parser::make_TOK_SYNOPSYS_PARALLEL_CASE(out_loc);
} }
<SYNOPSYS_FLAGS>. /* ignore everything else */ <SYNOPSYS_FLAGS>. /* ignore everything else */
<SYNOPSYS_FLAGS>"*/" { BEGIN(0); } <SYNOPSYS_FLAGS>"*/" { BEGIN(0); }
import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
BEGIN(IMPORT_DPI); BEGIN(IMPORT_DPI);
return TOK_DPI_FUNCTION; return parser::make_TOK_DPI_FUNCTION(out_loc);
} }
<IMPORT_DPI>[a-zA-Z_$][a-zA-Z0-9_$]* { <IMPORT_DPI>[a-zA-Z_$][a-zA-Z0-9_$]* {
yylval->string = new std::string(std::string("\\") + yytext); auto val = std::make_unique<std::string>(std::string("\\") + YYText());
return TOK_ID; return parser::make_TOK_ID(std::move(val), out_loc);
} }
<IMPORT_DPI>[ \t\r\n] /* ignore whitespaces */ <IMPORT_DPI>[ \t\r\n] /* ignore whitespaces */
<IMPORT_DPI>";" { <IMPORT_DPI>";" {
BEGIN(0); BEGIN(0);
return *yytext; return char_tok(*YYText(), out_loc);
} }
<IMPORT_DPI>. { <IMPORT_DPI>. {
return *yytext; return char_tok(*YYText(), out_loc);
} }
"\\"[^ \t\r\n]+ { "\\"[^ \t\r\n]+ {
yylval->string = new std::string(yytext); auto val = std::make_unique<std::string>(YYText());
return TOK_ID; return parser::make_TOK_ID(std::move(val), out_loc);
} }
"(*" { return ATTR_BEGIN; } "(*" { return parser::make_ATTR_BEGIN(out_loc); }
"*)" { return ATTR_END; } "*)" { return parser::make_ATTR_END(out_loc); }
"{*" { return DEFATTR_BEGIN; } "{*" { return parser::make_DEFATTR_BEGIN(out_loc); }
"*}" { return DEFATTR_END; } "*}" { return parser::make_DEFATTR_END(out_loc); }
"**" { return OP_POW; } "**" { return parser::make_OP_POW(out_loc); }
"||" { return OP_LOR; } "||" { return parser::make_OP_LOR(out_loc); }
"&&" { return OP_LAND; } "&&" { return parser::make_OP_LAND(out_loc); }
"==" { return OP_EQ; } "==" { return parser::make_OP_EQ(out_loc); }
"!=" { return OP_NE; } "!=" { return parser::make_OP_NE(out_loc); }
"<=" { return OP_LE; } "<=" { return parser::make_OP_LE(out_loc); }
">=" { return OP_GE; } ">=" { return parser::make_OP_GE(out_loc); }
"===" { return OP_EQX; } "===" { return parser::make_OP_EQX(out_loc); }
"!==" { return OP_NEX; } "!==" { return parser::make_OP_NEX(out_loc); }
"~&" { return OP_NAND; } "~&" { return parser::make_OP_NAND(out_loc); }
"~|" { return OP_NOR; } "~|" { return parser::make_OP_NOR(out_loc); }
"~^" { return OP_XNOR; } "~^" { return parser::make_OP_XNOR(out_loc); }
"^~" { return OP_XNOR; } "^~" { return parser::make_OP_XNOR(out_loc); }
"<<" { return OP_SHL; } "<<" { return parser::make_OP_SHL(out_loc); }
">>" { return OP_SHR; } ">>" { return parser::make_OP_SHR(out_loc); }
"<<<" { return OP_SSHL; } "<<<" { return parser::make_OP_SSHL(out_loc); }
">>>" { return OP_SSHR; } ">>>" { return parser::make_OP_SSHR(out_loc); }
"'" { return OP_CAST; } "'" { return parser::make_OP_CAST(out_loc); }
"::" { return TOK_PACKAGESEP; } "::" { return parser::make_TOK_PACKAGESEP(out_loc); }
"++" { return TOK_INCREMENT; } "++" { return parser::make_TOK_INCREMENT(out_loc); }
"--" { return TOK_DECREMENT; } "--" { return parser::make_TOK_DECREMENT(out_loc); }
"+:" { return TOK_POS_INDEXED; } "+:" { return parser::make_TOK_POS_INDEXED(out_loc); }
"-:" { return TOK_NEG_INDEXED; } "-:" { return parser::make_TOK_NEG_INDEXED(out_loc); }
".*" { return TOK_WILDCARD_CONNECT; } ".*" { return parser::make_TOK_WILDCARD_CONNECT(out_loc); }
"|=" { SV_KEYWORD(TOK_BIT_OR_ASSIGN); } "|=" { SV_KEYWORD(parser::make_TOK_BIT_OR_ASSIGN(out_loc)); }
"&=" { SV_KEYWORD(TOK_BIT_AND_ASSIGN); } "&=" { SV_KEYWORD(parser::make_TOK_BIT_AND_ASSIGN(out_loc)); }
"+=" { SV_KEYWORD(TOK_ADD_ASSIGN); } "+=" { SV_KEYWORD(parser::make_TOK_ADD_ASSIGN(out_loc)); }
"-=" { SV_KEYWORD(TOK_SUB_ASSIGN); } "-=" { SV_KEYWORD(parser::make_TOK_SUB_ASSIGN(out_loc)); }
"^=" { SV_KEYWORD(TOK_BIT_XOR_ASSIGN); } "^=" { SV_KEYWORD(parser::make_TOK_BIT_XOR_ASSIGN(out_loc)); }
"/=" { SV_KEYWORD(TOK_DIV_ASSIGN); } "/=" { SV_KEYWORD(parser::make_TOK_DIV_ASSIGN(out_loc)); }
"%=" { SV_KEYWORD(TOK_MOD_ASSIGN); } "%=" { SV_KEYWORD(parser::make_TOK_MOD_ASSIGN(out_loc)); }
"*=" { SV_KEYWORD(TOK_MUL_ASSIGN); } "*=" { SV_KEYWORD(parser::make_TOK_MUL_ASSIGN(out_loc)); }
"<<=" { SV_KEYWORD(TOK_SHL_ASSIGN); } "<<=" { SV_KEYWORD(parser::make_TOK_SHL_ASSIGN(out_loc)); }
">>=" { SV_KEYWORD(TOK_SHR_ASSIGN); } ">>=" { SV_KEYWORD(parser::make_TOK_SHR_ASSIGN(out_loc)); }
"<<<=" { SV_KEYWORD(TOK_SSHL_ASSIGN); } "<<<=" { SV_KEYWORD(parser::make_TOK_SSHL_ASSIGN(out_loc)); }
">>>=" { SV_KEYWORD(TOK_SSHR_ASSIGN); } ">>>=" { SV_KEYWORD(parser::make_TOK_SSHR_ASSIGN(out_loc)); }
[-+]?[=*]> { [-+]?[=*]> {
if (!specify_mode) REJECT; if (!mode->specify) REJECT;
yylval->string = new std::string(yytext); auto val = std::make_unique<std::string>(YYText());
return TOK_SPECIFY_OPER; return parser::make_TOK_SPECIFY_OPER(std::move(val), out_loc);
} }
"&&&" { "&&&" {
if (!specify_mode) return TOK_IGNORED_SPECIFY_AND; if (!mode->specify) return parser::make_TOK_IGNORED_SPECIFY_AND(out_loc);
return TOK_SPECIFY_AND; return parser::make_TOK_SPECIFY_AND(out_loc);
} }
{UNSIGNED_NUMBER}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; } {UNSIGNED_NUMBER}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); }
{FIXED_POINT_NUMBER_DEC}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; } {FIXED_POINT_NUMBER_DEC}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); }
{FIXED_POINT_NUMBER_NO_DEC}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; } {FIXED_POINT_NUMBER_NO_DEC}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); }
<INITIAL,BASED_CONST>"/*" { comment_caller=YY_START; BEGIN(COMMENT); } <INITIAL,BASED_CONST>"/*" { comment_caller=YY_START; BEGIN(COMMENT); }
<COMMENT>. /* ignore comment body */ <COMMENT>. /* ignore comment body */
<COMMENT>\n /* ignore comment body */ <COMMENT>\n /* ignore comment body */
<COMMENT>"*/" { BEGIN(comment_caller); } <COMMENT>"*/" { BEGIN(comment_caller); }
<INITIAL,BASED_CONST>[ \t\r\n] /* ignore whitespaces */ <INITIAL,BASED_CONST>[ \t\r\n] /* ignore whitespaces */
<INITIAL,BASED_CONST>\\[\r\n] /* ignore continuation sequence */ <INITIAL,BASED_CONST>\\[\r\n] /* ignore continuation sequence */
<INITIAL,BASED_CONST>"//"[^\r\n]* /* ignore one-line comments */ <INITIAL,BASED_CONST>"//"[^\r\n]* /* ignore one-line comments */
<INITIAL>. { return *yytext; } <INITIAL>. { return char_tok(*YYText(), out_loc); }
<*>. { BEGIN(0); return *yytext; } <*>. { BEGIN(0); return char_tok(*YYText(), out_loc); }
%% %%
// this is a hack to avoid the 'yyinput defined but not used' error msgs
void *frontend_verilog_avoid_input_warnings() {
return (void*)&yyinput;
}

View file

@ -0,0 +1,96 @@
#ifndef VERILOG_LOCATION_H
#define VERILOG_LOCATION_H
#include <memory>
#include <string>
#include <stack>
#include <string>
/**
* Provide frontend-wide location tracking like what bison generates
* but using shared_ptr for filename
*/
struct position {
std::shared_ptr<std::string> filename;
int line;
int column;
position(std::shared_ptr<std::string> filename, int line = 1, int column = 1)
: filename(filename), line(line), column(column) {}
position() = default;
position(const position& other) = default;
position& operator=(const position& other) = default;
void advance() { ++column; }
void columns(int count = 1) {
column += count;
}
void lines(int count = 1) {
line += count;
column = 1;
}
std::string to_string() const {
std::ostringstream oss;
if (filename && !filename->empty()) {
oss << *filename << ":";
}
oss << line << ":" << column;
return oss.str();
}
};
struct location {
position begin;
position end;
location() = default;
location(const position& b, const position& e)
: begin(b), end(e) {}
location(const location& other) = default;
location& operator=(const location& other) = default;
void step() { begin = end; }
void columns(int count = 1) {
end.columns(count);
}
void lines(int count = 1) {
end.lines(count);
}
std::string to_string() const {
std::ostringstream oss;
bool same_file = (!begin.filename && !end.filename) ||
(begin.filename && end.filename &&
*begin.filename == *end.filename);
if (same_file) {
if (begin.filename && !begin.filename->empty())
oss << *begin.filename << ":";
if (begin.line == end.line) {
if (begin.column == end.column) {
oss << begin.line << ":" << begin.column;
} else {
oss << begin.line << ":" << begin.column
<< "-" << end.column;
}
} else {
oss << begin.line << ":" << begin.column
<< "-" << end.line << ":" << end.column;
}
} else {
oss << begin.to_string() << "-" << end.to_string();
}
return oss.str();
}
};
static inline std::ostream& operator<<(std::ostream& os, const location& loc) {
return os << loc.to_string();
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -952,10 +952,6 @@ RTLIL::Design::~Design()
delete pr.second; delete pr.second;
for (auto n : bindings_) for (auto n : bindings_)
delete n; delete n;
for (auto n : verilog_packages)
delete n;
for (auto n : verilog_globals)
delete n;
#ifdef WITH_PYTHON #ifdef WITH_PYTHON
RTLIL::Design::get_all_designs()->erase(hashidx_); RTLIL::Design::get_all_designs()->erase(hashidx_);
#endif #endif
@ -5710,16 +5706,10 @@ static void sigspec_parse_split(std::vector<std::string> &tokens, const std::str
tokens.push_back(text.substr(start)); tokens.push_back(text.substr(start));
} }
static int sigspec_parse_get_dummy_line_num()
{
return 0;
}
bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str) bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str)
{ {
cover("kernel.rtlil.sigspec.parse"); cover("kernel.rtlil.sigspec.parse");
AST::current_filename = "input";
std::vector<std::string> tokens; std::vector<std::string> tokens;
sigspec_parse_split(tokens, str, ','); sigspec_parse_split(tokens, str, ',');
@ -5735,12 +5725,11 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri
if (('0' <= netname[0] && netname[0] <= '9') || netname[0] == '\'') { if (('0' <= netname[0] && netname[0] <= '9') || netname[0] == '\'') {
cover("kernel.rtlil.sigspec.parse.const"); cover("kernel.rtlil.sigspec.parse.const");
AST::get_line_num = sigspec_parse_get_dummy_line_num; VERILOG_FRONTEND::ConstParser p{location()};
AST::AstNode *ast = VERILOG_FRONTEND::const2ast(netname); auto ast = p.const2ast(netname);
if (ast == NULL) if (ast == nullptr)
return false; return false;
sig.append(RTLIL::Const(ast->bits)); sig.append(RTLIL::Const(ast->bits));
delete ast;
continue; continue;
} }

View file

@ -1334,7 +1334,7 @@ struct RTLIL::Design
dict<RTLIL::IdString, RTLIL::Module*> modules_; dict<RTLIL::IdString, RTLIL::Module*> modules_;
std::vector<RTLIL::Binding*> bindings_; std::vector<RTLIL::Binding*> bindings_;
std::vector<AST::AstNode*> verilog_packages, verilog_globals; std::vector<std::unique_ptr<AST::AstNode>> verilog_packages, verilog_globals;
std::unique_ptr<define_map_t> verilog_defines; std::unique_ptr<define_map_t> verilog_defines;
std::vector<RTLIL::Selection> selection_stack; std::vector<RTLIL::Selection> selection_stack;

View file

@ -20,6 +20,13 @@ mv zlib-1.2.11/* "$vcxsrc"/yosys/libs/zlib/.
rm -rf zlib-1.2.11 rm -rf zlib-1.2.11
pushd "$vcxsrc"/yosys pushd "$vcxsrc"/yosys
ls libs/zlib/*.c | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' >> ../../srcfiles.txt ls libs/zlib/*.c | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' >> ../../srcfiles.txt
if [ -f "/usr/include/FlexLexer.h" ] ; then
mkdir -p libs/flex
cp /usr/include/FlexLexer.h libs/flex/FlexLexer.h
ls libs/flex/*.h >> ../../srcfiles.txt
fi
popd popd
{ {
n=$(grep -B999 '<ItemGroup>' "$vcxsrc"/YosysVS/YosysVS.vcxproj | wc -l) n=$(grep -B999 '<ItemGroup>' "$vcxsrc"/YosysVS/YosysVS.vcxproj | wc -l)
@ -31,6 +38,9 @@ popd
} > "$vcxsrc"/YosysVS/YosysVS.vcxproj.new } > "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
sed -i 's,</AdditionalIncludeDirectories>,</AdditionalIncludeDirectories>\n <LanguageStandard>stdcpp17</LanguageStandard>\n <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>,g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new sed -i 's,</AdditionalIncludeDirectories>,</AdditionalIncludeDirectories>\n <LanguageStandard>stdcpp17</LanguageStandard>\n <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>,g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
if [ -f "/usr/include/FlexLexer.h" ] ; then
sed -i 's,</AdditionalIncludeDirectories>,;..\\yosys\\libs\\flex</AdditionalIncludeDirectories>,g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
fi
mv "$vcxsrc"/YosysVS/YosysVS.vcxproj.new "$vcxsrc"/YosysVS/YosysVS.vcxproj mv "$vcxsrc"/YosysVS/YosysVS.vcxproj.new "$vcxsrc"/YosysVS/YosysVS.vcxproj
mkdir -p "$vcxsrc"/yosys mkdir -p "$vcxsrc"/yosys

View file

@ -368,14 +368,8 @@ struct DesignPass : public Pass {
if (reset_mode || reset_vlog_mode || !load_name.empty() || push_mode || pop_mode) if (reset_mode || reset_vlog_mode || !load_name.empty() || push_mode || pop_mode)
{ {
for (auto node : design->verilog_packages)
delete node;
design->verilog_packages.clear(); design->verilog_packages.clear();
for (auto node : design->verilog_globals)
delete node;
design->verilog_globals.clear(); design->verilog_globals.clear();
design->verilog_defines->clear(); design->verilog_defines->clear();
} }

View file

@ -100,7 +100,7 @@ enum class WrTransKind {
struct WrTransDef { struct WrTransDef {
WrTransTargetKind target_kind; WrTransTargetKind target_kind;
int target_group; int target_group = 0;
WrTransKind kind; WrTransKind kind;
}; };