Merge branch 'master' into add_fifo_bram_macros
diff --git a/Makefile b/Makefile
index fc39ff4..70433f7 100644
--- a/Makefile
+++ b/Makefile
@@ -71,9 +71,9 @@
CLANG_FORMAT ?= clang-format-8
.PHONY: format
format:
- find . \( -name "*.h" -o -name "*.cc" \) -and -not -path './third_party/*' -print0 | xargs -0 -P $$(nproc) ${CLANG_FORMAT} -style=file -i
+ find . \( -name "*.h" -o -name "*.cc" \) -and -not -path '*/third_party/*' -print0 | xargs -0 -P $$(nproc) ${CLANG_FORMAT} -style=file -i
VERIBLE_FORMAT ?= verible-verilog-format
.PHONY: format-verilog
format-verilog:
- find */tests \( -name "*.v" -o -name "*.sv" \) -and -not -path './third_party/*' -print0 | xargs -0 $(VERIBLE_FORMAT) --inplace
+ find */tests \( -name "*.v" -o -name "*.sv" \) -and -not -path '*/third_party/*' -print0 | xargs -0 $(VERIBLE_FORMAT) --inplace
diff --git a/environment.yml b/environment.yml
index a4cf46c..dc51454 100644
--- a/environment.yml
+++ b/environment.yml
@@ -20,5 +20,5 @@
- litex-hub
dependencies:
- litex-hub::yosys=0.17_7_g990c9b8e1=20220512_085338_py37
- - litex-hub::surelog
+ - litex-hub::surelog=0.0_5519_g900fb2499=20221223_060448_py37
- litex-hub::iverilog
diff --git a/ql-qlf-plugin/synth_quicklogic.cc b/ql-qlf-plugin/synth_quicklogic.cc
index fbbacb5..b6b475e 100644
--- a/ql-qlf-plugin/synth_quicklogic.cc
+++ b/ql-qlf-plugin/synth_quicklogic.cc
@@ -554,11 +554,7 @@
if (check_label("blif")) {
if (!blif_file.empty()) {
- if (inferAdder) {
- run(stringf("write_blif -param %s", help_mode ? "<file-name>" : blif_file.c_str()));
- } else {
- run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str()));
- }
+ run(stringf("write_blif -param %s", help_mode ? "<file-name>" : blif_file.c_str()));
}
}
diff --git a/systemverilog-plugin/Makefile b/systemverilog-plugin/Makefile
index a1d69e1..af5320d 100644
--- a/systemverilog-plugin/Makefile
+++ b/systemverilog-plugin/Makefile
@@ -18,11 +18,11 @@
NAME = systemverilog
SOURCES = UhdmAst.cc \
- UhdmAstUpstream.cc \
uhdmastfrontend.cc \
uhdmcommonfrontend.cc \
uhdmsurelogastfrontend.cc \
- uhdmastreport.cc
+ uhdmastreport.cc \
+ third_party/yosys/const2ast.cc
# Directory to search for Surelog and UHDM libraries
UHDM_INSTALL_DIR ?= /usr/local
diff --git a/systemverilog-plugin/UhdmAst.cc b/systemverilog-plugin/UhdmAst.cc
index 20e68a0..00816d6 100644
--- a/systemverilog-plugin/UhdmAst.cc
+++ b/systemverilog-plugin/UhdmAst.cc
@@ -14,9 +14,33 @@
#include <uhdm/uhdm.h>
#include <uhdm/vpi_user.h>
-#include "UhdmAstUpstream.h"
+#include "third_party/yosys/const2ast.h"
YOSYS_NAMESPACE_BEGIN
+namespace VERILOG_FRONTEND
+{
+extern bool sv_mode;
+}
+YOSYS_NAMESPACE_END
+
+namespace systemverilog_plugin
+{
+
+using namespace ::Yosys;
+
+namespace AST
+{
+using namespace ::Yosys::AST;
+
+namespace Extended
+{
+enum AstNodeTypeExtended {
+ AST_DOT = ::Yosys::AST::AST_BIND + 1, // here we always want to point to the last element of yosys' AstNodeType
+ AST_BREAK,
+ AST_CONTINUE
+};
+}
+} // namespace AST
/*static*/ const IdString &UhdmAst::partial()
{
@@ -96,6 +120,13 @@
return objectName;
}
+static AST::AstNode *mkconst_real(double d)
+{
+ AST::AstNode *node = new AST::AstNode(AST::AST_REALVALUE);
+ node->realvalue = d;
+ return node;
+}
+
static AST::AstNode *make_range(int left, int right, bool is_signed = false)
{
// generate a pre-validated range node for a fixed signal range.
@@ -486,7 +517,7 @@
AST::AstNode *struct_range = nullptr;
for (auto c : search_node->children) {
- if (c->type == static_cast<int>(AST::AST_DOT)) {
+ if (c->type == static_cast<int>(AST::Extended::AST_DOT)) {
// There should be only 1 AST_DOT node children
log_assert(!sub_dot);
sub_dot = expand_dot(current_struct_elem, c);
@@ -851,8 +882,8 @@
static void simplify(AST::AstNode *current_node, AST::AstNode *parent_node)
{
- auto dot_it =
- std::find_if(current_node->children.begin(), current_node->children.end(), [](auto c) { return c->type == static_cast<int>(AST::AST_DOT); });
+ auto dot_it = std::find_if(current_node->children.begin(), current_node->children.end(),
+ [](auto c) { return c->type == static_cast<int>(AST::Extended::AST_DOT); });
AST::AstNode *dot = (dot_it != current_node->children.end()) ? *dot_it : nullptr;
AST::AstNode *expanded = nullptr;
@@ -875,8 +906,8 @@
break;
} else {
current_node->str += "." + dot->str.substr(1);
- dot_it =
- std::find_if(dot->children.begin(), dot->children.end(), [](auto c) { return c->type == static_cast<int>(AST::AST_DOT); });
+ dot_it = std::find_if(dot->children.begin(), dot->children.end(),
+ [](auto c) { return c->type == static_cast<int>(AST::Extended::AST_DOT); });
parent_node = dot;
dot = (dot_it != dot->children.end()) ? *dot_it : nullptr;
}
@@ -1155,7 +1186,7 @@
}
// handle vpiBinStrVal, vpiDecStrVal and vpiHexStrVal
if (std::strchr(val.value.str, '\'')) {
- return VERILOG_FRONTEND::const2ast(val.value.str, 0, false);
+ return ::systemverilog_plugin::const2ast(val.value.str, 0, false);
} else {
auto size = vpi_get(vpiSize, obj_h);
if (size == 0) {
@@ -1163,7 +1194,7 @@
c->is_unsized = true;
return c;
} else {
- return VERILOG_FRONTEND::const2ast(std::to_string(size) + strValType + val.value.str, 0, false);
+ return ::systemverilog_plugin::const2ast(std::to_string(size) + strValType + val.value.str, 0, false);
}
}
}
@@ -1233,15 +1264,15 @@
}
break;
}
- case AST::AST_BREAK:
- case AST::AST_CONTINUE: {
+ case AST::Extended::AST_BREAK:
+ case AST::Extended::AST_CONTINUE: {
std::for_each(it, block->children.end(), [](auto *node) { delete node; });
block->children.erase(it, block->children.end());
if (!continue_wire)
continue_wire = make_cond_var("$continue");
auto *continue_id = make_identifier(continue_wire->str);
block->children.push_back(make_ast_node(AST::AST_ASSIGN_EQ, {continue_id, AST::AstNode::mkconst_int(1, false)}));
- if (type == AST::AST_BREAK) {
+ if (type == AST::Extended::AST_BREAK) {
if (!break_wire)
break_wire = make_cond_var("$break");
auto *break_id = make_identifier(break_wire->str);
@@ -1998,42 +2029,67 @@
void UhdmAst::process_enum_typespec()
{
+ // BaseTypespec specifies underlying type of the enum.
+ // The BaseTypespec has at most one explicit packed dimension (range).
+ // When base type is not specified in SystemVerilog code, it is assumed to be an int.
+ // Type of enum items (constants) is the same as the enum type.
current_node = make_ast_node(AST::AST_ENUM);
+ bool has_base_type = false;
+ visit_one_to_one({vpiBaseTypespec}, obj_h, [&](AST::AstNode *node) {
+ has_base_type = true;
+ current_node->children = std::move(node->children);
+ current_node->attributes = std::move(node->attributes);
+ current_node->is_signed = node->is_signed;
+ current_node->is_logic = node->is_logic;
+ delete node;
+ });
+ if (!has_base_type) {
+ // Base typespec is `int` by default
+ // TODO (mglb): This is almost the same code as in `process_int_typespec()`. Put common code in dedicated function.
+ std::vector<AST::AstNode *> packed_ranges;
+ packed_ranges.push_back(make_range(31, 0));
+ add_multirange_wire(current_node, std::move(packed_ranges), {});
+ current_node->is_signed = true;
+ }
+ // We have to restore node's range_* properties if there's no range.
+ const auto range_left = current_node->range_left;
+ const auto range_right = current_node->range_right;
+ const auto range_valid = current_node->range_valid;
+ // Create a range from the typespec just for the purpose of copying it to consts.
+ convert_packed_unpacked_range(current_node);
+ const auto range_it = std::find_if(current_node->children.cbegin(), current_node->children.cend(),
+ [](const AST::AstNode *n) { return n->type == AST::AST_RANGE || n->type == AST::AST_MULTIRANGE; });
+ const auto *const range = range_it != current_node->children.cend() ? *range_it : nullptr;
+ if (range) {
+ current_node->children.erase(range_it);
+ } else {
+ current_node->range_left = range_left;
+ current_node->range_right = range_right;
+ current_node->range_valid = range_valid;
+ }
+
visit_one_to_one({vpiTypedefAlias}, obj_h, [&](AST::AstNode *node) {
if (node) {
- current_node->attributes["\\enum_base_type"] = node->clone();
+ current_node->attributes["\\enum_base_type"] = node;
}
});
- visit_one_to_many({vpiEnumConst}, obj_h, [&](AST::AstNode *node) { current_node->children.push_back(node); });
- vpiHandle typespec_h = vpi_handle(vpiBaseTypespec, obj_h);
- if (typespec_h) {
- int typespec_type = vpi_get(vpiType, typespec_h);
- switch (typespec_type) {
- case vpiLogicTypespec: {
- current_node->is_logic = true;
- shared.report.mark_handled(typespec_h);
- break;
+ visit_one_to_many({vpiEnumConst}, obj_h, [&](AST::AstNode *node) {
+ // Enum const must have the same type and ranges as the enum.
+ node->is_logic = current_node->is_logic;
+ node->is_signed = current_node->is_signed;
+ if (range) {
+ node->children.push_back(range->clone());
+ node->range_valid = true;
+ } else {
+ node->range_left = range_left;
+ node->range_right = range_right;
+ node->range_valid = range_valid;
}
- case vpiByteTypespec:
- case vpiIntTypespec:
- case vpiIntegerTypespec: {
- current_node->is_signed = vpi_get(vpiSigned, typespec_h);
- shared.report.mark_handled(typespec_h);
- break;
- }
- case vpiBitTypespec: {
- shared.report.mark_handled(typespec_h);
- break;
- }
- default: {
- const uhdm_handle *const handle = (const uhdm_handle *)typespec_h;
- const UHDM::BaseClass *const object = (const UHDM::BaseClass *)handle->object;
- report_error("%s:%d: Encountered unhandled typespec in process_enum_typespec: '%s' of type '%s'\n", object->VpiFile().c_str(),
- object->VpiLineNo(), object->VpiName().c_str(), UHDM::VpiTypeName(typespec_h).c_str());
- break;
- }
- }
- vpi_release_handle(typespec_h);
+ // IMPORTANT: invalidates `range_it`!
+ current_node->children.push_back(node);
+ });
+ if (range) {
+ delete range;
}
}
@@ -2045,7 +2101,6 @@
constant_node->filename = current_node->filename;
constant_node->location = current_node->location;
current_node->children.push_back(constant_node);
- current_node->children.push_back(make_range(constant_node->range_left, constant_node->range_right, true));
}
}
@@ -3462,7 +3517,7 @@
log_assert(!node->children.empty());
top_node->children.push_back(node->children[0]);
} else {
- node->type = static_cast<AST::AstNodeType>(AST::AST_DOT);
+ node->type = static_cast<AST::AstNodeType>(AST::Extended::AST_DOT);
top_node->children.push_back(node);
top_node = node;
}
@@ -3525,7 +3580,7 @@
if (vpi_get(vpiType, typespec_h) == vpiStringTypespec) {
std::string field_name = vpi_get_str(vpiName, typespec_h);
if (field_name != "default") { // TODO: better support of the default keyword
- auto field = new AST::AstNode(static_cast<AST::AstNodeType>(AST::AST_DOT));
+ auto field = new AST::AstNode(static_cast<AST::AstNodeType>(AST::Extended::AST_DOT));
field->str = field_name;
current_node->children[0]->children.push_back(field);
}
@@ -4315,11 +4370,11 @@
break;
case vpiBreak:
// Will be resolved later by loop processor
- current_node = make_ast_node(static_cast<AST::AstNodeType>(AST::AST_BREAK));
+ current_node = make_ast_node(static_cast<AST::AstNodeType>(AST::Extended::AST_BREAK));
break;
case vpiContinue:
// Will be resolved later by loop processor
- current_node = make_ast_node(static_cast<AST::AstNodeType>(AST::AST_CONTINUE));
+ current_node = make_ast_node(static_cast<AST::AstNodeType>(AST::Extended::AST_CONTINUE));
break;
case vpiGenScopeArray:
process_gen_scope_array();
@@ -4472,4 +4527,4 @@
}
}
-YOSYS_NAMESPACE_END
+} // namespace systemverilog_plugin
diff --git a/systemverilog-plugin/UhdmAst.h b/systemverilog-plugin/UhdmAst.h
index 1e77c17..f3b1017 100644
--- a/systemverilog-plugin/UhdmAst.h
+++ b/systemverilog-plugin/UhdmAst.h
@@ -8,7 +8,8 @@
#include "uhdmastshared.h"
#include <uhdm/uhdm.h>
-YOSYS_NAMESPACE_BEGIN
+namespace systemverilog_plugin
+{
class UhdmAst
{
@@ -16,43 +17,44 @@
// Walks through one-to-many relationships from given parent
// node through the VPI interface, visiting child nodes belonging to
// ChildrenNodeTypes that are present in the given object.
- void visit_one_to_many(const std::vector<int> child_node_types, vpiHandle parent_handle, const std::function<void(AST::AstNode *)> &f);
+ void visit_one_to_many(const std::vector<int> child_node_types, vpiHandle parent_handle, const std::function<void(::Yosys::AST::AstNode *)> &f);
// Walks through one-to-one relationships from given parent
// node through the VPI interface, visiting child nodes belonging to
// ChildrenNodeTypes that are present in the given object.
- void visit_one_to_one(const std::vector<int> child_node_types, vpiHandle parent_handle, const std::function<void(AST::AstNode *)> &f);
+ void visit_one_to_one(const std::vector<int> child_node_types, vpiHandle parent_handle, const std::function<void(::Yosys::AST::AstNode *)> &f);
// Visit children of type vpiRange that belong to the given parent node.
- void visit_range(vpiHandle obj_h, const std::function<void(AST::AstNode *)> &f);
+ void visit_range(vpiHandle obj_h, const std::function<void(::Yosys::AST::AstNode *)> &f);
// Visit the default expression assigned to a variable.
void visit_default_expr(vpiHandle obj_h);
// Create an AstNode of the specified type with metadata extracted from
// the given vpiHandle.
- AST::AstNode *make_ast_node(AST::AstNodeType type, std::vector<AST::AstNode *> children = {}, bool prefer_full_name = false);
+ ::Yosys::AST::AstNode *make_ast_node(::Yosys::AST::AstNodeType type, std::vector<::Yosys::AST::AstNode *> children = {},
+ bool prefer_full_name = false);
// Create an identifier AstNode
- AST::AstNode *make_identifier(const std::string &name);
+ ::Yosys::AST::AstNode *make_identifier(const std::string &name);
// Makes the passed node a cell node of the specified type
- void make_cell(vpiHandle obj_h, AST::AstNode *node, AST::AstNode *type);
+ void make_cell(vpiHandle obj_h, ::Yosys::AST::AstNode *node, ::Yosys::AST::AstNode *type);
// Moves a type node to the specified node
- void move_type_to_new_typedef(AST::AstNode *current_node, AST::AstNode *type_node);
+ void move_type_to_new_typedef(::Yosys::AST::AstNode *current_node, ::Yosys::AST::AstNode *type_node);
// Go up the UhdmAst to find a parent node of the specified type
- AST::AstNode *find_ancestor(const std::unordered_set<AST::AstNodeType> &types);
+ ::Yosys::AST::AstNode *find_ancestor(const std::unordered_set<::Yosys::AST::AstNodeType> &types);
// Reports that something went wrong with reading the UHDM file
void report_error(const char *format, ...) const;
// Processes the value connected to the specified node
- AST::AstNode *process_value(vpiHandle obj_h);
+ ::Yosys::AST::AstNode *process_value(vpiHandle obj_h);
// Transforms break and continue nodes into structures accepted by the AST frontend
- void transform_breaks_continues(AST::AstNode *loop, AST::AstNode *decl_block);
+ void transform_breaks_continues(::Yosys::AST::AstNode *loop, ::Yosys::AST::AstNode *decl_block);
// The parent UhdmAst
UhdmAst *parent;
@@ -64,7 +66,7 @@
vpiHandle obj_h = 0;
// The current Yosys AST node
- AST::AstNode *current_node = nullptr;
+ ::Yosys::AST::AstNode *current_node = nullptr;
// Indentation used for debug printing
std::string indent;
@@ -128,7 +130,7 @@
void process_logic_var();
void process_sys_func_call();
// use for task calls and function calls
- void process_tf_call(AST::AstNodeType type);
+ void process_tf_call(::Yosys::AST::AstNodeType type);
void process_immediate_assert();
void process_hier_path();
void process_logic_typespec();
@@ -148,7 +150,7 @@
void process_while();
void process_gate();
void process_primterm();
- void simplify_parameter(AST::AstNode *parameter, AST::AstNode *module_node = nullptr);
+ void simplify_parameter(::Yosys::AST::AstNode *parameter, ::Yosys::AST::AstNode *module_node = nullptr);
void process_unsupported_stmt(const UHDM::BaseClass *object);
UhdmAst(UhdmAst *p, UhdmAstShared &s, const std::string &i) : parent(p), shared(s), indent(i)
@@ -161,23 +163,19 @@
UhdmAst(UhdmAstShared &s, const std::string &i = "") : UhdmAst(nullptr, s, i) {}
// Visits single VPI object and creates proper AST node
- AST::AstNode *process_object(vpiHandle obj_h);
+ ::Yosys::AST::AstNode *process_object(vpiHandle obj_h);
// Visits all VPI design objects and returns created ASTs
- AST::AstNode *visit_designs(const std::vector<vpiHandle> &designs);
+ ::Yosys::AST::AstNode *visit_designs(const std::vector<vpiHandle> &designs);
- static const IdString &partial();
- static const IdString &packed_ranges();
- static const IdString &unpacked_ranges();
+ static const ::Yosys::IdString &partial();
+ static const ::Yosys::IdString &packed_ranges();
+ static const ::Yosys::IdString &unpacked_ranges();
// set this attribute to force conversion of multirange wire to single range. It is useful to force-convert some memories.
- static const IdString &force_convert();
- static const IdString &is_imported();
+ static const ::Yosys::IdString &force_convert();
+ static const ::Yosys::IdString &is_imported();
};
-namespace VERILOG_FRONTEND
-{
-extern bool sv_mode;
-}
-YOSYS_NAMESPACE_END
+} // namespace systemverilog_plugin
#endif
diff --git a/systemverilog-plugin/tests/Makefile b/systemverilog-plugin/tests/Makefile
index e078fa7..849a9f9 100644
--- a/systemverilog-plugin/tests/Makefile
+++ b/systemverilog-plugin/tests/Makefile
@@ -16,10 +16,18 @@
TESTS = counter \
break_continue \
- separate-compilation
+ separate-compilation \
+ debug-flag \
+ report-flag \
+ defines \
+ defaults
include $(shell pwd)/../../Makefile_test.common
counter_verify = true
break_continue_verify = $(call diff_test,break_continue,out)
separate-compilation_verify = true
+debug-flag_verify = true
+report-flag_verify = true
+defaults_verify = true
+defines_verify = true
diff --git a/systemverilog-plugin/tests/debug-flag/debug-flag-buf.sv b/systemverilog-plugin/tests/debug-flag/debug-flag-buf.sv
new file mode 100644
index 0000000..565946b
--- /dev/null
+++ b/systemverilog-plugin/tests/debug-flag/debug-flag-buf.sv
@@ -0,0 +1,21 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+module BUF (
+ input I,
+ output O
+);
+ assign O = I;
+endmodule;
diff --git a/systemverilog-plugin/tests/debug-flag/debug-flag-pkg.sv b/systemverilog-plugin/tests/debug-flag/debug-flag-pkg.sv
new file mode 100644
index 0000000..b0362fc
--- /dev/null
+++ b/systemverilog-plugin/tests/debug-flag/debug-flag-pkg.sv
@@ -0,0 +1,19 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+package pkg;
+ parameter BITS = 4;
+ parameter LOG2DELAY = 22;
+endpackage
diff --git a/systemverilog-plugin/tests/debug-flag/debug-flag.tcl b/systemverilog-plugin/tests/debug-flag/debug-flag.tcl
new file mode 100644
index 0000000..86cfee5
--- /dev/null
+++ b/systemverilog-plugin/tests/debug-flag/debug-flag.tcl
@@ -0,0 +1,16 @@
+yosys -import
+if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
+yosys -import ;# ingest plugin commands
+
+set TMP_DIR /tmp
+if { [info exists ::env(TMPDIR) ] } {
+ set TMP_DIR $::env(TMPDIR)
+}
+
+# Testing simple round-trip
+read_systemverilog -debug -odir $TMP_DIR/debug-flag-test -defer $::env(DESIGN_TOP)-pkg.sv
+read_systemverilog -debug -odir $TMP_DIR/debug-flag-test -defer $::env(DESIGN_TOP)-buf.sv
+read_systemverilog -debug -odir $TMP_DIR/debug-flag-test -defer $::env(DESIGN_TOP).v
+read_systemverilog -debug -odir $TMP_DIR/debug-flag-test -link
+hierarchy
+write_verilog
diff --git a/systemverilog-plugin/tests/debug-flag/debug-flag.v b/systemverilog-plugin/tests/debug-flag/debug-flag.v
new file mode 100644
index 0000000..5bd294a
--- /dev/null
+++ b/systemverilog-plugin/tests/debug-flag/debug-flag.v
@@ -0,0 +1,31 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+module top (
+ input clk,
+ output [3:0] led
+);
+
+ wire bufg;
+ BUF bufgctrl (
+ .I(clk),
+ .O(bufg)
+ );
+ reg [pkg::BITS + pkg::LOG2DELAY-1 : 0] counter = 0;
+ always @(posedge bufg) begin
+ counter <= counter + 1;
+ end
+ assign led[3:0] = counter >> pkg::LOG2DELAY;
+endmodule
diff --git a/systemverilog-plugin/tests/defaults/defaults.tcl b/systemverilog-plugin/tests/defaults/defaults.tcl
new file mode 100644
index 0000000..a363895
--- /dev/null
+++ b/systemverilog-plugin/tests/defaults/defaults.tcl
@@ -0,0 +1,23 @@
+yosys -import
+if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
+yosys -import ;# ingest plugin commands
+
+set TMP_DIR /tmp
+if { [info exists ::env(TMPDIR) ] } {
+ set TMP_DIR $::env(TMPDIR)
+}
+
+# Define forbidden value
+systemverilog_defaults -add -DPAKALA
+# Stash it
+systemverilog_defaults -push
+systemverilog_defaults -clear
+read_systemverilog $::env(DESIGN_TOP).v
+# Allow parsing the module again
+delete top
+systemverilog_defaults -pop
+# Skip check for forbidden value
+systemverilog_defaults -add -Pbypass=1
+read_systemverilog $::env(DESIGN_TOP).v
+hierarchy
+write_verilog
diff --git a/systemverilog-plugin/tests/defaults/defaults.v b/systemverilog-plugin/tests/defaults/defaults.v
new file mode 100644
index 0000000..f565a77
--- /dev/null
+++ b/systemverilog-plugin/tests/defaults/defaults.v
@@ -0,0 +1,28 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+module top #(
+ parameter bit bypass = 0
+)(
+ input clk,
+ output out
+);
+
+`ifdef PAKALA
+ initial if(!bypass) $stop("Defined forbidden value");
+`endif
+ assign out = clk;
+endmodule
diff --git a/systemverilog-plugin/tests/defines/defines.tcl b/systemverilog-plugin/tests/defines/defines.tcl
new file mode 100644
index 0000000..030c1ad
--- /dev/null
+++ b/systemverilog-plugin/tests/defines/defines.tcl
@@ -0,0 +1,15 @@
+yosys -import
+if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
+yosys -import ;# ingest plugin commands
+
+set TMP_DIR /tmp
+if { [info exists ::env(TMPDIR) ] } {
+ set TMP_DIR $::env(TMPDIR)
+}
+
+systemverilog_defines -DPONA
+systemverilog_defines -DPAKALA
+systemverilog_defines -UPAKALA
+read_systemverilog $::env(DESIGN_TOP).v
+hierarchy
+write_verilog
diff --git a/systemverilog-plugin/tests/defines/defines.v b/systemverilog-plugin/tests/defines/defines.v
new file mode 100644
index 0000000..528e9f1
--- /dev/null
+++ b/systemverilog-plugin/tests/defines/defines.v
@@ -0,0 +1,29 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+module top (
+ input clk,
+ output out
+);
+
+`ifndef PONA
+ initial $stop("Define failed");
+`endif
+`ifdef PAKALA
+ initial $stop("Undefine failed");
+`endif
+ assign out = clk;
+endmodule
diff --git a/systemverilog-plugin/tests/report-flag/report-flag-buf.sv b/systemverilog-plugin/tests/report-flag/report-flag-buf.sv
new file mode 100644
index 0000000..565946b
--- /dev/null
+++ b/systemverilog-plugin/tests/report-flag/report-flag-buf.sv
@@ -0,0 +1,21 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+module BUF (
+ input I,
+ output O
+);
+ assign O = I;
+endmodule;
diff --git a/systemverilog-plugin/tests/report-flag/report-flag-pkg.sv b/systemverilog-plugin/tests/report-flag/report-flag-pkg.sv
new file mode 100644
index 0000000..b0362fc
--- /dev/null
+++ b/systemverilog-plugin/tests/report-flag/report-flag-pkg.sv
@@ -0,0 +1,19 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+package pkg;
+ parameter BITS = 4;
+ parameter LOG2DELAY = 22;
+endpackage
diff --git a/systemverilog-plugin/tests/report-flag/report-flag.tcl b/systemverilog-plugin/tests/report-flag/report-flag.tcl
new file mode 100644
index 0000000..3a3cc6d
--- /dev/null
+++ b/systemverilog-plugin/tests/report-flag/report-flag.tcl
@@ -0,0 +1,16 @@
+yosys -import
+if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
+yosys -import ;# ingest plugin commands
+
+set TMP_DIR /tmp
+if { [info exists ::env(TMPDIR) ] } {
+ set TMP_DIR $::env(TMPDIR)
+}
+
+# Testing simple round-trip
+read_systemverilog -report $TMP_DIR/report-flag-test -odir $TMP_DIR/report-flag-test -defer $::env(DESIGN_TOP)-pkg.sv
+read_systemverilog -report $TMP_DIR/report-flag-test -odir $TMP_DIR/report-flag-test -defer $::env(DESIGN_TOP)-buf.sv
+read_systemverilog -report $TMP_DIR/report-flag-test -odir $TMP_DIR/report-flag-test -defer $::env(DESIGN_TOP).v
+read_systemverilog -report $TMP_DIR/report-flag-test -odir $TMP_DIR/report-flag-test -link
+hierarchy
+write_verilog
diff --git a/systemverilog-plugin/tests/report-flag/report-flag.v b/systemverilog-plugin/tests/report-flag/report-flag.v
new file mode 100644
index 0000000..5bd294a
--- /dev/null
+++ b/systemverilog-plugin/tests/report-flag/report-flag.v
@@ -0,0 +1,31 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+module top (
+ input clk,
+ output [3:0] led
+);
+
+ wire bufg;
+ BUF bufgctrl (
+ .I(clk),
+ .O(bufg)
+ );
+ reg [pkg::BITS + pkg::LOG2DELAY-1 : 0] counter = 0;
+ always @(posedge bufg) begin
+ counter <= counter + 1;
+ end
+ assign led[3:0] = counter >> pkg::LOG2DELAY;
+endmodule
diff --git a/systemverilog-plugin/third_party/yosys/README b/systemverilog-plugin/third_party/yosys/README
new file mode 100644
index 0000000..ceb62a9
--- /dev/null
+++ b/systemverilog-plugin/third_party/yosys/README
@@ -0,0 +1,17 @@
+Files in this directory were copied from Yosys sources and slightly adapted.
+Original sources and their license available at https://github.com/YosysHQ/yosys.
+
+Copied files, their sources, changes & notes:
+
+- const2ast.cc: yosys/frontends/verilog/const2ast.cc (rev. 72787f5)
+ - The file is a part of Yosys Verilog frontend, which is not publicly exposed
+ by Yosys. Copy has been made to avoid relying on internal details.
+ - Changes:
+ - C++ includes adapted to not rely on `verilog_frontend.h` file.
+ - Removed Yosys namespace; `const2ast()` has been placed inside
+ `systemverilog_plugin` namespace to avoid conflicts with the symbol from
+ Yosys when statically linking.
+
+Non-copied files placed here for interfacing purposes:
+
+- const2ast.h
diff --git a/systemverilog-plugin/third_party/yosys/const2ast.cc b/systemverilog-plugin/third_party/yosys/const2ast.cc
new file mode 100644
index 0000000..96ea6cc
--- /dev/null
+++ b/systemverilog-plugin/third_party/yosys/const2ast.cc
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ *
+ * ---
+ *
+ * The Verilog frontend.
+ *
+ * This frontend is using the AST frontend library (see frontends/ast/).
+ * Thus this frontend does not generate RTLIL code directly but creates an
+ * AST directly from the Verilog parse tree and then passes this AST to
+ * the AST frontend library.
+ *
+ * ---
+ *
+ * This file contains an ad-hoc parser for Verilog constants. The Verilog
+ * lexer does only recognize a constant but does not actually split it to its
+ * components. I.e. it just passes the Verilog code for the constant to the
+ * bison parser. The parser then uses the function const2ast() from this file
+ * to create an AST node for the constant.
+ *
+ * ---
+ *
+ * The file has been adapted for use in Yosys SystemVerilog Plugin.
+ *
+ */
+
+#include "const2ast.h"
+#include "frontends/ast/ast.h"
+#include "kernel/log.h"
+
+#include <string>
+#include <cmath>
+#include <vector>
+
+using namespace Yosys;
+using namespace Yosys::AST;
+
+// 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 carry = 0;
+ for (size_t i = 0; i < digits.size(); i++) {
+ if (digits[i] >= 10)
+ log_file_error(current_filename, get_line_num(), "Invalid use of [a-fxz?] in decimal constant.\n");
+ digits[i] += carry * 10;
+ carry = digits[i] % 2;
+ digits[i] /= 2;
+ }
+ while (!digits.empty() && !digits.front())
+ digits.erase(digits.begin());
+ return carry;
+}
+
+// find the number of significant bits in a binary number (not including the sign bit)
+static int my_ilog2(int x)
+{
+ int ret = 0;
+ while (x != 0 && x != -1) {
+ x = x >> 1;
+ ret++;
+ }
+ return ret;
+}
+
+// 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)
+{
+ // all digits in string (MSB at index 0)
+ std::vector<uint8_t> digits;
+
+ while (*str) {
+ if ('0' <= *str && *str <= '9')
+ digits.push_back(*str - '0');
+ else if ('a' <= *str && *str <= 'f')
+ digits.push_back(10 + *str - 'a');
+ else if ('A' <= *str && *str <= 'F')
+ digits.push_back(10 + *str - 'A');
+ else if (*str == 'x' || *str == 'X')
+ digits.push_back(0xf0);
+ else if (*str == 'z' || *str == 'Z' || *str == '?')
+ digits.push_back(0xf1);
+ str++;
+ }
+
+ if (base == 10 && GetSize(digits) == 1 && digits.front() >= 0xf0)
+ base = 2;
+
+ data.clear();
+
+ if (base == 10) {
+ while (!digits.empty())
+ data.push_back(my_decimal_div_by_two(digits) ? State::S1 : State::S0);
+ } else {
+ int bits_per_digit = my_ilog2(base-1);
+ for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) {
+ 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",
+ base-1, base);
+ for (int i = 0; i < bits_per_digit; i++) {
+ int bitmask = 1 << i;
+ if (*it == 0xf0)
+ data.push_back(case_type == 'x' ? RTLIL::Sa : RTLIL::Sx);
+ else if (*it == 0xf1)
+ data.push_back(case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz);
+ else
+ data.push_back((*it & bitmask) ? State::S1 : State::S0);
+ }
+ }
+ }
+
+ int len = GetSize(data);
+ RTLIL::State msb = data.empty() ? State::S0 : data.back();
+
+ if (len_in_bits < 0) {
+ if (len < 32)
+ data.resize(32, msb == State::S0 || msb == State::S1 ? RTLIL::S0 : msb);
+ return;
+ }
+
+ 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);
+
+ for (len = len - 1; len >= 0; len--)
+ if (data[len] == State::S1)
+ break;
+ if (msb == State::S0 || msb == State::S1) {
+ len += 1;
+ data.resize(len_in_bits, State::S0);
+ } else {
+ len += 2;
+ data.resize(len_in_bits, msb);
+ }
+
+ 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");
+
+ if (len > len_in_bits)
+ log_warning("Literal has a width of %d bit, but value requires %d bit. (%s:%d)\n",
+ len_in_bits, len, current_filename.c_str(), get_line_num());
+}
+
+// convert the Verilog code for a constant to an AST node
+AstNode *systemverilog_plugin::const2ast(std::string code, char case_type, bool warn_z)
+{
+ if (warn_z) {
+ AstNode *ret = const2ast(code, case_type);
+ 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",
+ current_filename.c_str(), get_line_num());
+ return ret;
+ }
+
+ const char *str = code.c_str();
+
+ // Strings
+ if (*str == '"') {
+ int len = strlen(str) - 2;
+ std::vector<RTLIL::State> data;
+ data.reserve(len * 8);
+ for (int i = 0; i < len; i++) {
+ unsigned char ch = str[len - i];
+ for (int j = 0; j < 8; j++) {
+ data.push_back((ch & 1) ? State::S1 : State::S0);
+ ch = ch >> 1;
+ }
+ }
+ AstNode *ast = AstNode::mkconst_bits(data, false);
+ ast->str = code;
+ return ast;
+ }
+
+ for (size_t i = 0; i < code.size(); i++)
+ if (code[i] == '_' || code[i] == ' ' || code[i] == '\t' || code[i] == '\r' || code[i] == '\n')
+ code.erase(code.begin()+(i--));
+ str = code.c_str();
+
+ char *endptr;
+ long len_in_bits = strtol(str, &endptr, 10);
+
+ // Simple base-10 integer
+ if (*endptr == 0) {
+ std::vector<RTLIL::State> data;
+ my_strtobin(data, str, -1, 10, case_type, false);
+ if (data.back() == State::S1)
+ data.push_back(State::S0);
+ return AstNode::mkconst_bits(data, true);
+ }
+
+ // unsized constant
+ if (str == endptr)
+ len_in_bits = -1;
+
+ // The "<bits>'[sS]?[bodhBODH]<digits>" syntax
+ if (*endptr == '\'')
+ {
+ std::vector<RTLIL::State> data;
+ bool is_signed = false;
+ bool is_unsized = len_in_bits < 0;
+ if (*(endptr+1) == 's' || *(endptr+1) == 'S') {
+ is_signed = true;
+ endptr++;
+ }
+ switch (*(endptr+1))
+ {
+ case 'b':
+ case 'B':
+ my_strtobin(data, endptr+2, len_in_bits, 2, case_type, is_unsized);
+ break;
+ case 'o':
+ case 'O':
+ my_strtobin(data, endptr+2, len_in_bits, 8, case_type, is_unsized);
+ break;
+ case 'd':
+ case 'D':
+ my_strtobin(data, endptr+2, len_in_bits, 10, case_type, is_unsized);
+ break;
+ case 'h':
+ case 'H':
+ my_strtobin(data, endptr+2, len_in_bits, 16, case_type, is_unsized);
+ break;
+ default:
+ char next_char = char(tolower(*(endptr+1)));
+ if (next_char == '0' || next_char == '1' || next_char == 'x' || next_char == 'z') {
+ is_unsized = true;
+ my_strtobin(data, endptr+1, 1, 2, case_type, is_unsized);
+ } else {
+ return NULL;
+ }
+ }
+ if (len_in_bits < 0) {
+ if (is_signed && data.back() == State::S1)
+ data.push_back(State::S0);
+ }
+ return AstNode::mkconst_bits(data, is_signed, is_unsized);
+ }
+
+ return NULL;
+}
diff --git a/systemverilog-plugin/third_party/yosys/const2ast.h b/systemverilog-plugin/third_party/yosys/const2ast.h
new file mode 100644
index 0000000..f7130a2
--- /dev/null
+++ b/systemverilog-plugin/third_party/yosys/const2ast.h
@@ -0,0 +1,13 @@
+#ifndef SYSTEMVERILOG_PLUGIN_CONST2AST_H
+#define SYSTEMVERILOG_PLUGIN_CONST2AST_H
+
+#include "frontends/ast/ast.h"
+#include <string>
+
+namespace systemverilog_plugin
+{
+ // this function converts a Verilog constant to an AST_CONSTANT node
+ Yosys::AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false);
+}
+
+#endif // SYSTEMVERILOG_PLUGIN_CONST2AST_H
diff --git a/systemverilog-plugin/uhdmastfrontend.cc b/systemverilog-plugin/uhdmastfrontend.cc
index 0ee97c0..427fb37 100644
--- a/systemverilog-plugin/uhdmastfrontend.cc
+++ b/systemverilog-plugin/uhdmastfrontend.cc
@@ -25,7 +25,10 @@
bool shallowVisit = false);
}
-YOSYS_NAMESPACE_BEGIN
+namespace systemverilog_plugin
+{
+
+using namespace ::Yosys;
struct UhdmAstFrontend : public UhdmCommonFrontend {
UhdmAstFrontend() : UhdmCommonFrontend("uhdm", "read UHDM file") {}
@@ -50,8 +53,8 @@
delete synthSubset;
if (this->shared.debug_flag || !this->report_directory.empty()) {
for (auto design : restoredDesigns) {
- std::stringstream strstr;
- UHDM::visit_object(design, 1, "", &this->shared.report.unhandled, this->shared.debug_flag ? std::cout : strstr);
+ std::ofstream null_stream;
+ UHDM::visit_object(design, 1, "", &this->shared.report.unhandled, this->shared.debug_flag ? std::cout : null_stream);
}
}
UhdmAst uhdm_ast(this->shared);
@@ -68,4 +71,4 @@
void call_log_header(RTLIL::Design *design) override { log_header(design, "Executing UHDM frontend.\n"); }
} UhdmAstFrontend;
-YOSYS_NAMESPACE_END
+} // namespace systemverilog_plugin
diff --git a/systemverilog-plugin/uhdmastreport.cc b/systemverilog-plugin/uhdmastreport.cc
index 9a2832f..1df94b3 100644
--- a/systemverilog-plugin/uhdmastreport.cc
+++ b/systemverilog-plugin/uhdmastreport.cc
@@ -5,7 +5,10 @@
#include <uhdm/BaseClass.h>
#include <unordered_set>
-YOSYS_NAMESPACE_BEGIN
+namespace systemverilog_plugin
+{
+
+using namespace ::Yosys;
void UhdmAstReport::mark_handled(const UHDM::BaseClass *object)
{
@@ -84,4 +87,4 @@
index_file << "</body>\n</html>" << std::endl;
}
-YOSYS_NAMESPACE_END
+} // namespace systemverilog_plugin
diff --git a/systemverilog-plugin/uhdmastreport.h b/systemverilog-plugin/uhdmastreport.h
index ae16b95..e2403fc 100644
--- a/systemverilog-plugin/uhdmastreport.h
+++ b/systemverilog-plugin/uhdmastreport.h
@@ -8,7 +8,8 @@
#undef cover
#include <uhdm/uhdm.h>
-YOSYS_NAMESPACE_BEGIN
+namespace systemverilog_plugin
+{
class UhdmAstReport
{
@@ -30,6 +31,6 @@
void write(const std::string &directory);
};
-YOSYS_NAMESPACE_END
+} // namespace systemverilog_plugin
#endif
diff --git a/systemverilog-plugin/uhdmastshared.h b/systemverilog-plugin/uhdmastshared.h
index a1ad1c6..b185975 100644
--- a/systemverilog-plugin/uhdmastshared.h
+++ b/systemverilog-plugin/uhdmastshared.h
@@ -5,7 +5,8 @@
#include <string>
#include <unordered_map>
-YOSYS_NAMESPACE_BEGIN
+namespace systemverilog_plugin
+{
class UhdmAstShared
{
@@ -51,19 +52,19 @@
bool link = false;
// Top nodes of the design (modules, interfaces)
- std::unordered_map<std::string, AST::AstNode *> top_nodes;
+ std::unordered_map<std::string, ::Yosys::AST::AstNode *> top_nodes;
// UHDM node coverage report
UhdmAstReport report;
// Map from AST param nodes to their types (used for params with struct types)
- std::unordered_map<std::string, AST::AstNode *> param_types;
+ std::unordered_map<std::string, ::Yosys::AST::AstNode *> param_types;
- AST::AstNode *current_top_node = nullptr;
+ ::Yosys::AST::AstNode *current_top_node = nullptr;
// Set of non-synthesizable objects to skip in current design;
std::set<const UHDM::BaseClass *> nonSynthesizableObjects;
};
-YOSYS_NAMESPACE_END
+} // namespace systemverilog_plugin
#endif
diff --git a/systemverilog-plugin/uhdmcommonfrontend.cc b/systemverilog-plugin/uhdmcommonfrontend.cc
index 651552a..167259c 100644
--- a/systemverilog-plugin/uhdmcommonfrontend.cc
+++ b/systemverilog-plugin/uhdmcommonfrontend.cc
@@ -19,7 +19,10 @@
#include "uhdmcommonfrontend.h"
-YOSYS_NAMESPACE_BEGIN
+namespace systemverilog_plugin
+{
+
+using namespace ::Yosys;
/* Stub for AST::process */
static void set_line_num(int) {}
@@ -147,4 +150,4 @@
}
}
-YOSYS_NAMESPACE_END
+} // namespace systemverilog_plugin
diff --git a/systemverilog-plugin/uhdmcommonfrontend.h b/systemverilog-plugin/uhdmcommonfrontend.h
index e8b59f9..4c10d10 100644
--- a/systemverilog-plugin/uhdmcommonfrontend.h
+++ b/systemverilog-plugin/uhdmcommonfrontend.h
@@ -26,7 +26,8 @@
#include <type_traits>
#include <vector>
-YOSYS_NAMESPACE_BEGIN
+namespace systemverilog_plugin
+{
// FIXME (mglb): temporary fix to support UHDM both before and after the following change:
// https://github.com/chipsalliance/UHDM/commit/d78d094448bd94926644e48adea4df293b82f101
@@ -45,16 +46,16 @@
return new ObjT(std::forward<ArgN>(arg_n)..., true);
}
-struct UhdmCommonFrontend : public Frontend {
+struct UhdmCommonFrontend : public ::Yosys::Frontend {
UhdmAstShared shared;
std::string report_directory;
std::vector<std::string> args;
UhdmCommonFrontend(std::string name, std::string short_help) : Frontend(name, short_help) {}
virtual void print_read_options();
virtual void help() = 0;
- virtual AST::AstNode *parse(std::string filename) = 0;
- virtual void call_log_header(RTLIL::Design *design) = 0;
- void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design);
+ virtual ::Yosys::AST::AstNode *parse(std::string filename) = 0;
+ virtual void call_log_header(::Yosys::RTLIL::Design *design) = 0;
+ void execute(std::istream *&f, std::string filename, std::vector<std::string> args, ::Yosys::RTLIL::Design *design);
};
-YOSYS_NAMESPACE_END
+} // namespace systemverilog_plugin
diff --git a/systemverilog-plugin/uhdmsurelogastfrontend.cc b/systemverilog-plugin/uhdmsurelogastfrontend.cc
index 4f664c7..a72b405 100644
--- a/systemverilog-plugin/uhdmsurelogastfrontend.cc
+++ b/systemverilog-plugin/uhdmsurelogastfrontend.cc
@@ -29,6 +29,9 @@
#include <sys/param.h>
#include <unistd.h>
#endif
+#include <memory>
+
+#include <list>
#include "Surelog/ErrorReporting/Report.h"
#include "Surelog/surelog.h"
@@ -39,44 +42,78 @@
bool shallowVisit = false);
}
-YOSYS_NAMESPACE_BEGIN
-
-std::vector<vpiHandle> executeCompilation(SURELOG::SymbolTable *symbolTable, SURELOG::ErrorContainer *errors, SURELOG::CommandLineParser *clp,
- SURELOG::scompiler *compiler)
+namespace systemverilog_plugin
{
- bool success = true;
- bool noFatalErrors = true;
- unsigned int codedReturn = 0;
- clp->setWriteUhdm(false);
- errors->printMessages(clp->muteStdout());
- std::vector<vpiHandle> the_design;
- if (success && (!clp->help())) {
- compiler = SURELOG::start_compiler(clp);
- if (!compiler)
+
+using namespace ::Yosys;
+
+// Store systemverilog defaults to be passed for every invocation of read_systemverilog
+static std::vector<std::string> systemverilog_defaults;
+static std::list<std::vector<std::string>> systemverilog_defaults_stack;
+
+// Store global definitions for top-level defines
+static std::vector<std::string> systemverilog_defines;
+
+// SURELOG::scompiler wrapper.
+// Owns UHDM/VPI resources used by designs returned from `execute`
+class Compiler
+{
+ public:
+ Compiler() = default;
+ ~Compiler()
+ {
+ if (this->scompiler) {
+ SURELOG::shutdown_compiler(this->scompiler);
+ }
+ }
+
+ const std::vector<vpiHandle> &execute(std::unique_ptr<SURELOG::ErrorContainer> errors, std::unique_ptr<SURELOG::CommandLineParser> clp)
+ {
+ log_assert(!this->errors && !this->clp && !this->scompiler);
+
+ bool success = true;
+ bool noFatalErrors = true;
+ unsigned int codedReturn = 0;
+ clp->setWriteUhdm(false);
+ errors->printMessages(clp->muteStdout());
+ if (success && (!clp->help())) {
+ this->scompiler = SURELOG::start_compiler(clp.get());
+ if (!this->scompiler)
+ codedReturn |= 1;
+ this->designs.push_back(SURELOG::get_uhdm_design(this->scompiler));
+ }
+ SURELOG::ErrorContainer::Stats stats;
+ if (!clp->help()) {
+ stats = errors->getErrorStats();
+ if (stats.nbFatal)
+ codedReturn |= 1;
+ if (stats.nbSyntax)
+ codedReturn |= 2;
+ }
+ bool noFErrors = true;
+ if (!clp->help())
+ noFErrors = errors->printStats(stats, clp->muteStdout());
+ if (noFErrors == false) {
+ noFatalErrors = false;
+ }
+ if ((!noFatalErrors) || (!success) || (errors->getErrorStats().nbError))
codedReturn |= 1;
- the_design.push_back(SURELOG::get_uhdm_design(compiler));
+ if (codedReturn) {
+ log_error("Error when parsing design. Aborting!\n");
+ }
+
+ this->clp = std::move(clp);
+ this->errors = std::move(errors);
+
+ return this->designs;
}
- SURELOG::ErrorContainer::Stats stats;
- if (!clp->help()) {
- stats = errors->getErrorStats();
- if (stats.nbFatal)
- codedReturn |= 1;
- if (stats.nbSyntax)
- codedReturn |= 2;
- }
- bool noFErrors = true;
- if (!clp->help())
- noFErrors = errors->printStats(stats, clp->muteStdout());
- if (noFErrors == false) {
- noFatalErrors = false;
- }
- if ((!noFatalErrors) || (!success) || (errors->getErrorStats().nbError))
- codedReturn |= 1;
- if (codedReturn) {
- log_error("Error when parsing design. Aborting!\n");
- }
- return the_design;
-}
+
+ private:
+ std::unique_ptr<SURELOG::ErrorContainer> errors = nullptr;
+ std::unique_ptr<SURELOG::CommandLineParser> clp = nullptr;
+ SURELOG::scompiler *scompiler = nullptr;
+ std::vector<vpiHandle> designs = {};
+};
struct UhdmSurelogAstFrontend : public UhdmCommonFrontend {
UhdmSurelogAstFrontend(std::string name, std::string short_help) : UhdmCommonFrontend(name, short_help) {}
@@ -94,13 +131,33 @@
AST::AstNode *parse(std::string filename) override
{
std::vector<const char *> cstrings;
- cstrings.reserve(this->args.size());
- for (size_t i = 0; i < this->args.size(); ++i)
+ bool link = false;
+ cstrings.reserve(this->args.size() + systemverilog_defaults.size() + systemverilog_defines.size());
+ for (size_t i = 0; i < this->args.size(); ++i) {
cstrings.push_back(const_cast<char *>(this->args[i].c_str()));
+ if (this->args[i] == "-link")
+ link = true;
+ }
- SURELOG::SymbolTable *symbolTable = new SURELOG::SymbolTable();
- SURELOG::ErrorContainer *errors = new SURELOG::ErrorContainer(symbolTable);
- SURELOG::CommandLineParser *clp = new SURELOG::CommandLineParser(errors, symbolTable, false, false);
+ if (!link) {
+ // Add systemverilog defaults args
+ for (size_t i = 0; i < systemverilog_defaults.size(); ++i) {
+ // Convert args to surelog compatible
+ if (systemverilog_defaults[i] == "-defer")
+ this->shared.defer = true;
+ // Pass any remainings args directly to surelog
+ else
+ cstrings.push_back(const_cast<char *>(systemverilog_defaults[i].c_str()));
+ }
+
+ // Add systemverilog defines args
+ for (size_t i = 0; i < systemverilog_defines.size(); ++i)
+ cstrings.push_back(const_cast<char *>(systemverilog_defines[i].c_str()));
+ }
+
+ auto symbolTable = std::make_unique<SURELOG::SymbolTable>();
+ auto errors = std::make_unique<SURELOG::ErrorContainer>(symbolTable.get());
+ auto clp = std::make_unique<SURELOG::CommandLineParser>(errors.get(), symbolTable.get(), false, false);
bool success = clp->parseCommandLine(cstrings.size(), &cstrings[0]);
if (!success) {
log_error("Error parsing Surelog arguments!\n");
@@ -122,25 +179,21 @@
clp->setLink(true);
}
- SURELOG::scompiler *compiler = nullptr;
- const std::vector<vpiHandle> uhdm_design = executeCompilation(symbolTable, errors, clp, compiler);
+ Compiler compiler;
+ const auto &uhdm_designs = compiler.execute(std::move(errors), std::move(clp));
+
if (this->shared.debug_flag || !this->report_directory.empty()) {
- for (auto design : uhdm_design) {
- std::stringstream strstr;
- UHDM::visit_object(design, 1, "", &this->shared.report.unhandled, this->shared.debug_flag ? std::cout : strstr);
+ for (auto design : uhdm_designs) {
+ std::ofstream null_stream;
+ UHDM::visit_object(design, 1, "", &this->shared.report.unhandled, this->shared.debug_flag ? std::cout : null_stream);
}
}
- SURELOG::shutdown_compiler(compiler);
- delete clp;
- delete symbolTable;
- delete errors;
// on parse_only mode, don't try to load design
// into yosys
if (this->shared.parse_only)
return nullptr;
- UhdmAst uhdm_ast(this->shared);
if (this->shared.defer && !this->shared.link)
return nullptr;
@@ -151,15 +204,19 @@
UHDM::Serializer serializer;
UHDM::SynthSubset *synthSubset =
make_new_object_with_optional_extra_true_arg<UHDM::SynthSubset>(&serializer, this->shared.nonSynthesizableObjects, false);
- synthSubset->listenDesigns(uhdm_design);
+ synthSubset->listenDesigns(uhdm_designs);
delete synthSubset;
}
- AST::AstNode *current_ast = uhdm_ast.visit_designs(uhdm_design);
+ UhdmAst uhdm_ast(this->shared);
+ AST::AstNode *current_ast = uhdm_ast.visit_designs(uhdm_designs);
if (!this->report_directory.empty()) {
this->shared.report.write(this->report_directory);
}
+ // FIXME: Check and reset remaining shared data
+ this->shared.top_nodes.clear();
+ this->shared.nonSynthesizableObjects.clear();
return current_ast;
}
void call_log_header(RTLIL::Design *design) override { log_header(design, "Executing Verilog with UHDM frontend.\n"); }
@@ -176,7 +233,164 @@
log("Read SystemVerilog files using Surelog into the current design\n");
log("\n");
this->print_read_options();
+ log(" -Ipath\n");
+ log(" add include path.\n");
+ log("\n");
+ log(" -Pparameter=value\n");
+ log(" define parameter as value.\n");
+ log("\n");
}
} UhdmSystemVerilogFrontend;
-YOSYS_NAMESPACE_END
+struct SystemVerilogDefaults : public Pass {
+ SystemVerilogDefaults() : Pass("systemverilog_defaults", "set default options for read_systemverilog") {}
+ void help() override
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" systemverilog_defaults -add [options]\n");
+ log("\n");
+ log("Add the specified options to the list of default options to read_systemverilog.\n");
+ log("\n");
+ log("\n");
+ log(" systemverilog_defaults -clear\n");
+ log("\n");
+ log("Clear the list of Systemverilog default options.\n");
+ log("\n");
+ log("\n");
+ log(" systemverilog_defaults -push\n");
+ log(" systemverilog_defaults -pop\n");
+ log("\n");
+ log("Push or pop the list of default options to a stack. Note that -push does\n");
+ log("not imply -clear.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *) override
+ {
+ if (args.size() < 2)
+ cmd_error(args, 1, "Missing argument.");
+
+ if (args[1] == "-add") {
+ systemverilog_defaults.insert(systemverilog_defaults.end(), args.begin() + 2, args.end());
+ return;
+ }
+
+ if (args.size() != 2)
+ cmd_error(args, 2, "Extra argument.");
+
+ if (args[1] == "-clear") {
+ systemverilog_defaults.clear();
+ return;
+ }
+
+ if (args[1] == "-push") {
+ systemverilog_defaults_stack.push_back(systemverilog_defaults);
+ return;
+ }
+
+ if (args[1] == "-pop") {
+ if (systemverilog_defaults_stack.empty()) {
+ systemverilog_defaults.clear();
+ } else {
+ systemverilog_defaults.swap(systemverilog_defaults_stack.back());
+ systemverilog_defaults_stack.pop_back();
+ }
+ return;
+ }
+ }
+} SystemVerilogDefaults;
+
+struct SystemVerilogDefines : public Pass {
+ SystemVerilogDefines() : Pass("systemverilog_defines", "define and undefine systemverilog defines")
+ {
+ systemverilog_defines.push_back("-DYOSYS=1");
+ }
+ void help() override
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" systemverilog_defines [options]\n");
+ log("\n");
+ log("Define and undefine systemverilog preprocessor macros.\n");
+ log("\n");
+ log(" -Dname[=definition]\n");
+ log(" define the preprocessor symbol 'name' and set its optional value\n");
+ log(" 'definition'\n");
+ log("\n");
+ log(" -Uname[=definition]\n");
+ log(" undefine the preprocessor symbol 'name'\n");
+ log("\n");
+ log(" -reset\n");
+ log(" clear list of defined preprocessor symbols\n");
+ log("\n");
+ log(" -list\n");
+ log(" list currently defined preprocessor symbols\n");
+ log("\n");
+ }
+ void remove(const std::string name)
+ {
+ auto it = systemverilog_defines.begin();
+ while (it != systemverilog_defines.end()) {
+ std::string nm;
+ size_t equal = (*it).find('=', 2);
+ if (equal == std::string::npos)
+ nm = (*it).substr(2, std::string::npos);
+ else
+ nm = (*it).substr(2, equal - 2);
+ if (name == nm)
+ systemverilog_defines.erase(it);
+ else
+ it++;
+ }
+ }
+ void dump(void)
+ {
+ for (size_t i = 0; i < systemverilog_defines.size(); ++i) {
+ std::string name, value = "";
+ size_t equal = systemverilog_defines[i].find('=', 2);
+ name = systemverilog_defines[i].substr(2, equal - 2);
+ if (equal != std::string::npos)
+ value = systemverilog_defines[i].substr(equal + 1, std::string::npos);
+ Yosys::log("`define %s %s\n", name.c_str(), value.c_str());
+ }
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
+ {
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ std::string arg = args[argidx];
+ if (arg == "-D" && argidx + 1 < args.size()) {
+ systemverilog_defines.push_back("-D" + args[++argidx]);
+ continue;
+ }
+ if (arg.compare(0, 2, "-D") == 0) {
+ systemverilog_defines.push_back(arg);
+ continue;
+ }
+ if (arg == "-U" && argidx + 1 < args.size()) {
+ std::string name = args[++argidx];
+ this->remove(name);
+ continue;
+ }
+ if (arg.compare(0, 2, "-U") == 0) {
+ std::string name = arg.substr(2);
+ this->remove(name);
+ continue;
+ }
+ if (arg == "-reset") {
+ systemverilog_defines.erase(systemverilog_defines.begin() + 1, systemverilog_defines.end());
+ continue;
+ }
+ if (arg == "-list") {
+ this->dump();
+ continue;
+ }
+ break;
+ }
+
+ if (args.size() != argidx)
+ cmd_error(args, argidx, "Extra argument.");
+ }
+} SystemVerilogDefines;
+
+} // namespace systemverilog_plugin