aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--frontends/ast/ast.h7
-rw-r--r--frontends/ast/genrtlil.cc6
-rw-r--r--frontends/ast/simplify.cc147
-rw-r--r--frontends/verific/verific.cc24
-rw-r--r--frontends/verilog/verilog_parser.y21
-rw-r--r--techlibs/nexus/cells_sim.v115
-rw-r--r--tests/simple/const_fold_func.v61
-rw-r--r--tests/simple/const_func_shadow.v33
-rw-r--r--tests/simple/genblk_port_shadow.v10
-rw-r--r--tests/various/port_sign_extend.v22
-rw-r--r--tests/various/port_sign_extend.ys13
-rw-r--r--tests/verilog/atom_type_signedness.ys19
-rw-r--r--tests/verilog/block_labels.ys26
-rw-r--r--tests/verilog/genblk_port_decl.ys12
15 files changed, 421 insertions, 97 deletions
diff --git a/Makefile b/Makefile
index 843ced935..809251be3 100644
--- a/Makefile
+++ b/Makefile
@@ -126,7 +126,7 @@ LDFLAGS += -rdynamic
LDLIBS += -lrt
endif
-YOSYS_VER := 0.9+3885
+YOSYS_VER := 0.9+3905
GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
OBJS = kernel/version_$(GIT_REV).o
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index 6f173ca22..d8818df31 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -264,10 +264,9 @@ namespace AST
// additional functionality for evaluating constant functions
struct varinfo_t { RTLIL::Const val; int offset; bool is_signed; };
- bool has_const_only_constructs(bool &recommend_const_eval);
- bool has_const_only_constructs(std::set<std::string>& visited, bool &recommend_const_eval);
- void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall);
- AstNode *eval_const_function(AstNode *fcall);
+ bool has_const_only_constructs();
+ bool replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall, bool must_succeed);
+ AstNode *eval_const_function(AstNode *fcall, bool must_succeed);
bool is_simple_const_expr();
std::string process_format_str(const std::string &sformat, int next_arg, int stage, int width_hint, bool sign_hint);
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index b8bfdf65e..24f5e1bef 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -49,6 +49,7 @@ static RTLIL::SigSpec uniop2rtlil(AstNode *that, IdString type, int result_width
RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", result_width);
wire->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", that->filename.c_str(), that->location.first_line, that->location.first_column, that->location.last_line, that->location.last_column);
+ wire->is_signed = that->is_signed;
if (gen_attributes)
for (auto &attr : that->attributes) {
@@ -80,6 +81,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", width);
wire->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", that->filename.c_str(), that->location.first_line, that->location.first_column, that->location.last_line, that->location.last_column);
+ wire->is_signed = that->is_signed;
if (that != NULL)
for (auto &attr : that->attributes) {
@@ -1050,6 +1052,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
RTLIL::Const val = children[0]->bitsAsConst();
RTLIL::Wire *wire = current_module->addWire(str, GetSize(val));
current_module->connect(wire, val);
+ wire->is_signed = children[0]->is_signed;
wire->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column);
wire->attributes[type == AST_PARAMETER ? ID::parameter : ID::localparam] = 1;
@@ -1551,6 +1554,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
int mem_width, mem_size, addr_bits;
is_signed = id2ast->is_signed;
+ wire->is_signed = is_signed;
id2ast->meminfo(mem_width, mem_size, addr_bits);
RTLIL::SigSpec addr_sig = children[0]->genRTLIL();
@@ -1740,7 +1744,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// non-trivial signed nodes are indirected through
// signed wires to enable sign extension
RTLIL::IdString wire_name = NEW_ID;
- RTLIL::Wire *wire = current_module->addWire(wire_name, arg->bits.size());
+ RTLIL::Wire *wire = current_module->addWire(wire_name, GetSize(sig));
wire->is_signed = true;
current_module->connect(wire, sig);
sig = wire;
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 77911e966..402b7257b 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -1218,11 +1218,6 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
current_block = this;
current_block_child = children[i];
}
- if (!in_param_here && type == AST_FCALL) {
- bool recommend_const_eval = false;
- bool require_const_eval = has_const_only_constructs(recommend_const_eval);
- in_param_here = recommend_const_eval || require_const_eval;
- }
if ((type == AST_ALWAYS || type == AST_INITIAL) && children[i]->type == AST_BLOCK)
current_top_block = children[i];
if (i == 0 && child_0_is_self_determined)
@@ -3186,10 +3181,9 @@ skip_dynamic_range_lvalue_expansion:;
decl->replace_result_wire_name_in_function(str, "$result"); // enables recursion
decl->expand_genblock(prefix);
- bool recommend_const_eval = false;
- bool require_const_eval = in_param ? false : has_const_only_constructs(recommend_const_eval);
- if ((in_param || recommend_const_eval || require_const_eval) && !decl->attributes.count(ID::via_celltype))
+ if (decl->type == AST_FUNCTION && !decl->attributes.count(ID::via_celltype))
{
+ bool require_const_eval = decl->has_const_only_constructs();
bool all_args_const = true;
for (auto child : children) {
while (child->simplify(true, false, false, 1, -1, false, true)) { }
@@ -3200,10 +3194,12 @@ skip_dynamic_range_lvalue_expansion:;
if (all_args_const) {
AstNode *func_workspace = decl->clone();
func_workspace->str = prefix_id(prefix, "$result");
- newNode = func_workspace->eval_const_function(this);
+ newNode = func_workspace->eval_const_function(this, in_param || require_const_eval);
delete func_workspace;
- delete decl;
- goto apply_newNode;
+ if (newNode) {
+ delete decl;
+ goto apply_newNode;
+ }
}
if (in_param)
@@ -4502,33 +4498,12 @@ bool AstNode::detect_latch(const std::string &var)
}
}
-bool AstNode::has_const_only_constructs(bool &recommend_const_eval)
+bool AstNode::has_const_only_constructs()
{
- std::set<std::string> visited;
- return has_const_only_constructs(visited, recommend_const_eval);
-}
-
-bool AstNode::has_const_only_constructs(std::set<std::string>& visited, bool &recommend_const_eval)
-{
- if (type == AST_FUNCTION || type == AST_TASK)
- {
- if (visited.count(str))
- {
- recommend_const_eval = true;
- return false;
- }
- visited.insert(str);
- }
-
- if (type == AST_FOR)
- recommend_const_eval = true;
if (type == AST_WHILE || type == AST_REPEAT)
return true;
- if (type == AST_FCALL && current_scope.count(str))
- if (current_scope[str]->has_const_only_constructs(visited, recommend_const_eval))
- return true;
for (auto child : children)
- if (child->AstNode::has_const_only_constructs(visited, recommend_const_eval))
+ if (child->has_const_only_constructs())
return true;
return false;
}
@@ -4544,19 +4519,26 @@ bool AstNode::is_simple_const_expr()
}
// helper function for AstNode::eval_const_function()
-void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall)
+bool AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall, bool must_succeed)
{
if (type == AST_IDENTIFIER && variables.count(str)) {
int offset = variables.at(str).offset, width = variables.at(str).val.bits.size();
if (!children.empty()) {
- if (children.size() != 1 || children.at(0)->type != AST_RANGE)
+ if (children.size() != 1 || children.at(0)->type != AST_RANGE) {
+ if (!must_succeed)
+ return false;
log_file_error(filename, location.first_line, "Memory access in constant function is not supported\n%s:%d.%d-%d.%d: ...called from here.\n",
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
- children.at(0)->replace_variables(variables, fcall);
+ }
+ if (!children.at(0)->replace_variables(variables, fcall, must_succeed))
+ return false;
while (simplify(true, false, false, 1, -1, false, true)) { }
- if (!children.at(0)->range_valid)
+ if (!children.at(0)->range_valid) {
+ if (!must_succeed)
+ return false;
log_file_error(filename, location.first_line, "Non-constant range\n%s:%d.%d-%d.%d: ... called from here.\n",
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
+ }
offset = min(children.at(0)->range_left, children.at(0)->range_right);
width = min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width);
}
@@ -4566,19 +4548,22 @@ void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &varia
AstNode *newNode = mkconst_bits(new_bits, variables.at(str).is_signed);
newNode->cloneInto(this);
delete newNode;
- return;
+ return true;
}
for (auto &child : children)
- child->replace_variables(variables, fcall);
+ if (!child->replace_variables(variables, fcall, must_succeed))
+ return false;
+ return true;
}
-// evaluate functions with all-const arguments
-AstNode *AstNode::eval_const_function(AstNode *fcall)
+// attempt to statically evaluate a functions with all-const arguments
+AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed)
{
- std::map<std::string, AstNode*> backup_scope;
+ std::map<std::string, AstNode*> backup_scope = current_scope;
std::map<std::string, AstNode::varinfo_t> variables;
AstNode *block = new AstNode(AST_BLOCK);
+ AstNode *result = nullptr;
size_t argidx = 0;
for (auto child : children)
@@ -4600,9 +4585,12 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
if (stmt->type == AST_WIRE)
{
while (stmt->simplify(true, false, false, 1, -1, false, true)) { }
- if (!stmt->range_valid)
+ if (!stmt->range_valid) {
+ if (!must_succeed)
+ goto finished;
log_file_error(stmt->filename, stmt->location.first_line, "Can't determine size of variable %s\n%s:%d.%d-%d.%d: ... called from here.\n",
stmt->str.c_str(), fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
+ }
variables[stmt->str].val = RTLIL::Const(RTLIL::State::Sx, abs(stmt->range_left - stmt->range_right)+1);
variables[stmt->str].offset = min(stmt->range_left, stmt->range_right);
variables[stmt->str].is_signed = stmt->is_signed;
@@ -4616,8 +4604,6 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
variables[stmt->str].val = arg_node->realAsConst(width);
}
}
- if (!backup_scope.count(stmt->str))
- backup_scope[stmt->str] = current_scope[stmt->str];
current_scope[stmt->str] = stmt;
block->children.erase(block->children.begin());
@@ -4630,8 +4616,6 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
{
while (stmt->simplify(true, false, false, 1, -1, false, true)) { }
- if (!backup_scope.count(stmt->str))
- backup_scope[stmt->str] = current_scope[stmt->str];
current_scope[stmt->str] = stmt;
block->children.erase(block->children.begin());
@@ -4642,32 +4626,46 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
{
if (stmt->children.at(0)->type == AST_IDENTIFIER && stmt->children.at(0)->children.size() != 0 &&
stmt->children.at(0)->children.at(0)->type == AST_RANGE)
- stmt->children.at(0)->children.at(0)->replace_variables(variables, fcall);
- stmt->children.at(1)->replace_variables(variables, fcall);
+ if (!stmt->children.at(0)->children.at(0)->replace_variables(variables, fcall, must_succeed))
+ goto finished;
+ if (!stmt->children.at(1)->replace_variables(variables, fcall, must_succeed))
+ goto finished;
while (stmt->simplify(true, false, false, 1, -1, false, true)) { }
if (stmt->type != AST_ASSIGN_EQ)
continue;
- if (stmt->children.at(1)->type != AST_CONSTANT)
+ if (stmt->children.at(1)->type != AST_CONSTANT) {
+ if (!must_succeed)
+ goto finished;
log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s:%d.%d-%d.%d: ... called from here. X\n",
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
+ }
- if (stmt->children.at(0)->type != AST_IDENTIFIER)
+ if (stmt->children.at(0)->type != AST_IDENTIFIER) {
+ if (!must_succeed)
+ goto finished;
log_file_error(stmt->filename, stmt->location.first_line, "Unsupported composite left hand side in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
+ }
- if (!variables.count(stmt->children.at(0)->str))
+ if (!variables.count(stmt->children.at(0)->str)) {
+ if (!must_succeed)
+ goto finished;
log_file_error(stmt->filename, stmt->location.first_line, "Assignment to non-local variable in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
+ }
if (stmt->children.at(0)->children.empty()) {
variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.bits.size());
} else {
AstNode *range = stmt->children.at(0)->children.at(0);
- if (!range->range_valid)
+ if (!range->range_valid) {
+ if (!must_succeed)
+ goto finished;
log_file_error(range->filename, range->location.first_line, "Non-constant range\n%s:%d.%d-%d.%d: ... called from here.\n",
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
+ }
int offset = min(range->range_left, range->range_right);
int width = std::abs(range->range_left - range->range_right) + 1;
varinfo_t &v = variables[stmt->children.at(0)->str];
@@ -4694,12 +4692,16 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
if (stmt->type == AST_WHILE)
{
AstNode *cond = stmt->children.at(0)->clone();
- cond->replace_variables(variables, fcall);
+ if (!cond->replace_variables(variables, fcall, must_succeed))
+ goto finished;
while (cond->simplify(true, false, false, 1, -1, false, true)) { }
- if (cond->type != AST_CONSTANT)
+ if (cond->type != AST_CONSTANT) {
+ if (!must_succeed)
+ goto finished;
log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
+ }
if (cond->asBool()) {
block->children.insert(block->children.begin(), stmt->children.at(1)->clone());
@@ -4715,12 +4717,16 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
if (stmt->type == AST_REPEAT)
{
AstNode *num = stmt->children.at(0)->clone();
- num->replace_variables(variables, fcall);
+ if (!num->replace_variables(variables, fcall, must_succeed))
+ goto finished;
while (num->simplify(true, false, false, 1, -1, false, true)) { }
- if (num->type != AST_CONSTANT)
+ if (num->type != AST_CONSTANT) {
+ if (!must_succeed)
+ goto finished;
log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
+ }
block->children.erase(block->children.begin());
for (int i = 0; i < num->bitsAsConst().as_int(); i++)
@@ -4734,7 +4740,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
if (stmt->type == AST_CASE)
{
AstNode *expr = stmt->children.at(0)->clone();
- expr->replace_variables(variables, fcall);
+ if (!expr->replace_variables(variables, fcall, must_succeed))
+ goto finished;
while (expr->simplify(true, false, false, 1, -1, false, true)) { }
AstNode *sel_case = NULL;
@@ -4751,14 +4758,18 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
for (size_t j = 0; j+1 < stmt->children.at(i)->children.size() && !found_match; j++)
{
AstNode *cond = stmt->children.at(i)->children.at(j)->clone();
- cond->replace_variables(variables, fcall);
+ if (!cond->replace_variables(variables, fcall, must_succeed))
+ goto finished;
cond = new AstNode(AST_EQ, expr->clone(), cond);
while (cond->simplify(true, false, false, 1, -1, false, true)) { }
- if (cond->type != AST_CONSTANT)
+ if (cond->type != AST_CONSTANT) {
+ if (!must_succeed)
+ goto finished;
log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
+ }
found_match = cond->asBool();
delete cond;
@@ -4790,20 +4801,20 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
continue;
}
+ if (!must_succeed)
+ goto finished;
log_file_error(stmt->filename, stmt->location.first_line, "Unsupported language construct in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
log_abort();
}
- delete block;
+ result = AstNode::mkconst_bits(variables.at(str).val.bits, variables.at(str).is_signed);
- for (auto &it : backup_scope)
- if (it.second == NULL)
- current_scope.erase(it.first);
- else
- current_scope[it.first] = it.second;
+finished:
+ delete block;
+ current_scope = backup_scope;
- return AstNode::mkconst_bits(variables.at(str).val.bits, variables.at(str).is_signed);
+ return result;
}
void AstNode::allocateDefaultEnumValues()
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index 81e14ac41..7aa3ebcbb 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -49,13 +49,16 @@ USING_YOSYS_NAMESPACE
#include "VeriWrite.h"
#include "VhdlUnits.h"
#include "VeriLibrary.h"
+
+#if defined(YOSYSHQ_VERIFIC_INITSTATE) || defined(YOSYSHQ_VERIFIC_TEMPLATES) || defined(YOSYSHQ_VERIFIC_FORMALAPPS)
#include "VeriExtensions.h"
+#endif
#ifndef YOSYSHQ_VERIFIC_API_VERSION
# error "Only YosysHQ flavored Verific is supported. Please contact office@yosyshq.com for commercial support for Yosys+Verific."
#endif
-#if YOSYSHQ_VERIFIC_API_VERSION < 20210101
+#if YOSYSHQ_VERIFIC_API_VERSION < 20210103
# error "Please update your version of YosysHQ flavored Verific."
#endif
@@ -1471,6 +1474,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
continue;
}
+#ifdef YOSYSHQ_VERIFIC_INITSTATE
if (inst->Type() == PRIM_YOSYSHQ_INITSTATE)
{
SigBit initstate = module->Initstate(new_verific_id(inst));
@@ -1480,7 +1484,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
if (!mode_keep)
continue;
}
-
+#endif
if (!mode_keep && verific_sva_prims.count(inst->Type())) {
if (verific_verbose)
log(" skipping SVA cell in non k-mode\n");
@@ -1958,9 +1962,10 @@ void verific_import(Design *design, const std::map<std::string,std::string> &par
for (const auto &i : parameters)
verific_params.Insert(i.first.c_str(), i.second.c_str());
+#ifdef YOSYSHQ_VERIFIC_INITSTATE
InitialAssertionRewriter rw;
rw.RegisterCallBack();
-
+#endif
if (top.empty()) {
netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &verific_params);
}
@@ -2217,7 +2222,7 @@ struct VerificPass : public Pass {
log("\n");
log("Applications:\n");
log("\n");
-#ifdef YOSYS_ENABLE_VERIFIC
+#if defined(YOSYS_ENABLE_VERIFIC) && defined(YOSYSHQ_VERIFIC_FORMALAPPS)
VerificFormalApplications vfa;
log("%s\n",vfa.GetHelp().c_str());
#else
@@ -2243,7 +2248,7 @@ struct VerificPass : public Pass {
log("\n");
log("Templates:\n");
log("\n");
-#ifdef YOSYS_ENABLE_VERIFIC
+#if defined(YOSYS_ENABLE_VERIFIC) && defined(YOSYSHQ_VERIFIC_TEMPLATES)
VerificTemplateGenerator vfg;
log("%s\n",vfg.GetHelp().c_str());
#else
@@ -2494,6 +2499,7 @@ struct VerificPass : public Pass {
goto check_error;
}
+#ifdef YOSYSHQ_VERIFIC_FORMALAPPS
if (argidx < GetSize(args) && args[argidx] == "-app")
{
if (!(argidx+1 < GetSize(args)))
@@ -2587,7 +2593,7 @@ struct VerificPass : public Pass {
}
goto check_error;
}
-
+#endif
if (argidx < GetSize(args) && args[argidx] == "-pp")
{
const char* filename = nullptr;
@@ -2630,6 +2636,7 @@ struct VerificPass : public Pass {
goto check_error;
}
+#ifdef YOSYSHQ_VERIFIC_TEMPLATES
if (argidx < GetSize(args) && args[argidx] == "-template")
{
if (!(argidx+1 < GetSize(args)))
@@ -2713,7 +2720,7 @@ struct VerificPass : public Pass {
fclose(of);
goto check_error;
}
-
+#endif
if (GetSize(args) > argidx && args[argidx] == "-import")
{
std::set<Netlist*> nl_todo, nl_done;
@@ -2798,9 +2805,10 @@ struct VerificPass : public Pass {
std::set<std::string> top_mod_names;
+#ifdef YOSYSHQ_VERIFIC_INITSTATE
InitialAssertionRewriter rw;
rw.RegisterCallBack();
-
+#endif
if (mode_all)
{
log("Running hier_tree::ElaborateAll().\n");
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 6255a4204..7fbd2aa27 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -1491,10 +1491,10 @@ enum_base_type: type_atom type_signing
| %empty { astbuf1->is_reg = true; addRange(astbuf1); }
;
-type_atom: TOK_INTEGER { astbuf1->is_reg = true; addRange(astbuf1); } // 4-state signed
- | TOK_INT { astbuf1->is_reg = true; addRange(astbuf1); } // 2-state signed
- | TOK_SHORTINT { astbuf1->is_reg = true; addRange(astbuf1, 15, 0); } // 2-state signed
- | TOK_BYTE { astbuf1->is_reg = true; addRange(astbuf1, 7, 0); } // 2-state signed
+type_atom: TOK_INTEGER { astbuf1->is_reg = true; astbuf1->is_signed = true; addRange(astbuf1); } // 4-state signed
+ | TOK_INT { astbuf1->is_reg = true; astbuf1->is_signed = true; addRange(astbuf1); } // 2-state signed
+ | TOK_SHORTINT { astbuf1->is_reg = true; astbuf1->is_signed = true; addRange(astbuf1, 15, 0); } // 2-state signed
+ | TOK_BYTE { astbuf1->is_reg = true; astbuf1->is_signed = true; addRange(astbuf1, 7, 0); } // 2-state signed
;
type_vec: TOK_REG { astbuf1->is_reg = true; } // unsigned
@@ -1784,7 +1784,13 @@ wire_name:
}
rewriteAsMemoryNode(node, $2);
}
- if (current_function_or_task == NULL) {
+ if (current_function_or_task) {
+ if (node->is_input || node->is_output)
+ node->port_id = current_function_or_task_port_id++;
+ } else if (ast_stack.back()->type == AST_GENBLOCK) {
+ if (node->is_input || node->is_output)
+ frontend_verilog_yyerror("Cannot declare module port `%s' within a generate block.", $1->c_str());
+ } else {
if (do_not_require_port_stubs && (node->is_input || node->is_output) && port_stubs.count(*$1) == 0) {
port_stubs[*$1] = ++port_counter;
}
@@ -1799,9 +1805,6 @@ wire_name:
if (node->is_input || node->is_output)
frontend_verilog_yyerror("Module port `%s' is not declared in module header.", $1->c_str());
}
- } else {
- if (node->is_input || node->is_output)
- node->port_id = current_function_or_task_port_id++;
}
//FIXME: for some reason, TOK_ID has a location which always points to one column *after* the real last column...
SET_AST_NODE_LOC(node, @1, @1);
@@ -2794,6 +2797,8 @@ gen_block:
ast_stack.push_back(node);
} module_gen_body TOK_END opt_label {
exitTypeScope();
+ if ($3 != NULL && $7 != NULL && *$3 != *$7)
+ frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $3->c_str()+1, $7->c_str()+1);
delete $3;
delete $7;
SET_AST_NODE_LOC(ast_stack.back(), @1, @7);
diff --git a/techlibs/nexus/cells_sim.v b/techlibs/nexus/cells_sim.v
index b5938e08f..1e876a210 100644
--- a/techlibs/nexus/cells_sim.v
+++ b/techlibs/nexus/cells_sim.v
@@ -941,3 +941,118 @@ module MULTADDSUB36X36 #(
.Z(Z)
);
endmodule
+
+module MULTADDSUB9X9WIDE #(
+ parameter REGINPUTAB0 = "REGISTER",
+ parameter REGINPUTAB1 = "REGISTER",
+ parameter REGINPUTAB2 = "REGISTER",
+ parameter REGINPUTAB3 = "REGISTER",
+ parameter REGINPUTC = "REGISTER",
+ parameter REGADDSUB = "REGISTER",
+ parameter REGLOADC = "REGISTER",
+ parameter REGLOADC2 = "REGISTER",
+ parameter REGPIPELINE = "REGISTER",
+ parameter REGOUTPUT = "REGISTER",
+ parameter GSR = "ENABLED",
+ parameter RESETMODE = "SYNC"
+) (
+ input [8:0] A0, B0, A1, B1, A2, B2, A3, B3,
+ input [53:0] C,
+ input CLK,
+ input CEA0A1, CEA2A3,
+ input RSTA0A1, RSTA2A3,
+ input CEB0B1, CEB2B3,
+ input RSTB0B1, RSTB2B3,
+ input CEC, RSTC,
+ input CECTRL, RSTCTRL,
+ input SIGNED,
+ input RSTPIPE, CEPIPE,
+ input RSTOUT, CEOUT,
+ input LOADC,
+ input [3:0] ADDSUB,
+ output [53:0] Z
+);
+ wire [17:0] m0, m1, m2, m3;
+
+ localparam M_WIDTH = 18;
+ localparam Z_WIDTH = 54;
+
+ MULT9X9 #(
+ .REGINPUTA(REGINPUTAB0), .REGINPUTB(REGINPUTAB0), .REGOUTPUT(REGPIPELINE), .GSR(GSR), .RESETMODE(RESETMODE)
+ ) m9_0 (
+ .A(A0), .B(B0), .SIGNEDA(SIGNED), .SIGNEDB(SIGNED),
+ .CLK(CLK),
+ .CEA(CEA0A1), .RSTA(RSTA0A1),
+ .CEB(CEB0B1), .RSTB(RSTB0B1),
+ .CEOUT(CEPIPE), .RSTOUT(RSTPIPE),
+ .Z(m0)
+ );
+ MULT9X9 #(
+ .REGINPUTA(REGINPUTAB1), .REGINPUTB(REGINPUTAB1), .REGOUTPUT(REGPIPELINE), .GSR(GSR), .RESETMODE(RESETMODE)
+ ) m9_1 (
+ .A(A1), .B(B1), .SIGNEDA(SIGNED), .SIGNEDB(SIGNED),
+ .CLK(CLK),
+ .CEA(CEA0A1), .RSTA(RSTA0A1),
+ .CEB(CEB0B1), .RSTB(RSTB0B1),
+ .CEOUT(CEPIPE), .RSTOUT(RSTPIPE),
+ .Z(m1)
+ );
+ MULT9X9 #(
+ .REGINPUTA(REGINPUTAB2), .REGINPUTB(REGINPUTAB2), .REGOUTPUT(REGPIPELINE), .GSR(GSR), .RESETMODE(RESETMODE)
+ ) m9_2 (
+ .A(A2), .B(B2), .SIGNEDA(SIGNED), .SIGNEDB(SIGNED),
+ .CLK(CLK),
+ .CEA(CEA2A3), .RSTA(RSTA2A3),
+ .CEB(CEB2B3), .RSTB(RSTB2B3),
+ .CEOUT(CEPIPE), .RSTOUT(RSTPIPE),
+ .Z(m2)
+ );
+ MULT9X9 #(
+ .REGINPUTA(REGINPUTAB3), .REGINPUTB(REGINPUTAB3), .REGOUTPUT(REGPIPELINE), .GSR(GSR), .RESETMODE(RESETMODE)
+ ) m9_3 (
+ .A(A3), .B(B3), .SIGNEDA(SIGNED), .SIGNEDB(SIGNED),
+ .CLK(CLK),
+ .CEA(CEA2A3), .RSTA(RSTA2A3),
+ .CEB(CEB2B3), .RSTB(RSTB2B3),
+ .CEOUT(CEPIPE), .RSTOUT(RSTPIPE),
+ .Z(m3)
+ );
+
+ wire [53:0] c_r, c_r2;
+ wire [3:0] addsub_r, addsub_r2;
+ wire sgd_r, sgd_r2, csgd_r, csgd_r2;
+ wire loadc_r, loadc_r2;
+
+ OXIDE_DSP_REG #(5, REGADDSUB, RESETMODE) addsub_reg(CLK, CECTRL, RSTCTRL, {SIGNED, ADDSUB}, {sgd_r, addsub_r});
+ OXIDE_DSP_REG #(5, REGADDSUB, RESETMODE) addsub2_reg(CLK, CECTRL, RSTCTRL, {sgd_r, addsub_r}, {sgd_r2, addsub_r2});
+
+ OXIDE_DSP_REG #(1, REGLOADC, RESETMODE) loadc_reg(CLK, CECTRL, RSTCTRL, LOADC, loadc_r);
+ OXIDE_DSP_REG #(1, REGLOADC2, RESETMODE) loadc2_reg(CLK, CECTRL, RSTCTRL, loadc_r, loadc_r2);
+
+ OXIDE_DSP_REG #(55, REGINPUTC, RESETMODE) c_reg(CLK, CEC, RSTC, {SIGNED, C}, {csgd_r, c_r});
+ OXIDE_DSP_REG #(55, REGPIPELINE, RESETMODE) c2_reg(CLK, CEC, RSTC, {csgd_r, c_r}, {csgd_r2, c_r2});
+
+
+ wire [18:0] m0_ext, m1_ext, m2_ext, m3_ext;
+
+ assign m0_ext = {sgd_r2 ? m0[M_WIDTH-1] : 1'b0, m0};
+ assign m1_ext = {sgd_r2 ? m1[M_WIDTH-1] : 1'b0, m1};
+ assign m2_ext = {sgd_r2 ? m2[M_WIDTH-1] : 1'b0, m2};
+ assign m3_ext = {sgd_r2 ? m3[M_WIDTH-1] : 1'b0, m3};
+
+ wire [18:0] s0 = addsub_r2[2] ? (m0_ext - m1_ext) : (m0_ext + m1_ext);
+ wire [18:0] s1 = addsub_r2[3] ? (m2_ext - m3_ext) : (m2_ext + m3_ext);
+
+ wire [53:0] s0_ext = {{(54-19){sgd_r2 ? s0[18] : 1'b0}}, s0};
+ wire [53:0] s1_ext = {{(54-19){sgd_r2 ? s1[18] : 1'b0}}, s1};
+
+ wire [53:0] c_op = loadc_r2 ? c_r2 : Z;
+
+ // The diagram in the docs is wrong! It is not two cascaded 2-input add/subs as shown,
+ // but a three-input unit with negation controls on two inputs (i.e. addsub_r2[0]
+ // negates s1 not (s1 +/- s0))
+ wire [53:0] z_d = c_op + (addsub_r2[0] ? -s1_ext : s1_ext) + (addsub_r2[1] ? -s0_ext : s0_ext);
+
+ OXIDE_DSP_REG #(Z_WIDTH, REGOUTPUT, RESETMODE) z_reg(CLK, CEOUT, RSTOUT, z_d, Z);
+
+endmodule
diff --git a/tests/simple/const_fold_func.v b/tests/simple/const_fold_func.v
new file mode 100644
index 000000000..ee2f12e06
--- /dev/null
+++ b/tests/simple/const_fold_func.v
@@ -0,0 +1,61 @@
+module top(
+ input wire [3:0] inp,
+ output wire [3:0] out1, out2, out3, out4, out5,
+ output reg [3:0] out6
+);
+ function automatic [3:0] flip;
+ input [3:0] inp;
+ flip = ~inp;
+ endfunction
+
+ function automatic [3:0] help;
+ input [3:0] inp;
+ help = flip(inp);
+ endfunction
+
+ // while loops are const-eval-only
+ function automatic [3:0] loop;
+ input [3:0] inp;
+ reg [3:0] val;
+ begin
+ val = inp;
+ loop = 1;
+ while (val != inp) begin
+ loop = loop * 2;
+ val = val + 1;
+ end
+ end
+ endfunction
+
+ // not const-eval-only, despite calling a const-eval-only function
+ function automatic [3:0] help_mul;
+ input [3:0] inp;
+ help_mul = inp * loop(2);
+ endfunction
+
+ // can be elaborated so long as exp is a constant
+ function automatic [3:0] pow_flip_a;
+ input [3:0] base, exp;
+ begin
+ pow_flip_a = 1;
+ if (exp > 0)
+ pow_flip_a = base * pow_flip_a(flip(base), exp - 1);
+ end
+ endfunction
+
+ function automatic [3:0] pow_flip_b;
+ input [3:0] base, exp;
+ begin
+ out6[exp] = base & 1;
+ pow_flip_b = 1;
+ if (exp > 0)
+ pow_flip_b = base * pow_flip_b(flip(base), exp - 1);
+ end
+ endfunction
+
+ assign out1 = flip(flip(inp));
+ assign out2 = help(flip(inp));
+ assign out3 = help_mul(inp);
+ assign out4 = pow_flip_a(flip(inp), 3);
+ assign out5 = pow_flip_b(2, 2);
+endmodule
diff --git a/tests/simple/const_func_shadow.v b/tests/simple/const_func_shadow.v
new file mode 100644
index 000000000..ca63606d9
--- /dev/null
+++ b/tests/simple/const_func_shadow.v
@@ -0,0 +1,33 @@
+module top(w, x, y, z);
+ function [11:0] func;
+ input reg [2:0] x;
+ input reg [2:0] y;
+ begin
+ x = x * (y + 1);
+ begin : foo
+ reg [2:0] y;
+ y = x + 1;
+ begin : bar
+ reg [2:0] x;
+ x = y + 1;
+ begin : blah
+ reg [2:0] y;
+ y = x + 1;
+ func[2:0] = y;
+ end
+ func[5:3] = x;
+ end
+ func[8:6] = y;
+ end
+ func[11:9] = x;
+ end
+ endfunction
+ output wire [func(2, 3) - 1:0] w;
+ output wire [func(1, 3) - 1:0] x;
+ output wire [func(3, 1) - 1:0] y;
+ output wire [func(5, 2) - 1:0] z;
+ assign w = 1'sb1;
+ assign x = 1'sb1;
+ assign y = 1'sb1;
+ assign z = 1'sb1;
+endmodule
diff --git a/tests/simple/genblk_port_shadow.v b/tests/simple/genblk_port_shadow.v
new file mode 100644
index 000000000..a04631a20
--- /dev/null
+++ b/tests/simple/genblk_port_shadow.v
@@ -0,0 +1,10 @@
+module top(x);
+ generate
+ if (1) begin : blk
+ wire x;
+ assign x = 0;
+ end
+ endgenerate
+ output wire x;
+ assign x = blk.x;
+endmodule
diff --git a/tests/various/port_sign_extend.v b/tests/various/port_sign_extend.v
index 446268268..813ceb503 100644
--- a/tests/various/port_sign_extend.v
+++ b/tests/various/port_sign_extend.v
@@ -24,8 +24,8 @@ module PassThrough(a, b);
assign b = a;
endmodule
-module act(o1, o2, o3, o4, o5, o6, yay1, nay1, yay2, nay2);
- output wire [3:0] o1, o2, o3, o4, o5, o6;
+module act(o1, o2, o3, o4, o5, o6, o7, o8, o9, yay1, nay1, yay2, nay2);
+ output wire [3:0] o1, o2, o3, o4, o5, o6, o7, o8, o9;
// unsigned constant
PassThrough pt1(1'b1, o1);
@@ -52,6 +52,17 @@ module act(o1, o2, o3, o4, o5, o6, yay1, nay1, yay2, nay2);
wire signed [2:0] tmp6b = 3'b001;
PassThrough pt6(tmp6a ? tmp6a : tmp6b, o6);
+ wire signed [2:0] tmp7 = 3'b011;
+ PassThrough pt7(~tmp7, o7);
+
+ reg signed [2:0] tmp8 [0:0];
+ initial tmp8[0] = 3'b101;
+ PassThrough pt8(tmp8[0], o8);
+
+ wire signed [2:0] tmp9a = 3'b100;
+ wire signed [1:0] tmp9b = 2'b11;
+ PassThrough pt9(0 ? tmp9a : tmp9b, o9);
+
output wire [2:0] yay1, nay1;
GeneratorSigned1 os1(yay1);
GeneratorUnsigned1 ou1(nay1);
@@ -61,8 +72,8 @@ module act(o1, o2, o3, o4, o5, o6, yay1, nay1, yay2, nay2);
GeneratorUnsigned2 ou2(nay2);
endmodule
-module ref(o1, o2, o3, o4, o5, o6, yay1, nay1, yay2, nay2);
- output wire [3:0] o1, o2, o3, o4, o5, o6;
+module ref(o1, o2, o3, o4, o5, o6, o7, o8, o9, yay1, nay1, yay2, nay2);
+ output wire [3:0] o1, o2, o3, o4, o5, o6, o7, o8, o9;
assign o1 = 4'b0001;
assign o2 = 4'b0001;
@@ -70,6 +81,9 @@ module ref(o1, o2, o3, o4, o5, o6, yay1, nay1, yay2, nay2);
assign o4 = 4'b1111;
assign o5 = 4'b1110;
assign o6 = 4'b1100;
+ assign o7 = 4'b1100;
+ assign o8 = 4'b1101;
+ assign o9 = 4'b1111;
output wire [2:0] yay1, nay1;
assign yay1 = 3'b111;
diff --git a/tests/various/port_sign_extend.ys b/tests/various/port_sign_extend.ys
index 0a6a93810..6d1adf7f3 100644
--- a/tests/various/port_sign_extend.ys
+++ b/tests/various/port_sign_extend.ys
@@ -1,22 +1,29 @@
-read_verilog port_sign_extend.v
+read_verilog -nomem2reg port_sign_extend.v
hierarchy
flatten
+proc
+memory
equiv_make ref act equiv
equiv_simple
equiv_status -assert
delete
-read_verilog port_sign_extend.v
+read_verilog -nomem2reg port_sign_extend.v
flatten
+proc
+memory
equiv_make ref act equiv
equiv_simple
equiv_status -assert
delete
-read_verilog port_sign_extend.v
+read_verilog -nomem2reg port_sign_extend.v
hierarchy
+proc
+memory
equiv_make ref act equiv
prep -flatten -top equiv
+equiv_induct
equiv_status -assert
diff --git a/tests/verilog/atom_type_signedness.ys b/tests/verilog/atom_type_signedness.ys
new file mode 100644
index 000000000..22bbe6efc
--- /dev/null
+++ b/tests/verilog/atom_type_signedness.ys
@@ -0,0 +1,19 @@
+read_verilog -dump_ast1 -dump_ast2 -sv <<EOT
+module dut();
+
+enum integer { uInteger = -10 } a;
+enum int { uInt = -11 } b;
+enum shortint { uShortInt = -12 } c;
+enum byte { uByte = -13 } d;
+
+always_comb begin
+ assert(-10 == uInteger);
+ assert(-11 == uInt);
+ assert(-12 == uShortInt);
+ assert(-13 == uByte);
+end
+endmodule
+EOT
+hierarchy; proc; opt
+select -module dut
+sat -verify -seq 1 -tempinduct -prove-asserts -show-all
diff --git a/tests/verilog/block_labels.ys b/tests/verilog/block_labels.ys
new file mode 100644
index 000000000..e76bcf771
--- /dev/null
+++ b/tests/verilog/block_labels.ys
@@ -0,0 +1,26 @@
+read_verilog <<EOT
+module foo;
+
+ genvar a = 0;
+ for (a = 0; a < 10; a++) begin : a
+ end : a
+endmodule
+EOT
+read_verilog <<EOT
+module foo2;
+
+ genvar a = 0;
+ for (a = 0; a < 10; a++) begin : a
+ end
+endmodule
+EOT
+
+logger -expect error "Begin label \(a\) and end label \(b\) don't match\." 1
+read_verilog <<EOT
+module foo3;
+
+ genvar a = 0;
+ for (a = 0; a < 10; a++) begin : a
+ end : b
+endmodule
+EOT
diff --git a/tests/verilog/genblk_port_decl.ys b/tests/verilog/genblk_port_decl.ys
new file mode 100644
index 000000000..589d3d2e1
--- /dev/null
+++ b/tests/verilog/genblk_port_decl.ys
@@ -0,0 +1,12 @@
+logger -expect error "Cannot declare module port `\\x' within a generate block\." 1
+read_verilog <<EOT
+module top(x);
+ generate
+ if (1) begin : blk
+ output wire x;
+ assign x = 1;
+ end
+ endgenerate
+ output wire x;
+endmodule
+EOT