aboutsummaryrefslogtreecommitdiffstats
path: root/frontends
diff options
context:
space:
mode:
Diffstat (limited to 'frontends')
-rw-r--r--frontends/ast/ast.cc6
-rw-r--r--frontends/ast/ast.h1
-rw-r--r--frontends/ast/simplify.cc122
-rw-r--r--frontends/verific/verific.cc118
-rw-r--r--frontends/verilog/verilog_parser.y3
5 files changed, 202 insertions, 48 deletions
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 9520ae32c..c8183580b 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -336,6 +336,12 @@ void AstNode::dumpAst(FILE *f, std::string indent) const
fprintf(f, " %d", v);
fprintf(f, " ]");
}
+ if (!multirange_swapped.empty()) {
+ fprintf(f, " multirange_swapped=[");
+ for (auto v : multirange_swapped)
+ fprintf(f, " %d", v);
+ fprintf(f, " ]");
+ }
if (is_enum) {
fprintf(f, " type=enum");
}
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index 203b50021..1b8ed22ca 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -202,6 +202,7 @@ namespace AST
// if this is a multirange memory then this vector contains offset and length of each dimension
std::vector<int> multirange_dimensions;
+ std::vector<bool> multirange_swapped; // true if range is swapped, not used for structs
// this is set by simplify and used during RTLIL generation
AstNode *id2ast;
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 153a42e19..fb6623f02 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -1504,11 +1504,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
int total_size = 1;
multirange_dimensions.clear();
+ multirange_swapped.clear();
for (auto range : children[1]->children) {
if (!range->range_valid)
log_file_error(filename, location.first_line, "Non-constant range on memory decl.\n");
multirange_dimensions.push_back(min(range->range_left, range->range_right));
multirange_dimensions.push_back(max(range->range_left, range->range_right) - min(range->range_left, range->range_right) + 1);
+ multirange_swapped.push_back(range->range_swapped);
total_size *= multirange_dimensions.back();
}
delete children[1];
@@ -1521,6 +1523,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
AstNode *index_expr = nullptr;
+ integer = children[0]->children.size(); // save original number of dimensions for $size() etc.
for (int i = 0; 2*i < GetSize(id2ast->multirange_dimensions); i++)
{
if (GetSize(children[0]->children) <= i)
@@ -1719,6 +1722,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
newNode = new AstNode(AST_IDENTIFIER, children[1]->clone());
newNode->str = wire_id;
+ newNode->integer = integer; // save original number of dimensions for $size() etc.
newNode->id2ast = wire;
goto apply_newNode;
}
@@ -2831,26 +2835,28 @@ skip_dynamic_range_lvalue_expansion:;
goto apply_newNode;
}
- if (str == "\\$size" || str == "\\$bits")
+ if (str == "\\$size" || str == "\\$bits" || str == "\\$high" || str == "\\$low" || str == "\\$left" || str == "\\$right")
{
- if (str == "\\$bits" && children.size() != 1)
- log_file_error(filename, location.first_line, "System function %s got %d arguments, expected 1.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
-
- if (str == "\\$size" && children.size() != 1 && children.size() != 2)
- log_file_error(filename, location.first_line, "System function %s got %d arguments, expected 1 or 2.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
-
int dim = 1;
- if (str == "\\$size" && children.size() == 2) {
- AstNode *buf = children[1]->clone();
- // Evaluate constant expression
- while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
- dim = buf->asInt(false);
- delete buf;
+ if (str == "\\$bits") {
+ if (children.size() != 1)
+ log_file_error(filename, location.first_line, "System function %s got %d arguments, expected 1.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
+ } else {
+ if (children.size() != 1 && children.size() != 2)
+ log_file_error(filename, location.first_line, "System function %s got %d arguments, expected 1 or 2.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
+ if (children.size() == 2) {
+ AstNode *buf = children[1]->clone();
+ // Evaluate constant expression
+ while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ dim = buf->asInt(false);
+ delete buf;
+ }
}
AstNode *buf = children[0]->clone();
int mem_depth = 1;
+ int result, high = 0, low = 0, left = 0, right = 0, width = 1; // defaults for a simple wire
AstNode *id_ast = NULL;
// Is this needed?
@@ -2863,6 +2869,31 @@ skip_dynamic_range_lvalue_expansion:;
id_ast = current_scope.at(buf->str);
if (!id_ast)
log_file_error(filename, location.first_line, "Failed to resolve identifier %s for width detection!\n", buf->str.c_str());
+ // a slice of our identifier means we advance to the next dimension, e.g. $size(a[3])
+ if (buf->children.size() > 0) {
+ // something is hanging below this identifier
+ if (buf->children[0]->type == AST_RANGE && buf->integer == 0)
+ // if integer == 0, this node was originally created as AST_RANGE so it's dimension is 1
+ dim++;
+ // more than one range, e.g. $size(a[3][2])
+ else // created an AST_MULTIRANGE, converted to AST_RANGE, but original dimension saved in 'integer' field
+ dim += buf->integer; // increment by multirange size
+ }
+ // We have 4 cases:
+ // wire x; ==> AST_WIRE, no AST_RANGE children
+ // wire [1:0]x; ==> AST_WIRE, AST_RANGE children
+ // wire [1:0]x[1:0]; ==> AST_MEMORY, two AST_RANGE children (1st for packed, 2nd for unpacked)
+ // wire [1:0]x[1:0][1:0]; ==> AST_MEMORY, one AST_RANGE child (0) for packed, then AST_MULTIRANGE child (1) for unpacked
+ // (updated: actually by the time we are here, AST_MULTIRANGE is converted into one big AST_RANGE)
+ // case 0 handled by default
+ if ((id_ast->type == AST_WIRE || id_ast->type == AST_MEMORY) && id_ast->children.size() > 0) {
+ // handle packed array left/right for case 1, and cases 2/3 when requesting the last dimension (packed side)
+ AstNode *wire_range = id_ast->children[0];
+ left = wire_range->children[0]->integer;
+ right = wire_range->children[1]->integer;
+ high = max(left, right);
+ low = min(left, right);
+ }
if (id_ast->type == AST_MEMORY) {
// We got here only if the argument is a memory
// Otherwise $size() and $bits() return the expression width
@@ -2875,29 +2906,58 @@ skip_dynamic_range_lvalue_expansion:;
} else
log_file_error(filename, location.first_line, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str());
} else {
- // $size()
+ // $size(), $left(), $right(), $high(), $low()
+ int dims = 1;
if (mem_range->type == AST_RANGE) {
- if (!mem_range->range_valid)
- log_file_error(filename, location.first_line, "Failed to detect width of memory access `%s'!\n", buf->str.c_str());
- int dims;
- if (id_ast->multirange_dimensions.empty())
- dims = 1;
- else
+ if (id_ast->multirange_dimensions.empty()) {
+ if (!mem_range->range_valid)
+ log_file_error(filename, location.first_line, "Failed to detect width of memory access `%s'!\n", buf->str.c_str());
+ if (dim == 1) {
+ left = mem_range->range_right;
+ right = mem_range->range_left;
+ high = max(left, right);
+ low = min(left, right);
+ }
+ } else {
dims = GetSize(id_ast->multirange_dimensions)/2;
- if (dim == 1)
- width_hint = (dims > 1) ? id_ast->multirange_dimensions[1] : (mem_range->range_left - mem_range->range_right + 1);
- else if (dim <= dims) {
- width_hint = id_ast->multirange_dimensions[2*dim-1];
- } else if ((dim > dims+1) || (dim < 0))
- log_file_error(filename, location.first_line, "Dimension %d out of range in `%s', as it only has dimensions 1..%d!\n", dim, buf->str.c_str(), dims+1);
- } else
+ if (dim <= dims) {
+ width_hint = id_ast->multirange_dimensions[2*dim-1];
+ high = id_ast->multirange_dimensions[2*dim-2] + id_ast->multirange_dimensions[2*dim-1] - 1;
+ low = id_ast->multirange_dimensions[2*dim-2];
+ if (id_ast->multirange_swapped[dim-1]) {
+ left = low;
+ right = high;
+ } else {
+ right = low;
+ left = high;
+ }
+ } else if ((dim > dims+1) || (dim < 0))
+ log_file_error(filename, location.first_line, "Dimension %d out of range in `%s', as it only has dimensions 1..%d!\n", dim, buf->str.c_str(), dims+1);
+ }
+ } else {
log_file_error(filename, location.first_line, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str());
+ }
}
}
+ width = high - low + 1;
+ } else {
+ width = width_hint;
}
delete buf;
-
- newNode = mkconst_int(width_hint * mem_depth, false);
+ if (str == "\\$high")
+ result = high;
+ else if (str == "\\$low")
+ result = low;
+ else if (str == "\\$left")
+ result = left;
+ else if (str == "\\$right")
+ result = right;
+ else if (str == "\\$size")
+ result = width;
+ else {
+ result = width * mem_depth;
+ }
+ newNode = mkconst_int(result, false);
goto apply_newNode;
}
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index 7bbda9d49..e236aaaf2 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -21,6 +21,7 @@
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
+#include "libs/sha1/sha1.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -54,7 +55,7 @@ USING_YOSYS_NAMESPACE
# error "Only Symbiotic EDA flavored Verific is supported. Please contact office@symbioticeda.com for commercial support for Yosys+Verific."
#endif
-#if SYMBIOTIC_VERIFIC_API_VERSION < 20200801
+#if SYMBIOTIC_VERIFIC_API_VERSION < 20200902
# error "Please update your version of Symbiotic EDA flavored Verific."
#endif
@@ -864,6 +865,21 @@ void VerificImporter::merge_past_ffs(pool<RTLIL::Cell*> &candidates)
merge_past_ffs_clock(it.second, it.first.first, it.first.second);
}
+static std::string sha1_if_contain_spaces(std::string str)
+{
+ if(str.find_first_of(' ') != std::string::npos) {
+ std::size_t open = str.find_first_of('(');
+ std::size_t closed = str.find_last_of(')');
+ if (open != std::string::npos && closed != std::string::npos) {
+ std::string content = str.substr(open + 1, closed - open - 1);
+ return str.substr(0, open + 1) + sha1(content) + str.substr(closed);
+ } else {
+ return sha1(str);
+ }
+ }
+ return str;
+}
+
void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*> &nl_todo, bool norename)
{
std::string netlist_name = nl->GetAtt(" \\top") ? nl->CellBaseName() : nl->Owner()->Name();
@@ -877,7 +893,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
module_name += nl->Name();
module_name += ")";
}
- module_name = "\\" + module_name;
+ module_name = "\\" + sha1_if_contain_spaces(module_name);
}
netlist = nl;
@@ -1512,7 +1528,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
inst_type += inst->View()->Name();
inst_type += ")";
}
- inst_type = "\\" + inst_type;
+ inst_type = "\\" + sha1_if_contain_spaces(inst_type);
}
RTLIL::Cell *cell = module->addCell(inst_name, inst_type);
@@ -2187,6 +2203,9 @@ struct VerificPass : public Pass {
log("\n");
log("Application options:\n");
log("\n");
+ log(" -module <module>\n");
+ log(" Run formal application only on specified module.\n");
+ log("\n");
log(" -blacklist <filename[:lineno]>\n");
log(" Do not run application on modules from files that match the filename\n");
log(" or filename and line number if provided in such format.\n");
@@ -2475,8 +2494,11 @@ struct VerificPass : public Pass {
goto check_error;
}
- if (argidx+1 < GetSize(args) && args[argidx] == "-app")
+ if (argidx < GetSize(args) && args[argidx] == "-app")
{
+ if (!(argidx+1 < GetSize(args)))
+ cmd_error(args, argidx, "No formal application specified.\n");
+
VerificFormalApplications vfa;
auto apps = vfa.GetApps();
std::string app = args[++argidx];
@@ -2484,15 +2506,42 @@ struct VerificPass : public Pass {
if (apps.find(app) == apps.end())
log_cmd_error("Application '%s' does not exist.\n", app.c_str());
+ FormalApplication *application = apps[app];
+ application->setLogger([](std::string msg) { log("%s",msg.c_str()); } );
+ VeriModule *selected_module = nullptr;
+
for (argidx++; argidx < GetSize(args); argidx++) {
- if (args[argidx] == "-blacklist" && argidx+1 < GetSize(args)) {
+ std::string error;
+ if (application->checkParams(args, argidx, error)) {
+ if (!error.empty())
+ cmd_error(args, argidx, error);
+ continue;
+ }
+
+ if (args[argidx] == "-module" && argidx < GetSize(args)) {
+ if (!(argidx+1 < GetSize(args)))
+ cmd_error(args, argidx+1, "No module name specified.\n");
+ std::string module = args[++argidx];
+ VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1);
+ selected_module = veri_lib ? veri_lib->GetModule(module.c_str(), 1) : nullptr;
+ if (!selected_module) {
+ log_error("Can't find module '%s'.\n", module.c_str());
+ }
+ continue;
+ }
+ if (args[argidx] == "-blacklist" && argidx < GetSize(args)) {
+ if (!(argidx+1 < GetSize(args)))
+ cmd_error(args, argidx+1, "No blacklist specified.\n");
+
std::string line = args[++argidx];
std::string p;
while (!(p = next_token(line, ",\t\r\n ")).empty())
blacklists.push_back(p);
continue;
}
- if (args[argidx] == "-blfile" && argidx+1 < GetSize(args)) {
+ if (args[argidx] == "-blfile" && argidx < GetSize(args)) {
+ if (!(argidx+1 < GetSize(args)))
+ cmd_error(args, argidx+1, "No blacklist file specified.\n");
std::string fn = args[++argidx];
std::ifstream f(fn);
if (f.fail())
@@ -2509,12 +2558,32 @@ struct VerificPass : public Pass {
}
if (argidx < GetSize(args))
cmd_error(args, argidx, "unknown option/parameter");
+
+ application->setBlacklists(&blacklists);
+ application->setSingleModuleMode(selected_module!=nullptr);
+
+ const char *err = application->validate();
+ if (err)
+ cmd_error(args, argidx, err);
+
MapIter mi;
- VeriModule *module ;
VeriLibrary *veri_lib = veri_file::GetLibrary(work.c_str(), 1);
log("Running formal application '%s'.\n", app.c_str());
- FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, module) {
- vfa.Run(module,apps[app],blacklists);
+
+ if (selected_module) {
+ std::string out;
+ if (!application->execute(selected_module, out))
+ log_error("%s", out.c_str());
+ }
+ else {
+ VeriModule *module ;
+ FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, module) {
+ std::string out;
+ if (!application->execute(module, out)) {
+ log_error("%s", out.c_str());
+ break;
+ }
+ }
}
goto check_error;
}
@@ -2563,8 +2632,8 @@ struct VerificPass : public Pass {
if (argidx < GetSize(args) && args[argidx] == "-template")
{
- if (!(argidx < GetSize(args)))
- cmd_error(args, argidx, "No template type specified.\n");
+ if (!(argidx+1 < GetSize(args)))
+ cmd_error(args, argidx+1, "No template type specified.\n");
VerificTemplateGenerator vfg;
auto gens = vfg.GetGenerators();
@@ -2572,8 +2641,9 @@ struct VerificPass : public Pass {
if (gens.find(app) == gens.end())
log_cmd_error("Template generator '%s' does not exist.\n", app.c_str());
TemplateGenerator *generator = gens[app];
- if (!(argidx < GetSize(args)))
- cmd_error(args, argidx, "No top module specified.\n");
+ if (!(argidx+1 < GetSize(args)))
+ cmd_error(args, argidx+1, "No top module specified.\n");
+ generator->setLogger([](std::string msg) { log("%s",msg.c_str()); } );
std::string module = args[++argidx];
VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1);
@@ -2588,9 +2658,19 @@ struct VerificPass : public Pass {
const char *out_filename = nullptr;
for (argidx++; argidx < GetSize(args); argidx++) {
- if (generator->checkParams(args, argidx))
+ std::string error;
+ if (generator->checkParams(args, argidx, error)) {
+ if (!error.empty())
+ cmd_error(args, argidx, error);
continue;
- if (args[argidx] == "-chparam" && argidx+2 < GetSize(args)) {
+ }
+
+ if (args[argidx] == "-chparam" && argidx < GetSize(args)) {
+ if (!(argidx+1 < GetSize(args)))
+ cmd_error(args, argidx+1, "No param name specified.\n");
+ if (!(argidx+2 < GetSize(args)))
+ cmd_error(args, argidx+2, "No param value specified.\n");
+
const std::string &key = args[++argidx];
const std::string &value = args[++argidx];
unsigned new_insertion = parameters.Insert(key.c_str(), value.c_str(),
@@ -2600,7 +2680,9 @@ struct VerificPass : public Pass {
continue;
}
- if (args[argidx] == "-out" && argidx+1 < GetSize(args)) {
+ if (args[argidx] == "-out" && argidx < GetSize(args)) {
+ if (!(argidx+1 < GetSize(args)))
+ cmd_error(args, argidx+1, "No output file specified.\n");
out_filename = args[++argidx].c_str();
continue;
}
@@ -2614,7 +2696,9 @@ struct VerificPass : public Pass {
if (err)
cmd_error(args, argidx, err);
- std::string val = generator->generate(veri_module, &parameters);
+ std::string val;
+ if (!generator->generate(veri_module, val, &parameters))
+ log_error("%s", val.c_str());
FILE *of = stdout;
if (out_filename) {
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 8e5236639..678ce6c87 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -1891,6 +1891,9 @@ cell_parameter:
astbuf1->children.push_back(node);
node->children.push_back($1);
} |
+ '.' TOK_ID '(' ')' {
+ // just ignore empty parameters
+ } |
'.' TOK_ID '(' expr ')' {
AstNode *node = new AstNode(AST_PARASET);
node->str = *$2;