aboutsummaryrefslogtreecommitdiffstats
path: root/frontends
diff options
context:
space:
mode:
Diffstat (limited to 'frontends')
-rw-r--r--frontends/ast/ast.cc66
-rw-r--r--frontends/ast/ast.h27
-rw-r--r--frontends/ast/dpicall.cc4
-rw-r--r--frontends/ast/genrtlil.cc167
-rw-r--r--frontends/ast/simplify.cc496
-rw-r--r--frontends/blif/Makefile.inc3
-rw-r--r--frontends/blif/blifparse.cc485
-rw-r--r--frontends/blif/blifparse.h31
-rw-r--r--frontends/ilang/Makefile.inc6
-rw-r--r--frontends/ilang/ilang_frontend.cc6
-rw-r--r--frontends/ilang/ilang_frontend.h4
-rw-r--r--frontends/ilang/ilang_lexer.l6
-rw-r--r--frontends/ilang/ilang_parser.y30
-rw-r--r--frontends/liberty/liberty.cc8
-rw-r--r--frontends/verific/Makefile.inc5
-rw-r--r--frontends/verific/build_amd64.txt4
-rw-r--r--frontends/verific/verific.cc99
-rw-r--r--frontends/verilog/Makefile.inc6
-rw-r--r--frontends/verilog/const2ast.cc93
-rw-r--r--frontends/verilog/preproc.cc11
-rw-r--r--frontends/verilog/verilog_frontend.cc88
-rw-r--r--frontends/verilog/verilog_frontend.h7
-rw-r--r--frontends/verilog/verilog_lexer.l28
-rw-r--r--frontends/verilog/verilog_parser.y124
-rw-r--r--frontends/vhdl2verilog/vhdl2verilog.cc10
25 files changed, 1446 insertions, 368 deletions
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 68b3327f9..57de725d8 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -30,15 +30,6 @@
#include "libs/sha1/sha1.h"
#include "ast.h"
-#include <sstream>
-#include <stdarg.h>
-
-#if defined(__APPLE__)
-# include <cmath>
-#else
-# include <math.h>
-#endif
-
YOSYS_NAMESPACE_BEGIN
using namespace AST;
@@ -53,12 +44,12 @@ namespace AST {
// instanciate global variables (private API)
namespace AST_INTERNAL {
- bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
+ bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
AstNode *current_ast, *current_ast_mod;
std::map<std::string, AstNode*> current_scope;
const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
RTLIL::SigSpec ignoreThisSignalsInInitial;
- AstNode *current_top_block, *current_block, *current_block_child;
+ AstNode *current_always, *current_top_block, *current_block, *current_block_child;
AstModule *current_module;
}
@@ -90,6 +81,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_IDENTIFIER)
X(AST_PREFIX)
X(AST_ASSERT)
+ X(AST_ASSUME)
X(AST_FCALL)
X(AST_TO_BITS)
X(AST_TO_SIGNED)
@@ -132,6 +124,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_TERNARY)
X(AST_MEMRD)
X(AST_MEMWR)
+ X(AST_MEMINIT)
X(AST_TCALL)
X(AST_ASSIGN)
X(AST_CELL)
@@ -144,6 +137,8 @@ std::string AST::type2str(AstNodeType type)
X(AST_ASSIGN_LE)
X(AST_CASE)
X(AST_COND)
+ X(AST_CONDX)
+ X(AST_CONDZ)
X(AST_DEFAULT)
X(AST_FOR)
X(AST_WHILE)
@@ -156,6 +151,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_POSEDGE)
X(AST_NEGEDGE)
X(AST_EDGE)
+ X(AST_PACKAGE)
#undef X
default:
log_abort();
@@ -327,7 +323,7 @@ static std::string id2vl(std::string txt)
return txt;
}
-// dump AST node as verilog pseudo-code
+// dump AST node as Verilog pseudo-code
void AstNode::dumpVlog(FILE *f, std::string indent)
{
bool first = true;
@@ -499,7 +495,12 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
break;
case AST_CASE:
- fprintf(f, "%s" "case (", indent.c_str());
+ if (!children.empty() && children[0]->type == AST_CONDX)
+ fprintf(f, "%s" "casex (", indent.c_str());
+ else if (!children.empty() && children[0]->type == AST_CONDZ)
+ fprintf(f, "%s" "casez (", indent.c_str());
+ else
+ fprintf(f, "%s" "case (", indent.c_str());
children[0]->dumpVlog(f, "");
fprintf(f, ")\n");
for (size_t i = 1; i < children.size(); i++) {
@@ -510,6 +511,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
break;
case AST_COND:
+ case AST_CONDX:
+ case AST_CONDZ:
for (auto child : children) {
if (child->type == AST_BLOCK) {
fprintf(f, ":\n");
@@ -553,7 +556,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
children[1]->dumpVlog(f, "");
fprintf(f, "}}");
break;
-
+
if (0) { case AST_BIT_NOT: txt = "~"; }
if (0) { case AST_REDUCE_AND: txt = "&"; }
if (0) { case AST_REDUCE_OR: txt = "|"; }
@@ -697,7 +700,7 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
for (size_t i = 0; i < 32; i++) {
if (i < node->bits.size())
node->integer |= (node->bits[i] == RTLIL::S1) << i;
- else if (is_signed)
+ else if (is_signed && !node->bits.empty())
node->integer |= (node->bits.back() == RTLIL::S1) << i;
}
node->range_valid = true;
@@ -818,7 +821,7 @@ uint64_t AstNode::asInt(bool is_signed)
}
if (type == AST_REALVALUE)
- return realvalue;
+ return uint64_t(realvalue);
log_abort();
}
@@ -829,7 +832,7 @@ double AstNode::asReal(bool is_signed)
{
RTLIL::Const val(bits);
- bool is_negative = is_signed && val.bits.back() == RTLIL::State::S1;
+ bool is_negative = is_signed && !val.bits.empty() && val.bits.back() == RTLIL::State::S1;
if (is_negative)
val = const_neg(val, val, false, false, val.bits.size());
@@ -892,7 +895,7 @@ static AstModule* process_module(AstNode *ast, bool defer)
AstNode *ast_before_simplify = ast->clone();
if (flag_dump_ast1) {
- log("Dumping verilog AST before simplification:\n");
+ log("Dumping Verilog AST before simplification:\n");
ast->dumpAst(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
@@ -902,13 +905,13 @@ static AstModule* process_module(AstNode *ast, bool defer)
while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { }
if (flag_dump_ast2) {
- log("Dumping verilog AST after simplification:\n");
+ log("Dumping Verilog AST after simplification:\n");
ast->dumpAst(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
if (flag_dump_vlog) {
- log("Dumping verilog AST (as requested by dump_vlog option):\n");
+ log("Dumping Verilog AST (as requested by dump_vlog option):\n");
ast->dumpVlog(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
@@ -957,6 +960,7 @@ static AstModule* process_module(AstNode *ast, bool defer)
current_module->ast = ast_before_simplify;
current_module->nolatches = flag_nolatches;
+ current_module->nomeminit = flag_nomeminit;
current_module->nomem2reg = flag_nomem2reg;
current_module->mem2reg = flag_mem2reg;
current_module->lib = flag_lib;
@@ -968,13 +972,14 @@ static AstModule* process_module(AstNode *ast, bool defer)
}
// create AstModule instances for all modules in the AST tree and add them to 'design'
-void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire)
+void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire)
{
current_ast = ast;
flag_dump_ast1 = dump_ast1;
flag_dump_ast2 = dump_ast2;
flag_dump_vlog = dump_vlog;
flag_nolatches = nolatches;
+ flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
flag_lib = lib;
@@ -992,6 +997,14 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
for (auto n : global_decls)
(*it)->children.push_back(n->clone());
+ for (auto n : design->verilog_packages){
+ for (auto o : n->children) {
+ AstNode *cloned_node = o->clone();
+ cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1);
+ (*it)->children.push_back(cloned_node);
+ }
+ }
+
if (flag_icells && (*it)->str.substr(0, 2) == "\\$")
(*it)->str = (*it)->str.substr(1);
@@ -1009,6 +1022,9 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
design->add(process_module(*it, defer));
}
+ else if ((*it)->type == AST_PACKAGE){
+ design->verilog_packages.push_back((*it)->clone());
+ }
else
global_decls.push_back(*it);
}
@@ -1029,13 +1045,14 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R
if (stripped_name.substr(0, 9) == "$abstract")
stripped_name = stripped_name.substr(9);
- log_header("Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str());
+ log_header(design, "Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str());
current_ast = NULL;
flag_dump_ast1 = false;
flag_dump_ast2 = false;
flag_dump_vlog = false;
flag_nolatches = nolatches;
+ flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
flag_lib = lib;
@@ -1102,6 +1119,7 @@ RTLIL::Module *AstModule::clone() const
new_mod->ast = ast->clone();
new_mod->nolatches = nolatches;
+ new_mod->nomeminit = nomeminit;
new_mod->nomem2reg = nomem2reg;
new_mod->mem2reg = mem2reg;
new_mod->lib = lib;
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index 180646267..3dcd32bd4 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -64,6 +64,7 @@ namespace AST
AST_IDENTIFIER,
AST_PREFIX,
AST_ASSERT,
+ AST_ASSUME,
AST_FCALL,
AST_TO_BITS,
@@ -107,6 +108,7 @@ namespace AST
AST_TERNARY,
AST_MEMRD,
AST_MEMWR,
+ AST_MEMINIT,
AST_TCALL,
AST_ASSIGN,
@@ -120,6 +122,8 @@ namespace AST
AST_ASSIGN_LE,
AST_CASE,
AST_COND,
+ AST_CONDX,
+ AST_CONDZ,
AST_DEFAULT,
AST_FOR,
AST_WHILE,
@@ -133,7 +137,9 @@ namespace AST
AST_POSEDGE,
AST_NEGEDGE,
- AST_EDGE
+ AST_EDGE,
+
+ AST_PACKAGE
};
// convert an node type to a string (e.g. for debug output)
@@ -208,13 +214,14 @@ namespace AST
// simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc.
// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()
bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param);
- AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr);
+ AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init);
void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map);
void replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules);
void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
- void mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block);
+ bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block);
bool mem2reg_check(pool<AstNode*> &mem2reg_set);
+ void mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes);
void meminfo(int &mem_width, int &mem_size, int &addr_bits);
// additional functionality for evaluating constant functions
@@ -264,13 +271,13 @@ namespace AST
};
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
- void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);
+ void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);
// parametric modules are supported directly by the AST library
- // therfore we need our own derivate of RTLIL::Module with overloaded virtual functions
+ // therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
struct AstModule : RTLIL::Module {
AstNode *ast;
- bool nolatches, nomem2reg, mem2reg, lib, noopt, icells, autowire;
+ bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;
virtual ~AstModule();
virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters);
virtual RTLIL::Module *clone() const;
@@ -294,12 +301,12 @@ namespace AST
namespace AST_INTERNAL
{
// internal state variables
- extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
+ extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
extern AST::AstNode *current_ast, *current_ast_mod;
extern std::map<std::string, AST::AstNode*> current_scope;
extern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
extern RTLIL::SigSpec ignoreThisSignalsInInitial;
- extern AST::AstNode *current_top_block, *current_block, *current_block_child;
+ extern AST::AstNode *current_always, *current_top_block, *current_block, *current_block_child;
extern AST::AstModule *current_module;
struct ProcessGenerator;
}
diff --git a/frontends/ast/dpicall.cc b/frontends/ast/dpicall.cc
index e566d653d..e241142d3 100644
--- a/frontends/ast/dpicall.cc
+++ b/frontends/ast/dpicall.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 71248663e..3e359170b 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -176,13 +176,13 @@ struct AST_INTERNAL::ProcessGenerator
RTLIL::Process *proc;
RTLIL::SigSpec outputSignals;
- // This always points to the RTLIL::CaseRule beeing filled at the moment
+ // This always points to the RTLIL::CaseRule being filled at the moment
RTLIL::CaseRule *current_case;
// This map contains the replacement pattern to be used in the right hand side
// of an assignment. E.g. in the code "foo = bar; foo = func(foo);" the foo in the right
// hand side of the 2nd assignment needs to be replace with the temporary signal holding
- // the value assigned in the first assignment. So when the first assignement is processed
+ // the value assigned in the first assignment. So when the first assignment is processed
// the according information is appended to subst_rvalue_from and subst_rvalue_to.
stackmap<RTLIL::SigBit, RTLIL::SigBit> subst_rvalue_map;
@@ -192,7 +192,7 @@ struct AST_INTERNAL::ProcessGenerator
// signal that is used as input for the register that drives the signal foo.
stackmap<RTLIL::SigBit, RTLIL::SigBit> subst_lvalue_map;
- // The code here generates a number of temprorary signal for each output register. This
+ // The code here generates a number of temporary signal for each output register. This
// map helps generating nice numbered names for all this temporary signals.
std::map<RTLIL::Wire*, int> new_temp_count;
@@ -338,12 +338,14 @@ struct AST_INTERNAL::ProcessGenerator
case AST_CASE:
for (auto child : ast->children)
if (child != ast->children[0]) {
- log_assert(child->type == AST_COND);
+ log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ);
collect_lvalues(reg, child, type_eq, type_le, false);
}
break;
case AST_COND:
+ case AST_CONDX:
+ case AST_CONDZ:
case AST_ALWAYS:
case AST_INITIAL:
for (auto child : ast->children)
@@ -379,7 +381,7 @@ struct AST_INTERNAL::ProcessGenerator
// e.g. when the last statement in the code "a = 23; if (b) a = 42; a = 0;" is processed this
// function is called to clean up the first two assignments as they are overwritten by
// the third assignment.
- void removeSignalFromCaseTree(const std::set<RTLIL::SigBit> &pattern, RTLIL::CaseRule *cs)
+ void removeSignalFromCaseTree(const RTLIL::SigSpec &pattern, RTLIL::CaseRule *cs)
{
for (auto it = cs->actions.begin(); it != cs->actions.end(); it++)
it->first.remove2(pattern, &it->second);
@@ -427,6 +429,17 @@ struct AST_INTERNAL::ProcessGenerator
{
RTLIL::SigSpec unmapped_lvalue = ast->children[0]->genRTLIL(), lvalue = unmapped_lvalue;
RTLIL::SigSpec rvalue = ast->children[1]->genWidthRTLIL(lvalue.size(), &subst_rvalue_map.stdmap());
+
+ pool<SigBit> lvalue_sigbits;
+ for (int i = 0; i < GetSize(lvalue); i++) {
+ if (lvalue_sigbits.count(lvalue[i]) > 0) {
+ unmapped_lvalue.remove(i);
+ lvalue.remove(i);
+ rvalue.remove(i--);
+ } else
+ lvalue_sigbits.insert(lvalue[i]);
+ }
+
lvalue.replace(subst_lvalue_map.stdmap());
if (ast->type == AST_ASSIGN_EQ) {
@@ -434,7 +447,7 @@ struct AST_INTERNAL::ProcessGenerator
subst_rvalue_map.set(unmapped_lvalue[i], rvalue[i]);
}
- removeSignalFromCaseTree(lvalue.to_sigbit_set(), current_case);
+ removeSignalFromCaseTree(lvalue, current_case);
remove_unwanted_lvalue_bits(lvalue, rvalue);
current_case->actions.push_back(RTLIL::SigSig(lvalue, rvalue));
}
@@ -467,7 +480,7 @@ struct AST_INTERNAL::ProcessGenerator
{
if (child == ast->children[0])
continue;
- log_assert(child->type == AST_COND);
+ log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ);
subst_lvalue_map.save();
subst_rvalue_map.save();
@@ -511,7 +524,7 @@ struct AST_INTERNAL::ProcessGenerator
subst_rvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]);
this_case_eq_lvalue.replace(subst_lvalue_map.stdmap());
- removeSignalFromCaseTree(this_case_eq_lvalue.to_sigbit_set(), current_case);
+ removeSignalFromCaseTree(this_case_eq_lvalue, current_case);
addChunkActions(current_case->actions, this_case_eq_lvalue, this_case_eq_ltemp);
}
break;
@@ -520,6 +533,11 @@ struct AST_INTERNAL::ProcessGenerator
log_error("Found wire declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum);
break;
+ case AST_PARAMETER:
+ case AST_LOCALPARAM:
+ log_error("Found parameter declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum);
+ break;
+
case AST_TCALL:
case AST_FOR:
break;
@@ -547,14 +565,14 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
switch (type)
{
case AST_CONSTANT:
- width_hint = std::max(width_hint, int(bits.size()));
+ width_hint = max(width_hint, int(bits.size()));
if (!is_signed)
sign_hint = false;
break;
case AST_REALVALUE:
*found_real = true;
- width_hint = std::max(width_hint, 32);
+ width_hint = max(width_hint, 32);
break;
case AST_IDENTIFIER:
@@ -567,9 +585,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (id_ast->children.size() > 1 && id_ast->children[1]->range_valid) {
this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1;
} else
- if (id_ast->children[0]->type == AST_CONSTANT) {
+ if (id_ast->children[0]->type != AST_CONSTANT)
+ while (id_ast->simplify(true, false, false, 1, -1, false, true)) { }
+ if (id_ast->children[0]->type == AST_CONSTANT)
this_width = id_ast->children[0]->bits.size();
- } else
+ else
log_error("Failed to detect width for parameter %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
if (children.size() != 0)
range = children[0];
@@ -582,7 +602,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
// log("---\n");
// id_ast->dumpAst(NULL, "decl> ");
// dumpAst(NULL, "ref> ");
- log_error("Failed to detect with of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_error("Failed to detect width of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
}
} else {
this_width = id_ast->range_left - id_ast->range_right + 1;
@@ -593,7 +613,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
this_width = 32;
} else if (id_ast->type == AST_MEMORY) {
if (!id_ast->children[0]->range_valid)
- log_error("Failed to detect with of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
} else
log_error("Failed to detect width for identifier %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
@@ -615,7 +635,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
this_width = range->range_left - range->range_right + 1;
sign_hint = false;
}
- width_hint = std::max(width_hint, this_width);
+ width_hint = max(width_hint, this_width);
if (!id_ast->is_signed)
sign_hint = false;
break;
@@ -625,7 +645,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (children[0]->type != AST_CONSTANT)
log_error("Left operand of tobits expression is not constant at %s:%d!\n", filename.c_str(), linenum);
children[1]->detectSignWidthWorker(sub_width_hint, sign_hint);
- width_hint = std::max(width_hint, children[0]->bitsAsConst().as_int());
+ width_hint = max(width_hint, children[0]->bitsAsConst().as_int());
break;
case AST_TO_SIGNED:
@@ -644,7 +664,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
child->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
this_width += sub_width_hint;
}
- width_hint = std::max(width_hint, this_width);
+ width_hint = max(width_hint, this_width);
sign_hint = false;
break;
@@ -653,7 +673,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (children[0]->type != AST_CONSTANT)
log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum);
children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
- width_hint = std::max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint);
+ width_hint = max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint);
sign_hint = false;
break;
@@ -676,7 +696,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_REDUCE_XOR:
case AST_REDUCE_XNOR:
case AST_REDUCE_BOOL:
- width_hint = std::max(width_hint, 1);
+ width_hint = max(width_hint, 1);
sign_hint = false;
break;
@@ -696,7 +716,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_NEX:
case AST_GE:
case AST_GT:
- width_hint = std::max(width_hint, 1);
+ width_hint = max(width_hint, 1);
sign_hint = false;
break;
@@ -712,7 +732,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_LOGIC_AND:
case AST_LOGIC_OR:
case AST_LOGIC_NOT:
- width_hint = std::max(width_hint, 1);
+ width_hint = max(width_hint, 1);
sign_hint = false;
break;
@@ -725,9 +745,9 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (!id2ast->is_signed)
sign_hint = false;
if (!id2ast->children[0]->range_valid)
- log_error("Failed to detect with of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
this_width = id2ast->children[0]->range_left - id2ast->children[0]->range_right + 1;
- width_hint = std::max(width_hint, this_width);
+ width_hint = max(width_hint, this_width);
break;
// everything should have been handled above -> print error if not.
@@ -764,7 +784,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// in the following big switch() statement there are some uses of
// Clifford's Device (http://www.clifford.at/cfun/cliffdev/). In this
// cases this variable is used to hold the type of the cell that should
- // be instanciated for this type of AST node.
+ // be instantiated for this type of AST node.
std::string type_name;
current_filename = filename;
@@ -773,7 +793,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
switch (type)
{
// simply ignore this nodes.
- // they are eighter leftovers from simplify() or are referenced by other nodes
+ // they are either leftovers from simplify() or are referenced by other nodes
// and are only accessed here thru this references
case AST_TASK:
case AST_FUNCTION:
@@ -786,6 +806,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_GENBLOCK:
case AST_GENIF:
case AST_GENCASE:
+ case AST_PACKAGE:
break;
// remember the parameter, needed for example in techmap
@@ -1052,7 +1073,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
detectSignWidth(width_hint, sign_hint);
RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint);
RTLIL::SigSpec right = children[1]->genRTLIL(width_hint, sign_hint);
- int width = std::max(left.size(), right.size());
+ int width = max(left.size(), right.size());
if (width_hint > 0)
width = width_hint;
is_signed = children[0]->is_signed && children[1]->is_signed;
@@ -1066,16 +1087,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (0) { case AST_REDUCE_XNOR: type_name = "$reduce_xnor"; }
{
RTLIL::SigSpec arg = children[0]->genRTLIL();
- RTLIL::SigSpec sig = uniop2rtlil(this, type_name, std::max(width_hint, 1), arg);
+ RTLIL::SigSpec sig = uniop2rtlil(this, type_name, max(width_hint, 1), arg);
return sig;
}
// generate cells for unary operations: $reduce_bool
- // (this is actually just an $reduce_or, but for clearity a different cell type is used)
+ // (this is actually just an $reduce_or, but for clarity a different cell type is used)
if (0) { case AST_REDUCE_BOOL: type_name = "$reduce_bool"; }
{
RTLIL::SigSpec arg = children[0]->genRTLIL();
- RTLIL::SigSpec sig = arg.size() > 1 ? uniop2rtlil(this, type_name, std::max(width_hint, 1), arg) : arg;
+ RTLIL::SigSpec sig = arg.size() > 1 ? uniop2rtlil(this, type_name, max(width_hint, 1), arg) : arg;
return sig;
}
@@ -1121,7 +1142,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (0) { case AST_GE: type_name = "$ge"; }
if (0) { case AST_GT: type_name = "$gt"; }
{
- int width = std::max(width_hint, 1);
+ int width = max(width_hint, 1);
width_hint = -1, sign_hint = true;
children[0]->detectSignWidthWorker(width_hint, sign_hint);
children[1]->detectSignWidthWorker(width_hint, sign_hint);
@@ -1143,7 +1164,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint);
RTLIL::SigSpec right = children[1]->genRTLIL(width_hint, sign_hint);
#if 0
- int width = std::max(left.size(), right.size());
+ int width = max(left.size(), right.size());
if (width > width_hint && width_hint > 0)
width = width_hint;
if (width < width_hint) {
@@ -1152,10 +1173,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (type == AST_SUB && (!children[0]->is_signed || !children[1]->is_signed))
width = width_hint;
if (type == AST_MUL)
- width = std::min(left.size() + right.size(), width_hint);
+ width = min(left.size() + right.size(), width_hint);
}
#else
- int width = std::max(std::max(left.size(), right.size()), width_hint);
+ int width = max(max(left.size(), right.size()), width_hint);
#endif
is_signed = children[0]->is_signed && children[1]->is_signed;
return binop2rtlil(this, type_name, width, left, right);
@@ -1167,14 +1188,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
{
RTLIL::SigSpec left = children[0]->genRTLIL();
RTLIL::SigSpec right = children[1]->genRTLIL();
- return binop2rtlil(this, type_name, std::max(width_hint, 1), left, right);
+ return binop2rtlil(this, type_name, max(width_hint, 1), left, right);
}
// generate cells for unary operations: $logic_not
case AST_LOGIC_NOT:
{
RTLIL::SigSpec arg = children[0]->genRTLIL();
- return uniop2rtlil(this, "$logic_not", std::max(width_hint, 1), arg);
+ return uniop2rtlil(this, "$logic_not", max(width_hint, 1), arg);
}
// generate multiplexer for ternary operator (aka ?:-operator)
@@ -1190,7 +1211,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (cond.size() > 1)
cond = uniop2rtlil(this, "$reduce_bool", 1, cond, false);
- int width = std::max(val1.size(), val2.size());
+ int width = max(val1.size(), val2.size());
is_signed = children[1]->is_signed && children[2]->is_signed;
widthExtend(this, val1, width, is_signed);
widthExtend(this, val2, width, is_signed);
@@ -1214,11 +1235,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_DATA", current_module->memories[str]->width);
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
- int addr_bits = 1;
- while ((1 << addr_bits) < current_module->memories[str]->size)
- addr_bits++;
+ int mem_width, mem_size, addr_bits;
+ id2ast->meminfo(mem_width, mem_size, addr_bits);
cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
+ cell->setPort("\\EN", RTLIL::SigSpec(RTLIL::State::Sx, 1));
cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits));
cell->setPort("\\DATA", RTLIL::SigSpec(wire));
@@ -1235,28 +1256,38 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// generate $memwr cells for memory write ports
case AST_MEMWR:
+ case AST_MEMINIT:
{
std::stringstream sstr;
- sstr << "$memwr$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
+ sstr << (type == AST_MEMWR ? "$memwr$" : "$meminit$") << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
- RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$memwr");
+ RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_MEMWR ? "$memwr" : "$meminit");
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
- int addr_bits = 1;
- while ((1 << addr_bits) < current_module->memories[str]->size)
- addr_bits++;
+ int mem_width, mem_size, addr_bits;
+ id2ast->meminfo(mem_width, mem_size, addr_bits);
+
+ int num_words = 1;
+ if (type == AST_MEMINIT) {
+ if (children[2]->type != AST_CONSTANT)
+ log_error("Memory init with non-constant word count at %s:%d!\n", filename.c_str(), linenum);
+ num_words = int(children[2]->asInt(false));
+ cell->parameters["\\WORDS"] = RTLIL::Const(num_words);
+ }
- cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits));
- cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width));
- cell->setPort("\\EN", children[2]->genRTLIL());
+ cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width * num_words));
cell->parameters["\\MEMID"] = RTLIL::Const(str);
cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits);
cell->parameters["\\WIDTH"] = RTLIL::Const(current_module->memories[str]->width);
- cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0);
- cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0);
+ if (type == AST_MEMWR) {
+ cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
+ cell->setPort("\\EN", children[2]->genRTLIL());
+ cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0);
+ cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0);
+ }
cell->parameters["\\PRIORITY"] = RTLIL::Const(autoidx-1);
}
@@ -1264,19 +1295,22 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// generate $assert cells
case AST_ASSERT:
+ case AST_ASSUME:
{
log_assert(children.size() == 2);
RTLIL::SigSpec check = children[0]->genRTLIL();
- log_assert(check.size() == 1);
+ if (GetSize(check) != 1)
+ check = current_module->ReduceBool(NEW_ID, check);
RTLIL::SigSpec en = children[1]->genRTLIL();
- log_assert(en.size() == 1);
+ if (GetSize(en) != 1)
+ en = current_module->ReduceBool(NEW_ID, en);
std::stringstream sstr;
- sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++);
+ sstr << (type == AST_ASSERT ? "$assert$" : "$assume$") << filename << ":" << linenum << "$" << (autoidx++);
- RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$assert");
+ RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_ASSERT ? "$assert" : "$assume");
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
for (auto &attr : attributes) {
@@ -1335,16 +1369,19 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
continue;
}
if (child->type == AST_PARASET) {
- if (child->children[0]->type != AST_CONSTANT)
- log_error("Parameter `%s' with non-constant value at %s:%d!\n",
- child->str.c_str(), filename.c_str(), linenum);
- if (child->str.size() == 0) {
- char buf[100];
- snprintf(buf, 100, "$%d", ++para_counter);
- cell->parameters[buf] = child->children[0]->asParaConst();
- } else {
- cell->parameters[child->str] = child->children[0]->asParaConst();
+ IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
+ if (child->children[0]->type == AST_REALVALUE) {
+ log_warning("Replacing floating point parameter %s.%s = %f with string at %s:%d.\n",
+ log_id(cell), log_id(paraname), child->children[0]->realvalue,
+ filename.c_str(), linenum);
+ auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue));
+ strnode->cloneInto(child->children[0]);
+ delete strnode;
}
+ if (child->children[0]->type != AST_CONSTANT)
+ log_error("Parameter %s.%s with non-constant value at %s:%d!\n",
+ log_id(cell), log_id(paraname), filename.c_str(), linenum);
+ cell->parameters[paraname] = child->children[0]->asParaConst();
continue;
}
if (child->type == AST_ARGUMENT) {
@@ -1398,7 +1435,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
// this is a wrapper for AstNode::genRTLIL() when a specific signal width is requested and/or
-// signals must be substituted before beeing used as input values (used by ProcessGenerator)
+// signals must be substituted before being used as input values (used by ProcessGenerator)
// note that this is using some global variables to communicate this special settings to AstNode::genRTLIL().
RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr)
{
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index e9750eba6..c09b912c2 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -41,7 +41,7 @@ YOSYS_NAMESPACE_BEGIN
using namespace AST;
using namespace AST_INTERNAL;
-// convert the AST into a simpler AST that has all parameters subsitited by their
+// convert the AST into a simpler AST that has all parameters substituted by their
// values, unrolled for-loops, expanded generate blocks, etc. when this function
// is done with an AST it can be converted into RTLIL using genRTLIL().
//
@@ -49,15 +49,24 @@ using namespace AST_INTERNAL;
// nodes that link to a different node using names and lexical scoping.
bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)
{
+ static int recursion_counter = 0;
+ static pair<string, int> last_blocking_assignment_warn;
+ static bool deep_recursion_warning = false;
+
+ if (recursion_counter++ == 1000 && deep_recursion_warning) {
+ log_warning("Deep recursion in AST simplifier.\nDoes this design contain insanely long expressions?\n");
+ deep_recursion_warning = false;
+ }
+
AstNode *newNode = NULL;
bool did_something = false;
- static pair<string, int> last_blocking_assignment_warn;
#if 0
log("-------------\n");
+ log("AST simplify[%d] depth %d at %s:%d,\n", stage, recursion_counter, filename.c_str(), linenum);
log("const_fold=%d, at_zero=%d, in_lvalue=%d, stage=%d, width_hint=%d, sign_hint=%d, in_param=%d\n",
int(const_fold), int(at_zero), int(in_lvalue), int(stage), int(width_hint), int(sign_hint), int(in_param));
- dumpAst(NULL, "> ");
+ // dumpAst(NULL, "> ");
#endif
if (stage == 0)
@@ -65,6 +74,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
log_assert(type == AST_MODULE);
last_blocking_assignment_warn = pair<string, int>();
+ deep_recursion_warning = true;
while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { }
if (!flag_nomem2reg && !get_bool_attribute("\\nomem2reg"))
@@ -79,11 +89,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
AstNode *mem = it.first;
uint32_t memflags = it.second;
+ bool this_nomeminit = flag_nomeminit;
log_assert((memflags & ~0x00ffff00) == 0);
if (mem->get_bool_attribute("\\nomem2reg"))
continue;
+ if (mem->get_bool_attribute("\\nomeminit") || get_bool_attribute("\\nomeminit"))
+ this_nomeminit = true;
+
if (memflags & AstNode::MEM2REG_FL_FORCED)
goto silent_activate;
@@ -93,7 +107,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (memflags & AstNode::MEM2REG_FL_SET_ASYNC)
goto verbose_activate;
- if ((memflags & AstNode::MEM2REG_FL_SET_INIT) && (memflags & AstNode::MEM2REG_FL_SET_ELSE))
+ if ((memflags & AstNode::MEM2REG_FL_SET_INIT) && (memflags & AstNode::MEM2REG_FL_SET_ELSE) && this_nomeminit)
goto verbose_activate;
if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS)
@@ -134,17 +148,17 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
- mem2reg_as_needed_pass2(mem2reg_set, this, NULL);
+ while (mem2reg_as_needed_pass2(mem2reg_set, this, NULL)) { }
- for (size_t i = 0; i < children.size(); i++) {
- if (mem2reg_set.count(children[i]) > 0) {
- delete children[i];
- children.erase(children.begin() + (i--));
- }
- }
+ vector<AstNode*> delnodes;
+ mem2reg_remove(mem2reg_set, delnodes);
+
+ for (auto node : delnodes)
+ delete node;
}
while (simplify(const_fold, at_zero, in_lvalue, 2, width_hint, sign_hint, in_param)) { }
+ recursion_counter--;
return false;
}
@@ -152,18 +166,144 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
set_line_num(linenum);
// we do not look inside a task or function
- // (but as soon as a task of function is instanciated we process the generated AST as usual)
- if (type == AST_FUNCTION || type == AST_TASK)
+ // (but as soon as a task or function is instantiated we process the generated AST as usual)
+ if (type == AST_FUNCTION || type == AST_TASK) {
+ recursion_counter--;
return false;
+ }
- // deactivate all calls to non-synthesis system taks
- if ((type == AST_FCALL || type == AST_TCALL) && (str == "$display" || str == "$strobe" || str == "$monitor" || str == "$time" || str == "$stop" || str == "$finish" ||
+ // deactivate all calls to non-synthesis system tasks
+ // note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list
+ if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" ||
str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) {
log_warning("Ignoring call to system %s %s at %s:%d.\n", type == AST_FCALL ? "function" : "task", str.c_str(), filename.c_str(), linenum);
delete_children();
str = std::string();
}
+ if ((type == AST_TCALL) && (str == "$display" || str == "$write") && (!current_always || current_always->type != AST_INITIAL)) {
+ log_warning("System task `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ delete_children();
+ str = std::string();
+ }
+
+ // print messages if this a call to $display() or $write()
+ // This code implements only a small subset of Verilog-2005 $display() format specifiers,
+ // but should be good enough for most uses
+ if ((type == AST_TCALL) && ((str == "$display") || (str == "$write")))
+ {
+ int nargs = GetSize(children);
+ if (nargs < 1)
+ log_error("System task `%s' got %d arguments, expected >= 1 at %s:%d.\n",
+ str.c_str(), int(children.size()), filename.c_str(), linenum);
+
+ // First argument is the format string
+ AstNode *node_string = children[0];
+ while (node_string->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ if (node_string->type != AST_CONSTANT)
+ log_error("Failed to evaluate system task `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ std::string sformat = node_string->bitsAsConst().decode_string();
+
+ // Other arguments are placeholders. Process the string as we go through it
+ std::string sout;
+ int next_arg = 1;
+ for (size_t i = 0; i < sformat.length(); i++)
+ {
+ // format specifier
+ if (sformat[i] == '%')
+ {
+ // If there's no next character, that's a problem
+ if (i+1 >= sformat.length())
+ log_error("System task `%s' called with `%%' at end of string at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+
+ char cformat = sformat[++i];
+
+ // %% is special, does not need a matching argument
+ if (cformat == '%')
+ {
+ sout += '%';
+ continue;
+ }
+
+ // Simplify the argument
+ AstNode *node_arg = nullptr;
+
+ // Everything from here on depends on the format specifier
+ switch (cformat)
+ {
+ case 's':
+ case 'S':
+ case 'd':
+ case 'D':
+ case 'x':
+ case 'X':
+ if (next_arg >= GetSize(children))
+ log_error("Missing argument for %%%c format specifier in system task `%s' at %s:%d.\n",
+ cformat, str.c_str(), filename.c_str(), linenum);
+
+ node_arg = children[next_arg++];
+ while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ if (node_arg->type != AST_CONSTANT)
+ log_error("Failed to evaluate system task `%s' with non-constant argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ break;
+
+ case 'm':
+ case 'M':
+ break;
+
+ default:
+ log_error("System task `%s' called with invalid/unsupported format specifier at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ break;
+ }
+
+ switch (cformat)
+ {
+ case 's':
+ case 'S':
+ sout += node_arg->bitsAsConst().decode_string();
+ break;
+
+ case 'd':
+ case 'D':
+ {
+ char tmp[128];
+ snprintf(tmp, sizeof(tmp), "%d", node_arg->bitsAsConst().as_int());
+ sout += tmp;
+ }
+ break;
+
+ case 'x':
+ case 'X':
+ {
+ char tmp[128];
+ snprintf(tmp, sizeof(tmp), "%x", node_arg->bitsAsConst().as_int());
+ sout += tmp;
+ }
+ break;
+
+ case 'm':
+ case 'M':
+ sout += log_id(current_module->name);
+ break;
+
+ default:
+ log_abort();
+ }
+ }
+
+ // not a format specifier
+ else
+ sout += sformat[i];
+ }
+
+ // Finally, print the message (only include a \n for $display, not for $write)
+ log("%s", sout.c_str());
+ if (str == "$display")
+ log("\n");
+ delete_children();
+ str = std::string();
+ }
+
// activate const folding if this is anything that must be evaluated statically (ranges, parameters, attributes, etc.)
if (type == AST_WIRE || type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_RANGE || type == AST_PREFIX)
const_fold = true;
@@ -255,6 +395,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
auto backup_current_block = current_block;
auto backup_current_block_child = current_block_child;
auto backup_current_top_block = current_top_block;
+ auto backup_current_always = current_always;
+
+ if (type == AST_ALWAYS || type == AST_INITIAL)
+ current_always = this;
int backup_width_hint = width_hint;
bool backup_sign_hint = sign_hint;
@@ -277,7 +421,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
did_something = true;
children[0]->detectSignWidth(backup_width_hint, backup_sign_hint);
children[1]->detectSignWidth(width_hint, sign_hint);
- width_hint = std::max(width_hint, backup_width_hint);
+ width_hint = max(width_hint, backup_width_hint);
child_0_is_self_determined = true;
break;
@@ -291,7 +435,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
did_something = true;
if (!children[1]->range_valid)
log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum);
- width_hint = std::max(width_hint, children[1]->range_left - children[1]->range_right + 1);
+ width_hint = max(width_hint, children[1]->range_left - children[1]->range_right + 1);
}
break;
@@ -362,7 +506,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
detect_width_simple = true;
child_0_is_self_determined = true;
break;
-
+
case AST_MEMRD:
detect_width_simple = true;
children_are_self_determined = true;
@@ -395,6 +539,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
+ if (type == AST_CONDX && children.size() > 0 && children.at(0)->type == AST_CONSTANT) {
+ for (auto &bit : children.at(0)->bits)
+ if (bit == State::Sz || bit == State::Sx)
+ bit = State::Sa;
+ }
+
+ if (type == AST_CONDZ && children.size() > 0 && children.at(0)->type == AST_CONSTANT) {
+ for (auto &bit : children.at(0)->bits)
+ if (bit == State::Sz)
+ bit = State::Sa;
+ }
+
if (const_fold && type == AST_CASE)
{
while (children[0]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { }
@@ -403,7 +559,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
new_children.push_back(children[0]);
for (int i = 1; i < GetSize(children); i++) {
AstNode *child = children[i];
- log_assert(child->type == AST_COND);
+ log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ);
for (auto v : child->children) {
if (v->type == AST_DEFAULT)
goto keep_const_cond;
@@ -494,6 +650,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
current_block = backup_current_block;
current_block_child = backup_current_block_child;
current_top_block = backup_current_top_block;
+ current_always = backup_current_always;
for (auto it = backup_scope.begin(); it != backup_scope.end(); it++) {
if (it->second == NULL)
@@ -530,6 +687,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// dumpAst(NULL, "> ");
log_error("Index in generate block prefix syntax at %s:%d is not constant!\n", filename.c_str(), linenum);
}
+ if (children[1]->type == AST_PREFIX)
+ children[1]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param);
log_assert(children[1]->type == AST_IDENTIFIER);
newNode = children[1]->clone();
const char *second_part = children[1]->str.c_str();
@@ -609,8 +768,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
for (auto range : children[1]->children) {
if (!range->range_valid)
log_error("Non-constant range on memory decl at %s:%d.\n", filename.c_str(), linenum);
- multirange_dimensions.push_back(std::min(range->range_left, range->range_right));
- multirange_dimensions.push_back(std::max(range->range_left, range->range_right) - std::min(range->range_left, range->range_right) + 1);
+ multirange_dimensions.push_back(min(range->range_left, range->range_right));
+ multirange_dimensions.push_back(max(range->range_left, range->range_right) - min(range->range_left, range->range_right) + 1);
total_size *= multirange_dimensions.back();
}
delete children[1];
@@ -636,10 +795,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (i == 0)
index_expr = new_index_expr;
else
- index_expr = new AstNode(AST_ADD, new AstNode(AST_MUL, index_expr, AstNode::mkconst_int(id2ast->multirange_dimensions[2*i-1], true)), new_index_expr);
+ index_expr = new AstNode(AST_ADD, new AstNode(AST_MUL, index_expr, AstNode::mkconst_int(id2ast->multirange_dimensions[2*i+1], true)), new_index_expr);
}
- for (int i = GetSize(id2ast->multirange_dimensions)/1; i < GetSize(children[0]->children); i++)
+ for (int i = GetSize(id2ast->multirange_dimensions)/2; i < GetSize(children[0]->children); i++)
children.push_back(children[0]->children[i]->clone());
delete children[0];
@@ -656,7 +815,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (children.size() > 1 && children[1]->type == AST_RANGE) {
if (!children[1]->range_valid)
log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum);
- int width = children[1]->range_left - children[1]->range_right + 1;
+ int width = std::abs(children[1]->range_left - children[1]->range_right) + 1;
if (children[0]->type == AST_REALVALUE) {
RTLIL::Const constvalue = children[0]->realAsConst(width);
log_warning("converting real value %e to binary %s at %s:%d.\n",
@@ -670,7 +829,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
RTLIL::SigSpec sig(children[0]->bits);
sig.extend_u0(width, children[0]->is_signed);
AstNode *old_child_0 = children[0];
- children[0] = mkconst_bits(sig.as_const().bits, children[0]->is_signed);
+ children[0] = mkconst_bits(sig.as_const().bits, is_signed);
delete old_child_0;
}
children[0]->is_signed = is_signed;
@@ -803,7 +962,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// eval 1st expression
AstNode *varbuf = init_ast->children[1]->clone();
- while (varbuf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ while (varbuf->simplify(true, false, false, stage, 32, true, false)) { }
if (varbuf->type != AST_CONSTANT)
log_error("Right hand side of 1st expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
@@ -866,7 +1025,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// eval 3rd expression
buf = next_ast->children[1]->clone();
- while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ while (buf->simplify(true, false, false, stage, 32, true, false)) { }
if (buf->type != AST_CONSTANT)
log_error("Right hand side of 3rd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
@@ -889,7 +1048,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
std::vector<AstNode*> new_children;
for (size_t i = 0; i < children.size(); i++)
- if (children[i]->type == AST_WIRE) {
+ if (children[i]->type == AST_WIRE || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM) {
children[i]->simplify(false, false, false, stage, -1, false, false);
current_ast_mod->children.push_back(children[i]);
current_scope[children[i]->str] = children[i];
@@ -977,7 +1136,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
AstNode *selected_case = NULL;
for (size_t i = 1; i < children.size(); i++)
{
- log_assert(children.at(i)->type == AST_COND);
+ log_assert(children.at(i)->type == AST_COND || children.at(i)->type == AST_CONDX || children.at(i)->type == AST_CONDZ);
AstNode *this_genblock = NULL;
for (auto child : children.at(i)->children) {
@@ -1045,7 +1204,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
log_error("Non-constant array range on cell array at %s:%d.\n", filename.c_str(), linenum);
newNode = new AstNode(AST_GENBLOCK);
- int num = std::max(children.at(0)->range_left, children.at(0)->range_right) - std::min(children.at(0)->range_left, children.at(0)->range_right) + 1;
+ int num = max(children.at(0)->range_left, children.at(0)->range_right) - min(children.at(0)->range_left, children.at(0)->range_right) + 1;
for (int i = 0; i < num; i++) {
int idx = children.at(0)->range_left > children.at(0)->range_right ? children.at(0)->range_right + i : children.at(0)->range_right - i;
@@ -1063,7 +1222,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
goto apply_newNode;
}
- // replace primitives with assignmens
+ // replace primitives with assignments
if (type == AST_PRIMITIVE)
{
if (children.size() < 2)
@@ -1189,7 +1348,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
skip_dynamic_range_lvalue_expansion:;
- if (stage > 1 && type == AST_ASSERT && current_block != NULL)
+ if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && current_block != NULL)
{
std::stringstream sstr;
sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++);
@@ -1233,7 +1392,7 @@ skip_dynamic_range_lvalue_expansion:;
newNode->children.push_back(assign_check);
newNode->children.push_back(assign_en);
- AstNode *assertnode = new AstNode(AST_ASSERT);
+ AstNode *assertnode = new AstNode(type);
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
assertnode->children[0]->str = id_check;
@@ -1244,16 +1403,15 @@ skip_dynamic_range_lvalue_expansion:;
goto apply_newNode;
}
- if (stage > 1 && type == AST_ASSERT && children.size() == 1)
+ if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && children.size() == 1)
{
- children[0] = new AstNode(AST_REDUCE_BOOL, children[0]->clone());
children.push_back(mkconst_int(1, false, 1));
did_something = true;
}
// found right-hand side identifier for memory -> replace with memory read port
if (stage > 1 && type == AST_IDENTIFIER && id2ast != NULL && id2ast->type == AST_MEMORY && !in_lvalue &&
- children[0]->type == AST_RANGE && children[0]->children.size() == 1) {
+ children.size() == 1 && children[0]->type == AST_RANGE && children[0]->children.size() == 1) {
newNode = new AstNode(AST_MEMRD, children[0]->children[0]->clone());
newNode->str = str;
newNode->id2ast = id2ast;
@@ -1293,11 +1451,14 @@ skip_dynamic_range_lvalue_expansion:;
current_scope[wire_data->str] = wire_data;
while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
- AstNode *wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
- wire_en->str = id_en;
- current_ast_mod->children.push_back(wire_en);
- current_scope[wire_en->str] = wire_en;
- while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
+ AstNode *wire_en = nullptr;
+ if (current_always->type != AST_INITIAL) {
+ wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
+ wire_en->str = id_en;
+ current_ast_mod->children.push_back(wire_en);
+ current_scope[wire_en->str] = wire_en;
+ while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
+ }
std::vector<RTLIL::State> x_bits_addr, x_bits_data, set_bits_en;
for (int i = 0; i < addr_bits; i++)
@@ -1313,13 +1474,17 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false));
assign_data->children[0]->str = id_data;
- AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width));
- assign_en->children[0]->str = id_en;
+ AstNode *assign_en = nullptr;
+ if (current_always->type != AST_INITIAL) {
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width));
+ assign_en->children[0]->str = id_en;
+ }
AstNode *default_signals = new AstNode(AST_BLOCK);
default_signals->children.push_back(assign_addr);
default_signals->children.push_back(assign_data);
- default_signals->children.push_back(assign_en);
+ if (current_always->type != AST_INITIAL)
+ default_signals->children.push_back(assign_en);
current_top_block->children.insert(current_top_block->children.begin(), default_signals);
assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone());
@@ -1334,15 +1499,16 @@ skip_dynamic_range_lvalue_expansion:;
std::vector<RTLIL::State> padding_x(offset, RTLIL::State::Sx);
- for (int i = 0; i < mem_width; i++)
- set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0;
-
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
new AstNode(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone()));
assign_data->children[0]->str = id_data;
- assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
- assign_en->children[0]->str = id_en;
+ if (current_always->type != AST_INITIAL) {
+ for (int i = 0; i < mem_width; i++)
+ set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0;
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
+ assign_en->children[0]->str = id_en;
+ }
}
else
{
@@ -1357,16 +1523,17 @@ skip_dynamic_range_lvalue_expansion:;
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
- for (int i = 0; i < mem_width; i++)
- set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0;
-
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone()));
assign_data->children[0]->str = id_data;
- assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
- new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone()));
- assign_en->children[0]->str = id_en;
+ if (current_always->type != AST_INITIAL) {
+ for (int i = 0; i < mem_width; i++)
+ set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0;
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
+ new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone()));
+ assign_en->children[0]->str = id_en;
+ }
delete left_at_zero_ast;
delete right_at_zero_ast;
@@ -1378,23 +1545,31 @@ skip_dynamic_range_lvalue_expansion:;
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone());
assign_data->children[0]->str = id_data;
- assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
- assign_en->children[0]->str = id_en;
+ if (current_always->type != AST_INITIAL) {
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
+ assign_en->children[0]->str = id_en;
+ }
}
newNode = new AstNode(AST_BLOCK);
newNode->children.push_back(assign_addr);
newNode->children.push_back(assign_data);
- newNode->children.push_back(assign_en);
+ if (current_always->type != AST_INITIAL)
+ newNode->children.push_back(assign_en);
- AstNode *wrnode = new AstNode(AST_MEMWR);
- wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
+ AstNode *wrnode = new AstNode(current_always->type == AST_INITIAL ? AST_MEMINIT : AST_MEMWR);
wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
+ if (current_always->type != AST_INITIAL)
+ wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
+ else
+ wrnode->children.push_back(AstNode::mkconst_int(1, false));
wrnode->str = children[0]->str;
+ wrnode->id2ast = children[0]->id2ast;
wrnode->children[0]->str = id_addr;
wrnode->children[1]->str = id_data;
- wrnode->children[2]->str = id_en;
+ if (current_always->type != AST_INITIAL)
+ wrnode->children[2]->str = id_en;
current_ast_mod->children.push_back(wrnode);
goto apply_newNode;
@@ -1531,7 +1706,17 @@ skip_dynamic_range_lvalue_expansion:;
if (current_scope.count(str) == 0 || current_scope[str]->type != AST_FUNCTION)
log_error("Can't resolve function name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
}
- if (type == AST_TCALL) {
+
+ if (type == AST_TCALL)
+ {
+ if (str == "$finish" || str == "$stop")
+ {
+ if (!current_always || current_always->type != AST_INITIAL)
+ log_error("System task `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+
+ log_error("System task `%s' executed at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ }
+
if (str == "\\$readmemh" || str == "\\$readmemb")
{
if (GetSize(children) < 2 || GetSize(children) > 4)
@@ -1555,7 +1740,7 @@ skip_dynamic_range_lvalue_expansion:;
while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_addr->type != AST_CONSTANT)
log_error("Failed to evaluate system function `%s' with non-constant 3rd argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
- start_addr = node_addr->asInt(false);
+ start_addr = int(node_addr->asInt(false));
}
if (GetSize(children) > 3) {
@@ -1563,10 +1748,27 @@ skip_dynamic_range_lvalue_expansion:;
while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_addr->type != AST_CONSTANT)
log_error("Failed to evaluate system function `%s' with non-constant 4th argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
- finish_addr = node_addr->asInt(false);
+ finish_addr = int(node_addr->asInt(false));
}
- newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr);
+ bool unconditional_init = false;
+ if (current_always->type == AST_INITIAL) {
+ pool<AstNode*> queue;
+ log_assert(current_always->children[0]->type == AST_BLOCK);
+ queue.insert(current_always->children[0]);
+ while (!unconditional_init && !queue.empty()) {
+ pool<AstNode*> next_queue;
+ for (auto n : queue)
+ for (auto c : n->children) {
+ if (c == this)
+ unconditional_init = true;
+ next_queue.insert(c);
+ }
+ next_queue.swap(queue);
+ }
+ }
+
+ newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init);
goto apply_newNode;
}
@@ -1606,6 +1808,8 @@ skip_dynamic_range_lvalue_expansion:;
size_t arg_count = 0;
std::map<std::string, std::string> replace_rules;
+ vector<AstNode*> added_mod_children;
+ dict<std::string, AstNode*> wire_cache;
if (current_block == NULL)
{
@@ -1698,17 +1902,41 @@ skip_dynamic_range_lvalue_expansion:;
}
for (auto child : decl->children)
- if (child->type == AST_WIRE)
+ if (child->type == AST_WIRE || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
{
- AstNode *wire = child->clone();
- wire->str = prefix + wire->str;
- wire->port_id = 0;
- wire->is_input = false;
- wire->is_output = false;
- current_ast_mod->children.push_back(wire);
- while (wire->simplify(true, false, false, 1, -1, false, false)) { }
+ AstNode *wire = nullptr;
+
+ if (wire_cache.count(child->str))
+ {
+ wire = wire_cache.at(child->str);
+ if (wire->children.empty()) {
+ for (auto c : child->children)
+ wire->children.push_back(c->clone());
+ } else {
+ if (!child->children.empty())
+ log_error("Incompatible re-declaration of wire %s at %s:%d.\n", child->str.c_str(), filename.c_str(), linenum);
+ }
+ }
+ else
+ {
+ wire = child->clone();
+ wire->str = prefix + wire->str;
+ wire->port_id = 0;
+ wire->is_input = false;
+ wire->is_output = false;
+ if (!child->is_output)
+ wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
+ wire_cache[child->str] = wire;
+
+ current_ast_mod->children.push_back(wire);
+ added_mod_children.push_back(wire);
+ }
+
+ if (child->type == AST_WIRE)
+ while (wire->simplify(true, false, false, 1, -1, false, false)) { }
replace_rules[child->str] = wire->str;
+ current_scope[wire->str] = wire;
if ((child->is_input || child->is_output) && arg_count < children.size())
{
@@ -1728,8 +1956,13 @@ skip_dynamic_range_lvalue_expansion:;
}
}
+ for (auto child : added_mod_children) {
+ child->replace_ids(prefix, replace_rules);
+ while (child->simplify(true, false, false, 1, -1, false, false)) { }
+ }
+
for (auto child : decl->children)
- if (child->type != AST_WIRE)
+ if (child->type != AST_WIRE && child->type != AST_PARAMETER && child->type != AST_LOCALPARAM)
{
AstNode *stmt = child->clone();
stmt->replace_ids(prefix, replace_rules);
@@ -1876,7 +2109,7 @@ skip_dynamic_range_lvalue_expansion:;
if (0) { case AST_GE: const_func = RTLIL::const_ge; }
if (0) { case AST_GT: const_func = RTLIL::const_gt; }
if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) {
- int cmp_width = std::max(children[0]->bits.size(), children[1]->bits.size());
+ int cmp_width = max(children[0]->bits.size(), children[1]->bits.size());
bool cmp_signed = children[0]->is_signed && children[1]->is_signed;
RTLIL::Const y = const_func(children[0]->bitsAsConst(cmp_width, cmp_signed),
children[1]->bitsAsConst(cmp_width, cmp_signed), cmp_signed, cmp_signed, 1);
@@ -2036,6 +2269,7 @@ apply_newNode:
if (!did_something)
basic_prep = true;
+ recursion_counter--;
return did_something;
}
@@ -2048,10 +2282,18 @@ static void replace_result_wire_name_in_function(AstNode *node, std::string &fro
}
// replace a readmem[bh] TCALL ast node with a block of memory assignments
-AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr)
+AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init)
{
+ int mem_width, mem_size, addr_bits;
+ memory->meminfo(mem_width, mem_size, addr_bits);
+
AstNode *block = new AstNode(AST_BLOCK);
+ AstNode *meminit = nullptr;
+ int next_meminit_cursor=0;
+ vector<State> meminit_bits;
+ int meminit_size=0;
+
std::ifstream f;
f.open(mem_filename.c_str());
@@ -2060,13 +2302,13 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
log_assert(GetSize(memory->children) == 2 && memory->children[1]->type == AST_RANGE && memory->children[1]->range_valid);
int range_left = memory->children[1]->range_left, range_right = memory->children[1]->range_right;
- int range_min = std::min(range_left, range_right), range_max = std::max(range_left, range_right);
+ int range_min = min(range_left, range_right), range_max = max(range_left, range_right);
if (start_addr < 0)
start_addr = range_min;
if (finish_addr < 0)
- finish_addr = range_max;
+ finish_addr = range_max + 1;
bool in_comment = false;
int increment = start_addr <= finish_addr ? +1 : -1;
@@ -2106,21 +2348,56 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
continue;
}
- AstNode *value = VERILOG_FRONTEND::const2ast((is_readmemh ? "'h" : "'b") + token);
+ AstNode *value = VERILOG_FRONTEND::const2ast(stringf("%d'%c", mem_width, is_readmemh ? 'h' : 'b') + token);
+
+ if (unconditional_init)
+ {
+ if (meminit == nullptr || cursor != next_meminit_cursor)
+ {
+ if (meminit != nullptr) {
+ meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false);
+ meminit->children[2] = AstNode::mkconst_int(meminit_size, false);
+ }
+
+ meminit = new AstNode(AST_MEMINIT);
+ meminit->children.push_back(AstNode::mkconst_int(cursor, false));
+ meminit->children.push_back(nullptr);
+ meminit->children.push_back(nullptr);
+ meminit->str = memory->str;
+ meminit->id2ast = memory;
+ meminit_bits.clear();
+ meminit_size = 0;
+
+ current_ast_mod->children.push_back(meminit);
+ next_meminit_cursor = cursor;
+ }
- block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value));
- block->children.back()->children[0]->str = memory->str;
- block->children.back()->children[0]->id2ast = memory;
+ meminit_size++;
+ next_meminit_cursor++;
+ meminit_bits.insert(meminit_bits.end(), value->bits.begin(), value->bits.end());
+ delete value;
+ }
+ else
+ {
+ block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value));
+ block->children.back()->children[0]->str = memory->str;
+ block->children.back()->children[0]->id2ast = memory;
+ }
- if ((cursor == finish_addr) || (increment > 0 && cursor >= range_max) || (increment < 0 && cursor <= range_min))
+ if ((cursor == finish_addr) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min))
break;
cursor += increment;
}
- if ((cursor == finish_addr) || (increment > 0 && cursor >= range_max) || (increment < 0 && cursor <= range_min))
+ if ((cursor == finish_addr) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min))
break;
}
+ if (meminit != nullptr) {
+ meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false);
+ meminit->children[2] = AstNode::mkconst_int(meminit_size, false);
+ }
+
return block;
}
@@ -2171,7 +2448,7 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
name_map.swap(backup_name_map);
}
-// rename stuff (used when tasks of functions are instanciated)
+// rename stuff (used when tasks of functions are instantiated)
void AstNode::replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules)
{
if (type == AST_BLOCK)
@@ -2328,9 +2605,28 @@ bool AstNode::mem2reg_check(pool<AstNode*> &mem2reg_set)
return true;
}
+void AstNode::mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes)
+{
+ log_assert(mem2reg_set.count(this) == 0);
+
+ if (mem2reg_set.count(id2ast))
+ id2ast = nullptr;
+
+ for (size_t i = 0; i < children.size(); i++) {
+ if (mem2reg_set.count(children[i]) > 0) {
+ delnodes.push_back(children[i]);
+ children.erase(children.begin() + (i--));
+ } else {
+ children[i]->mem2reg_remove(mem2reg_set, delnodes);
+ }
+ }
+}
+
// actually replace memories with registers
-void AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block)
+bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block)
{
+ bool did_something = false;
+
if (type == AST_BLOCK)
block = this;
@@ -2389,6 +2685,8 @@ void AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
children[0]->id2ast = NULL;
children[0]->str = id_data;
type = AST_ASSIGN_EQ;
+
+ did_something = true;
}
if (mem2reg_check(mem2reg_set))
@@ -2489,10 +2787,13 @@ void AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
auto children_list = children;
for (size_t i = 0; i < children_list.size(); i++)
- children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block);
+ if (children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block))
+ did_something = true;
+
+ return did_something;
}
-// calulate memory dimensions
+// calculate memory dimensions
void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits)
{
log_assert(type == AST_MEMORY);
@@ -2502,7 +2803,7 @@ void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits)
if (mem_size < 0)
mem_size *= -1;
- mem_size += std::min(children[1]->range_left, children[1]->range_right) + 1;
+ mem_size += min(children[1]->range_left, children[1]->range_right) + 1;
addr_bits = 1;
while ((1 << addr_bits) < mem_size)
@@ -2538,8 +2839,8 @@ void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &varia
if (!children.at(0)->range_valid)
log_error("Non-constant range in %s:%d (called from %s:%d).\n",
filename.c_str(), linenum, fcall->filename.c_str(), fcall->linenum);
- offset = std::min(children.at(0)->range_left, children.at(0)->range_right);
- width = std::min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width);
+ offset = min(children.at(0)->range_left, children.at(0)->range_right);
+ width = min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width);
}
offset -= variables.at(str).offset;
std::vector<RTLIL::State> &var_bits = variables.at(str).val.bits;
@@ -2579,7 +2880,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
log_error("Can't determine size of variable %s in %s:%d (called from %s:%d).\n",
child->str.c_str(), child->filename.c_str(), child->linenum, fcall->filename.c_str(), fcall->linenum);
variables[child->str].val = RTLIL::Const(RTLIL::State::Sx, abs(child->range_left - child->range_right)+1);
- variables[child->str].offset = std::min(child->range_left, child->range_right);
+ variables[child->str].offset = min(child->range_left, child->range_right);
variables[child->str].is_signed = child->is_signed;
if (child->is_input && argidx < fcall->children.size())
variables[child->str].val = fcall->children.at(argidx++)->bitsAsConst(variables[child->str].val.bits.size());
@@ -2610,6 +2911,9 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
if (stmt->type == AST_ASSIGN_EQ)
{
+ if (stmt->children.at(0)->type == AST_IDENTIFIER && stmt->children.at(0)->children.size() != 0 &&
+ stmt->children.at(0)->children.at(0)->type == AST_RANGE)
+ stmt->children.at(0)->children.at(0)->replace_variables(variables, fcall);
stmt->children.at(1)->replace_variables(variables, fcall);
while (stmt->simplify(true, false, false, 1, -1, false, true)) { }
@@ -2635,7 +2939,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
if (!range->range_valid)
log_error("Non-constant range in %s:%d (called from %s:%d).\n",
range->filename.c_str(), range->linenum, fcall->filename.c_str(), fcall->linenum);
- int offset = std::min(range->range_left, range->range_right);
+ int offset = min(range->range_left, range->range_right);
int width = std::abs(range->range_left - range->range_right) + 1;
varinfo_t &v = variables[stmt->children.at(0)->str];
RTLIL::Const r = stmt->children.at(1)->bitsAsConst(v.val.bits.size());
@@ -2708,7 +3012,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
for (size_t i = 1; i < stmt->children.size(); i++)
{
bool found_match = false;
- log_assert(stmt->children.at(i)->type == AST_COND);
+ log_assert(stmt->children.at(i)->type == AST_COND || stmt->children.at(i)->type == AST_CONDX || stmt->children.at(i)->type == AST_CONDZ);
if (stmt->children.at(i)->children.front()->type == AST_DEFAULT) {
sel_case = stmt->children.at(i)->children.back();
diff --git a/frontends/blif/Makefile.inc b/frontends/blif/Makefile.inc
new file mode 100644
index 000000000..9729184eb
--- /dev/null
+++ b/frontends/blif/Makefile.inc
@@ -0,0 +1,3 @@
+
+OBJS += frontends/blif/blifparse.o
+
diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc
new file mode 100644
index 000000000..1f6d0ee37
--- /dev/null
+++ b/frontends/blif/blifparse.cc
@@ -0,0 +1,485 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "blifparse.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+static bool read_next_line(char *&buffer, size_t &buffer_size, int &line_count, std::istream &f)
+{
+ int buffer_len = 0;
+ buffer[0] = 0;
+
+ while (1)
+ {
+ buffer_len += strlen(buffer + buffer_len);
+ while (buffer_len > 0 && (buffer[buffer_len-1] == ' ' || buffer[buffer_len-1] == '\t' ||
+ buffer[buffer_len-1] == '\r' || buffer[buffer_len-1] == '\n'))
+ buffer[--buffer_len] = 0;
+
+ if (buffer_size-buffer_len < 4096) {
+ buffer_size *= 2;
+ buffer = (char*)realloc(buffer, buffer_size);
+ }
+
+ if (buffer_len == 0 || buffer[buffer_len-1] == '\\') {
+ if (buffer_len > 0 && buffer[buffer_len-1] == '\\')
+ buffer[--buffer_len] = 0;
+ line_count++;
+ if (!f.getline(buffer+buffer_len, buffer_size-buffer_len))
+ return false;
+ } else
+ return true;
+ }
+}
+
+void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean, bool sop_mode)
+{
+ RTLIL::Module *module = nullptr;
+ RTLIL::Const *lutptr = NULL;
+ RTLIL::Cell *sopcell = NULL;
+ RTLIL::State lut_default_state = RTLIL::State::Sx;
+ int blif_maxnum = 0, sopmode = -1;
+
+ auto blif_wire = [&](const std::string &wire_name) -> Wire*
+ {
+ if (wire_name[0] == '$')
+ {
+ for (int i = 0; i+1 < GetSize(wire_name); i++)
+ {
+ if (wire_name[i] != '$')
+ continue;
+
+ int len = 0;
+ while (i+len+1 < GetSize(wire_name) && '0' <= wire_name[i+len+1] && wire_name[i+len+1] <= '9')
+ len++;
+
+ if (len > 0) {
+ string num_str = wire_name.substr(i+1, len);
+ int num = atoi(num_str.c_str()) & 0x0fffffff;
+ blif_maxnum = std::max(blif_maxnum, num);
+ }
+ }
+ }
+
+ IdString wire_id = RTLIL::escape_id(wire_name);
+ Wire *wire = module->wire(wire_id);
+
+ if (wire == nullptr)
+ wire = module->addWire(wire_id);
+
+ return wire;
+ };
+
+ dict<RTLIL::IdString, RTLIL::Const> *obj_attributes = nullptr;
+ dict<RTLIL::IdString, RTLIL::Const> *obj_parameters = nullptr;
+
+ size_t buffer_size = 4096;
+ char *buffer = (char*)malloc(buffer_size);
+ int line_count = 0;
+
+ while (1)
+ {
+ if (!read_next_line(buffer, buffer_size, line_count, f)) {
+ if (module != nullptr)
+ goto error;
+ free(buffer);
+ return;
+ }
+
+ continue_without_read:
+ if (buffer[0] == '#')
+ continue;
+
+ if (buffer[0] == '.')
+ {
+ if (lutptr) {
+ for (auto &bit : lutptr->bits)
+ if (bit == RTLIL::State::Sx)
+ bit = lut_default_state;
+ lutptr = NULL;
+ lut_default_state = RTLIL::State::Sx;
+ }
+
+ if (sopcell) {
+ sopcell = NULL;
+ sopmode = -1;
+ }
+
+ char *cmd = strtok(buffer, " \t\r\n");
+
+ if (!strcmp(cmd, ".model")) {
+ if (module != nullptr)
+ goto error;
+ module = new RTLIL::Module;
+ module->name = RTLIL::escape_id(strtok(NULL, " \t\r\n"));
+ obj_attributes = &module->attributes;
+ obj_parameters = nullptr;
+ if (design->module(module->name))
+ log_error("Duplicate definition of module %s in line %d!\n", log_id(module->name), line_count);
+ design->add(module);
+ continue;
+ }
+
+ if (module == nullptr)
+ goto error;
+
+ if (!strcmp(cmd, ".end"))
+ {
+ module->fixup_ports();
+
+ if (run_clean)
+ {
+ Const buffer_lut(vector<RTLIL::State>({State::S0, State::S1}));
+ vector<Cell*> remove_cells;
+
+ for (auto cell : module->cells())
+ if (cell->type == "$lut" && cell->getParam("\\LUT") == buffer_lut) {
+ module->connect(cell->getPort("\\Y"), cell->getPort("\\A"));
+ remove_cells.push_back(cell);
+ }
+
+ for (auto cell : remove_cells)
+ module->remove(cell);
+
+ Wire *true_wire = module->wire("$true");
+ Wire *false_wire = module->wire("$false");
+ Wire *undef_wire = module->wire("$undef");
+
+ if (true_wire != nullptr)
+ module->rename(true_wire, stringf("$true$%d", ++blif_maxnum));
+
+ if (false_wire != nullptr)
+ module->rename(false_wire, stringf("$false$%d", ++blif_maxnum));
+
+ if (undef_wire != nullptr)
+ module->rename(undef_wire, stringf("$undef$%d", ++blif_maxnum));
+
+ autoidx = std::max(autoidx, blif_maxnum+1);
+ blif_maxnum = 0;
+ }
+
+ module = nullptr;
+ obj_attributes = nullptr;
+ obj_parameters = nullptr;
+ continue;
+ }
+
+ if (!strcmp(cmd, ".inputs") || !strcmp(cmd, ".outputs")) {
+ char *p;
+ while ((p = strtok(NULL, " \t\r\n")) != NULL) {
+ RTLIL::IdString wire_name(stringf("\\%s", p));
+ RTLIL::Wire *wire = module->wire(wire_name);
+ if (wire == nullptr)
+ wire = module->addWire(wire_name);
+ if (!strcmp(cmd, ".inputs"))
+ wire->port_input = true;
+ else
+ wire->port_output = true;
+ }
+ obj_attributes = nullptr;
+ obj_parameters = nullptr;
+ continue;
+ }
+
+ if (!strcmp(cmd, ".attr") || !strcmp(cmd, ".param")) {
+ char *n = strtok(NULL, " \t\r\n");
+ char *v = strtok(NULL, "\r\n");
+ IdString id_n = RTLIL::escape_id(n);
+ Const const_v;
+ if (v[0] == '"') {
+ std::string str(v+1);
+ if (str.back() == '"')
+ str.resize(str.size()-1);
+ const_v = Const(str);
+ } else {
+ int n = strlen(v);
+ const_v.bits.resize(n);
+ for (int i = 0; i < n; i++)
+ const_v.bits[i] = v[n-i-1] != '0' ? State::S1 : State::S0;
+ }
+ if (!strcmp(cmd, ".attr")) {
+ if (obj_attributes == nullptr)
+ goto error;
+ (*obj_attributes)[id_n] = const_v;
+ } else {
+ if (obj_parameters == nullptr)
+ goto error;
+ (*obj_parameters)[id_n] = const_v;
+ }
+ continue;
+ }
+
+ if (!strcmp(cmd, ".latch"))
+ {
+ char *d = strtok(NULL, " \t\r\n");
+ char *q = strtok(NULL, " \t\r\n");
+ char *edge = strtok(NULL, " \t\r\n");
+ char *clock = strtok(NULL, " \t\r\n");
+ char *init = strtok(NULL, " \t\r\n");
+ RTLIL::Cell *cell = nullptr;
+
+ if (clock == nullptr && edge != nullptr) {
+ init = edge;
+ edge = nullptr;
+ }
+
+ if (init != nullptr && (init[0] == '0' || init[0] == '1'))
+ blif_wire(d)->attributes["\\init"] = Const(init[0] == '1' ? 1 : 0, 1);
+
+ if (clock == nullptr)
+ goto no_latch_clock;
+
+ if (!strcmp(edge, "re"))
+ cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q));
+ else if (!strcmp(edge, "fe"))
+ cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false);
+ else if (!strcmp(edge, "ah"))
+ cell = module->addDlatch(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q));
+ else if (!strcmp(edge, "al"))
+ cell = module->addDlatch(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false);
+ else {
+ no_latch_clock:
+ cell = module->addCell(NEW_ID, dff_name);
+ cell->setPort("\\D", blif_wire(d));
+ cell->setPort("\\Q", blif_wire(q));
+ }
+
+ obj_attributes = &cell->attributes;
+ obj_parameters = &cell->parameters;
+ continue;
+ }
+
+ if (!strcmp(cmd, ".gate") || !strcmp(cmd, ".subckt"))
+ {
+ char *p = strtok(NULL, " \t\r\n");
+ if (p == NULL)
+ goto error;
+
+ IdString celltype = RTLIL::escape_id(p);
+ RTLIL::Cell *cell = module->addCell(NEW_ID, celltype);
+
+ while ((p = strtok(NULL, " \t\r\n")) != NULL) {
+ char *q = strchr(p, '=');
+ if (q == NULL || !q[0])
+ goto error;
+ *(q++) = 0;
+ cell->setPort(RTLIL::escape_id(p), *q ? blif_wire(q) : SigSpec());
+ }
+
+ obj_attributes = &cell->attributes;
+ obj_parameters = &cell->parameters;
+ continue;
+ }
+
+ obj_attributes = nullptr;
+ obj_parameters = nullptr;
+
+ if (!strcmp(cmd, ".barbuf"))
+ {
+ char *p = strtok(NULL, " \t\r\n");
+ if (p == NULL)
+ goto error;
+
+ char *q = strtok(NULL, " \t\r\n");
+ if (q == NULL)
+ goto error;
+
+ module->connect(blif_wire(q), blif_wire(p));
+ continue;
+ }
+
+ if (!strcmp(cmd, ".names"))
+ {
+ char *p;
+ RTLIL::SigSpec input_sig, output_sig;
+ while ((p = strtok(NULL, " \t\r\n")) != NULL)
+ input_sig.append(blif_wire(p));
+ output_sig = input_sig.extract(input_sig.size()-1, 1);
+ input_sig = input_sig.extract(0, input_sig.size()-1);
+
+ if (input_sig.size() == 0)
+ {
+ RTLIL::State state = RTLIL::State::Sa;
+ while (1) {
+ if (!read_next_line(buffer, buffer_size, line_count, f))
+ goto error;
+ for (int i = 0; buffer[i]; i++) {
+ if (buffer[i] == ' ' || buffer[i] == '\t')
+ continue;
+ if (i == 0 && buffer[i] == '.')
+ goto finished_parsing_constval;
+ if (buffer[i] == '0') {
+ if (state == RTLIL::State::S1)
+ goto error;
+ state = RTLIL::State::S0;
+ continue;
+ }
+ if (buffer[i] == '1') {
+ if (state == RTLIL::State::S0)
+ goto error;
+ state = RTLIL::State::S1;
+ continue;
+ }
+ goto error;
+ }
+ }
+
+ finished_parsing_constval:
+ if (state == RTLIL::State::Sa)
+ state = RTLIL::State::S0;
+ if (output_sig.as_wire()->name == "$undef")
+ state = RTLIL::State::Sx;
+ module->connect(RTLIL::SigSig(output_sig, state));
+ goto continue_without_read;
+ }
+
+ if (sop_mode)
+ {
+ sopcell = module->addCell(NEW_ID, "$sop");
+ sopcell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.size());
+ sopcell->parameters["\\DEPTH"] = 0;
+ sopcell->parameters["\\TABLE"] = RTLIL::Const();
+ sopcell->setPort("\\A", input_sig);
+ sopcell->setPort("\\Y", output_sig);
+ sopmode = -1;
+ }
+ else
+ {
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$lut");
+ cell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.size());
+ cell->parameters["\\LUT"] = RTLIL::Const(RTLIL::State::Sx, 1 << input_sig.size());
+ cell->setPort("\\A", input_sig);
+ cell->setPort("\\Y", output_sig);
+ lutptr = &cell->parameters.at("\\LUT");
+ lut_default_state = RTLIL::State::Sx;
+ }
+ continue;
+ }
+
+ goto error;
+ }
+
+ if (lutptr == NULL && sopcell == NULL)
+ goto error;
+
+ char *input = strtok(buffer, " \t\r\n");
+ char *output = strtok(NULL, " \t\r\n");
+
+ if (input == NULL || output == NULL || (strcmp(output, "0") && strcmp(output, "1")))
+ goto error;
+
+ int input_len = strlen(input);
+
+ if (sopcell)
+ {
+ log_assert(sopcell->parameters["\\WIDTH"].as_int() == input_len);
+ sopcell->parameters["\\DEPTH"] = sopcell->parameters["\\DEPTH"].as_int() + 1;
+
+ for (int i = 0; i < input_len; i++)
+ switch (input[i]) {
+ case '0':
+ sopcell->parameters["\\TABLE"].bits.push_back(State::S1);
+ sopcell->parameters["\\TABLE"].bits.push_back(State::S0);
+ break;
+ case '1':
+ sopcell->parameters["\\TABLE"].bits.push_back(State::S0);
+ sopcell->parameters["\\TABLE"].bits.push_back(State::S1);
+ break;
+ default:
+ sopcell->parameters["\\TABLE"].bits.push_back(State::S0);
+ sopcell->parameters["\\TABLE"].bits.push_back(State::S0);
+ break;
+ }
+
+ if (sopmode == -1) {
+ sopmode = (*output == '1');
+ if (!sopmode) {
+ SigSpec outnet = sopcell->getPort("\\Y");
+ SigSpec tempnet = module->addWire(NEW_ID);
+ module->addNotGate(NEW_ID, tempnet, outnet);
+ sopcell->setPort("\\Y", tempnet);
+ }
+ } else
+ log_assert(sopmode == (*output == '1'));
+ }
+
+ if (lutptr)
+ {
+ if (input_len > 8)
+ goto error;
+
+ for (int i = 0; i < (1 << input_len); i++) {
+ for (int j = 0; j < input_len; j++) {
+ char c1 = input[j];
+ if (c1 != '-') {
+ char c2 = (i & (1 << j)) != 0 ? '1' : '0';
+ if (c1 != c2)
+ goto try_next_value;
+ }
+ }
+ lutptr->bits.at(i) = !strcmp(output, "0") ? RTLIL::State::S0 : RTLIL::State::S1;
+ try_next_value:;
+ }
+
+ lut_default_state = !strcmp(output, "0") ? RTLIL::State::S1 : RTLIL::State::S0;
+ }
+ }
+
+error:
+ log_error("Syntax error in line %d!\n", line_count);
+}
+
+struct BlifFrontend : public Frontend {
+ BlifFrontend() : Frontend("blif", "read BLIF file") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" read_blif [filename]\n");
+ log("\n");
+ log("Load modules from a BLIF file into the current design.\n");
+ log("\n");
+ log(" -sop\n");
+ log(" Create $sop cells instead of $lut cells\n");
+ log("\n");
+ }
+ virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ {
+ bool sop_mode = false;
+
+ log_header(design, "Executing BLIF frontend.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ std::string arg = args[argidx];
+ if (arg == "-sop") {
+ sop_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
+ parse_blif(design, *f, "\\DFF", true, sop_mode);
+ }
+} BlifFrontend;
+
+YOSYS_NAMESPACE_END
+
diff --git a/frontends/blif/blifparse.h b/frontends/blif/blifparse.h
new file mode 100644
index 000000000..058087d81
--- /dev/null
+++ b/frontends/blif/blifparse.h
@@ -0,0 +1,31 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef ABC_BLIFPARSE
+#define ABC_BLIFPARSE
+
+#include "kernel/yosys.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+extern void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean = false, bool sop_mode = false);
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/frontends/ilang/Makefile.inc b/frontends/ilang/Makefile.inc
index c15e2cc47..e2a476c93 100644
--- a/frontends/ilang/Makefile.inc
+++ b/frontends/ilang/Makefile.inc
@@ -5,13 +5,15 @@ GENFILES += frontends/ilang/ilang_parser.output
GENFILES += frontends/ilang/ilang_lexer.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) mkdir -p $(dir $@)
+ $(P) $(BISON) -d -r all -b frontends/ilang/ilang_parser $<
$(Q) mv frontends/ilang/ilang_parser.tab.c frontends/ilang/ilang_parser.tab.cc
frontends/ilang/ilang_parser.tab.h: frontends/ilang/ilang_parser.tab.cc
frontends/ilang/ilang_lexer.cc: frontends/ilang/ilang_lexer.l
- $(P) flex -o frontends/ilang/ilang_lexer.cc frontends/ilang/ilang_lexer.l
+ $(Q) mkdir -p $(dir $@)
+ $(P) flex -o frontends/ilang/ilang_lexer.cc $<
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 7a4687a3c..ed6789987 100644
--- a/frontends/ilang/ilang_frontend.cc
+++ b/frontends/ilang/ilang_frontend.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -47,7 +47,7 @@ struct IlangFrontend : public Frontend {
}
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing ILANG frontend.\n");
+ log_header(design, "Executing ILANG frontend.\n");
extra_args(f, filename, args, 1);
log("Input filename: %s\n", filename.c_str());
diff --git a/frontends/ilang/ilang_frontend.h b/frontends/ilang/ilang_frontend.h
index b04d6c512..ad3ffec90 100644
--- a/frontends/ilang/ilang_frontend.h
+++ b/frontends/ilang/ilang_frontend.h
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
diff --git a/frontends/ilang/ilang_lexer.l b/frontends/ilang/ilang_lexer.l
index ace992fbd..415de74eb 100644
--- a/frontends/ilang/ilang_lexer.l
+++ b/frontends/ilang/ilang_lexer.l
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -29,7 +29,7 @@
#pragma clang diagnostic ignored "-Wdeprecated-register"
#endif
-#include "ilang_frontend.h"
+#include "frontends/ilang/ilang_frontend.h"
#include "ilang_parser.tab.h"
USING_YOSYS_NAMESPACE
diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y
index 4661d5772..cc31c8642 100644
--- a/frontends/ilang/ilang_parser.y
+++ b/frontends/ilang/ilang_parser.y
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -24,7 +24,7 @@
%{
#include <list>
-#include "ilang_frontend.h"
+#include "frontends/ilang/ilang_frontend.h"
YOSYS_NAMESPACE_BEGIN
namespace ILANG_FRONTEND {
std::istream *lexin;
@@ -50,6 +50,7 @@ USING_YOSYS_NAMESPACE
int integer;
YOSYS_NAMESPACE_PREFIX RTLIL::Const *data;
YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec *sigspec;
+ std::vector<YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec> *rsigspec;
}
%token <string> TOK_ID TOK_VALUE TOK_STRING
@@ -60,6 +61,7 @@ USING_YOSYS_NAMESPACE
%token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET
%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_UPTO
+%type <rsigspec> sigspec_list_reversed
%type <sigspec> sigspec sigspec_list
%type <integer> sync_type
%type <data> constant
@@ -121,7 +123,7 @@ attr_stmt:
autoidx_stmt:
TOK_AUTOIDX TOK_INT EOL {
- autoidx = std::max(autoidx, $2);
+ autoidx = max(autoidx, $2);
};
wire_stmt:
@@ -274,8 +276,8 @@ compare_list:
/* empty */;
case_body:
- switch_stmt case_body |
- assign_stmt case_body |
+ case_body switch_stmt |
+ case_body assign_stmt |
/* empty */;
assign_stmt:
@@ -389,16 +391,20 @@ sigspec:
$$ = $2;
};
-sigspec_list:
- sigspec_list sigspec {
- $$ = new RTLIL::SigSpec;
- $$->append(*$2);
- $$->append(*$1);
- delete $1;
+sigspec_list_reversed:
+ sigspec_list_reversed sigspec {
+ $$->push_back(*$2);
delete $2;
} |
/* empty */ {
+ $$ = new std::vector<RTLIL::SigSpec>;
+ };
+
+sigspec_list: sigspec_list_reversed {
$$ = new RTLIL::SigSpec;
+ for (auto it = $1->rbegin(); it != $1->rend(); it++)
+ $$->append(*it);
+ delete $1;
};
conn_stmt:
diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc
index 464c5c942..0be58b6da 100644
--- a/frontends/liberty/liberty.cc
+++ b/frontends/liberty/liberty.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -40,7 +40,7 @@ static RTLIL::SigSpec parse_func_identifier(RTLIL::Module *module, const char *&
if (id_len == 0)
log_error("Expected identifier at `%s'.\n", expr);
-
+
if (id_len == 1 && (*expr == '0' || *expr == '1'))
return *(expr++) == '0' ? RTLIL::State::S0 : RTLIL::State::S1;
@@ -437,7 +437,7 @@ struct LibertyFrontend : public Frontend {
bool flag_ignore_miss_dir = false;
std::vector<std::string> attributes;
- log_header("Executing Liberty frontend.\n");
+ log_header(design, "Executing Liberty frontend.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/frontends/verific/Makefile.inc b/frontends/verific/Makefile.inc
index 13f242c4b..68ef9aed1 100644
--- a/frontends/verific/Makefile.inc
+++ b/frontends/verific/Makefile.inc
@@ -8,8 +8,9 @@ EXTRA_TARGETS += share/verific
share/verific:
$(P) rm -rf share/verific.new
$(Q) mkdir -p share/verific.new
- $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs share/verific.new/vhdl_vdbs_1993
- $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_2008 share/verific.new/vhdl_vdbs_2008
+ $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1987/. share/verific.new/vhdl_vdbs_1987
+ $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1993/. share/verific.new/vhdl_vdbs_1993
+ $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_2008/. share/verific.new/vhdl_vdbs_2008
$(Q) mv share/verific.new share/verific
endif
diff --git a/frontends/verific/build_amd64.txt b/frontends/verific/build_amd64.txt
index 9bb6e3203..d6952820e 100644
--- a/frontends/verific/build_amd64.txt
+++ b/frontends/verific/build_amd64.txt
@@ -8,8 +8,6 @@ only have the i386 eval version of Verific:
--snip--
CONFIG := clang
ENABLE_TCL := 0
-ENABLE_QT4 := 0
-ENABLE_ABC := 0
ENABLE_PLUGINS := 0
ENABLE_VERIFIC := 1
CXXFLAGS += -m32
@@ -21,7 +19,7 @@ VERIFIC_DIR = /usr/local/src/verific_lib_eval
2.) Install the necessary multilib packages
Hint: On debian/ubuntu the multilib packages have names such as
-libreadline-dev:amd64 or lib32readline6-dev, depending on the
+libreadline-dev:i386 or lib32readline6-dev, depending on the
exact version of debian/ubuntu you are working with.
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index 79abcf245..7dd36a747 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -65,7 +65,7 @@ static void msg_func(msg_type_t msg_type, const char *message_id, linefile_type
log("\n");
}
-static void import_attributes(std::map<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj)
+static void import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj)
{
MapIter mi;
Att *attr;
@@ -186,6 +186,16 @@ static bool import_netlist_instance_gates(RTLIL::Module *module, std::map<Net*,
return true;
}
+ if (inst->Type() == PRIM_XNOR) {
+ module->addXnorGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_BUF) {
+ module->addBufGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
if (inst->Type() == PRIM_INV) {
module->addNotGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
return true;
@@ -314,6 +324,16 @@ static bool import_netlist_instance_cells(RTLIL::Module *module, std::map<Net*,
return true;
}
+ if (inst->Type() == PRIM_DLATCHRS)
+ {
+ if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd())
+ module->addDlatch(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetControl()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ else
+ module->addDlatchsr(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetControl()), net_map.at(inst->GetSet()), net_map.at(inst->GetReset()),
+ net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
#define IN operatorInput(inst, net_map)
#define IN1 operatorInput1(inst, net_map)
#define IN2 operatorInput2(inst, net_map)
@@ -359,6 +379,26 @@ static bool import_netlist_instance_cells(RTLIL::Module *module, std::map<Net*,
return true;
}
+ if (inst->Type() == OPER_ENABLED_DECODER) {
+ RTLIL::SigSpec vec;
+ vec.append(net_map.at(inst->GetControl()));
+ for (unsigned i = 1; i < inst->OutputSize(); i++) {
+ vec.append(RTLIL::State::S0);
+ }
+ module->addShl(RTLIL::escape_id(inst->Name()), vec, IN, OUT, false);
+ return true;
+ }
+
+ if (inst->Type() == OPER_DECODER) {
+ RTLIL::SigSpec vec;
+ vec.append(RTLIL::State::S1);
+ for (unsigned i = 1; i < inst->OutputSize(); i++) {
+ vec.append(RTLIL::State::S0);
+ }
+ module->addShl(RTLIL::escape_id(inst->Name()), vec, IN, OUT, false);
+ return true;
+ }
+
if (inst->Type() == OPER_SHIFT_RIGHT) {
Net *net_cin = inst->GetCin();
Net *net_a_msb = inst->GetInput1Bit(0);
@@ -541,7 +581,7 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
// log(" importing portbus %s.\n", portbus->Name());
RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(portbus->Name()), portbus->Size());
- wire->start_offset = std::min(portbus->LeftIndex(), portbus->RightIndex());
+ wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex());
import_attributes(wire->attributes, portbus);
if (portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_IN)
@@ -580,11 +620,11 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
int bits_in_word = number_of_bits;
FOREACH_PORTREF_OF_NET(net, si, pr) {
if (pr->GetInst()->Type() == OPER_READ_PORT) {
- bits_in_word = std::min<int>(bits_in_word, pr->GetInst()->OutputSize());
+ bits_in_word = min<int>(bits_in_word, pr->GetInst()->OutputSize());
continue;
}
if (pr->GetInst()->Type() == OPER_WRITE_PORT || pr->GetInst()->Type() == OPER_CLOCKED_WRITE_PORT) {
- bits_in_word = std::min<int>(bits_in_word, pr->GetInst()->Input2Size());
+ bits_in_word = min<int>(bits_in_word, pr->GetInst()->Input2Size());
continue;
}
log_error("Verific RamNet %s is connected to unsupported instance type %s (%s).\n",
@@ -630,7 +670,7 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
RTLIL::IdString wire_name = module->uniquify(RTLIL::escape_id(netbus->Name()));
RTLIL::Wire *wire = module->addWire(wire_name, netbus->Size());
- wire->start_offset = std::min(netbus->LeftIndex(), netbus->RightIndex());
+ wire->start_offset = min(netbus->LeftIndex(), netbus->RightIndex());
import_attributes(wire->attributes, netbus);
for (int i = netbus->LeftIndex();; i += netbus->IsUp() ? +1 : -1) {
@@ -666,6 +706,11 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
continue;
}
+ if (inst->Type() == PRIM_BUF) {
+ module->addBufGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ continue;
+ }
+
if (inst->Type() == PRIM_X) {
module->connect(net_map.at(inst->GetOutput()), RTLIL::State::Sx);
continue;
@@ -692,7 +737,8 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
cell->parameters["\\TRANSPARENT"] = false;
cell->parameters["\\ABITS"] = GetSize(addr);
cell->parameters["\\WIDTH"] = GetSize(data);
- cell->setPort("\\CLK", RTLIL::State::S0);
+ cell->setPort("\\CLK", RTLIL::State::Sx);
+ cell->setPort("\\EN", RTLIL::State::Sx);
cell->setPort("\\ADDR", addr);
cell->setPort("\\DATA", data);
continue;
@@ -737,13 +783,15 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
}
if (inst->IsPrimitive())
- log_error("Unsupported Verific primitive: %s\n", inst->View()->Owner()->Name());
+ log_error("Unsupported Verific primitive %s of type %s\n", inst->Name(), inst->View()->Owner()->Name());
nl_todo.insert(inst->View());
RTLIL::Cell *cell = module->addCell(RTLIL::escape_id(inst->Name()), inst->IsOperator() ?
std::string("$verific$") + inst->View()->Owner()->Name() : RTLIL::escape_id(inst->View()->Owner()->Name()));
+ dict<IdString, vector<SigBit>> cell_port_conns;
+
FOREACH_PORTREF_OF_INST(inst, mi2, pr) {
// log(" .%s(%s)\n", pr->GetPort()->Name(), pr->GetNet()->Name());
const char *port_name = pr->GetPort()->Name();
@@ -751,18 +799,21 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
if (pr->GetPort()->Bus()) {
port_name = pr->GetPort()->Bus()->Name();
port_offset = pr->GetPort()->Bus()->IndexOf(pr->GetPort()) -
- std::min(pr->GetPort()->Bus()->LeftIndex(), pr->GetPort()->Bus()->RightIndex());
+ min(pr->GetPort()->Bus()->LeftIndex(), pr->GetPort()->Bus()->RightIndex());
}
- RTLIL::SigSpec conn;
- if (cell->hasPort(RTLIL::escape_id(port_name)))
- conn = cell->getPort(RTLIL::escape_id(port_name));
- while (GetSize(conn) <= port_offset) {
- if (pr->GetPort()->GetDir() != DIR_IN)
- conn.append(module->addWire(NEW_ID, port_offset - GetSize(conn)));
- conn.append(RTLIL::State::Sz);
+ IdString port_name_id = RTLIL::escape_id(port_name);
+ auto &sigvec = cell_port_conns[port_name_id];
+ if (GetSize(sigvec) <= port_offset) {
+ SigSpec zwires = module->addWire(NEW_ID, port_offset+1-GetSize(sigvec));
+ for (auto bit : zwires)
+ sigvec.push_back(bit);
}
- conn.replace(port_offset, net_map.at(pr->GetNet()));
- cell->setPort(RTLIL::escape_id(port_name), conn);
+ sigvec[port_offset] = net_map.at(pr->GetNet());
+ }
+
+ for (auto &it : cell_port_conns) {
+ // log(" .%s(%s)\n", log_id(it.first), log_signal(it.second));
+ cell->setPort(it.first, it.second);
}
}
}
@@ -789,7 +840,7 @@ struct VerificPass : public Pass {
log("\n");
log(" verific -import [-gates] {-all | <top-module>..}\n");
log("\n");
- log("Elaborate the design for the sepcified top modules, import to Yosys and\n");
+ log("Elaborate the design for the specified top modules, import to Yosys and\n");
log("reset the internal state of Verific. A gate-level netlist is created\n");
log("when called with -gates.\n");
log("\n");
@@ -799,7 +850,7 @@ struct VerificPass : public Pass {
#ifdef YOSYS_ENABLE_VERIFIC
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing VERIFIC (loading Verilog and VHDL designs using Verific).\n");
+ log_header(design, "Executing VERIFIC (loading Verilog and VHDL designs using Verific).\n");
Message::SetConsoleOutput(0);
Message::RegisterCallBackMsg(msg_func);
@@ -840,7 +891,7 @@ struct VerificPass : public Pass {
}
if (args.size() > 1 && args[1] == "-vhdl87") {
- vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str());
+ vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1987").c_str());
for (size_t argidx = 2; argidx < args.size(); argidx++)
if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_87))
log_cmd_error("Reading `%s' in VHDL_87 mode failed.\n", args[argidx].c_str());
@@ -917,10 +968,12 @@ struct VerificPass : public Pass {
for (; argidx < args.size(); argidx++) {
if (veri_file::GetModule(args[argidx].c_str())) {
+ log("Running veri_file::Elaborate(\"%s\").\n", args[argidx].c_str());
if (!veri_file::Elaborate(args[argidx].c_str()))
log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str());
nl_todo.insert(Netlist::PresentDesign());
} else {
+ log("Running vhdl_file::Elaborate(\"%s\").\n", args[argidx].c_str());
if (!vhdl_file::Elaborate(args[argidx].c_str()))
log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str());
nl_todo.insert(Netlist::PresentDesign());
@@ -947,6 +1000,6 @@ struct VerificPass : public Pass {
}
#endif
} VerificPass;
-
+
YOSYS_NAMESPACE_END
diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc
index 92cbd0b87..a06c1d5ab 100644
--- a/frontends/verilog/Makefile.inc
+++ b/frontends/verilog/Makefile.inc
@@ -5,13 +5,15 @@ GENFILES += frontends/verilog/verilog_parser.output
GENFILES += frontends/verilog/verilog_lexer.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) mkdir -p $(dir $@)
+ $(P) $(BISON) -d -r all -b frontends/verilog/verilog_parser $<
$(Q) mv frontends/verilog/verilog_parser.tab.c frontends/verilog/verilog_parser.tab.cc
frontends/verilog/verilog_parser.tab.h: frontends/verilog/verilog_parser.tab.cc
frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
- $(P) flex -o frontends/verilog/verilog_lexer.cc frontends/verilog/verilog_lexer.l
+ $(Q) mkdir -p $(dir $@)
+ $(P) flex -o frontends/verilog/verilog_lexer.cc $<
OBJS += frontends/verilog/verilog_parser.tab.o
OBJS += frontends/verilog/verilog_lexer.o
diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc
index 735bc5f99..4a58357bf 100644
--- a/frontends/verilog/const2ast.cc
+++ b/frontends/verilog/const2ast.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -48,7 +48,9 @@ static int my_decimal_div_by_two(std::vector<uint8_t> &digits)
{
int carry = 0;
for (size_t i = 0; i < digits.size(); i++) {
- log_assert(digits[i] < 10);
+ if (digits[i] >= 10)
+ log_error("Invalid use of [a-fxz?] in decimal constant at %s:%d.\n",
+ current_filename.c_str(), get_line_num());
digits[i] += carry * 10;
carry = digits[i] % 2;
digits[i] /= 2;
@@ -91,54 +93,67 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
str++;
}
+ if (base == 10 && GetSize(digits) == 1 && digits.front() >= 0xf0)
+ base = 2;
+
+ data.clear();
+
if (base == 10) {
- data.clear();
- if (len_in_bits < 0) {
- while (!digits.empty())
- data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0);
- while (data.size() < 32)
- data.push_back(RTLIL::S0);
- } else {
- for (int i = 0; i < len_in_bits; i++)
- data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0);
+ while (!digits.empty())
+ data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0);
+ } else {
+ int bits_per_digit = my_ilog2(base-1);
+ for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) {
+ if (*it > (base-1) && *it < 0xf0)
+ log_error("Digit larger than %d used in in base-%d constant at %s:%d.\n",
+ base-1, base, current_filename.c_str(), get_line_num());
+ for (int i = 0; i < bits_per_digit; i++) {
+ int bitmask = 1 << i;
+ if (*it == 0xf0)
+ data.push_back(case_type == 'x' ? RTLIL::Sa : RTLIL::Sx);
+ else if (*it == 0xf1)
+ data.push_back(case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz);
+ else if (*it == 0xf2)
+ data.push_back(RTLIL::Sa);
+ else
+ data.push_back((*it & bitmask) ? RTLIL::S1 : RTLIL::S0);
+ }
}
- return;
}
- int bits_per_digit = my_ilog2(base-1);
- if (len_in_bits < 0)
- len_in_bits = std::max<int>(digits.size() * bits_per_digit, 32);
+ int len = GetSize(data);
+ RTLIL::State msb = data.empty() ? RTLIL::S0 : data.back();
- data.clear();
- data.resize(len_in_bits);
-
- for (int i = 0; i < len_in_bits; i++) {
- int bitmask = 1 << (i % bits_per_digit);
- int digitidx = digits.size() - (i / bits_per_digit) - 1;
- if (digitidx < 0) {
- if (i > 0 && (data[i-1] == RTLIL::Sz || data[i-1] == RTLIL::Sx || data[i-1] == RTLIL::Sa))
- data[i] = data[i-1];
- else
- data[i] = RTLIL::S0;
- } else if (digits[digitidx] == 0xf0)
- data[i] = case_type == 'x' ? RTLIL::Sa : RTLIL::Sx;
- else if (digits[digitidx] == 0xf1)
- data[i] = case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz;
- else if (digits[digitidx] == 0xf2)
- data[i] = RTLIL::Sa;
- else
- data[i] = (digits[digitidx] & bitmask) ? RTLIL::S1 : RTLIL::S0;
+ if (len_in_bits < 0) {
+ if (len < 32)
+ data.resize(32, msb == RTLIL::S0 || msb == RTLIL::S1 ? RTLIL::S0 : msb);
+ return;
+ }
+
+ for (len = len - 1; len >= 0; len--)
+ if (data[len] == RTLIL::S1)
+ break;
+ if (msb == RTLIL::S0 || msb == RTLIL::S1) {
+ len += 1;
+ data.resize(len_in_bits, RTLIL::S0);
+ } else {
+ len += 2;
+ data.resize(len_in_bits, msb);
}
+
+ if (len > len_in_bits)
+ log_warning("Literal has a width of %d bit, but value requires %d bit. (%s:%d)\n",
+ len_in_bits, len, current_filename.c_str(), get_line_num());
}
-// convert the verilog code for a constant to an AST node
+// convert the Verilog code for a constant to an AST node
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());
+ log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n",
+ current_filename.c_str(), get_line_num());
return ret;
}
@@ -215,8 +230,6 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
if (len_in_bits < 0) {
if (is_signed && data.back() == RTLIL::S1)
data.push_back(RTLIL::S0);
- while (data.size() < 32)
- data.push_back(RTLIL::S0);
}
return AstNode::mkconst_bits(data, is_signed);
}
diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc
index 4e5d16599..997920b89 100644
--- a/frontends/verilog/preproc.cc
+++ b/frontends/verilog/preproc.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -39,6 +39,7 @@
#include <string.h>
YOSYS_NAMESPACE_BEGIN
+using namespace VERILOG_FRONTEND;
static std::list<std::string> output_code;
static std::list<std::string> input_buffer;
@@ -109,7 +110,7 @@ static std::string next_token(bool pass_newline = false)
}
return token;
}
-
+
if (ch == ' ' || ch == '\t')
{
while ((ch = next_char()) != 0) {
@@ -201,7 +202,7 @@ 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");
+ 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);
@@ -222,7 +223,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
input_file(f, filename);
defines_map["YOSYS"] = "1";
- defines_map["SYNTHESIS"] = "1";
+ defines_map[formal_mode ? "FORMAL" : "SYNTHESIS"] = "1";
while (!input_buffer.empty())
{
diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc
index 23d35f682..576f068b3 100644
--- a/frontends/verilog/verilog_frontend.cc
+++ b/frontends/verilog/verilog_frontend.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -39,21 +39,33 @@ using namespace VERILOG_FRONTEND;
static std::vector<std::string> verilog_defaults;
static std::list<std::vector<std::string>> verilog_defaults_stack;
+static void error_on_dpi_function(AST::AstNode *node)
+{
+ if (node->type == AST::AST_DPI_FUNCTION)
+ log_error("Found DPI function %s at %s:%d.\n", node->str.c_str(), node->filename.c_str(), node->linenum);
+ for (auto child : node->children)
+ error_on_dpi_function(child);
+}
+
struct VerilogFrontend : public Frontend {
- VerilogFrontend() : Frontend("verilog", "read modules from verilog file") { }
+ VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" read_verilog [options] [filename]\n");
log("\n");
- log("Load modules from a verilog file to the current design. A large subset of\n");
+ log("Load modules from a Verilog file to the current design. A large subset of\n");
log("Verilog-2005 is supported.\n");
log("\n");
log(" -sv\n");
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() from SystemVerilog\n");
+ log(" replace the implicit -D SYNTHESIS with -D FORMAL\n");
+ log("\n");
log(" -dump_ast1\n");
log(" dump abstract syntax tree (before simplification)\n");
log("\n");
@@ -61,7 +73,7 @@ struct VerilogFrontend : public Frontend {
log(" dump abstract syntax tree (after simplification)\n");
log("\n");
log(" -dump_vlog\n");
- log(" dump ast as verilog code (after simplification)\n");
+ log(" dump ast as Verilog code (after simplification)\n");
log("\n");
log(" -yydebug\n");
log(" enable parser debug output\n");
@@ -83,19 +95,31 @@ 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(" dump Verilog code after pre-processor\n");
log("\n");
log(" -nopp\n");
log(" do not run the pre-processor\n");
log("\n");
+ log(" -nodpi\n");
+ log(" disable DPI-C support\n");
+ log("\n");
log(" -lib\n");
- log(" only create empty blackbox modules\n");
+ log(" only create empty blackbox modules. This implies -DBLACKBOX.\n");
log("\n");
log(" -noopt\n");
log(" don't perform basic optimizations (such as const folding) in the\n");
@@ -113,6 +137,9 @@ struct VerilogFrontend : public Frontend {
log(" to a later 'hierarchy' command. Useful in cases where the default\n");
log(" parameters of modules yield invalid or not synthesizable code.\n");
log("\n");
+ log(" -noautowire\n");
+ log(" make the default of `default_nettype be \"none\" instead of \"wire\".\n");
+ log("\n");
log(" -setattr <attribute_name>\n");
log(" set the specified attribute (to the value 1) on all loaded modules\n");
log("\n");
@@ -129,9 +156,12 @@ struct VerilogFrontend : public Frontend {
log("\n");
log("Note that the Verilog frontend does a pretty good job of processing valid\n");
log("verilog input, but has not very good error reporting. It generally is\n");
- log("recommended to use a simulator (for example icarus verilog) for checking\n");
+ log("recommended to use a simulator (for example Icarus Verilog) for checking\n");
log("the syntax of the code, rather than to rely on read_verilog for that.\n");
log("\n");
+ log("See the Yosys README file for a list of non-standard Verilog features\n");
+ log("supported by the Yosys Verilog front-end.\n");
+ log("\n");
}
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
@@ -139,10 +169,12 @@ 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;
bool flag_nopp = false;
+ bool flag_nodpi = false;
bool flag_lib = false;
bool flag_noopt = false;
bool flag_icells = false;
@@ -154,8 +186,10 @@ struct VerilogFrontend : public Frontend {
frontend_verilog_yydebug = false;
sv_mode = false;
+ formal_mode = false;
+ default_nettype_wire = true;
- log_header("Executing Verilog-2005 frontend.\n");
+ log_header(design, "Executing Verilog-2005 frontend.\n");
args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end());
@@ -166,6 +200,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 +224,10 @@ struct VerilogFrontend : public Frontend {
flag_nolatches = true;
continue;
}
+ if (arg == "-nomeminit") {
+ flag_nomeminit = true;
+ continue;
+ }
if (arg == "-nomem2reg") {
flag_nomem2reg = true;
continue;
@@ -202,8 +244,13 @@ struct VerilogFrontend : public Frontend {
flag_nopp = true;
continue;
}
+ if (arg == "-nodpi") {
+ flag_nodpi = true;
+ continue;
+ }
if (arg == "-lib") {
flag_lib = true;
+ defines_map["BLACKBOX"] = string();
continue;
}
if (arg == "-noopt") {
@@ -222,6 +269,10 @@ struct VerilogFrontend : public Frontend {
flag_defer = true;
continue;
}
+ if (arg == "-noautowire") {
+ default_nettype_wire = false;
+ continue;
+ }
if (arg == "-setattr" && argidx+1 < args.size()) {
attributes.push_back(RTLIL::escape_id(args[++argidx]));
continue;
@@ -257,14 +308,14 @@ struct VerilogFrontend : public Frontend {
}
extra_args(f, filename, args, argidx);
- log("Parsing %s input from `%s' to AST representation.\n", sv_mode ? "SystemVerilog" : "Verilog", 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;
AST::get_line_num = &frontend_verilog_yyget_lineno;
current_ast = new AST::AstNode(AST::AST_DESIGN);
- default_nettype_wire = true;
lexin = f;
std::string code_after_preproc;
@@ -288,7 +339,10 @@ 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);
+ if (flag_nodpi)
+ error_on_dpi_function(current_ast);
+
+ 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;
@@ -308,16 +362,16 @@ struct VerilogDefaults : public Pass {
log("\n");
log(" verilog_defaults -add [options]\n");
log("\n");
- log("Add the sepcified options to the list of default options to read_verilog.\n");
+ log("Add the specified options to the list of default options to read_verilog.\n");
log("\n");
log("\n");
- log(" verilog_defaults -clear");
+ log(" verilog_defaults -clear\n");
log("\n");
- log("Clear the list of verilog default options.\n");
+ log("Clear the list of Verilog default options.\n");
log("\n");
log("\n");
- log(" verilog_defaults -push");
- log(" verilog_defaults -pop");
+ log(" verilog_defaults -push\n");
+ log(" verilog_defaults -pop\n");
log("\n");
log("Push or pop the list of default options to a stack. Note that -push does\n");
log("not imply -clear.\n");
diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h
index e277f3e3c..fb98f4afb 100644
--- a/frontends/verilog/verilog_frontend.h
+++ b/frontends/verilog/verilog_frontend.h
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -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/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index cb8fafcb2..107a2dfdd 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -40,7 +40,7 @@
#endif
#include "kernel/log.h"
-#include "verilog_frontend.h"
+#include "frontends/verilog/verilog_frontend.h"
#include "frontends/ast/ast.h"
#include "verilog_parser.tab.h"
@@ -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++;
@@ -134,6 +141,8 @@ YOSYS_NAMESPACE_END
"endfunction" { return TOK_ENDFUNCTION; }
"task" { return TOK_TASK; }
"endtask" { return TOK_ENDTASK; }
+"package" { SV_KEYWORD(TOK_PACKAGE); }
+"endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); }
"parameter" { return TOK_PARAMETER; }
"localparam" { return TOK_LOCALPARAM; }
"defparam" { return TOK_DEFPARAM; }
@@ -162,8 +171,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; SV_KEYWORD(TOK_ASSUME); }
+"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }
"logic" { SV_KEYWORD(TOK_REG); }
"bit" { SV_KEYWORD(TOK_REG); }
@@ -240,7 +250,7 @@ and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 {
supply0 { return TOK_SUPPLY0; }
supply1 { return TOK_SUPPLY1; }
-"$"(display|strobe|monitor|time|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) {
+"$"(display|write|strobe|monitor|time|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_ID;
}
@@ -273,7 +283,7 @@ supply1 { return TOK_SUPPLY1; }
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");
+ "Yosys does support them but it is recommended to use Verilog `full_case' attributes instead!\n");
printed_warning = true;
}
return TOK_SYNOPSYS_FULL_CASE;
@@ -282,7 +292,7 @@ supply1 { return TOK_SUPPLY1; }
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");
+ "Yosys does support them but it is recommended to use Verilog `parallel_case' attributes instead!\n");
printed_warning = true;
}
return TOK_SYNOPSYS_PARALLEL_CASE;
@@ -343,6 +353,8 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
"<<<" { return OP_SSHL; }
">>>" { return OP_SSHR; }
+"::" { SV_KEYWORD(TOK_PACKAGESEP); }
+
"+:" { return TOK_POS_INDEXED; }
"-:" { return TOK_NEG_INDEXED; }
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 621b6cc18..e7c3578c7 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -36,7 +36,7 @@
%{
#include <list>
#include <string.h>
-#include "verilog_frontend.h"
+#include "frontends/verilog/verilog_frontend.h"
#include "kernel/log.h"
USING_YOSYS_NAMESPACE
@@ -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
@@ -102,6 +102,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%token <string> TOK_STRING TOK_ID TOK_CONST TOK_REALVAL TOK_PRIMITIVE
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
+%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
@@ -111,7 +112,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,6 +140,7 @@ 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();
@@ -152,6 +154,9 @@ design:
module design |
defattr design |
task_func_decl design |
+ param_decl design |
+ localparam_decl design |
+ package design |
/* empty */;
attr:
@@ -209,6 +214,14 @@ hierarchical_id:
TOK_ID {
$$ = $1;
} |
+ hierarchical_id TOK_PACKAGESEP TOK_ID {
+ if ($3->substr(0, 1) == "\\")
+ *$1 += "::" + $3->substr(1);
+ else
+ *$1 += "::" + *$3;
+ delete $3;
+ $$ = $1;
+ } |
hierarchical_id '.' TOK_ID {
if ($3->substr(0, 1) == "\\")
*$1 += "." + $3->substr(1);
@@ -243,11 +256,10 @@ module_para_opt:
'#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | /* empty */;
module_para_list:
- single_module_para |
- single_module_para ',' module_para_list |
- /* empty */;
+ single_module_para | module_para_list ',' single_module_para;
single_module_para:
+ /* empty */ |
TOK_PARAMETER {
if (astbuf1) delete astbuf1;
astbuf1 = new AstNode(AST_PARAMETER);
@@ -299,7 +311,7 @@ module_arg:
node->children.push_back($3);
if (!node->is_input && !node->is_output)
frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $4->c_str());
- if (node->is_reg && node->is_input && !node->is_output)
+ if (node->is_reg && node->is_input && !node->is_output && !sv_mode)
frontend_verilog_yyerror("Input port `%s' is declared as register.", $4->c_str());
ast_stack.back()->children.push_back(node);
append_attr(node, $1);
@@ -309,10 +321,36 @@ module_arg:
do_not_require_port_stubs = true;
};
+package:
+ attr TOK_PACKAGE TOK_ID {
+ AstNode *mod = new AstNode(AST_PACKAGE);
+ ast_stack.back()->children.push_back(mod);
+ ast_stack.push_back(mod);
+ current_ast_mod = mod;
+ mod->str = *$3;
+ append_attr(mod, $1);
+ } ';' package_body TOK_ENDPACKAGE {
+ ast_stack.pop_back();
+ current_ast_mod = NULL;
+ };
+
+package_body:
+ package_body package_body_stmt |;
+
+package_body_stmt:
+ localparam_decl;
+
+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;
};
@@ -700,6 +738,8 @@ wire_name_and_opt_assign:
wire_name:
TOK_ID range_or_multirange {
+ if (astbuf1 == nullptr)
+ frontend_verilog_yyerror("Syntax error.");
AstNode *node = astbuf1->clone();
node->str = *$1;
append_attr_clone(node, albuf);
@@ -724,7 +764,7 @@ wire_name:
if (port_stubs.count(*$1) != 0) {
if (!node->is_input && !node->is_output)
frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $1->c_str());
- if (node->is_reg && node->is_input && !node->is_output)
+ if (node->is_reg && node->is_input && !node->is_output && !sv_mode)
frontend_verilog_yyerror("Input port `%s' is declared as register.", $1->c_str());
node->port_id = port_stubs[*$1];
port_stubs.erase(*$1);
@@ -741,13 +781,13 @@ 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;
assign_expr:
- expr '=' expr {
+ lvalue '=' expr {
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, $1, $3));
};
@@ -761,7 +801,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);
@@ -813,10 +853,10 @@ cell_parameter_list_opt:
'#' '(' cell_parameter_list ')' | /* empty */;
cell_parameter_list:
- /* empty */ | cell_parameter |
- cell_parameter ',' cell_parameter_list;
+ cell_parameter | cell_parameter_list ',' cell_parameter;
cell_parameter:
+ /* empty */ |
expr {
AstNode *node = new AstNode(AST_PARASET);
astbuf1->children.push_back(node);
@@ -831,14 +871,10 @@ cell_parameter:
};
cell_port_list:
- /* empty */ | cell_port |
- cell_port ',' cell_port_list |
- /* empty */ ',' {
- AstNode *node = new AstNode(AST_ARGUMENT);
- astbuf2->children.push_back(node);
- } cell_port_list;
+ cell_port | cell_port_list ',' cell_port;
cell_port:
+ /* empty */ |
expr {
AstNode *node = new AstNode(AST_ARGUMENT);
astbuf2->children.push_back(node);
@@ -926,27 +962,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 ';' |
+ defattr | assert | wire_decl | param_decl | localparam_decl |
+ non_opt_delay behavioral_stmt |
+ simple_behavioral_stmt ';' | ';' |
hierarchical_id attr {
AstNode *node = new AstNode(AST_TCALL);
node->str = *$1;
@@ -1039,13 +1082,13 @@ behavioral_stmt:
};
case_type:
- TOK_CASE {
+ TOK_CASE {
case_type_stack.push_back(0);
} |
- TOK_CASEX {
+ TOK_CASEX {
case_type_stack.push_back('x');
} |
- TOK_CASEZ {
+ TOK_CASEZ {
case_type_stack.push_back('z');
};
@@ -1060,10 +1103,6 @@ opt_synopsys_attr:
} |
/* empty */;
-behavioral_stmt_opt:
- behavioral_stmt |
- ';' ;
-
behavioral_stmt_list:
behavioral_stmt_list behavioral_stmt |
/* empty */;
@@ -1084,7 +1123,9 @@ case_body:
case_item:
{
- AstNode *node = new AstNode(AST_COND);
+ AstNode *node = new AstNode(
+ case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX :
+ case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
} case_select {
@@ -1092,7 +1133,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();
@@ -1104,7 +1145,9 @@ gen_case_body:
gen_case_item:
{
- AstNode *node = new AstNode(AST_COND);
+ AstNode *node = new AstNode(
+ case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX :
+ case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
} case_select {
@@ -1330,6 +1373,11 @@ basic_expr:
'(' expr ')' {
$$ = $2;
} |
+ '(' expr ':' expr ':' expr ')' {
+ delete $2;
+ $$ = $4;
+ delete $6;
+ } |
'{' concat_list '}' {
$$ = $2;
} |
diff --git a/frontends/vhdl2verilog/vhdl2verilog.cc b/frontends/vhdl2verilog/vhdl2verilog.cc
index 82ff7b502..6f9c0e3f5 100644
--- a/frontends/vhdl2verilog/vhdl2verilog.cc
+++ b/frontends/vhdl2verilog/vhdl2verilog.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -74,7 +74,7 @@ struct Vhdl2verilogPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing VHDL2VERILOG (importing VHDL designs using vhdl2verilog).\n");
+ log_header(design, "Executing VHDL2VERILOG (importing VHDL designs using vhdl2verilog).\n");
log_push();
std::string out_file, top_entity;
@@ -173,11 +173,11 @@ struct Vhdl2verilogPass : public Pass {
Frontend::frontend_call(design, &ff, stringf("%s/vhdl2verilog_output.v", tempdir_name.c_str()), "verilog");
}
- log_header("Removing temp directory `%s':\n", tempdir_name.c_str());
+ log_header(design, "Removing temp directory `%s':\n", tempdir_name.c_str());
remove_directory(tempdir_name);
log_pop();
}
} Vhdl2verilogPass;
-
+
YOSYS_NAMESPACE_END