aboutsummaryrefslogtreecommitdiffstats
path: root/frontends/ast
diff options
context:
space:
mode:
Diffstat (limited to 'frontends/ast')
-rw-r--r--frontends/ast/ast.cc66
-rw-r--r--frontends/ast/ast.h27
-rw-r--r--frontends/ast/dpicall.cc4
-rw-r--r--frontends/ast/genrtlil.cc167
-rw-r--r--frontends/ast/simplify.cc496
5 files changed, 563 insertions, 197 deletions
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 68b3327f9..57de725d8 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* 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
@@ -30,15 +30,6 @@
#include "libs/sha1/sha1.h"
#include "ast.h"
-#include <sstream>
-#include <stdarg.h>
-
-#if defined(__APPLE__)
-# include <cmath>
-#else
-# include <math.h>
-#endif
-
YOSYS_NAMESPACE_BEGIN
using namespace AST;
@@ -53,12 +44,12 @@ namespace AST {
// instanciate global variables (private API)
namespace AST_INTERNAL {
- bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
+ bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
AstNode *current_ast, *current_ast_mod;
std::map<std::string, AstNode*> current_scope;
const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
RTLIL::SigSpec ignoreThisSignalsInInitial;
- AstNode *current_top_block, *current_block, *current_block_child;
+ AstNode *current_always, *current_top_block, *current_block, *current_block_child;
AstModule *current_module;
}
@@ -90,6 +81,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_IDENTIFIER)
X(AST_PREFIX)
X(AST_ASSERT)
+ X(AST_ASSUME)
X(AST_FCALL)
X(AST_TO_BITS)
X(AST_TO_SIGNED)
@@ -132,6 +124,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_TERNARY)
X(AST_MEMRD)
X(AST_MEMWR)
+ X(AST_MEMINIT)
X(AST_TCALL)
X(AST_ASSIGN)
X(AST_CELL)
@@ -144,6 +137,8 @@ std::string AST::type2str(AstNodeType type)
X(AST_ASSIGN_LE)
X(AST_CASE)
X(AST_COND)
+ X(AST_CONDX)
+ X(AST_CONDZ)
X(AST_DEFAULT)
X(AST_FOR)
X(AST_WHILE)
@@ -156,6 +151,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_POSEDGE)
X(AST_NEGEDGE)
X(AST_EDGE)
+ X(AST_PACKAGE)
#undef X
default:
log_abort();
@@ -327,7 +323,7 @@ static std::string id2vl(std::string txt)
return txt;
}
-// dump AST node as verilog pseudo-code
+// dump AST node as Verilog pseudo-code
void AstNode::dumpVlog(FILE *f, std::string indent)
{
bool first = true;
@@ -499,7 +495,12 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
break;
case AST_CASE:
- fprintf(f, "%s" "case (", indent.c_str());
+ if (!children.empty() && children[0]->type == AST_CONDX)
+ fprintf(f, "%s" "casex (", indent.c_str());
+ else if (!children.empty() && children[0]->type == AST_CONDZ)
+ fprintf(f, "%s" "casez (", indent.c_str());
+ else
+ fprintf(f, "%s" "case (", indent.c_str());
children[0]->dumpVlog(f, "");
fprintf(f, ")\n");
for (size_t i = 1; i < children.size(); i++) {
@@ -510,6 +511,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
break;
case AST_COND:
+ case AST_CONDX:
+ case AST_CONDZ:
for (auto child : children) {
if (child->type == AST_BLOCK) {
fprintf(f, ":\n");
@@ -553,7 +556,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
children[1]->dumpVlog(f, "");
fprintf(f, "}}");
break;
-
+
if (0) { case AST_BIT_NOT: txt = "~"; }
if (0) { case AST_REDUCE_AND: txt = "&"; }
if (0) { case AST_REDUCE_OR: txt = "|"; }
@@ -697,7 +700,7 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
for (size_t i = 0; i < 32; i++) {
if (i < node->bits.size())
node->integer |= (node->bits[i] == RTLIL::S1) << i;
- else if (is_signed)
+ else if (is_signed && !node->bits.empty())
node->integer |= (node->bits.back() == RTLIL::S1) << i;
}
node->range_valid = true;
@@ -818,7 +821,7 @@ uint64_t AstNode::asInt(bool is_signed)
}
if (type == AST_REALVALUE)
- return realvalue;
+ return uint64_t(realvalue);
log_abort();
}
@@ -829,7 +832,7 @@ double AstNode::asReal(bool is_signed)
{
RTLIL::Const val(bits);
- bool is_negative = is_signed && val.bits.back() == RTLIL::State::S1;
+ bool is_negative = is_signed && !val.bits.empty() && val.bits.back() == RTLIL::State::S1;
if (is_negative)
val = const_neg(val, val, false, false, val.bits.size());
@@ -892,7 +895,7 @@ static AstModule* process_module(AstNode *ast, bool defer)
AstNode *ast_before_simplify = ast->clone();
if (flag_dump_ast1) {
- log("Dumping verilog AST before simplification:\n");
+ log("Dumping Verilog AST before simplification:\n");
ast->dumpAst(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
@@ -902,13 +905,13 @@ static AstModule* process_module(AstNode *ast, bool defer)
while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { }
if (flag_dump_ast2) {
- log("Dumping verilog AST after simplification:\n");
+ log("Dumping Verilog AST after simplification:\n");
ast->dumpAst(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
if (flag_dump_vlog) {
- log("Dumping verilog AST (as requested by dump_vlog option):\n");
+ log("Dumping Verilog AST (as requested by dump_vlog option):\n");
ast->dumpVlog(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
@@ -957,6 +960,7 @@ static AstModule* process_module(AstNode *ast, bool defer)
current_module->ast = ast_before_simplify;
current_module->nolatches = flag_nolatches;
+ current_module->nomeminit = flag_nomeminit;
current_module->nomem2reg = flag_nomem2reg;
current_module->mem2reg = flag_mem2reg;
current_module->lib = flag_lib;
@@ -968,13 +972,14 @@ static AstModule* process_module(AstNode *ast, bool defer)
}
// create AstModule instances for all modules in the AST tree and add them to 'design'
-void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire)
+void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire)
{
current_ast = ast;
flag_dump_ast1 = dump_ast1;
flag_dump_ast2 = dump_ast2;
flag_dump_vlog = dump_vlog;
flag_nolatches = nolatches;
+ flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
flag_lib = lib;
@@ -992,6 +997,14 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
for (auto n : global_decls)
(*it)->children.push_back(n->clone());
+ for (auto n : design->verilog_packages){
+ for (auto o : n->children) {
+ AstNode *cloned_node = o->clone();
+ cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1);
+ (*it)->children.push_back(cloned_node);
+ }
+ }
+
if (flag_icells && (*it)->str.substr(0, 2) == "\\$")
(*it)->str = (*it)->str.substr(1);
@@ -1009,6 +1022,9 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
design->add(process_module(*it, defer));
}
+ else if ((*it)->type == AST_PACKAGE){
+ design->verilog_packages.push_back((*it)->clone());
+ }
else
global_decls.push_back(*it);
}
@@ -1029,13 +1045,14 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R
if (stripped_name.substr(0, 9) == "$abstract")
stripped_name = stripped_name.substr(9);
- log_header("Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str());
+ log_header(design, "Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str());
current_ast = NULL;
flag_dump_ast1 = false;
flag_dump_ast2 = false;
flag_dump_vlog = false;
flag_nolatches = nolatches;
+ flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
flag_lib = lib;
@@ -1102,6 +1119,7 @@ RTLIL::Module *AstModule::clone() const
new_mod->ast = ast->clone();
new_mod->nolatches = nolatches;
+ new_mod->nomeminit = nomeminit;
new_mod->nomem2reg = nomem2reg;
new_mod->mem2reg = mem2reg;
new_mod->lib = lib;
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index 180646267..3dcd32bd4 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* 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
@@ -64,6 +64,7 @@ namespace AST
AST_IDENTIFIER,
AST_PREFIX,
AST_ASSERT,
+ AST_ASSUME,
AST_FCALL,
AST_TO_BITS,
@@ -107,6 +108,7 @@ namespace AST
AST_TERNARY,
AST_MEMRD,
AST_MEMWR,
+ AST_MEMINIT,
AST_TCALL,
AST_ASSIGN,
@@ -120,6 +122,8 @@ namespace AST
AST_ASSIGN_LE,
AST_CASE,
AST_COND,
+ AST_CONDX,
+ AST_CONDZ,
AST_DEFAULT,
AST_FOR,
AST_WHILE,
@@ -133,7 +137,9 @@ namespace AST
AST_POSEDGE,
AST_NEGEDGE,
- AST_EDGE
+ AST_EDGE,
+
+ AST_PACKAGE
};
// convert an node type to a string (e.g. for debug output)
@@ -208,13 +214,14 @@ namespace AST
// simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc.
// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()
bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param);
- AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr);
+ AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init);
void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map);
void replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules);
void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
- void mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block);
+ bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block);
bool mem2reg_check(pool<AstNode*> &mem2reg_set);
+ void mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes);
void meminfo(int &mem_width, int &mem_size, int &addr_bits);
// additional functionality for evaluating constant functions
@@ -264,13 +271,13 @@ namespace AST
};
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
- void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);
+ void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);
// parametric modules are supported directly by the AST library
- // therfore we need our own derivate of RTLIL::Module with overloaded virtual functions
+ // therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
struct AstModule : RTLIL::Module {
AstNode *ast;
- bool nolatches, nomem2reg, mem2reg, lib, noopt, icells, autowire;
+ bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;
virtual ~AstModule();
virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters);
virtual RTLIL::Module *clone() const;
@@ -294,12 +301,12 @@ namespace AST
namespace AST_INTERNAL
{
// internal state variables
- extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
+ extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
extern AST::AstNode *current_ast, *current_ast_mod;
extern std::map<std::string, AST::AstNode*> current_scope;
extern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
extern RTLIL::SigSpec ignoreThisSignalsInInitial;
- extern AST::AstNode *current_top_block, *current_block, *current_block_child;
+ extern AST::AstNode *current_always, *current_top_block, *current_block, *current_block_child;
extern AST::AstModule *current_module;
struct ProcessGenerator;
}
diff --git a/frontends/ast/dpicall.cc b/frontends/ast/dpicall.cc
index e566d653d..e241142d3 100644
--- a/frontends/ast/dpicall.cc
+++ b/frontends/ast/dpicall.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* 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
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 71248663e..3e359170b 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* 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
@@ -176,13 +176,13 @@ struct AST_INTERNAL::ProcessGenerator
RTLIL::Process *proc;
RTLIL::SigSpec outputSignals;
- // This always points to the RTLIL::CaseRule beeing filled at the moment
+ // This always points to the RTLIL::CaseRule being filled at the moment
RTLIL::CaseRule *current_case;
// This map contains the replacement pattern to be used in the right hand side
// of an assignment. E.g. in the code "foo = bar; foo = func(foo);" the foo in the right
// hand side of the 2nd assignment needs to be replace with the temporary signal holding
- // the value assigned in the first assignment. So when the first assignement is processed
+ // the value assigned in the first assignment. So when the first assignment is processed
// the according information is appended to subst_rvalue_from and subst_rvalue_to.
stackmap<RTLIL::SigBit, RTLIL::SigBit> subst_rvalue_map;
@@ -192,7 +192,7 @@ struct AST_INTERNAL::ProcessGenerator
// signal that is used as input for the register that drives the signal foo.
stackmap<RTLIL::SigBit, RTLIL::SigBit> subst_lvalue_map;
- // The code here generates a number of temprorary signal for each output register. This
+ // The code here generates a number of temporary signal for each output register. This
// map helps generating nice numbered names for all this temporary signals.
std::map<RTLIL::Wire*, int> new_temp_count;
@@ -338,12 +338,14 @@ struct AST_INTERNAL::ProcessGenerator
case AST_CASE:
for (auto child : ast->children)
if (child != ast->children[0]) {
- log_assert(child->type == AST_COND);
+ log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ);
collect_lvalues(reg, child, type_eq, type_le, false);
}
break;
case AST_COND:
+ case AST_CONDX:
+ case AST_CONDZ:
case AST_ALWAYS:
case AST_INITIAL:
for (auto child : ast->children)
@@ -379,7 +381,7 @@ struct AST_INTERNAL::ProcessGenerator
// e.g. when the last statement in the code "a = 23; if (b) a = 42; a = 0;" is processed this
// function is called to clean up the first two assignments as they are overwritten by
// the third assignment.
- void removeSignalFromCaseTree(const std::set<RTLIL::SigBit> &pattern, RTLIL::CaseRule *cs)
+ void removeSignalFromCaseTree(const RTLIL::SigSpec &pattern, RTLIL::CaseRule *cs)
{
for (auto it = cs->actions.begin(); it != cs->actions.end(); it++)
it->first.remove2(pattern, &it->second);
@@ -427,6 +429,17 @@ struct AST_INTERNAL::ProcessGenerator
{
RTLIL::SigSpec unmapped_lvalue = ast->children[0]->genRTLIL(), lvalue = unmapped_lvalue;
RTLIL::SigSpec rvalue = ast->children[1]->genWidthRTLIL(lvalue.size(), &subst_rvalue_map.stdmap());
+
+ pool<SigBit> lvalue_sigbits;
+ for (int i = 0; i < GetSize(lvalue); i++) {
+ if (lvalue_sigbits.count(lvalue[i]) > 0) {
+ unmapped_lvalue.remove(i);
+ lvalue.remove(i);
+ rvalue.remove(i--);
+ } else
+ lvalue_sigbits.insert(lvalue[i]);
+ }
+
lvalue.replace(subst_lvalue_map.stdmap());
if (ast->type == AST_ASSIGN_EQ) {
@@ -434,7 +447,7 @@ struct AST_INTERNAL::ProcessGenerator
subst_rvalue_map.set(unmapped_lvalue[i], rvalue[i]);
}
- removeSignalFromCaseTree(lvalue.to_sigbit_set(), current_case);
+ removeSignalFromCaseTree(lvalue, current_case);
remove_unwanted_lvalue_bits(lvalue, rvalue);
current_case->actions.push_back(RTLIL::SigSig(lvalue, rvalue));
}
@@ -467,7 +480,7 @@ struct AST_INTERNAL::ProcessGenerator
{
if (child == ast->children[0])
continue;
- log_assert(child->type == AST_COND);
+ log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ);
subst_lvalue_map.save();
subst_rvalue_map.save();
@@ -511,7 +524,7 @@ struct AST_INTERNAL::ProcessGenerator
subst_rvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]);
this_case_eq_lvalue.replace(subst_lvalue_map.stdmap());
- removeSignalFromCaseTree(this_case_eq_lvalue.to_sigbit_set(), current_case);
+ removeSignalFromCaseTree(this_case_eq_lvalue, current_case);
addChunkActions(current_case->actions, this_case_eq_lvalue, this_case_eq_ltemp);
}
break;
@@ -520,6 +533,11 @@ struct AST_INTERNAL::ProcessGenerator
log_error("Found wire declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum);
break;
+ case AST_PARAMETER:
+ case AST_LOCALPARAM:
+ log_error("Found parameter declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum);
+ break;
+
case AST_TCALL:
case AST_FOR:
break;
@@ -547,14 +565,14 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
switch (type)
{
case AST_CONSTANT:
- width_hint = std::max(width_hint, int(bits.size()));
+ width_hint = max(width_hint, int(bits.size()));
if (!is_signed)
sign_hint = false;
break;
case AST_REALVALUE:
*found_real = true;
- width_hint = std::max(width_hint, 32);
+ width_hint = max(width_hint, 32);
break;
case AST_IDENTIFIER:
@@ -567,9 +585,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (id_ast->children.size() > 1 && id_ast->children[1]->range_valid) {
this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1;
} else
- if (id_ast->children[0]->type == AST_CONSTANT) {
+ if (id_ast->children[0]->type != AST_CONSTANT)
+ while (id_ast->simplify(true, false, false, 1, -1, false, true)) { }
+ if (id_ast->children[0]->type == AST_CONSTANT)
this_width = id_ast->children[0]->bits.size();
- } else
+ else
log_error("Failed to detect width for parameter %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
if (children.size() != 0)
range = children[0];
@@ -582,7 +602,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
// log("---\n");
// id_ast->dumpAst(NULL, "decl> ");
// dumpAst(NULL, "ref> ");
- log_error("Failed to detect with of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_error("Failed to detect width of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
}
} else {
this_width = id_ast->range_left - id_ast->range_right + 1;
@@ -593,7 +613,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
this_width = 32;
} else if (id_ast->type == AST_MEMORY) {
if (!id_ast->children[0]->range_valid)
- log_error("Failed to detect with of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
} else
log_error("Failed to detect width for identifier %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
@@ -615,7 +635,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
this_width = range->range_left - range->range_right + 1;
sign_hint = false;
}
- width_hint = std::max(width_hint, this_width);
+ width_hint = max(width_hint, this_width);
if (!id_ast->is_signed)
sign_hint = false;
break;
@@ -625,7 +645,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (children[0]->type != AST_CONSTANT)
log_error("Left operand of tobits expression is not constant at %s:%d!\n", filename.c_str(), linenum);
children[1]->detectSignWidthWorker(sub_width_hint, sign_hint);
- width_hint = std::max(width_hint, children[0]->bitsAsConst().as_int());
+ width_hint = max(width_hint, children[0]->bitsAsConst().as_int());
break;
case AST_TO_SIGNED:
@@ -644,7 +664,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
child->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
this_width += sub_width_hint;
}
- width_hint = std::max(width_hint, this_width);
+ width_hint = max(width_hint, this_width);
sign_hint = false;
break;
@@ -653,7 +673,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (children[0]->type != AST_CONSTANT)
log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum);
children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
- width_hint = std::max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint);
+ width_hint = max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint);
sign_hint = false;
break;
@@ -676,7 +696,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_REDUCE_XOR:
case AST_REDUCE_XNOR:
case AST_REDUCE_BOOL:
- width_hint = std::max(width_hint, 1);
+ width_hint = max(width_hint, 1);
sign_hint = false;
break;
@@ -696,7 +716,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_NEX:
case AST_GE:
case AST_GT:
- width_hint = std::max(width_hint, 1);
+ width_hint = max(width_hint, 1);
sign_hint = false;
break;
@@ -712,7 +732,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_LOGIC_AND:
case AST_LOGIC_OR:
case AST_LOGIC_NOT:
- width_hint = std::max(width_hint, 1);
+ width_hint = max(width_hint, 1);
sign_hint = false;
break;
@@ -725,9 +745,9 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (!id2ast->is_signed)
sign_hint = false;
if (!id2ast->children[0]->range_valid)
- log_error("Failed to detect with of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
this_width = id2ast->children[0]->range_left - id2ast->children[0]->range_right + 1;
- width_hint = std::max(width_hint, this_width);
+ width_hint = max(width_hint, this_width);
break;
// everything should have been handled above -> print error if not.
@@ -764,7 +784,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// in the following big switch() statement there are some uses of
// Clifford's Device (http://www.clifford.at/cfun/cliffdev/). In this
// cases this variable is used to hold the type of the cell that should
- // be instanciated for this type of AST node.
+ // be instantiated for this type of AST node.
std::string type_name;
current_filename = filename;
@@ -773,7 +793,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
switch (type)
{
// simply ignore this nodes.
- // they are eighter leftovers from simplify() or are referenced by other nodes
+ // they are either leftovers from simplify() or are referenced by other nodes
// and are only accessed here thru this references
case AST_TASK:
case AST_FUNCTION:
@@ -786,6 +806,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_GENBLOCK:
case AST_GENIF:
case AST_GENCASE:
+ case AST_PACKAGE:
break;
// remember the parameter, needed for example in techmap
@@ -1052,7 +1073,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
detectSignWidth(width_hint, sign_hint);
RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint);
RTLIL::SigSpec right = children[1]->genRTLIL(width_hint, sign_hint);
- int width = std::max(left.size(), right.size());
+ int width = max(left.size(), right.size());
if (width_hint > 0)
width = width_hint;
is_signed = children[0]->is_signed && children[1]->is_signed;
@@ -1066,16 +1087,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (0) { case AST_REDUCE_XNOR: type_name = "$reduce_xnor"; }
{
RTLIL::SigSpec arg = children[0]->genRTLIL();
- RTLIL::SigSpec sig = uniop2rtlil(this, type_name, std::max(width_hint, 1), arg);
+ RTLIL::SigSpec sig = uniop2rtlil(this, type_name, max(width_hint, 1), arg);
return sig;
}
// generate cells for unary operations: $reduce_bool
- // (this is actually just an $reduce_or, but for clearity a different cell type is used)
+ // (this is actually just an $reduce_or, but for clarity a different cell type is used)
if (0) { case AST_REDUCE_BOOL: type_name = "$reduce_bool"; }
{
RTLIL::SigSpec arg = children[0]->genRTLIL();
- RTLIL::SigSpec sig = arg.size() > 1 ? uniop2rtlil(this, type_name, std::max(width_hint, 1), arg) : arg;
+ RTLIL::SigSpec sig = arg.size() > 1 ? uniop2rtlil(this, type_name, max(width_hint, 1), arg) : arg;
return sig;
}
@@ -1121,7 +1142,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (0) { case AST_GE: type_name = "$ge"; }
if (0) { case AST_GT: type_name = "$gt"; }
{
- int width = std::max(width_hint, 1);
+ int width = max(width_hint, 1);
width_hint = -1, sign_hint = true;
children[0]->detectSignWidthWorker(width_hint, sign_hint);
children[1]->detectSignWidthWorker(width_hint, sign_hint);
@@ -1143,7 +1164,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint);
RTLIL::SigSpec right = children[1]->genRTLIL(width_hint, sign_hint);
#if 0
- int width = std::max(left.size(), right.size());
+ int width = max(left.size(), right.size());
if (width > width_hint && width_hint > 0)
width = width_hint;
if (width < width_hint) {
@@ -1152,10 +1173,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (type == AST_SUB && (!children[0]->is_signed || !children[1]->is_signed))
width = width_hint;
if (type == AST_MUL)
- width = std::min(left.size() + right.size(), width_hint);
+ width = min(left.size() + right.size(), width_hint);
}
#else
- int width = std::max(std::max(left.size(), right.size()), width_hint);
+ int width = max(max(left.size(), right.size()), width_hint);
#endif
is_signed = children[0]->is_signed && children[1]->is_signed;
return binop2rtlil(this, type_name, width, left, right);
@@ -1167,14 +1188,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
{
RTLIL::SigSpec left = children[0]->genRTLIL();
RTLIL::SigSpec right = children[1]->genRTLIL();
- return binop2rtlil(this, type_name, std::max(width_hint, 1), left, right);
+ return binop2rtlil(this, type_name, max(width_hint, 1), left, right);
}
// generate cells for unary operations: $logic_not
case AST_LOGIC_NOT:
{
RTLIL::SigSpec arg = children[0]->genRTLIL();
- return uniop2rtlil(this, "$logic_not", std::max(width_hint, 1), arg);
+ return uniop2rtlil(this, "$logic_not", max(width_hint, 1), arg);
}
// generate multiplexer for ternary operator (aka ?:-operator)
@@ -1190,7 +1211,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (cond.size() > 1)
cond = uniop2rtlil(this, "$reduce_bool", 1, cond, false);
- int width = std::max(val1.size(), val2.size());
+ int width = max(val1.size(), val2.size());
is_signed = children[1]->is_signed && children[2]->is_signed;
widthExtend(this, val1, width, is_signed);
widthExtend(this, val2, width, is_signed);
@@ -1214,11 +1235,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_DATA", current_module->memories[str]->width);
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
- int addr_bits = 1;
- while ((1 << addr_bits) < current_module->memories[str]->size)
- addr_bits++;
+ int mem_width, mem_size, addr_bits;
+ id2ast->meminfo(mem_width, mem_size, addr_bits);
cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
+ cell->setPort("\\EN", RTLIL::SigSpec(RTLIL::State::Sx, 1));
cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits));
cell->setPort("\\DATA", RTLIL::SigSpec(wire));
@@ -1235,28 +1256,38 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// generate $memwr cells for memory write ports
case AST_MEMWR:
+ case AST_MEMINIT:
{
std::stringstream sstr;
- sstr << "$memwr$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
+ sstr << (type == AST_MEMWR ? "$memwr$" : "$meminit$") << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
- RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$memwr");
+ RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_MEMWR ? "$memwr" : "$meminit");
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
- int addr_bits = 1;
- while ((1 << addr_bits) < current_module->memories[str]->size)
- addr_bits++;
+ int mem_width, mem_size, addr_bits;
+ id2ast->meminfo(mem_width, mem_size, addr_bits);
+
+ int num_words = 1;
+ if (type == AST_MEMINIT) {
+ if (children[2]->type != AST_CONSTANT)
+ log_error("Memory init with non-constant word count at %s:%d!\n", filename.c_str(), linenum);
+ num_words = int(children[2]->asInt(false));
+ cell->parameters["\\WORDS"] = RTLIL::Const(num_words);
+ }
- cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits));
- cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width));
- cell->setPort("\\EN", children[2]->genRTLIL());
+ cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width * num_words));
cell->parameters["\\MEMID"] = RTLIL::Const(str);
cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits);
cell->parameters["\\WIDTH"] = RTLIL::Const(current_module->memories[str]->width);
- cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0);
- cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0);
+ if (type == AST_MEMWR) {
+ cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
+ cell->setPort("\\EN", children[2]->genRTLIL());
+ cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0);
+ cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0);
+ }
cell->parameters["\\PRIORITY"] = RTLIL::Const(autoidx-1);
}
@@ -1264,19 +1295,22 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// generate $assert cells
case AST_ASSERT:
+ case AST_ASSUME:
{
log_assert(children.size() == 2);
RTLIL::SigSpec check = children[0]->genRTLIL();
- log_assert(check.size() == 1);
+ if (GetSize(check) != 1)
+ check = current_module->ReduceBool(NEW_ID, check);
RTLIL::SigSpec en = children[1]->genRTLIL();
- log_assert(en.size() == 1);
+ if (GetSize(en) != 1)
+ en = current_module->ReduceBool(NEW_ID, en);
std::stringstream sstr;
- sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++);
+ sstr << (type == AST_ASSERT ? "$assert$" : "$assume$") << filename << ":" << linenum << "$" << (autoidx++);
- RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$assert");
+ RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_ASSERT ? "$assert" : "$assume");
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
for (auto &attr : attributes) {
@@ -1335,16 +1369,19 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
continue;
}
if (child->type == AST_PARASET) {
- if (child->children[0]->type != AST_CONSTANT)
- log_error("Parameter `%s' with non-constant value at %s:%d!\n",
- child->str.c_str(), filename.c_str(), linenum);
- if (child->str.size() == 0) {
- char buf[100];
- snprintf(buf, 100, "$%d", ++para_counter);
- cell->parameters[buf] = child->children[0]->asParaConst();
- } else {
- cell->parameters[child->str] = child->children[0]->asParaConst();
+ IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
+ if (child->children[0]->type == AST_REALVALUE) {
+ log_warning("Replacing floating point parameter %s.%s = %f with string at %s:%d.\n",
+ log_id(cell), log_id(paraname), child->children[0]->realvalue,
+ filename.c_str(), linenum);
+ auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue));
+ strnode->cloneInto(child->children[0]);
+ delete strnode;
}
+ if (child->children[0]->type != AST_CONSTANT)
+ log_error("Parameter %s.%s with non-constant value at %s:%d!\n",
+ log_id(cell), log_id(paraname), filename.c_str(), linenum);
+ cell->parameters[paraname] = child->children[0]->asParaConst();
continue;
}
if (child->type == AST_ARGUMENT) {
@@ -1398,7 +1435,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
// this is a wrapper for AstNode::genRTLIL() when a specific signal width is requested and/or
-// signals must be substituted before beeing used as input values (used by ProcessGenerator)
+// signals must be substituted before being used as input values (used by ProcessGenerator)
// note that this is using some global variables to communicate this special settings to AstNode::genRTLIL().
RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr)
{
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index e9750eba6..c09b912c2 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* 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
@@ -41,7 +41,7 @@ YOSYS_NAMESPACE_BEGIN
using namespace AST;
using namespace AST_INTERNAL;
-// convert the AST into a simpler AST that has all parameters subsitited by their
+// convert the AST into a simpler AST that has all parameters substituted by their
// values, unrolled for-loops, expanded generate blocks, etc. when this function
// is done with an AST it can be converted into RTLIL using genRTLIL().
//
@@ -49,15 +49,24 @@ using namespace AST_INTERNAL;
// nodes that link to a different node using names and lexical scoping.
bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)
{
+ static int recursion_counter = 0;
+ static pair<string, int> last_blocking_assignment_warn;
+ static bool deep_recursion_warning = false;
+
+ if (recursion_counter++ == 1000 && deep_recursion_warning) {
+ log_warning("Deep recursion in AST simplifier.\nDoes this design contain insanely long expressions?\n");
+ deep_recursion_warning = false;
+ }
+
AstNode *newNode = NULL;
bool did_something = false;
- static pair<string, int> last_blocking_assignment_warn;
#if 0
log("-------------\n");
+ log("AST simplify[%d] depth %d at %s:%d,\n", stage, recursion_counter, filename.c_str(), linenum);
log("const_fold=%d, at_zero=%d, in_lvalue=%d, stage=%d, width_hint=%d, sign_hint=%d, in_param=%d\n",
int(const_fold), int(at_zero), int(in_lvalue), int(stage), int(width_hint), int(sign_hint), int(in_param));
- dumpAst(NULL, "> ");
+ // dumpAst(NULL, "> ");
#endif
if (stage == 0)
@@ -65,6 +74,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
log_assert(type == AST_MODULE);
last_blocking_assignment_warn = pair<string, int>();
+ deep_recursion_warning = true;
while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { }
if (!flag_nomem2reg && !get_bool_attribute("\\nomem2reg"))
@@ -79,11 +89,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
AstNode *mem = it.first;
uint32_t memflags = it.second;
+ bool this_nomeminit = flag_nomeminit;
log_assert((memflags & ~0x00ffff00) == 0);
if (mem->get_bool_attribute("\\nomem2reg"))
continue;
+ if (mem->get_bool_attribute("\\nomeminit") || get_bool_attribute("\\nomeminit"))
+ this_nomeminit = true;
+
if (memflags & AstNode::MEM2REG_FL_FORCED)
goto silent_activate;
@@ -93,7 +107,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (memflags & AstNode::MEM2REG_FL_SET_ASYNC)
goto verbose_activate;
- if ((memflags & AstNode::MEM2REG_FL_SET_INIT) && (memflags & AstNode::MEM2REG_FL_SET_ELSE))
+ if ((memflags & AstNode::MEM2REG_FL_SET_INIT) && (memflags & AstNode::MEM2REG_FL_SET_ELSE) && this_nomeminit)
goto verbose_activate;
if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS)
@@ -134,17 +148,17 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
- mem2reg_as_needed_pass2(mem2reg_set, this, NULL);
+ while (mem2reg_as_needed_pass2(mem2reg_set, this, NULL)) { }
- for (size_t i = 0; i < children.size(); i++) {
- if (mem2reg_set.count(children[i]) > 0) {
- delete children[i];
- children.erase(children.begin() + (i--));
- }
- }
+ vector<AstNode*> delnodes;
+ mem2reg_remove(mem2reg_set, delnodes);
+
+ for (auto node : delnodes)
+ delete node;
}
while (simplify(const_fold, at_zero, in_lvalue, 2, width_hint, sign_hint, in_param)) { }
+ recursion_counter--;
return false;
}
@@ -152,18 +166,144 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
set_line_num(linenum);
// we do not look inside a task or function
- // (but as soon as a task of function is instanciated we process the generated AST as usual)
- if (type == AST_FUNCTION || type == AST_TASK)
+ // (but as soon as a task or function is instantiated we process the generated AST as usual)
+ if (type == AST_FUNCTION || type == AST_TASK) {
+ recursion_counter--;
return false;
+ }
- // deactivate all calls to non-synthesis system taks
- if ((type == AST_FCALL || type == AST_TCALL) && (str == "$display" || str == "$strobe" || str == "$monitor" || str == "$time" || str == "$stop" || str == "$finish" ||
+ // deactivate all calls to non-synthesis system tasks
+ // note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list
+ if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" ||
str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) {
log_warning("Ignoring call to system %s %s at %s:%d.\n", type == AST_FCALL ? "function" : "task", str.c_str(), filename.c_str(), linenum);
delete_children();
str = std::string();
}
+ if ((type == AST_TCALL) && (str == "$display" || str == "$write") && (!current_always || current_always->type != AST_INITIAL)) {
+ log_warning("System task `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ delete_children();
+ str = std::string();
+ }
+
+ // print messages if this a call to $display() or $write()
+ // This code implements only a small subset of Verilog-2005 $display() format specifiers,
+ // but should be good enough for most uses
+ if ((type == AST_TCALL) && ((str == "$display") || (str == "$write")))
+ {
+ int nargs = GetSize(children);
+ if (nargs < 1)
+ log_error("System task `%s' got %d arguments, expected >= 1 at %s:%d.\n",
+ str.c_str(), int(children.size()), filename.c_str(), linenum);
+
+ // First argument is the format string
+ AstNode *node_string = children[0];
+ while (node_string->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ if (node_string->type != AST_CONSTANT)
+ log_error("Failed to evaluate system task `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ std::string sformat = node_string->bitsAsConst().decode_string();
+
+ // Other arguments are placeholders. Process the string as we go through it
+ std::string sout;
+ int next_arg = 1;
+ for (size_t i = 0; i < sformat.length(); i++)
+ {
+ // format specifier
+ if (sformat[i] == '%')
+ {
+ // If there's no next character, that's a problem
+ if (i+1 >= sformat.length())
+ log_error("System task `%s' called with `%%' at end of string at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+
+ char cformat = sformat[++i];
+
+ // %% is special, does not need a matching argument
+ if (cformat == '%')
+ {
+ sout += '%';
+ continue;
+ }
+
+ // Simplify the argument
+ AstNode *node_arg = nullptr;
+
+ // Everything from here on depends on the format specifier
+ switch (cformat)
+ {
+ case 's':
+ case 'S':
+ case 'd':
+ case 'D':
+ case 'x':
+ case 'X':
+ if (next_arg >= GetSize(children))
+ log_error("Missing argument for %%%c format specifier in system task `%s' at %s:%d.\n",
+ cformat, str.c_str(), filename.c_str(), linenum);
+
+ node_arg = children[next_arg++];
+ while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ if (node_arg->type != AST_CONSTANT)
+ log_error("Failed to evaluate system task `%s' with non-constant argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ break;
+
+ case 'm':
+ case 'M':
+ break;
+
+ default:
+ log_error("System task `%s' called with invalid/unsupported format specifier at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ break;
+ }
+
+ switch (cformat)
+ {
+ case 's':
+ case 'S':
+ sout += node_arg->bitsAsConst().decode_string();
+ break;
+
+ case 'd':
+ case 'D':
+ {
+ char tmp[128];
+ snprintf(tmp, sizeof(tmp), "%d", node_arg->bitsAsConst().as_int());
+ sout += tmp;
+ }
+ break;
+
+ case 'x':
+ case 'X':
+ {
+ char tmp[128];
+ snprintf(tmp, sizeof(tmp), "%x", node_arg->bitsAsConst().as_int());
+ sout += tmp;
+ }
+ break;
+
+ case 'm':
+ case 'M':
+ sout += log_id(current_module->name);
+ break;
+
+ default:
+ log_abort();
+ }
+ }
+
+ // not a format specifier
+ else
+ sout += sformat[i];
+ }
+
+ // Finally, print the message (only include a \n for $display, not for $write)
+ log("%s", sout.c_str());
+ if (str == "$display")
+ log("\n");
+ delete_children();
+ str = std::string();
+ }
+
// activate const folding if this is anything that must be evaluated statically (ranges, parameters, attributes, etc.)
if (type == AST_WIRE || type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_RANGE || type == AST_PREFIX)
const_fold = true;
@@ -255,6 +395,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
auto backup_current_block = current_block;
auto backup_current_block_child = current_block_child;
auto backup_current_top_block = current_top_block;
+ auto backup_current_always = current_always;
+
+ if (type == AST_ALWAYS || type == AST_INITIAL)
+ current_always = this;
int backup_width_hint = width_hint;
bool backup_sign_hint = sign_hint;
@@ -277,7 +421,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
did_something = true;
children[0]->detectSignWidth(backup_width_hint, backup_sign_hint);
children[1]->detectSignWidth(width_hint, sign_hint);
- width_hint = std::max(width_hint, backup_width_hint);
+ width_hint = max(width_hint, backup_width_hint);
child_0_is_self_determined = true;
break;
@@ -291,7 +435,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
did_something = true;
if (!children[1]->range_valid)
log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum);
- width_hint = std::max(width_hint, children[1]->range_left - children[1]->range_right + 1);
+ width_hint = max(width_hint, children[1]->range_left - children[1]->range_right + 1);
}
break;
@@ -362,7 +506,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
detect_width_simple = true;
child_0_is_self_determined = true;
break;
-
+
case AST_MEMRD:
detect_width_simple = true;
children_are_self_determined = true;
@@ -395,6 +539,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
+ if (type == AST_CONDX && children.size() > 0 && children.at(0)->type == AST_CONSTANT) {
+ for (auto &bit : children.at(0)->bits)
+ if (bit == State::Sz || bit == State::Sx)
+ bit = State::Sa;
+ }
+
+ if (type == AST_CONDZ && children.size() > 0 && children.at(0)->type == AST_CONSTANT) {
+ for (auto &bit : children.at(0)->bits)
+ if (bit == State::Sz)
+ bit = State::Sa;
+ }
+
if (const_fold && type == AST_CASE)
{
while (children[0]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { }
@@ -403,7 +559,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
new_children.push_back(children[0]);
for (int i = 1; i < GetSize(children); i++) {
AstNode *child = children[i];
- log_assert(child->type == AST_COND);
+ log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ);
for (auto v : child->children) {
if (v->type == AST_DEFAULT)
goto keep_const_cond;
@@ -494,6 +650,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
current_block = backup_current_block;
current_block_child = backup_current_block_child;
current_top_block = backup_current_top_block;
+ current_always = backup_current_always;
for (auto it = backup_scope.begin(); it != backup_scope.end(); it++) {
if (it->second == NULL)
@@ -530,6 +687,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// dumpAst(NULL, "> ");
log_error("Index in generate block prefix syntax at %s:%d is not constant!\n", filename.c_str(), linenum);
}
+ if (children[1]->type == AST_PREFIX)
+ children[1]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param);
log_assert(children[1]->type == AST_IDENTIFIER);
newNode = children[1]->clone();
const char *second_part = children[1]->str.c_str();
@@ -609,8 +768,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
for (auto range : children[1]->children) {
if (!range->range_valid)
log_error("Non-constant range on memory decl at %s:%d.\n", filename.c_str(), linenum);
- multirange_dimensions.push_back(std::min(range->range_left, range->range_right));
- multirange_dimensions.push_back(std::max(range->range_left, range->range_right) - std::min(range->range_left, range->range_right) + 1);
+ 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);
total_size *= multirange_dimensions.back();
}
delete children[1];
@@ -636,10 +795,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (i == 0)
index_expr = new_index_expr;
else
- index_expr = new AstNode(AST_ADD, new AstNode(AST_MUL, index_expr, AstNode::mkconst_int(id2ast->multirange_dimensions[2*i-1], true)), new_index_expr);
+ index_expr = new AstNode(AST_ADD, new AstNode(AST_MUL, index_expr, AstNode::mkconst_int(id2ast->multirange_dimensions[2*i+1], true)), new_index_expr);
}
- for (int i = GetSize(id2ast->multirange_dimensions)/1; i < GetSize(children[0]->children); i++)
+ for (int i = GetSize(id2ast->multirange_dimensions)/2; i < GetSize(children[0]->children); i++)
children.push_back(children[0]->children[i]->clone());
delete children[0];
@@ -656,7 +815,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (children.size() > 1 && children[1]->type == AST_RANGE) {
if (!children[1]->range_valid)
log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum);
- int width = children[1]->range_left - children[1]->range_right + 1;
+ int width = std::abs(children[1]->range_left - children[1]->range_right) + 1;
if (children[0]->type == AST_REALVALUE) {
RTLIL::Const constvalue = children[0]->realAsConst(width);
log_warning("converting real value %e to binary %s at %s:%d.\n",
@@ -670,7 +829,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
RTLIL::SigSpec sig(children[0]->bits);
sig.extend_u0(width, children[0]->is_signed);
AstNode *old_child_0 = children[0];
- children[0] = mkconst_bits(sig.as_const().bits, children[0]->is_signed);
+ children[0] = mkconst_bits(sig.as_const().bits, is_signed);
delete old_child_0;
}
children[0]->is_signed = is_signed;
@@ -803,7 +962,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// eval 1st expression
AstNode *varbuf = init_ast->children[1]->clone();
- while (varbuf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ while (varbuf->simplify(true, false, false, stage, 32, true, false)) { }
if (varbuf->type != AST_CONSTANT)
log_error("Right hand side of 1st expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
@@ -866,7 +1025,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// eval 3rd expression
buf = next_ast->children[1]->clone();
- while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ while (buf->simplify(true, false, false, stage, 32, true, false)) { }
if (buf->type != AST_CONSTANT)
log_error("Right hand side of 3rd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
@@ -889,7 +1048,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
std::vector<AstNode*> new_children;
for (size_t i = 0; i < children.size(); i++)
- if (children[i]->type == AST_WIRE) {
+ if (children[i]->type == AST_WIRE || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM) {
children[i]->simplify(false, false, false, stage, -1, false, false);
current_ast_mod->children.push_back(children[i]);
current_scope[children[i]->str] = children[i];
@@ -977,7 +1136,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
AstNode *selected_case = NULL;
for (size_t i = 1; i < children.size(); i++)
{
- log_assert(children.at(i)->type == AST_COND);
+ log_assert(children.at(i)->type == AST_COND || children.at(i)->type == AST_CONDX || children.at(i)->type == AST_CONDZ);
AstNode *this_genblock = NULL;
for (auto child : children.at(i)->children) {
@@ -1045,7 +1204,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
log_error("Non-constant array range on cell array at %s:%d.\n", filename.c_str(), linenum);
newNode = new AstNode(AST_GENBLOCK);
- int num = std::max(children.at(0)->range_left, children.at(0)->range_right) - std::min(children.at(0)->range_left, children.at(0)->range_right) + 1;
+ int num = max(children.at(0)->range_left, children.at(0)->range_right) - min(children.at(0)->range_left, children.at(0)->range_right) + 1;
for (int i = 0; i < num; i++) {
int idx = children.at(0)->range_left > children.at(0)->range_right ? children.at(0)->range_right + i : children.at(0)->range_right - i;
@@ -1063,7 +1222,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
goto apply_newNode;
}
- // replace primitives with assignmens
+ // replace primitives with assignments
if (type == AST_PRIMITIVE)
{
if (children.size() < 2)
@@ -1189,7 +1348,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
skip_dynamic_range_lvalue_expansion:;
- if (stage > 1 && type == AST_ASSERT && current_block != NULL)
+ if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && current_block != NULL)
{
std::stringstream sstr;
sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++);
@@ -1233,7 +1392,7 @@ skip_dynamic_range_lvalue_expansion:;
newNode->children.push_back(assign_check);
newNode->children.push_back(assign_en);
- AstNode *assertnode = new AstNode(AST_ASSERT);
+ AstNode *assertnode = new AstNode(type);
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
assertnode->children[0]->str = id_check;
@@ -1244,16 +1403,15 @@ skip_dynamic_range_lvalue_expansion:;
goto apply_newNode;
}
- if (stage > 1 && type == AST_ASSERT && children.size() == 1)
+ if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && children.size() == 1)
{
- children[0] = new AstNode(AST_REDUCE_BOOL, children[0]->clone());
children.push_back(mkconst_int(1, false, 1));
did_something = true;
}
// found right-hand side identifier for memory -> replace with memory read port
if (stage > 1 && type == AST_IDENTIFIER && id2ast != NULL && id2ast->type == AST_MEMORY && !in_lvalue &&
- children[0]->type == AST_RANGE && children[0]->children.size() == 1) {
+ children.size() == 1 && children[0]->type == AST_RANGE && children[0]->children.size() == 1) {
newNode = new AstNode(AST_MEMRD, children[0]->children[0]->clone());
newNode->str = str;
newNode->id2ast = id2ast;
@@ -1293,11 +1451,14 @@ skip_dynamic_range_lvalue_expansion:;
current_scope[wire_data->str] = wire_data;
while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
- AstNode *wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
- wire_en->str = id_en;
- current_ast_mod->children.push_back(wire_en);
- current_scope[wire_en->str] = wire_en;
- while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
+ AstNode *wire_en = nullptr;
+ if (current_always->type != AST_INITIAL) {
+ wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
+ wire_en->str = id_en;
+ current_ast_mod->children.push_back(wire_en);
+ current_scope[wire_en->str] = wire_en;
+ while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
+ }
std::vector<RTLIL::State> x_bits_addr, x_bits_data, set_bits_en;
for (int i = 0; i < addr_bits; i++)
@@ -1313,13 +1474,17 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false));
assign_data->children[0]->str = id_data;
- AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width));
- assign_en->children[0]->str = id_en;
+ AstNode *assign_en = nullptr;
+ if (current_always->type != AST_INITIAL) {
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width));
+ assign_en->children[0]->str = id_en;
+ }
AstNode *default_signals = new AstNode(AST_BLOCK);
default_signals->children.push_back(assign_addr);
default_signals->children.push_back(assign_data);
- default_signals->children.push_back(assign_en);
+ if (current_always->type != AST_INITIAL)
+ default_signals->children.push_back(assign_en);
current_top_block->children.insert(current_top_block->children.begin(), default_signals);
assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone());
@@ -1334,15 +1499,16 @@ skip_dynamic_range_lvalue_expansion:;
std::vector<RTLIL::State> padding_x(offset, RTLIL::State::Sx);
- for (int i = 0; i < mem_width; i++)
- set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0;
-
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
new AstNode(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone()));
assign_data->children[0]->str = id_data;
- assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
- assign_en->children[0]->str = id_en;
+ if (current_always->type != AST_INITIAL) {
+ for (int i = 0; i < mem_width; i++)
+ set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0;
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
+ assign_en->children[0]->str = id_en;
+ }
}
else
{
@@ -1357,16 +1523,17 @@ skip_dynamic_range_lvalue_expansion:;
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
- for (int i = 0; i < mem_width; i++)
- set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0;
-
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone()));
assign_data->children[0]->str = id_data;
- assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
- new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone()));
- assign_en->children[0]->str = id_en;
+ if (current_always->type != AST_INITIAL) {
+ for (int i = 0; i < mem_width; i++)
+ set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0;
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
+ new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone()));
+ assign_en->children[0]->str = id_en;
+ }
delete left_at_zero_ast;
delete right_at_zero_ast;
@@ -1378,23 +1545,31 @@ skip_dynamic_range_lvalue_expansion:;
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone());
assign_data->children[0]->str = id_data;
- assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
- assign_en->children[0]->str = id_en;
+ if (current_always->type != AST_INITIAL) {
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
+ assign_en->children[0]->str = id_en;
+ }
}
newNode = new AstNode(AST_BLOCK);
newNode->children.push_back(assign_addr);
newNode->children.push_back(assign_data);
- newNode->children.push_back(assign_en);
+ if (current_always->type != AST_INITIAL)
+ newNode->children.push_back(assign_en);
- AstNode *wrnode = new AstNode(AST_MEMWR);
- wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
+ AstNode *wrnode = new AstNode(current_always->type == AST_INITIAL ? AST_MEMINIT : AST_MEMWR);
wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
+ if (current_always->type != AST_INITIAL)
+ wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
+ else
+ wrnode->children.push_back(AstNode::mkconst_int(1, false));
wrnode->str = children[0]->str;
+ wrnode->id2ast = children[0]->id2ast;
wrnode->children[0]->str = id_addr;
wrnode->children[1]->str = id_data;
- wrnode->children[2]->str = id_en;
+ if (current_always->type != AST_INITIAL)
+ wrnode->children[2]->str = id_en;
current_ast_mod->children.push_back(wrnode);
goto apply_newNode;
@@ -1531,7 +1706,17 @@ skip_dynamic_range_lvalue_expansion:;
if (current_scope.count(str) == 0 || current_scope[str]->type != AST_FUNCTION)
log_error("Can't resolve function name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
}
- if (type == AST_TCALL) {
+
+ if (type == AST_TCALL)
+ {
+ if (str == "$finish" || str == "$stop")
+ {
+ if (!current_always || current_always->type != AST_INITIAL)
+ log_error("System task `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+
+ log_error("System task `%s' executed at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ }
+
if (str == "\\$readmemh" || str == "\\$readmemb")
{
if (GetSize(children) < 2 || GetSize(children) > 4)
@@ -1555,7 +1740,7 @@ skip_dynamic_range_lvalue_expansion:;
while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_addr->type != AST_CONSTANT)
log_error("Failed to evaluate system function `%s' with non-constant 3rd argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
- start_addr = node_addr->asInt(false);
+ start_addr = int(node_addr->asInt(false));
}
if (GetSize(children) > 3) {
@@ -1563,10 +1748,27 @@ skip_dynamic_range_lvalue_expansion:;
while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_addr->type != AST_CONSTANT)
log_error("Failed to evaluate system function `%s' with non-constant 4th argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
- finish_addr = node_addr->asInt(false);
+ finish_addr = int(node_addr->asInt(false));
}
- newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr);
+ bool unconditional_init = false;
+ if (current_always->type == AST_INITIAL) {
+ pool<AstNode*> queue;
+ log_assert(current_always->children[0]->type == AST_BLOCK);
+ queue.insert(current_always->children[0]);
+ while (!unconditional_init && !queue.empty()) {
+ pool<AstNode*> next_queue;
+ for (auto n : queue)
+ for (auto c : n->children) {
+ if (c == this)
+ unconditional_init = true;
+ next_queue.insert(c);
+ }
+ next_queue.swap(queue);
+ }
+ }
+
+ newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init);
goto apply_newNode;
}
@@ -1606,6 +1808,8 @@ skip_dynamic_range_lvalue_expansion:;
size_t arg_count = 0;
std::map<std::string, std::string> replace_rules;
+ vector<AstNode*> added_mod_children;
+ dict<std::string, AstNode*> wire_cache;
if (current_block == NULL)
{
@@ -1698,17 +1902,41 @@ skip_dynamic_range_lvalue_expansion:;
}
for (auto child : decl->children)
- if (child->type == AST_WIRE)
+ if (child->type == AST_WIRE || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
{
- AstNode *wire = child->clone();
- wire->str = prefix + wire->str;
- wire->port_id = 0;
- wire->is_input = false;
- wire->is_output = false;
- current_ast_mod->children.push_back(wire);
- while (wire->simplify(true, false, false, 1, -1, false, false)) { }
+ AstNode *wire = nullptr;
+
+ if (wire_cache.count(child->str))
+ {
+ wire = wire_cache.at(child->str);
+ if (wire->children.empty()) {
+ for (auto c : child->children)
+ wire->children.push_back(c->clone());
+ } else {
+ if (!child->children.empty())
+ log_error("Incompatible re-declaration of wire %s at %s:%d.\n", child->str.c_str(), filename.c_str(), linenum);
+ }
+ }
+ else
+ {
+ wire = child->clone();
+ wire->str = prefix + wire->str;
+ wire->port_id = 0;
+ wire->is_input = false;
+ wire->is_output = false;
+ if (!child->is_output)
+ wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
+ wire_cache[child->str] = wire;
+
+ current_ast_mod->children.push_back(wire);
+ added_mod_children.push_back(wire);
+ }
+
+ if (child->type == AST_WIRE)
+ while (wire->simplify(true, false, false, 1, -1, false, false)) { }
replace_rules[child->str] = wire->str;
+ current_scope[wire->str] = wire;
if ((child->is_input || child->is_output) && arg_count < children.size())
{
@@ -1728,8 +1956,13 @@ skip_dynamic_range_lvalue_expansion:;
}
}
+ for (auto child : added_mod_children) {
+ child->replace_ids(prefix, replace_rules);
+ while (child->simplify(true, false, false, 1, -1, false, false)) { }
+ }
+
for (auto child : decl->children)
- if (child->type != AST_WIRE)
+ if (child->type != AST_WIRE && child->type != AST_PARAMETER && child->type != AST_LOCALPARAM)
{
AstNode *stmt = child->clone();
stmt->replace_ids(prefix, replace_rules);
@@ -1876,7 +2109,7 @@ skip_dynamic_range_lvalue_expansion:;
if (0) { case AST_GE: const_func = RTLIL::const_ge; }
if (0) { case AST_GT: const_func = RTLIL::const_gt; }
if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) {
- int cmp_width = std::max(children[0]->bits.size(), children[1]->bits.size());
+ int cmp_width = max(children[0]->bits.size(), children[1]->bits.size());
bool cmp_signed = children[0]->is_signed && children[1]->is_signed;
RTLIL::Const y = const_func(children[0]->bitsAsConst(cmp_width, cmp_signed),
children[1]->bitsAsConst(cmp_width, cmp_signed), cmp_signed, cmp_signed, 1);
@@ -2036,6 +2269,7 @@ apply_newNode:
if (!did_something)
basic_prep = true;
+ recursion_counter--;
return did_something;
}
@@ -2048,10 +2282,18 @@ static void replace_result_wire_name_in_function(AstNode *node, std::string &fro
}
// replace a readmem[bh] TCALL ast node with a block of memory assignments
-AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr)
+AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init)
{
+ int mem_width, mem_size, addr_bits;
+ memory->meminfo(mem_width, mem_size, addr_bits);
+
AstNode *block = new AstNode(AST_BLOCK);
+ AstNode *meminit = nullptr;
+ int next_meminit_cursor=0;
+ vector<State> meminit_bits;
+ int meminit_size=0;
+
std::ifstream f;
f.open(mem_filename.c_str());
@@ -2060,13 +2302,13 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
log_assert(GetSize(memory->children) == 2 && memory->children[1]->type == AST_RANGE && memory->children[1]->range_valid);
int range_left = memory->children[1]->range_left, range_right = memory->children[1]->range_right;
- int range_min = std::min(range_left, range_right), range_max = std::max(range_left, range_right);
+ int range_min = min(range_left, range_right), range_max = max(range_left, range_right);
if (start_addr < 0)
start_addr = range_min;
if (finish_addr < 0)
- finish_addr = range_max;
+ finish_addr = range_max + 1;
bool in_comment = false;
int increment = start_addr <= finish_addr ? +1 : -1;
@@ -2106,21 +2348,56 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
continue;
}
- AstNode *value = VERILOG_FRONTEND::const2ast((is_readmemh ? "'h" : "'b") + token);
+ AstNode *value = VERILOG_FRONTEND::const2ast(stringf("%d'%c", mem_width, is_readmemh ? 'h' : 'b') + token);
+
+ if (unconditional_init)
+ {
+ if (meminit == nullptr || cursor != next_meminit_cursor)
+ {
+ if (meminit != nullptr) {
+ meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false);
+ meminit->children[2] = AstNode::mkconst_int(meminit_size, false);
+ }
+
+ meminit = new AstNode(AST_MEMINIT);
+ meminit->children.push_back(AstNode::mkconst_int(cursor, false));
+ meminit->children.push_back(nullptr);
+ meminit->children.push_back(nullptr);
+ meminit->str = memory->str;
+ meminit->id2ast = memory;
+ meminit_bits.clear();
+ meminit_size = 0;
+
+ current_ast_mod->children.push_back(meminit);
+ next_meminit_cursor = cursor;
+ }
- block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value));
- block->children.back()->children[0]->str = memory->str;
- block->children.back()->children[0]->id2ast = memory;
+ meminit_size++;
+ next_meminit_cursor++;
+ meminit_bits.insert(meminit_bits.end(), value->bits.begin(), value->bits.end());
+ delete value;
+ }
+ else
+ {
+ block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value));
+ block->children.back()->children[0]->str = memory->str;
+ block->children.back()->children[0]->id2ast = memory;
+ }
- if ((cursor == finish_addr) || (increment > 0 && cursor >= range_max) || (increment < 0 && cursor <= range_min))
+ if ((cursor == finish_addr) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min))
break;
cursor += increment;
}
- if ((cursor == finish_addr) || (increment > 0 && cursor >= range_max) || (increment < 0 && cursor <= range_min))
+ if ((cursor == finish_addr) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min))
break;
}
+ if (meminit != nullptr) {
+ meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false);
+ meminit->children[2] = AstNode::mkconst_int(meminit_size, false);
+ }
+
return block;
}
@@ -2171,7 +2448,7 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
name_map.swap(backup_name_map);
}
-// rename stuff (used when tasks of functions are instanciated)
+// rename stuff (used when tasks of functions are instantiated)
void AstNode::replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules)
{
if (type == AST_BLOCK)
@@ -2328,9 +2605,28 @@ bool AstNode::mem2reg_check(pool<AstNode*> &mem2reg_set)
return true;
}
+void AstNode::mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes)
+{
+ log_assert(mem2reg_set.count(this) == 0);
+
+ if (mem2reg_set.count(id2ast))
+ id2ast = nullptr;
+
+ for (size_t i = 0; i < children.size(); i++) {
+ if (mem2reg_set.count(children[i]) > 0) {
+ delnodes.push_back(children[i]);
+ children.erase(children.begin() + (i--));
+ } else {
+ children[i]->mem2reg_remove(mem2reg_set, delnodes);
+ }
+ }
+}
+
// actually replace memories with registers
-void AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block)
+bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block)
{
+ bool did_something = false;
+
if (type == AST_BLOCK)
block = this;
@@ -2389,6 +2685,8 @@ void AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
children[0]->id2ast = NULL;
children[0]->str = id_data;
type = AST_ASSIGN_EQ;
+
+ did_something = true;
}
if (mem2reg_check(mem2reg_set))
@@ -2489,10 +2787,13 @@ void AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
auto children_list = children;
for (size_t i = 0; i < children_list.size(); i++)
- children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block);
+ if (children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block))
+ did_something = true;
+
+ return did_something;
}
-// calulate memory dimensions
+// calculate memory dimensions
void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits)
{
log_assert(type == AST_MEMORY);
@@ -2502,7 +2803,7 @@ void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits)
if (mem_size < 0)
mem_size *= -1;
- mem_size += std::min(children[1]->range_left, children[1]->range_right) + 1;
+ mem_size += min(children[1]->range_left, children[1]->range_right) + 1;
addr_bits = 1;
while ((1 << addr_bits) < mem_size)
@@ -2538,8 +2839,8 @@ void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &varia
if (!children.at(0)->range_valid)
log_error("Non-constant range in %s:%d (called from %s:%d).\n",
filename.c_str(), linenum, fcall->filename.c_str(), fcall->linenum);
- offset = std::min(children.at(0)->range_left, children.at(0)->range_right);
- width = std::min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width);
+ 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);
}
offset -= variables.at(str).offset;
std::vector<RTLIL::State> &var_bits = variables.at(str).val.bits;
@@ -2579,7 +2880,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
log_error("Can't determine size of variable %s in %s:%d (called from %s:%d).\n",
child->str.c_str(), child->filename.c_str(), child->linenum, fcall->filename.c_str(), fcall->linenum);
variables[child->str].val = RTLIL::Const(RTLIL::State::Sx, abs(child->range_left - child->range_right)+1);
- variables[child->str].offset = std::min(child->range_left, child->range_right);
+ variables[child->str].offset = min(child->range_left, child->range_right);
variables[child->str].is_signed = child->is_signed;
if (child->is_input && argidx < fcall->children.size())
variables[child->str].val = fcall->children.at(argidx++)->bitsAsConst(variables[child->str].val.bits.size());
@@ -2610,6 +2911,9 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
if (stmt->type == AST_ASSIGN_EQ)
{
+ 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);
while (stmt->simplify(true, false, false, 1, -1, false, true)) { }
@@ -2635,7 +2939,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
if (!range->range_valid)
log_error("Non-constant range in %s:%d (called from %s:%d).\n",
range->filename.c_str(), range->linenum, fcall->filename.c_str(), fcall->linenum);
- int offset = std::min(range->range_left, range->range_right);
+ 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];
RTLIL::Const r = stmt->children.at(1)->bitsAsConst(v.val.bits.size());
@@ -2708,7 +3012,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
for (size_t i = 1; i < stmt->children.size(); i++)
{
bool found_match = false;
- log_assert(stmt->children.at(i)->type == AST_COND);
+ log_assert(stmt->children.at(i)->type == AST_COND || stmt->children.at(i)->type == AST_CONDX || stmt->children.at(i)->type == AST_CONDZ);
if (stmt->children.at(i)->children.front()->type == AST_DEFAULT) {
sel_case = stmt->children.at(i)->children.back();