aboutsummaryrefslogtreecommitdiffstats
path: root/frontends
diff options
context:
space:
mode:
Diffstat (limited to 'frontends')
-rw-r--r--frontends/ast/ast.cc35
-rw-r--r--frontends/ast/ast.h28
-rw-r--r--frontends/ast/dpicall.cc12
-rw-r--r--frontends/ast/genrtlil.cc134
-rw-r--r--frontends/ast/simplify.cc378
-rw-r--r--frontends/ilang/.gitignore8
-rw-r--r--frontends/ilang/Makefile.inc22
-rw-r--r--frontends/ilang/ilang_frontend.cc6
-rw-r--r--frontends/ilang/ilang_lexer.l (renamed from frontends/ilang/lexer.l)6
-rw-r--r--frontends/ilang/ilang_parser.y (renamed from frontends/ilang/parser.y)5
-rw-r--r--frontends/liberty/liberty.cc1
-rw-r--r--frontends/verific/build_amd64.txt1
-rw-r--r--frontends/verific/verific.cc25
-rw-r--r--frontends/verilog/.gitignore8
-rw-r--r--frontends/verilog/Makefile.inc24
-rw-r--r--frontends/verilog/const2ast.cc16
-rw-r--r--frontends/verilog/preproc.cc9
-rw-r--r--frontends/verilog/verilog_frontend.cc60
-rw-r--r--frontends/verilog/verilog_frontend.h5
-rw-r--r--frontends/verilog/verilog_lexer.l (renamed from frontends/verilog/lexer.l)51
-rw-r--r--frontends/verilog/verilog_parser.y (renamed from frontends/verilog/parser.y)136
-rw-r--r--frontends/vhdl2verilog/vhdl2verilog.cc45
22 files changed, 689 insertions, 326 deletions
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 1e43875ae..0b63248d8 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -26,13 +26,18 @@
*
*/
-#include "kernel/log.h"
+#include "kernel/yosys.h"
#include "libs/sha1/sha1.h"
#include "ast.h"
#include <sstream>
#include <stdarg.h>
-#include <math.h>
+
+#if defined(__APPLE__)
+# include <cmath>
+#else
+# include <math.h>
+#endif
YOSYS_NAMESPACE_BEGIN
@@ -48,12 +53,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 std::map<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
+ 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;
}
@@ -85,6 +90,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)
@@ -127,6 +133,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)
@@ -175,6 +182,10 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
// (the optional child arguments make it easier to create AST trees)
AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2)
{
+ static unsigned int hashidx_count = 123456789;
+ hashidx_count = mkhash_xorshift(hashidx_count);
+ hashidx_ = hashidx_count;
+
this->type = type;
filename = current_filename;
linenum = get_line_num();
@@ -267,7 +278,7 @@ void AstNode::dumpAst(FILE *f, std::string indent)
bits[i-1] == RTLIL::S1 ? '1' :
bits[i-1] == RTLIL::Sx ? 'x' :
bits[i-1] == RTLIL::Sz ? 'z' : '?');
- fprintf(f, "'(%zd)", bits.size());
+ fprintf(f, "'(%d)", GetSize(bits));
}
if (is_input)
fprintf(f, " input");
@@ -471,7 +482,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
else if (bits.size() == 32)
fprintf(f, "%d", RTLIL::Const(bits).as_int());
else
- fprintf(f, "%zd'b %s", bits.size(), RTLIL::Const(bits).as_string().c_str());
+ fprintf(f, "%d'b %s", GetSize(bits), RTLIL::Const(bits).as_string().c_str());
break;
case AST_REALVALUE:
@@ -701,6 +712,8 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
{
AstNode *node = mkconst_str(RTLIL::Const(v).decode_string());
+ while (GetSize(node->bits) < GetSize(v))
+ node->bits.push_back(RTLIL::State::S0);
log_assert(node->bits == v);
return node;
}
@@ -946,6 +959,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;
@@ -957,13 +971,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;
@@ -1011,7 +1026,7 @@ AstModule::~AstModule()
}
// create a new parametric module (when needed) and return the name of the generated module
-RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters)
+RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters)
{
std::string stripped_name = name.str();
@@ -1025,6 +1040,7 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
flag_dump_ast2 = false;
flag_dump_vlog = false;
flag_nolatches = nolatches;
+ flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
flag_lib = lib;
@@ -1091,6 +1107,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 0a4016736..d57e91e5a 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -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,
@@ -142,6 +144,10 @@ namespace AST
// The AST is built using instances of this struct
struct AstNode
{
+ // for dict<> and pool<>
+ unsigned int hashidx_;
+ unsigned int hash() const { return hashidx_; }
+
// this nodes type
AstNodeType type;
@@ -204,11 +210,13 @@ 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);
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(std::map<AstNode*, std::set<std::string>> &mem2reg_places,
- std::map<AstNode*, uint32_t> &mem2reg_flags, std::map<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
- void mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block);
+ 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_check(pool<AstNode*> &mem2reg_set);
void meminfo(int &mem_width, int &mem_size, int &addr_bits);
// additional functionality for evaluating constant functions
@@ -229,7 +237,7 @@ namespace AST
// for expressions the resulting signal vector is returned
// all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module
RTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false);
- RTLIL::SigSpec genWidthRTLIL(int width, const std::map<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = NULL);
+ RTLIL::SigSpec genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = NULL);
// compare AST nodes
bool operator==(const AstNode &other) const;
@@ -258,15 +266,15 @@ 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
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, std::map<RTLIL::IdString, RTLIL::Const> parameters);
+ virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters);
virtual RTLIL::Module *clone() const;
};
@@ -288,12 +296,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 std::map<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
+ 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 2eb104fa0..e566d653d 100644
--- a/frontends/ast/dpicall.cc
+++ b/frontends/ast/dpicall.cc
@@ -24,6 +24,8 @@
#include <dlfcn.h>
#include <ffi.h>
+YOSYS_NAMESPACE_BEGIN
+
typedef void (*ffi_fptr) ();
static ffi_fptr resolve_fn (std::string symbol_name)
@@ -73,8 +75,8 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
log("Calling DPI function `%s' and returning `%s':\n", fname.c_str(), rtype.c_str());
- log_assert(SIZE(args) == SIZE(argtypes));
- for (int i = 0; i < SIZE(args); i++) {
+ log_assert(GetSize(args) == GetSize(argtypes));
+ for (int i = 0; i < GetSize(args); i++) {
if (argtypes[i] == "real") {
log(" arg %d (%s): %f\n", i, argtypes[i].c_str(), args[i]->asReal(args[i]->is_signed));
value_store[i].f64 = args[i]->asReal(args[i]->is_signed);
@@ -129,12 +131,18 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
return newNode;
}
+YOSYS_NAMESPACE_END
+
#else /* YOSYS_ENABLE_PLUGINS */
+YOSYS_NAMESPACE_BEGIN
+
AST::AstNode *AST::dpi_call(const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<AstNode*>&)
{
log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str());
}
+YOSYS_NAMESPACE_END
+
#endif /* YOSYS_ENABLE_PLUGINS */
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index f87a68f67..8ed8c673a 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -73,7 +73,7 @@ static RTLIL::SigSpec uniop2rtlil(AstNode *that, std::string type, int result_wi
static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_signed)
{
if (width <= sig.size()) {
- sig.extend(width, is_signed);
+ sig.extend_u0(width, is_signed);
return;
}
@@ -254,7 +254,7 @@ struct AST_INTERNAL::ProcessGenerator
// create initial assignments for the temporary signals
if ((flag_nolatches || always->get_bool_attribute("\\nolatches") || current_module->get_bool_attribute("\\nolatches")) && !found_clocked_sync) {
- subst_rvalue_map = subst_lvalue_from.to_sigbit_map(RTLIL::SigSpec(RTLIL::State::Sx, SIZE(subst_lvalue_from)));
+ subst_rvalue_map = subst_lvalue_from.to_sigbit_dict(RTLIL::SigSpec(RTLIL::State::Sx, GetSize(subst_lvalue_from)));
} else {
addChunkActions(current_case->actions, subst_lvalue_to, subst_lvalue_from);
}
@@ -289,8 +289,8 @@ struct AST_INTERNAL::ProcessGenerator
{
RTLIL::SigSpec new_lhs, new_rhs;
- log_assert(SIZE(lhs) == SIZE(rhs));
- for (int i = 0; i < SIZE(lhs); i++) {
+ log_assert(GetSize(lhs) == GetSize(rhs));
+ for (int i = 0; i < GetSize(lhs); i++) {
if (lhs[i].wire == nullptr)
continue;
new_lhs.append(lhs[i]);
@@ -306,7 +306,7 @@ struct AST_INTERNAL::ProcessGenerator
{
std::vector<RTLIL::SigChunk> chunks = sig.chunks();
- for (int i = 0; i < SIZE(chunks); i++)
+ for (int i = 0; i < GetSize(chunks); i++)
{
RTLIL::SigChunk &chunk = chunks[i];
if (chunk.wire == NULL)
@@ -430,7 +430,7 @@ struct AST_INTERNAL::ProcessGenerator
lvalue.replace(subst_lvalue_map.stdmap());
if (ast->type == AST_ASSIGN_EQ) {
- for (int i = 0; i < SIZE(unmapped_lvalue); i++)
+ for (int i = 0; i < GetSize(unmapped_lvalue); i++)
subst_rvalue_map.set(unmapped_lvalue[i], rvalue[i]);
}
@@ -472,7 +472,7 @@ struct AST_INTERNAL::ProcessGenerator
subst_lvalue_map.save();
subst_rvalue_map.save();
- for (int i = 0; i < SIZE(this_case_eq_lvalue); i++)
+ for (int i = 0; i < GetSize(this_case_eq_lvalue); i++)
subst_lvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]);
RTLIL::CaseRule *backup_case = current_case;
@@ -507,7 +507,7 @@ struct AST_INTERNAL::ProcessGenerator
sw->cases.push_back(default_case);
}
- for (int i = 0; i < SIZE(this_case_eq_lvalue); i++)
+ for (int i = 0; i < GetSize(this_case_eq_lvalue); i++)
subst_rvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]);
this_case_eq_lvalue.replace(subst_lvalue_map.stdmap());
@@ -567,9 +567,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];
@@ -839,14 +841,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
memory->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
memory->name = str;
memory->width = children[0]->range_left - children[0]->range_right + 1;
- memory->start_offset = children[0]->range_right;
- memory->size = children[1]->range_left - children[1]->range_right;
+ if (children[1]->range_right < children[1]->range_left) {
+ memory->start_offset = children[1]->range_right;
+ memory->size = children[1]->range_left - children[1]->range_right + 1;
+ } else {
+ memory->start_offset = children[1]->range_left;
+ memory->size = children[1]->range_right - children[1]->range_left + 1;
+ }
current_module->memories[memory->name] = memory;
- if (memory->size < 0)
- memory->size *= -1;
- memory->size += std::min(children[1]->range_left, children[1]->range_right) + 1;
-
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
@@ -869,7 +872,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_REALVALUE:
{
RTLIL::SigSpec sig = realAsConst(width_hint);
- log("Warning: converting real value %e to binary %s at %s:%d.\n",
+ log_warning("converting real value %e to binary %s at %s:%d.\n",
realvalue, log_signal(sig), filename.c_str(), linenum);
return sig;
}
@@ -890,7 +893,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
wire->name = str;
if (flag_autowire)
- log("Warning: Identifier `%s' is implicitly declared at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_warning("Identifier `%s' is implicitly declared at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
else
log_error("Identifier `%s' is implicitly declared at %s:%d and `default_nettype is set to none.\n", str.c_str(), filename.c_str(), linenum);
}
@@ -941,7 +944,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
shift_val = current_module->Sub(NEW_ID, RTLIL::SigSpec(source_width - width), shift_val, fake_ast->children[1]->is_signed);
fake_ast->children[1]->is_signed = true;
}
- if (SIZE(shift_val) >= 32)
+ if (GetSize(shift_val) >= 32)
fake_ast->children[1]->is_signed = true;
RTLIL::SigSpec sig = binop2rtlil(fake_ast, "$shiftx", width, fake_ast->children[0]->genRTLIL(), shift_val);
delete left_at_zero_ast;
@@ -955,10 +958,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk.offset = (id2ast->range_left - id2ast->range_right + 1) - (chunk.offset + chunk.width);
if (chunk.offset >= source_width || chunk.offset + chunk.width < 0) {
if (chunk.width == 1)
- log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting result bit to undef.\n",
+ log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting result bit to undef.\n",
str.c_str(), filename.c_str(), linenum);
else
- log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting all %d result bits to undef.\n",
+ log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting all %d result bits to undef.\n",
str.c_str(), filename.c_str(), linenum, chunk.width);
chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);
} else {
@@ -972,10 +975,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk.offset += add_undef_bits_lsb;
}
if (add_undef_bits_lsb)
- log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting %d LSB bits to undef.\n",
+ log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting %d LSB bits to undef.\n",
str.c_str(), filename.c_str(), linenum, add_undef_bits_lsb);
if (add_undef_bits_msb)
- log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting %d MSB bits to undef.\n",
+ log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting %d MSB bits to undef.\n",
str.c_str(), filename.c_str(), linenum, add_undef_bits_msb);
}
}
@@ -1213,9 +1216,8 @@ 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("\\ADDR", children[0]->genWidthRTLIL(addr_bits));
@@ -1234,28 +1236,30 @@ 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);
- 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->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);
}
@@ -1263,19 +1267,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) {
@@ -1293,15 +1300,23 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// add entries to current_module->connections for assignments (outside of always blocks)
case AST_ASSIGN:
{
- if (children[0]->type == AST_IDENTIFIER && children[0]->id2ast && children[0]->id2ast->type == AST_AUTOWIRE) {
- RTLIL::SigSpec right = children[1]->genRTLIL();
- RTLIL::SigSpec left = children[0]->genWidthRTLIL(right.size());
- current_module->connect(RTLIL::SigSig(left, right));
- } else {
- RTLIL::SigSpec left = children[0]->genRTLIL();
- RTLIL::SigSpec right = children[1]->genWidthRTLIL(left.size());
- current_module->connect(RTLIL::SigSig(left, right));
+ RTLIL::SigSpec left = children[0]->genRTLIL();
+ RTLIL::SigSpec right = children[1]->genWidthRTLIL(left.size());
+ if (left.has_const()) {
+ RTLIL::SigSpec new_left, new_right;
+ for (int i = 0; i < GetSize(left); i++)
+ if (left[i].wire) {
+ new_left.append(left[i]);
+ new_right.append(right[i]);
+ }
+ log_warning("Ignoring assignment to constant bits at %s:%d:\n"
+ " old assignment: %s = %s\n new assignment: %s = %s.\n",
+ filename.c_str(), linenum, log_signal(left), log_signal(right),
+ log_signal(new_left), log_signal(new_right));
+ left = new_left;
+ right = new_right;
}
+ current_module->connect(RTLIL::SigSig(left, right));
}
break;
@@ -1326,16 +1341,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) {
@@ -1391,9 +1409,9 @@ 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)
// note that this is using some global variables to communicate this special settings to AstNode::genRTLIL().
-RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const std::map<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr)
+RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr)
{
- const std::map<RTLIL::SigBit, RTLIL::SigBit> *backup_subst_ptr = genRTLIL_subst_ptr;
+ const dict<RTLIL::SigBit, RTLIL::SigBit> *backup_subst_ptr = genRTLIL_subst_ptr;
if (new_subst_ptr)
genRTLIL_subst_ptr = new_subst_ptr;
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 969cc2302..a65d2dbb1 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -28,10 +28,12 @@
#include "kernel/log.h"
#include "libs/sha1/sha1.h"
+#include "frontends/verilog/verilog_frontend.h"
#include "ast.h"
#include <sstream>
#include <stdarg.h>
+#include <stdlib.h>
#include <math.h>
YOSYS_NAMESPACE_BEGIN
@@ -47,39 +49,55 @@ 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;
#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)
{
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"))
{
- std::map<AstNode*, std::set<std::string>> mem2reg_places;
- std::map<AstNode*, uint32_t> mem2reg_candidates, dummy_proc_flags;
+ dict<AstNode*, pool<std::string>> mem2reg_places;
+ dict<AstNode*, uint32_t> mem2reg_candidates, dummy_proc_flags;
uint32_t flags = flag_mem2reg ? AstNode::MEM2REG_FL_ALL : 0;
mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, dummy_proc_flags, flags);
- std::set<AstNode*> mem2reg_set;
+ pool<AstNode*> mem2reg_set;
for (auto &it : mem2reg_candidates)
{
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;
@@ -89,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)
@@ -100,13 +118,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
verbose_activate:
if (mem2reg_set.count(mem) == 0) {
- log("Warning: Replacing memory %s with list of registers.", mem->str.c_str());
+ std::string message = stringf("Replacing memory %s with list of registers.", mem->str.c_str());
bool first_element = true;
for (auto &place : mem2reg_places[it.first]) {
- log("%s%s", first_element ? " See " : ", ", place.c_str());
+ message += stringf("%s%s", first_element ? " See " : ", ", place.c_str());
first_element = false;
}
- log("\n");
+ log_warning("%s\n", message.c_str());
}
silent_activate:
@@ -141,6 +159,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
while (simplify(const_fold, at_zero, in_lvalue, 2, width_hint, sign_hint, in_param)) { }
+ recursion_counter--;
return false;
}
@@ -149,11 +168,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// 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)
+ 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 == "$stop" || str == "$finish")) {
+ if ((type == AST_FCALL || type == AST_TCALL) && (str == "$display" || str == "$strobe" || str == "$monitor" || str == "$time" || str == "$stop" || str == "$finish" ||
+ 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();
}
@@ -182,6 +205,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
AstNode *first_node = this_wire_scope[node->str];
if (!node->is_input && !node->is_output && node->is_reg && node->children.size() == 0)
goto wires_are_compatible;
+ if (first_node->children.size() == 0 && node->children.size() == 1 && node->children[0]->type == AST_RANGE) {
+ AstNode *r = node->children[0];
+ if (r->range_valid && r->range_left == 0 && r->range_right == 0) {
+ delete r;
+ node->children.pop_back();
+ }
+ }
if (first_node->children.size() != node->children.size())
goto wires_are_incompatible;
for (size_t j = 0; j < node->children.size(); j++) {
@@ -242,6 +272,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;
@@ -382,6 +416,41 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
+ if (const_fold && type == AST_CASE)
+ {
+ while (children[0]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { }
+ if (children[0]->type == AST_CONSTANT && children[0]->bits_only_01()) {
+ std::vector<AstNode*> new_children;
+ new_children.push_back(children[0]);
+ for (int i = 1; i < GetSize(children); i++) {
+ AstNode *child = children[i];
+ log_assert(child->type == AST_COND);
+ for (auto v : child->children) {
+ if (v->type == AST_DEFAULT)
+ goto keep_const_cond;
+ if (v->type == AST_BLOCK)
+ continue;
+ while (v->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { }
+ if (v->type == AST_CONSTANT && v->bits_only_01()) {
+ if (v->bits == children[0]->bits) {
+ while (i+1 < GetSize(children))
+ delete children[++i];
+ goto keep_const_cond;
+ }
+ continue;
+ }
+ goto keep_const_cond;
+ }
+ if (0)
+ keep_const_cond:
+ new_children.push_back(child);
+ else
+ delete child;
+ }
+ new_children.swap(children);
+ }
+ }
+
// simplify all children first
// (iterate by index as e.g. auto wires can add new children in the process)
for (size_t i = 0; i < children.size(); i++) {
@@ -446,6 +515,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)
@@ -575,9 +645,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
AstNode *index_expr = nullptr;
- for (int i = 0; 2*i < SIZE(id2ast->multirange_dimensions); i++)
+ for (int i = 0; 2*i < GetSize(id2ast->multirange_dimensions); i++)
{
- if (SIZE(children[0]->children) < i)
+ if (GetSize(children[0]->children) < i)
log_error("Insufficient number of array indices for %s at %s:%d.\n", log_id(str), filename.c_str(), linenum);
AstNode *new_index_expr = children[0]->children[i]->children.at(0)->clone();
@@ -591,7 +661,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
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 = SIZE(id2ast->multirange_dimensions)/1; i < SIZE(children[0]->children); i++)
+ for (int i = GetSize(id2ast->multirange_dimensions)/1; i < GetSize(children[0]->children); i++)
children.push_back(children[0]->children[i]->clone());
delete children[0];
@@ -611,7 +681,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
int width = 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",
+ log_warning("converting real value %e to binary %s at %s:%d.\n",
children[0]->realvalue, log_signal(constvalue), filename.c_str(), linenum);
delete children[0];
children[0] = mkconst_bits(constvalue.bits, sign_hint);
@@ -653,7 +723,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
if (current_scope.count(str) == 0) {
- // log("Warning: Creating auto-wire `%s' in module `%s'.\n", str.c_str(), current_ast_mod->str.c_str());
+ // log_warning("Creating auto-wire `%s' in module `%s'.\n", str.c_str(), current_ast_mod->str.c_str());
AstNode *auto_wire = new AstNode(AST_AUTOWIRE);
auto_wire->str = str;
current_ast_mod->children.push_back(auto_wire);
@@ -1123,7 +1193,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
str.c_str(), filename.c_str(), linenum);
- result_width = abs(left_at_zero_ast->integer - right_at_zero_ast->integer) + 1;
+ result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
}
did_something = true;
newNode = new AstNode(AST_CASE, shift_expr);
@@ -1141,7 +1211,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++);
@@ -1185,7 +1255,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;
@@ -1196,9 +1266,8 @@ 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;
}
@@ -1222,9 +1291,13 @@ skip_dynamic_range_lvalue_expansion:;
sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN";
- if (type == AST_ASSIGN_EQ)
- log("Warning: Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n",
- filename.c_str(), linenum);
+ if (type == AST_ASSIGN_EQ) {
+ pair<string, int> this_blocking_assignment_warn(filename, linenum);
+ if (this_blocking_assignment_warn != last_blocking_assignment_warn)
+ log_warning("Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n",
+ filename.c_str(), linenum);
+ last_blocking_assignment_warn = this_blocking_assignment_warn;
+ }
int mem_width, mem_size, addr_bits;
children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits);
@@ -1241,11 +1314,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++)
@@ -1261,13 +1337,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());
@@ -1282,15 +1362,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
{
@@ -1305,16 +1386,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;
@@ -1326,23 +1408,29 @@ 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));
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;
@@ -1366,7 +1454,7 @@ skip_dynamic_range_lvalue_expansion:;
RTLIL::Const arg_value = buf->bitsAsConst();
if (arg_value.as_bool())
- arg_value = const_sub(arg_value, 1, false, false, SIZE(arg_value));
+ arg_value = const_sub(arg_value, 1, false, false, GetSize(arg_value));
delete buf;
uint32_t result = 0;
@@ -1455,9 +1543,9 @@ skip_dynamic_range_lvalue_expansion:;
rtype = RTLIL::unescape_id(dpi_decl->children.at(0)->str);
fname = RTLIL::unescape_id(dpi_decl->children.at(1)->str);
- for (int i = 2; i < SIZE(dpi_decl->children); i++)
+ for (int i = 2; i < GetSize(dpi_decl->children); i++)
{
- if (i-2 >= SIZE(children))
+ if (i-2 >= GetSize(children))
log_error("Insufficient number of arguments in DPI function call at %s:%d.\n", filename.c_str(), linenum);
argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str));
@@ -1480,6 +1568,44 @@ skip_dynamic_range_lvalue_expansion:;
log_error("Can't resolve function name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
}
if (type == AST_TCALL) {
+ if (str == "\\$readmemh" || str == "\\$readmemb")
+ {
+ if (GetSize(children) < 2 || GetSize(children) > 4)
+ log_error("System function %s got %d arguments, expected 2-4 at %s:%d.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+
+ AstNode *node_filename = children[0]->clone();
+ while (node_filename->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ if (node_filename->type != AST_CONSTANT)
+ log_error("Failed to evaluate system function `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+
+ AstNode *node_memory = children[1]->clone();
+ while (node_memory->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ if (node_memory->type != AST_IDENTIFIER || node_memory->id2ast == nullptr || node_memory->id2ast->type != AST_MEMORY)
+ log_error("Failed to evaluate system function `%s' with non-memory 2nd argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+
+ int start_addr = -1, finish_addr = -1;
+
+ if (GetSize(children) > 2) {
+ AstNode *node_addr = children[2]->clone();
+ 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);
+ }
+
+ if (GetSize(children) > 3) {
+ AstNode *node_addr = children[3]->clone();
+ 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);
+ }
+
+ newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr);
+ goto apply_newNode;
+ }
+
if (current_scope.count(str) == 0 || current_scope[str]->type != AST_TASK)
log_error("Can't resolve task name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
}
@@ -1558,7 +1684,7 @@ skip_dynamic_range_lvalue_expansion:;
celltype = RTLIL::escape_id(celltype);
AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE));
- cell->str = prefix.substr(0, SIZE(prefix)-1);
+ cell->str = prefix.substr(0, GetSize(prefix)-1);
cell->children[0]->str = celltype;
for (auto attr : decl->attributes)
@@ -1681,7 +1807,7 @@ skip_dynamic_range_lvalue_expansion:;
bool param_upto = current_scope[str]->range_valid && current_scope[str]->range_swapped;
int param_offset = current_scope[str]->range_valid ? current_scope[str]->range_right : 0;
int param_width = current_scope[str]->range_valid ? current_scope[str]->range_left - current_scope[str]->range_right + 1 :
- SIZE(current_scope[str]->children[0]->bits);
+ GetSize(current_scope[str]->children[0]->bits);
int tmp_range_left = children[0]->range_left, tmp_range_right = children[0]->range_right;
if (param_upto) {
tmp_range_left = (param_width + 2*param_offset) - children[0]->range_right - 1;
@@ -1843,37 +1969,6 @@ skip_dynamic_range_lvalue_expansion:;
newNode->realvalue = -children[0]->asReal(sign_hint);
}
break;
- case AST_CASE:
- if (children[0]->type == AST_CONSTANT && children[0]->bits_only_01()) {
- std::vector<AstNode*> new_children;
- new_children.push_back(children[0]);
- for (int i = 1; i < SIZE(children); i++) {
- AstNode *child = children[i];
- log_assert(child->type == AST_COND);
- for (auto v : child->children) {
- if (v->type == AST_DEFAULT)
- goto keep_const_cond;
- if (v->type == AST_BLOCK)
- continue;
- if (v->type == AST_CONSTANT && v->bits_only_01()) {
- if (v->bits == children[0]->bits) {
- while (i+1 < SIZE(children))
- delete children[++i];
- goto keep_const_cond;
- }
- continue;
- }
- goto keep_const_cond;
- }
- if (0)
- keep_const_cond:
- new_children.push_back(child);
- else
- delete child;
- }
- new_children.swap(children);
- }
- break;
case AST_TERNARY:
if (children[0]->isConst())
{
@@ -1977,6 +2072,7 @@ apply_newNode:
if (!did_something)
basic_prep = true;
+ recursion_counter--;
return did_something;
}
@@ -1988,6 +2084,83 @@ static void replace_result_wire_name_in_function(AstNode *node, std::string &fro
node->str = to;
}
+// 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 *block = new AstNode(AST_BLOCK);
+
+ std::ifstream f;
+ f.open(mem_filename.c_str());
+
+ if (f.fail())
+ log_error("Can not open file `%s` for %s at %s:%d.\n", mem_filename.c_str(), str.c_str(), filename.c_str(), linenum);
+
+ 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);
+
+ if (start_addr < 0)
+ start_addr = range_min;
+
+ if (finish_addr < 0)
+ finish_addr = range_max;
+
+ bool in_comment = false;
+ int increment = start_addr <= finish_addr ? +1 : -1;
+ int cursor = start_addr;
+
+ while (!f.eof())
+ {
+ std::string line, token;
+ std::getline(f, line);
+
+ for (int i = 0; i < GetSize(line); i++) {
+ if (in_comment && line.substr(i, 2) == "*/") {
+ line[i] = ' ';
+ line[i+1] = ' ';
+ in_comment = false;
+ continue;
+ }
+ if (!in_comment && line.substr(i, 2) == "/*")
+ in_comment = true;
+ if (in_comment)
+ line[i] = ' ';
+ }
+
+ while (1)
+ {
+ token = next_token(line, " \t\r\n");
+ if (token.empty() || token.substr(0, 2) == "//")
+ break;
+
+ if (token[0] == '@') {
+ token = token.substr(1);
+ const char *nptr = token.c_str();
+ char *endptr;
+ cursor = strtol(nptr, &endptr, 16);
+ if (!*nptr || *endptr)
+ log_error("Can not parse address `%s` for %s at %s:%d.\n", nptr, str.c_str(), filename.c_str(), linenum);
+ continue;
+ }
+
+ AstNode *value = VERILOG_FRONTEND::const2ast((is_readmemh ? "'h" : "'b") + token);
+
+ 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))
+ break;
+ cursor += increment;
+ }
+
+ if ((cursor == finish_addr) || (increment > 0 && cursor >= range_max) || (increment < 0 && cursor <= range_min))
+ break;
+ }
+
+ return block;
+}
+
// annotate the names of all wires and other named objects in a generate block
void AstNode::expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map)
{
@@ -2063,8 +2236,8 @@ void AstNode::replace_ids(const std::string &prefix, const std::map<std::string,
}
// helper function for mem2reg_as_needed_pass1
-static void mark_memories_assign_lhs_complex(std::map<AstNode*, std::set<std::string>> &mem2reg_places,
- std::map<AstNode*, uint32_t> &mem2reg_candidates, AstNode *that)
+static void mark_memories_assign_lhs_complex(dict<AstNode*, pool<std::string>> &mem2reg_places,
+ dict<AstNode*, uint32_t> &mem2reg_candidates, AstNode *that)
{
for (auto &child : that->children)
mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, child);
@@ -2078,8 +2251,8 @@ static void mark_memories_assign_lhs_complex(std::map<AstNode*, std::set<std::st
}
// find memories that should be replaced by registers
-void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>> &mem2reg_places,
- std::map<AstNode*, uint32_t> &mem2reg_candidates, std::map<AstNode*, uint32_t> &proc_flags, uint32_t &flags)
+void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
+ dict<AstNode*, uint32_t> &mem2reg_candidates, dict<AstNode*, uint32_t> &proc_flags, uint32_t &flags)
{
uint32_t children_flags = 0;
int ignore_children_counter = 0;
@@ -2141,7 +2314,7 @@ void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>>
if (type == AST_MODULE && get_bool_attribute("\\mem2reg"))
children_flags |= AstNode::MEM2REG_FL_ALL;
- std::map<AstNode*, uint32_t> *proc_flags_p = NULL;
+ dict<AstNode*, uint32_t> *proc_flags_p = NULL;
if (type == AST_ALWAYS) {
int count_edge_events = 0;
@@ -2150,12 +2323,12 @@ void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>>
count_edge_events++;
if (count_edge_events != 1)
children_flags |= AstNode::MEM2REG_FL_ASYNC;
- proc_flags_p = new std::map<AstNode*, uint32_t>;
+ proc_flags_p = new dict<AstNode*, uint32_t>;
}
if (type == AST_INITIAL) {
children_flags |= AstNode::MEM2REG_FL_INIT;
- proc_flags_p = new std::map<AstNode*, uint32_t>;
+ proc_flags_p = new dict<AstNode*, uint32_t>;
}
uint32_t backup_flags = flags;
@@ -2173,20 +2346,33 @@ void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>>
flags &= ~children_flags | backup_flags;
if (proc_flags_p) {
+#ifndef NDEBUG
for (auto it : *proc_flags_p)
log_assert((it.second & ~0xff000000) == 0);
+#endif
delete proc_flags_p;
}
}
+bool AstNode::mem2reg_check(pool<AstNode*> &mem2reg_set)
+{
+ if (type != AST_IDENTIFIER || !id2ast || !mem2reg_set.count(id2ast))
+ return false;
+
+ if (children.empty() || children[0]->type != AST_RANGE || GetSize(children[0]->children) != 1)
+ log_error("Invalid array access at %s:%d.\n", filename.c_str(), linenum);
+
+ return true;
+}
+
// actually replace memories with registers
-void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block)
+void AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block)
{
if (type == AST_BLOCK)
block = this;
- if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && block != NULL && children[0]->id2ast &&
- mem2reg_set.count(children[0]->id2ast) > 0 && children[0]->children[0]->children[0]->type != AST_CONSTANT)
+ if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && block != NULL &&
+ children[0]->mem2reg_check(mem2reg_set) && children[0]->children[0]->children[0]->type != AST_CONSTANT)
{
std::stringstream sstr;
sstr << "$mem2reg_wr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
@@ -2242,7 +2428,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
type = AST_ASSIGN_EQ;
}
- if (type == AST_IDENTIFIER && id2ast && mem2reg_set.count(id2ast) > 0)
+ if (mem2reg_check(mem2reg_set))
{
AstNode *bit_part_sel = NULL;
if (children.size() == 2)
@@ -2446,7 +2632,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
}
log_assert(block != NULL);
- log_assert(variables.count(str));
+ log_assert(variables.count(str) != 0);
while (!block->children.empty())
{
diff --git a/frontends/ilang/.gitignore b/frontends/ilang/.gitignore
index 72b06b0bf..43106a814 100644
--- a/frontends/ilang/.gitignore
+++ b/frontends/ilang/.gitignore
@@ -1,4 +1,4 @@
-lexer.cc
-parser.output
-parser.tab.cc
-parser.tab.h
+ilang_lexer.cc
+ilang_parser.output
+ilang_parser.tab.cc
+ilang_parser.tab.h
diff --git a/frontends/ilang/Makefile.inc b/frontends/ilang/Makefile.inc
index e832cfed8..c15e2cc47 100644
--- a/frontends/ilang/Makefile.inc
+++ b/frontends/ilang/Makefile.inc
@@ -1,18 +1,18 @@
-GENFILES += frontends/ilang/parser.tab.cc
-GENFILES += frontends/ilang/parser.tab.h
-GENFILES += frontends/ilang/parser.output
-GENFILES += frontends/ilang/lexer.cc
+GENFILES += frontends/ilang/ilang_parser.tab.cc
+GENFILES += frontends/ilang/ilang_parser.tab.h
+GENFILES += frontends/ilang/ilang_parser.output
+GENFILES += frontends/ilang/ilang_lexer.cc
-frontends/ilang/parser.tab.cc: frontends/ilang/parser.y
- $(P) bison -d -r all -b frontends/ilang/parser frontends/ilang/parser.y
- $(Q) mv frontends/ilang/parser.tab.c frontends/ilang/parser.tab.cc
+frontends/ilang/ilang_parser.tab.cc: frontends/ilang/ilang_parser.y
+ $(P) $(BISON) -d -r all -b frontends/ilang/ilang_parser frontends/ilang/ilang_parser.y
+ $(Q) mv frontends/ilang/ilang_parser.tab.c frontends/ilang/ilang_parser.tab.cc
-frontends/ilang/parser.tab.h: frontends/ilang/parser.tab.cc
+frontends/ilang/ilang_parser.tab.h: frontends/ilang/ilang_parser.tab.cc
-frontends/ilang/lexer.cc: frontends/ilang/lexer.l
- $(P) flex -o frontends/ilang/lexer.cc frontends/ilang/lexer.l
+frontends/ilang/ilang_lexer.cc: frontends/ilang/ilang_lexer.l
+ $(P) flex -o frontends/ilang/ilang_lexer.cc frontends/ilang/ilang_lexer.l
-OBJS += frontends/ilang/parser.tab.o frontends/ilang/lexer.o
+OBJS += frontends/ilang/ilang_parser.tab.o frontends/ilang/ilang_lexer.o
OBJS += frontends/ilang/ilang_frontend.o
diff --git a/frontends/ilang/ilang_frontend.cc b/frontends/ilang/ilang_frontend.cc
index f6f926db1..7a4687a3c 100644
--- a/frontends/ilang/ilang_frontend.cc
+++ b/frontends/ilang/ilang_frontend.cc
@@ -26,13 +26,13 @@
#include "kernel/register.h"
#include "kernel/log.h"
-YOSYS_NAMESPACE_BEGIN
-
void rtlil_frontend_ilang_yyerror(char const *s)
{
- log_error("Parser error in line %d: %s\n", rtlil_frontend_ilang_yyget_lineno(), s);
+ YOSYS_NAMESPACE_PREFIX log_error("Parser error in line %d: %s\n", rtlil_frontend_ilang_yyget_lineno(), s);
}
+YOSYS_NAMESPACE_BEGIN
+
struct IlangFrontend : public Frontend {
IlangFrontend() : Frontend("ilang", "read modules from ilang file") { }
virtual void help()
diff --git a/frontends/ilang/lexer.l b/frontends/ilang/ilang_lexer.l
index 4109cd4bc..ace992fbd 100644
--- a/frontends/ilang/lexer.l
+++ b/frontends/ilang/ilang_lexer.l
@@ -30,10 +30,12 @@
#endif
#include "ilang_frontend.h"
-#include "parser.tab.h"
+#include "ilang_parser.tab.h"
+
+USING_YOSYS_NAMESPACE
#define YY_INPUT(buf,result,max_size) \
- result = ILANG_FRONTEND::lexin->readsome(buf, max_size);
+ result = readsome(*ILANG_FRONTEND::lexin, buf, max_size)
%}
diff --git a/frontends/ilang/parser.y b/frontends/ilang/ilang_parser.y
index a5cc06898..4661d5772 100644
--- a/frontends/ilang/parser.y
+++ b/frontends/ilang/ilang_parser.y
@@ -36,7 +36,7 @@ namespace ILANG_FRONTEND {
RTLIL::Process *current_process;
std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack;
std::vector<RTLIL::CaseRule*> case_stack;
- std::map<RTLIL::IdString, RTLIL::Const> attrbuf;
+ dict<RTLIL::IdString, RTLIL::Const> attrbuf;
}
using namespace ILANG_FRONTEND;
YOSYS_NAMESPACE_END
@@ -183,6 +183,9 @@ memory_options:
memory_options TOK_SIZE TOK_INT {
current_memory->size = $3;
} |
+ memory_options TOK_OFFSET TOK_INT {
+ current_memory->start_offset = $3;
+ } |
/* empty */;
cell_stmt:
diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc
index a9ab022a4..464c5c942 100644
--- a/frontends/liberty/liberty.cc
+++ b/frontends/liberty/liberty.cc
@@ -22,7 +22,6 @@
#include "kernel/log.h"
YOSYS_NAMESPACE_BEGIN
-using namespace PASS_DFFLIBMAP;
struct token_t {
char type;
diff --git a/frontends/verific/build_amd64.txt b/frontends/verific/build_amd64.txt
index 94615d38d..9bb6e3203 100644
--- a/frontends/verific/build_amd64.txt
+++ b/frontends/verific/build_amd64.txt
@@ -10,6 +10,7 @@ CONFIG := clang
ENABLE_TCL := 0
ENABLE_QT4 := 0
ENABLE_ABC := 0
+ENABLE_PLUGINS := 0
ENABLE_VERIFIC := 1
CXXFLAGS += -m32
LDFLAGS += -m32
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index d0f148386..79abcf245 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -20,11 +20,14 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
-#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <dirent.h>
+
+#ifndef _WIN32
+# include <unistd.h>
+# include <dirent.h>
+#endif
USING_YOSYS_NAMESPACE
@@ -324,7 +327,7 @@ static bool import_netlist_instance_cells(RTLIL::Module *module, std::map<Net*,
if (inst->GetCin()->IsGnd()) {
module->addAdd(RTLIL::escape_id(inst->Name()), IN1, IN2, out, SIGNED);
} else {
- RTLIL::SigSpec tmp = module->addWire(NEW_ID, SIZE(out));
+ RTLIL::SigSpec tmp = module->addWire(NEW_ID, GetSize(out));
module->addAdd(NEW_ID, IN1, IN2, tmp, SIGNED);
module->addAdd(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetCin()), out, false);
}
@@ -687,8 +690,8 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
cell->parameters["\\CLK_ENABLE"] = false;
cell->parameters["\\CLK_POLARITY"] = true;
cell->parameters["\\TRANSPARENT"] = false;
- cell->parameters["\\ABITS"] = SIZE(addr);
- cell->parameters["\\WIDTH"] = SIZE(data);
+ cell->parameters["\\ABITS"] = GetSize(addr);
+ cell->parameters["\\WIDTH"] = GetSize(data);
cell->setPort("\\CLK", RTLIL::State::S0);
cell->setPort("\\ADDR", addr);
cell->setPort("\\DATA", data);
@@ -709,9 +712,9 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
cell->parameters["\\CLK_ENABLE"] = false;
cell->parameters["\\CLK_POLARITY"] = true;
cell->parameters["\\PRIORITY"] = 0;
- cell->parameters["\\ABITS"] = SIZE(addr);
- cell->parameters["\\WIDTH"] = SIZE(data);
- cell->setPort("\\EN", RTLIL::SigSpec(net_map.at(inst->GetControl())).repeat(SIZE(data)));
+ cell->parameters["\\ABITS"] = GetSize(addr);
+ cell->parameters["\\WIDTH"] = GetSize(data);
+ cell->setPort("\\EN", RTLIL::SigSpec(net_map.at(inst->GetControl())).repeat(GetSize(data)));
cell->setPort("\\CLK", RTLIL::State::S0);
cell->setPort("\\ADDR", addr);
cell->setPort("\\DATA", data);
@@ -727,7 +730,7 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
if (import_netlist_instance_cells(module, net_map, inst))
continue;
if (inst->IsOperator())
- log("Warning: Unsupported Verific operator: %s (fallback to gate level implementation provided by verific)\n", inst->View()->Owner()->Name());
+ log_warning("Unsupported Verific operator: %s (fallback to gate level implementation provided by verific)\n", inst->View()->Owner()->Name());
} else {
if (import_netlist_instance_gates(module, net_map, inst))
continue;
@@ -753,9 +756,9 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
RTLIL::SigSpec conn;
if (cell->hasPort(RTLIL::escape_id(port_name)))
conn = cell->getPort(RTLIL::escape_id(port_name));
- while (SIZE(conn) <= port_offset) {
+ while (GetSize(conn) <= port_offset) {
if (pr->GetPort()->GetDir() != DIR_IN)
- conn.append(module->addWire(NEW_ID, port_offset - SIZE(conn)));
+ conn.append(module->addWire(NEW_ID, port_offset - GetSize(conn)));
conn.append(RTLIL::State::Sz);
}
conn.replace(port_offset, net_map.at(pr->GetNet()));
diff --git a/frontends/verilog/.gitignore b/frontends/verilog/.gitignore
index 72b06b0bf..1d4ae9e5c 100644
--- a/frontends/verilog/.gitignore
+++ b/frontends/verilog/.gitignore
@@ -1,4 +1,4 @@
-lexer.cc
-parser.output
-parser.tab.cc
-parser.tab.h
+verilog_lexer.cc
+verilog_parser.output
+verilog_parser.tab.cc
+verilog_parser.tab.h
diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc
index 49eb320ec..92cbd0b87 100644
--- a/frontends/verilog/Makefile.inc
+++ b/frontends/verilog/Makefile.inc
@@ -1,20 +1,20 @@
-GENFILES += frontends/verilog/parser.tab.cc
-GENFILES += frontends/verilog/parser.tab.h
-GENFILES += frontends/verilog/parser.output
-GENFILES += frontends/verilog/lexer.cc
+GENFILES += frontends/verilog/verilog_parser.tab.cc
+GENFILES += frontends/verilog/verilog_parser.tab.h
+GENFILES += frontends/verilog/verilog_parser.output
+GENFILES += frontends/verilog/verilog_lexer.cc
-frontends/verilog/parser.tab.cc: frontends/verilog/parser.y
- $(P) bison -d -r all -b frontends/verilog/parser frontends/verilog/parser.y
- $(Q) mv frontends/verilog/parser.tab.c frontends/verilog/parser.tab.cc
+frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y
+ $(P) $(BISON) -d -r all -b frontends/verilog/verilog_parser frontends/verilog/verilog_parser.y
+ $(Q) mv frontends/verilog/verilog_parser.tab.c frontends/verilog/verilog_parser.tab.cc
-frontends/verilog/parser.tab.h: frontends/verilog/parser.tab.cc
+frontends/verilog/verilog_parser.tab.h: frontends/verilog/verilog_parser.tab.cc
-frontends/verilog/lexer.cc: frontends/verilog/lexer.l
- $(P) flex -o frontends/verilog/lexer.cc frontends/verilog/lexer.l
+frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
+ $(P) flex -o frontends/verilog/verilog_lexer.cc frontends/verilog/verilog_lexer.l
-OBJS += frontends/verilog/parser.tab.o
-OBJS += frontends/verilog/lexer.o
+OBJS += frontends/verilog/verilog_parser.tab.o
+OBJS += frontends/verilog/verilog_lexer.o
OBJS += frontends/verilog/preproc.o
OBJS += frontends/verilog/verilog_frontend.o
OBJS += frontends/verilog/const2ast.o
diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc
index a81e3010f..735bc5f99 100644
--- a/frontends/verilog/const2ast.cc
+++ b/frontends/verilog/const2ast.cc
@@ -132,8 +132,16 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
}
// convert the verilog code for a constant to an AST node
-AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type)
+AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn_z)
{
+ if (warn_z) {
+ AstNode *ret = const2ast(code, case_type);
+ if (std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
+ log_warning("Yosys does not support tri-state logic at the moment. (%s:%d)\n",
+ current_filename.c_str(), frontend_verilog_yyget_lineno());
+ return ret;
+ }
+
const char *str = code.c_str();
// Strings
@@ -174,7 +182,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type)
if (str == endptr)
len_in_bits = -1;
- // The "<bits>'s?[bodh]<digits>" syntax
+ // The "<bits>'s?[bodhBODH]<digits>" syntax
if (*endptr == '\'')
{
std::vector<RTLIL::State> data;
@@ -186,15 +194,19 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type)
switch (*(endptr+1))
{
case 'b':
+ case 'B':
my_strtobin(data, endptr+2, len_in_bits, 2, case_type);
break;
case 'o':
+ case 'O':
my_strtobin(data, endptr+2, len_in_bits, 8, case_type);
break;
case 'd':
+ case 'D':
my_strtobin(data, endptr+2, len_in_bits, 10, case_type);
break;
case 'h':
+ case 'H':
my_strtobin(data, endptr+2, len_in_bits, 16, case_type);
break;
default:
diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc
index f83433219..e2118630e 100644
--- a/frontends/verilog/preproc.cc
+++ b/frontends/verilog/preproc.cc
@@ -201,8 +201,8 @@ static void input_file(std::istream &f, std::string filename)
insert_input("");
auto it = input_buffer.begin();
- input_buffer.insert(it, "`file_push " + filename + "\n");
- while ((rc = f.readsome(buffer, sizeof(buffer)-1)) > 0) {
+ input_buffer.insert(it, "`file_push \"" + filename + "\"\n");
+ while ((rc = readsome(f, buffer, sizeof(buffer)-1)) > 0) {
buffer[rc] = 0;
input_buffer.insert(it, buffer);
}
@@ -221,7 +221,8 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
input_buffer_charp = 0;
input_file(f, filename);
- defines_map["__YOSYS__"] = "1";
+ defines_map["YOSYS"] = "1";
+ defines_map["SYNTHESIS"] = "1";
while (!input_buffer.empty())
{
@@ -422,7 +423,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
if (tok == "(" || tok == "{" || tok == "[")
level++;
}
- for (size_t i = 0; i < args.size(); i++)
+ for (int i = 0; i < GetSize(args); i++)
defines_map[stringf("macro_%s_arg%d", name.c_str(), i+1)] = args[i];
} else {
insert_input(tok);
diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc
index c6d4a0b79..635c9ce47 100644
--- a/frontends/verilog/verilog_frontend.cc
+++ b/frontends/verilog/verilog_frontend.cc
@@ -54,6 +54,10 @@ struct VerilogFrontend : public Frontend {
log(" enable support for SystemVerilog features. (only a small subset\n");
log(" of SystemVerilog is supported)\n");
log("\n");
+ log(" -formal\n");
+ log(" enable support for assert() and assume() statements\n");
+ log(" (assert support is also enabled with -sv)\n");
+ log("\n");
log(" -dump_ast1\n");
log(" dump abstract syntax tree (before simplification)\n");
log("\n");
@@ -83,11 +87,20 @@ struct VerilogFrontend : public Frontend {
log(" this can also be achieved by setting the 'nomem2reg'\n");
log(" attribute on the respective module or register.\n");
log("\n");
+ log(" This is potentially dangerous. Usually the front-end has good\n");
+ log(" reasons for converting an array to a list of registers.\n");
+ log(" Prohibiting this step will likely result in incorrect synthesis\n");
+ log(" results.\n");
+ log("\n");
log(" -mem2reg\n");
log(" always convert memories to registers. this can also be\n");
log(" achieved by setting the 'mem2reg' attribute on the respective\n");
log(" module or register.\n");
log("\n");
+ log(" -nomeminit\n");
+ log(" do not infer $meminit cells and instead convert initialized\n");
+ log(" memories to registers directly in the front-end.\n");
+ log("\n");
log(" -ppdump\n");
log(" dump verilog code after pre-processor\n");
log("\n");
@@ -139,6 +152,7 @@ struct VerilogFrontend : public Frontend {
bool flag_dump_ast2 = false;
bool flag_dump_vlog = false;
bool flag_nolatches = false;
+ bool flag_nomeminit = false;
bool flag_nomem2reg = false;
bool flag_mem2reg = false;
bool flag_ppdump = false;
@@ -154,6 +168,7 @@ struct VerilogFrontend : public Frontend {
frontend_verilog_yydebug = false;
sv_mode = false;
+ formal_mode = false;
log_header("Executing Verilog-2005 frontend.\n");
@@ -166,6 +181,10 @@ struct VerilogFrontend : public Frontend {
sv_mode = true;
continue;
}
+ if (arg == "-formal") {
+ formal_mode = true;
+ continue;
+ }
if (arg == "-dump_ast1") {
flag_dump_ast1 = true;
continue;
@@ -186,6 +205,10 @@ struct VerilogFrontend : public Frontend {
flag_nolatches = true;
continue;
}
+ if (arg == "-nomeminit") {
+ flag_nomeminit = true;
+ continue;
+ }
if (arg == "-nomem2reg") {
flag_nomem2reg = true;
continue;
@@ -257,7 +280,8 @@ struct VerilogFrontend : public Frontend {
}
extra_args(f, filename, args, argidx);
- log("Parsing Verilog input from `%s' to AST representation.\n", filename.c_str());
+ log("Parsing %s%s input from `%s' to AST representation.\n",
+ formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str());
AST::current_filename = filename;
AST::set_line_num = &frontend_verilog_yyset_lineno;
@@ -288,7 +312,7 @@ struct VerilogFrontend : public Frontend {
child->attributes[attr] = AST::AstNode::mkconst_int(1, false);
}
- AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire);
+ AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire);
if (!flag_nopp)
delete lexin;
@@ -300,22 +324,6 @@ struct VerilogFrontend : public Frontend {
}
} VerilogFrontend;
-// the yyerror function used by bison to report parser errors
-void frontend_verilog_yyerror(char const *fmt, ...)
-{
- va_list ap;
- char buffer[1024];
- char *p = buffer;
- p += snprintf(p, buffer + sizeof(buffer) - p, "Parser error in line %s:%d: ",
- AST::current_filename.c_str(), frontend_verilog_yyget_lineno());
- va_start(ap, fmt);
- p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
- va_end(ap);
- p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
- log_error("%s", buffer);
- exit(1);
-}
-
struct VerilogDefaults : public Pass {
VerilogDefaults() : Pass("verilog_defaults", "set default options for read_verilog") { }
virtual void help()
@@ -376,3 +384,19 @@ struct VerilogDefaults : public Pass {
YOSYS_NAMESPACE_END
+// the yyerror function used by bison to report parser errors
+void frontend_verilog_yyerror(char const *fmt, ...)
+{
+ va_list ap;
+ char buffer[1024];
+ char *p = buffer;
+ p += snprintf(p, buffer + sizeof(buffer) - p, "Parser error in line %s:%d: ",
+ YOSYS_NAMESPACE_PREFIX AST::current_filename.c_str(), frontend_verilog_yyget_lineno());
+ va_start(ap, fmt);
+ p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
+ va_end(ap);
+ p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
+ YOSYS_NAMESPACE_PREFIX log_error("%s", buffer);
+ exit(1);
+}
+
diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h
index af6495f8f..5561f54cd 100644
--- a/frontends/verilog/verilog_frontend.h
+++ b/frontends/verilog/verilog_frontend.h
@@ -43,7 +43,7 @@ namespace VERILOG_FRONTEND
extern struct AST::AstNode *current_ast;
// this function converts a Verilog constant to an AST_CONSTANT node
- AST::AstNode *const2ast(std::string code, char case_type = 0);
+ AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false);
// state of `default_nettype
extern bool default_nettype_wire;
@@ -51,6 +51,9 @@ namespace VERILOG_FRONTEND
// running in SystemVerilog mode
extern bool sv_mode;
+ // running in -formal mode
+ extern bool formal_mode;
+
// lexer input stream
extern std::istream *lexin;
}
diff --git a/frontends/verilog/lexer.l b/frontends/verilog/verilog_lexer.l
index c9302aba8..8fbaa953d 100644
--- a/frontends/verilog/lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -42,7 +42,7 @@
#include "kernel/log.h"
#include "verilog_frontend.h"
#include "frontends/ast/ast.h"
-#include "parser.tab.h"
+#include "verilog_parser.tab.h"
USING_YOSYS_NAMESPACE
using namespace AST;
@@ -64,7 +64,7 @@ YOSYS_NAMESPACE_END
return TOK_ID;
#define YY_INPUT(buf,result,max_size) \
- result = lexin->readsome(buf, max_size);
+ result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size)
%}
@@ -85,6 +85,10 @@ YOSYS_NAMESPACE_END
fn_stack.push_back(current_filename);
ln_stack.push_back(frontend_verilog_yyget_lineno());
current_filename = yytext+11;
+ if (!current_filename.empty() && current_filename.front() == '"')
+ current_filename = current_filename.substr(1);
+ if (!current_filename.empty() && current_filename.back() == '"')
+ current_filename = current_filename.substr(0, current_filename.size()-1);
frontend_verilog_yyset_lineno(0);
}
@@ -112,6 +116,9 @@ YOSYS_NAMESPACE_END
"`timescale"[ \t]+[^ \t\r\n/]+[ \t]*"/"[ \t]*[^ \t\r\n]* /* ignore timescale directive */
+"`celldefine"[^\n]* /* ignore `celldefine */
+"`endcelldefine"[^\n]* /* ignore `endcelldefine */
+
"`default_nettype"[ \t]+[^ \t\r\n/]+ {
char *p = yytext;
while (*p != 0 && *p != ' ' && *p != '\t') p++;
@@ -162,8 +169,9 @@ YOSYS_NAMESPACE_END
"always_ff" { SV_KEYWORD(TOK_ALWAYS); }
"always_latch" { SV_KEYWORD(TOK_ALWAYS); }
-"assert" { SV_KEYWORD(TOK_ASSERT); }
-"property" { SV_KEYWORD(TOK_PROPERTY); }
+"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
+"assume" { if (formal_mode) return TOK_ASSUME; return TOK_ID; }
+"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }
"logic" { SV_KEYWORD(TOK_REG); }
"bit" { SV_KEYWORD(TOK_REG); }
@@ -177,12 +185,12 @@ YOSYS_NAMESPACE_END
"genvar" { return TOK_GENVAR; }
"real" { return TOK_REAL; }
-[0-9]+ {
+[0-9][0-9_]* {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_CONST;
}
-[0-9]*[ \t]*\'s?[bodh][ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
+[0-9]*[ \t]*\'s?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_CONST;
}
@@ -240,7 +248,7 @@ and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 {
supply0 { return TOK_SUPPLY0; }
supply1 { return TOK_SUPPLY1; }
-"$"(display|time|stop|finish) {
+"$"(display|strobe|monitor|time|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_ID;
}
@@ -254,8 +262,12 @@ supply1 { return TOK_SUPPLY1; }
}
"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
- log("Warning: Found one of those horrible `(synopsys|synthesis) translate_off' comments.\n");
- log("It is strongly suggested to use `ifdef constructs instead!\n");
+ static bool printed_warning = false;
+ if (!printed_warning) {
+ log_warning("Found one of those horrible `(synopsys|synthesis) translate_off' comments.\n"
+ "Yosys does support them but it is recommended to use `ifdef constructs instead!\n");
+ printed_warning = true;
+ }
BEGIN(SYNOPSYS_TRANSLATE_OFF);
}
<SYNOPSYS_TRANSLATE_OFF>. /* ignore synopsys translate_off body */
@@ -266,13 +278,21 @@ supply1 { return TOK_SUPPLY1; }
BEGIN(SYNOPSYS_FLAGS);
}
<SYNOPSYS_FLAGS>full_case {
- log("Warning: Found one of those horrible `(synopsys|synthesis) full_case' comments.\n");
- log("It is strongly suggested to use verilog x-values and default branches instead!\n");
+ static bool printed_warning = false;
+ if (!printed_warning) {
+ log_warning("Found one of those horrible `(synopsys|synthesis) full_case' comments.\n"
+ "Yosys does support them but it is recommended to use verilog `full_case' attributes instead!\n");
+ printed_warning = true;
+ }
return TOK_SYNOPSYS_FULL_CASE;
}
<SYNOPSYS_FLAGS>parallel_case {
- log("Warning: Found one of those horrible `(synopsys|synthesis) parallel_case' comments.\n");
- log("It is strongly suggested to use verilog `parallel_case' attributes instead!\n");
+ static bool printed_warning = false;
+ if (!printed_warning) {
+ log_warning("Found one of those horrible `(synopsys|synthesis) parallel_case' comments.\n"
+ "Yosys does support them but it is recommended to use verilog `parallel_case' attributes instead!\n");
+ printed_warning = true;
+ }
return TOK_SYNOPSYS_PARALLEL_CASE;
}
<SYNOPSYS_FLAGS>. /* ignore everything else */
@@ -342,7 +362,10 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
[ \t\r\n] /* ignore whitespaces */
\\[\r\n] /* ignore continuation sequence */
"//"[^\r\n]* /* ignore one-line comments */
-"#"[$a-zA-Z_0-9\.]+ /* ignore simulation timings */
+
+"#"\ *[0-9][0-9_]* /* ignore simulation timings */
+"#"\ *[0-9][0-9_]*\.[0-9][0-9_]* /* ignore simulation timings */
+"#"\ *[$a-zA-Z_\.][$a-zA-Z_0-9\.]* /* ignore simulation timings */
. { return *yytext; }
diff --git a/frontends/verilog/parser.y b/frontends/verilog/verilog_parser.y
index a9f69a49c..d935cab37 100644
--- a/frontends/verilog/parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -57,7 +57,7 @@ namespace VERILOG_FRONTEND {
std::vector<char> case_type_stack;
bool do_not_require_port_stubs;
bool default_nettype_wire;
- bool sv_mode;
+ bool sv_mode, formal_mode;
std::istream *lexin;
}
YOSYS_NAMESPACE_END
@@ -111,7 +111,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
-%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_PROPERTY
+%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME TOK_PROPERTY
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
@@ -139,10 +139,11 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%%
input: {
+ ast_stack.clear();
ast_stack.push_back(current_ast);
} design {
ast_stack.pop_back();
- log_assert(SIZE(ast_stack) == 0);
+ log_assert(GetSize(ast_stack) == 0);
for (auto &it : default_attr_list)
delete it.second;
default_attr_list.clear();
@@ -240,7 +241,7 @@ module:
};
module_para_opt:
- '#' '(' module_para_list ')' | /* empty */;
+ '#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | /* empty */;
module_para_list:
single_module_para |
@@ -249,11 +250,10 @@ module_para_list:
single_module_para:
TOK_PARAMETER {
+ if (astbuf1) delete astbuf1;
astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
- } param_signed param_integer param_range single_param_decl {
- delete astbuf1;
- };
+ } param_signed param_integer param_range single_param_decl | single_param_decl;
module_args_opt:
'(' ')' | /* empty */ | '(' module_args optional_comma ')';
@@ -310,10 +310,17 @@ module_arg:
do_not_require_port_stubs = true;
};
+non_opt_delay:
+ '#' '(' expr ')' { delete $3; } |
+ '#' '(' expr ':' expr ':' expr ')' { delete $3; delete $5; delete $7; };
+
+delay:
+ non_opt_delay | /* empty */;
+
wire_type:
{
astbuf3 = new AstNode(AST_WIRE);
- } wire_type_token_list {
+ } wire_type_token_list delay {
$$ = astbuf3;
};
@@ -449,7 +456,7 @@ task_func_decl:
} opt_dpi_function_args ';' {
current_function_or_task = NULL;
} |
- attr TOK_TASK TOK_ID ';' {
+ attr TOK_TASK TOK_ID {
current_function_or_task = new AstNode(AST_TASK);
current_function_or_task->str = *$3;
append_attr(current_function_or_task, $1);
@@ -457,11 +464,11 @@ task_func_decl:
ast_stack.push_back(current_function_or_task);
current_function_or_task_port_id = 1;
delete $3;
- } task_func_body TOK_ENDTASK {
+ } task_func_args_opt ';' task_func_body TOK_ENDTASK {
current_function_or_task = NULL;
ast_stack.pop_back();
} |
- attr TOK_FUNCTION opt_signed range_or_signed_int TOK_ID ';' {
+ attr TOK_FUNCTION opt_signed range_or_signed_int TOK_ID {
current_function_or_task = new AstNode(AST_FUNCTION);
current_function_or_task->str = *$5;
append_attr(current_function_or_task, $1);
@@ -478,7 +485,7 @@ task_func_decl:
current_function_or_task->children.push_back(outreg);
current_function_or_task_port_id = 1;
delete $5;
- } task_func_body TOK_ENDFUNCTION {
+ } task_func_args_opt ';' task_func_body TOK_ENDFUNCTION {
current_function_or_task = NULL;
ast_stack.pop_back();
};
@@ -512,6 +519,45 @@ opt_signed:
$$ = false;
};
+task_func_args_opt:
+ '(' ')' | /* empty */ | '(' {
+ albuf = nullptr;
+ astbuf1 = nullptr;
+ astbuf2 = nullptr;
+ } task_func_args optional_comma {
+ delete astbuf1;
+ if (astbuf2 != NULL)
+ delete astbuf2;
+ free_attr(albuf);
+ } ')';
+
+task_func_args:
+ task_func_port | task_func_args ',' task_func_port;
+
+task_func_port:
+ attr wire_type range {
+ if (albuf) {
+ delete astbuf1;
+ if (astbuf2 != NULL)
+ delete astbuf2;
+ free_attr(albuf);
+ }
+ albuf = $1;
+ astbuf1 = $2;
+ astbuf2 = $3;
+ if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) {
+ if (astbuf2) {
+ frontend_verilog_yyerror("Syntax error.");
+ } else {
+ astbuf2 = new AstNode(AST_RANGE);
+ astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true));
+ astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_right, true));
+ }
+ }
+ if (astbuf2 && astbuf2->children.size() != 2)
+ frontend_verilog_yyerror("Syntax error.");
+ } wire_name | wire_name;
+
task_func_body:
task_func_body behavioral_stmt |
/* empty */;
@@ -568,6 +614,8 @@ param_decl_list:
single_param_decl:
TOK_ID '=' expr {
+ if (astbuf1 == nullptr)
+ frontend_verilog_yyerror("syntax error");
AstNode *node = astbuf1->clone();
node->str = *$1;
delete node->children[0];
@@ -609,27 +657,39 @@ wire_decl:
}
if (astbuf2 && astbuf2->children.size() != 2)
frontend_verilog_yyerror("Syntax error.");
- } wire_name_list ';' {
+ } wire_name_list {
delete astbuf1;
if (astbuf2 != NULL)
delete astbuf2;
free_attr(albuf);
- } |
- attr TOK_SUPPLY0 TOK_ID ';' {
+ } ';' |
+ attr TOK_SUPPLY0 TOK_ID {
ast_stack.back()->children.push_back(new AstNode(AST_WIRE));
ast_stack.back()->children.back()->str = *$3;
append_attr(ast_stack.back()->children.back(), $1);
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1)));
ast_stack.back()->children.back()->children[0]->str = *$3;
delete $3;
- } |
- attr TOK_SUPPLY1 TOK_ID ';' {
+ } opt_supply_wires ';' |
+ attr TOK_SUPPLY1 TOK_ID {
ast_stack.back()->children.push_back(new AstNode(AST_WIRE));
ast_stack.back()->children.back()->str = *$3;
append_attr(ast_stack.back()->children.back(), $1);
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(1, false, 1)));
ast_stack.back()->children.back()->children[0]->str = *$3;
delete $3;
+ } opt_supply_wires ';';
+
+opt_supply_wires:
+ /* empty */ |
+ opt_supply_wires ',' TOK_ID {
+ AstNode *wire_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-2)->clone();
+ AstNode *assign_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-1)->clone();
+ wire_node->str = *$3;
+ assign_node->children[0]->str = *$3;
+ ast_stack.back()->children.push_back(wire_node);
+ ast_stack.back()->children.push_back(assign_node);
+ delete $3;
};
wire_name_list:
@@ -689,7 +749,7 @@ wire_name:
};
assign_stmt:
- TOK_ASSIGN assign_expr_list ';';
+ TOK_ASSIGN delay assign_expr_list ';';
assign_expr_list:
assign_expr | assign_expr_list ',' assign_expr;
@@ -709,7 +769,7 @@ cell_stmt:
} cell_parameter_list_opt cell_list ';' {
delete astbuf1;
} |
- attr tok_prim_wrapper {
+ attr tok_prim_wrapper delay {
astbuf1 = new AstNode(AST_PRIMITIVE);
astbuf1->str = *$2;
append_attr(astbuf1, $1);
@@ -874,27 +934,34 @@ opt_label:
assert:
TOK_ASSERT '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $3));
+ } |
+ TOK_ASSUME '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3));
};
assert_property:
TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $4));
+ } |
+ TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
};
simple_behavioral_stmt:
- lvalue '=' expr {
- AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3);
+ lvalue '=' delay expr {
+ AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $4);
ast_stack.back()->children.push_back(node);
} |
- lvalue OP_LE expr {
- AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $3);
+ lvalue OP_LE delay expr {
+ AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $4);
ast_stack.back()->children.push_back(node);
};
// this production creates the obligatory if-else shift/reduce conflict
behavioral_stmt:
defattr | assert | wire_decl |
- simple_behavioral_stmt ';' |
+ non_opt_delay behavioral_stmt |
+ simple_behavioral_stmt ';' | ';' |
hierarchical_id attr {
AstNode *node = new AstNode(AST_TCALL);
node->str = *$1;
@@ -1008,10 +1075,6 @@ opt_synopsys_attr:
} |
/* empty */;
-behavioral_stmt_opt:
- behavioral_stmt |
- ';' ;
-
behavioral_stmt_list:
behavioral_stmt_list behavioral_stmt |
/* empty */;
@@ -1040,7 +1103,7 @@ case_item:
ast_stack.back()->children.push_back(block);
ast_stack.push_back(block);
case_type_stack.push_back(0);
- } behavioral_stmt_opt {
+ } behavioral_stmt {
case_type_stack.pop_back();
ast_stack.pop_back();
ast_stack.pop_back();
@@ -1211,7 +1274,7 @@ basic_expr:
if ($4->substr(0, 1) != "'")
frontend_verilog_yyerror("Syntax error.");
AstNode *bits = $2;
- AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
+ AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
if (val == NULL)
log_error("Value conversion failed: `%s'\n", $4->c_str());
$$ = new AstNode(AST_TO_BITS, bits, val);
@@ -1222,7 +1285,7 @@ basic_expr:
frontend_verilog_yyerror("Syntax error.");
AstNode *bits = new AstNode(AST_IDENTIFIER);
bits->str = *$1;
- AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
+ AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
if (val == NULL)
log_error("Value conversion failed: `%s'\n", $2->c_str());
$$ = new AstNode(AST_TO_BITS, bits, val);
@@ -1230,14 +1293,14 @@ basic_expr:
delete $2;
} |
TOK_CONST TOK_CONST {
- $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
+ $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
if ($$ == NULL || (*$2)[0] != '\'')
log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str());
delete $1;
delete $2;
} |
TOK_CONST {
- $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
+ $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
if ($$ == NULL)
log_error("Value conversion failed: `%s'\n", $1->c_str());
delete $1;
@@ -1278,10 +1341,15 @@ basic_expr:
'(' expr ')' {
$$ = $2;
} |
+ '(' expr ':' expr ':' expr ')' {
+ delete $2;
+ $$ = $4;
+ delete $6;
+ } |
'{' concat_list '}' {
$$ = $2;
} |
- '{' expr '{' expr '}' '}' {
+ '{' expr '{' concat_list '}' '}' {
$$ = new AstNode(AST_REPLICATE, $2, $4);
} |
'~' attr basic_expr %prec UNARY_OPS {
diff --git a/frontends/vhdl2verilog/vhdl2verilog.cc b/frontends/vhdl2verilog/vhdl2verilog.cc
index b408d621b..82ff7b502 100644
--- a/frontends/vhdl2verilog/vhdl2verilog.cc
+++ b/frontends/vhdl2verilog/vhdl2verilog.cc
@@ -20,14 +20,17 @@
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
-#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <dirent.h>
#include <errno.h>
#include <limits.h>
+#ifndef _WIN32
+# include <unistd.h>
+# include <dirent.h>
+#endif
+
YOSYS_NAMESPACE_BEGIN
struct Vhdl2verilogPass : public Pass {
@@ -120,11 +123,8 @@ struct Vhdl2verilogPass : public Pass {
if (top_entity.empty())
log_cmd_error("Missing -top option.\n");
- char tempdir_name[] = "/tmp/yosys-vhdl2verilog-XXXXXX";
- char *p = mkdtemp(tempdir_name);
- log("Using temp directory %s.\n", tempdir_name);
- if (p == NULL)
- log_error("For some reason mkdtemp() failed!\n");
+ std::string tempdir_name = make_temp_dir("/tmp/yosys-vhdl2verilog-XXXXXX");
+ log("Using temp directory %s.\n", tempdir_name.c_str());
if (!out_file.empty() && out_file[0] != '/') {
char pwd[PATH_MAX];
@@ -135,7 +135,7 @@ struct Vhdl2verilogPass : public Pass {
out_file = pwd + ("/" + out_file);
}
- FILE *f = fopen(stringf("%s/files.list", tempdir_name).c_str(), "wt");
+ FILE *f = fopen(stringf("%s/files.list", tempdir_name.c_str()).c_str(), "wt");
while (argidx < args.size()) {
std::string file = args[argidx++];
if (file.empty())
@@ -156,38 +156,25 @@ struct Vhdl2verilogPass : public Pass {
std::string command = "exec 2>&1; ";
if (!vhdl2verilog_dir.empty())
command += stringf("cd '%s'; . ./setup_env.sh; ", vhdl2verilog_dir.c_str());
- command += stringf("cd '%s'; vhdl2verilog -out '%s' -filelist files.list -top '%s'%s", tempdir_name,
+ command += stringf("cd '%s'; vhdl2verilog -out '%s' -filelist files.list -top '%s'%s", tempdir_name.c_str(),
out_file.empty() ? "vhdl2verilog_output.v" : out_file.c_str(), top_entity.c_str(), extra_opts.c_str());
log("Running '%s'..\n", command.c_str());
- errno = ENOMEM; // popen does not set errno if memory allocation fails, therefore set it by hand
- f = popen(command.c_str(), "r");
- if (f == NULL)
- log_error("Opening pipe to `%s' for reading failed: %s\n", command.c_str(), strerror(errno));
-
- char logbuf[1024];
- while (fgets(logbuf, 1024, f) != NULL)
- log("%s", logbuf);
-
- int ret = pclose(f);
- if (ret < 0)
- log_error("Closing pipe to `%s' failed: %s\n", command.c_str(), strerror(errno));
- if (WEXITSTATUS(ret) != 0)
- log_error("Execution of command \"%s\" failed: the shell returned %d\n", command.c_str(), WEXITSTATUS(ret));
+ int ret = run_command(command, [](const std::string &line) { log("%s", line.c_str()); });
+ if (ret != 0)
+ log_error("Execution of command \"%s\" failed: return code %d.\n", command.c_str(), ret);
if (out_file.empty()) {
std::ifstream ff;
- ff.open(stringf("%s/vhdl2verilog_output.v", tempdir_name).c_str());
+ ff.open(stringf("%s/vhdl2verilog_output.v", tempdir_name.c_str()).c_str());
if (ff.fail())
log_error("Can't open vhdl2verilog output file `vhdl2verilog_output.v'.\n");
- Frontend::frontend_call(design, &ff, stringf("%s/vhdl2verilog_output.v", tempdir_name), "verilog");
+ Frontend::frontend_call(design, &ff, stringf("%s/vhdl2verilog_output.v", tempdir_name.c_str()), "verilog");
}
- log_header("Removing temp directory `%s':\n", tempdir_name);
- if (system(stringf("rm -rf '%s'", tempdir_name).c_str()) != 0)
- log_error("Execution of \"rm -rf '%s'\" failed!\n", tempdir_name);
-
+ log_header("Removing temp directory `%s':\n", tempdir_name.c_str());
+ remove_directory(tempdir_name);
log_pop();
}
} Vhdl2verilogPass;