Avoid creation of bogus initial blocks for assert/assume in always @*
[yosys.git] / frontends / ast / ast.cc
index 589b08e1dcd33b52d66df00a6b7e6b7ca5605fe9..fd27240090bd448a72c06903359cc69b11a16ca3 100644 (file)
@@ -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
 #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,13 +44,15 @@ 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_dump_rtlil, flag_nolatches, flag_nomeminit;
+       bool 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_always, *current_top_block, *current_block, *current_block_child;
        AstModule *current_module;
+       bool current_always_clocked;
 }
 
 // convert node types to string
@@ -90,6 +83,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)
@@ -145,6 +139,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)
@@ -157,6 +153,7 @@ std::string AST::type2str(AstNodeType type)
        X(AST_POSEDGE)
        X(AST_NEGEDGE)
        X(AST_EDGE)
+       X(AST_PACKAGE)
 #undef X
        default:
                log_abort();
@@ -179,7 +176,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
 
 // create new node (AstNode constructor)
 // (the optional child arguments make it easier to create AST trees)
-AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2)
+AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *child3)
 {
        static unsigned int hashidx_count = 123456789;
        hashidx_count = mkhash_xorshift(hashidx_count);
@@ -207,6 +204,8 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2)
                children.push_back(child1);
        if (child2)
                children.push_back(child2);
+       if (child3)
+               children.push_back(child3);
 }
 
 // create a (deep recursive) copy of a node
@@ -310,6 +309,8 @@ void AstNode::dumpAst(FILE *f, std::string indent)
 
        for (size_t i = 0; i < children.size(); i++)
                children[i]->dumpAst(f, indent + "  ");
+
+       fflush(f);
 }
 
 // helper function for AstNode::dumpVlog()
@@ -328,7 +329,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;
@@ -434,16 +435,15 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
                break;
 
        case AST_ALWAYS:
-               fprintf(f, "%s" "always @(", indent.c_str());
+               fprintf(f, "%s" "always @", indent.c_str());
                for (auto child : children) {
                        if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
                                continue;
-                       if (!first)
-                               fprintf(f, ", ");
+                       fprintf(f, first ? "(" : ", ");
                        child->dumpVlog(f, "");
                        first = false;
                }
-               fprintf(f, ")\n");
+               fprintf(f, first ? "*\n" : ")\n");
                for (auto child : children) {
                        if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
                                child->dumpVlog(f, indent + "  ");
@@ -500,7 +500,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++) {
@@ -511,6 +516,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");
@@ -527,6 +534,14 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
                }
                break;
 
+       case AST_ASSIGN:
+               fprintf(f, "%sassign ", indent.c_str());
+               children[0]->dumpVlog(f, "");
+               fprintf(f, " = ");
+               children[1]->dumpVlog(f, "");
+               fprintf(f, ";\n");
+               break;
+
        case AST_ASSIGN_EQ:
        case AST_ASSIGN_LE:
                fprintf(f, "%s", indent.c_str());
@@ -554,7 +569,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 = "|";  }
@@ -615,6 +630,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
                fprintf(f, "%s" "/** %s **/%s", indent.c_str(), type_name.c_str(), indent.empty() ? "" : "\n");
                // dumpAst(f, indent, NULL);
        }
+
+       fflush(f);
 }
 
 // check if two AST nodes are identical
@@ -698,7 +715,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;
@@ -819,7 +836,7 @@ uint64_t AstNode::asInt(bool is_signed)
        }
 
        if (type == AST_REALVALUE)
-               return realvalue;
+               return uint64_t(realvalue);
 
        log_abort();
 }
@@ -830,7 +847,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());
 
@@ -893,7 +910,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");
        }
@@ -903,13 +920,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");
                }
@@ -958,6 +975,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;
@@ -965,17 +983,27 @@ static AstModule* process_module(AstNode *ast, bool defer)
        current_module->icells = flag_icells;
        current_module->autowire = flag_autowire;
        current_module->fixup_ports();
+
+       if (flag_dump_rtlil) {
+               log("Dumping generated RTLIL:\n");
+               log_module(current_module);
+               log("--- END OF RTLIL DUMP ---\n");
+       }
+
        return current_module;
 }
 
 // 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 dump_rtlil,
+               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_dump_rtlil = dump_rtlil;
        flag_nolatches = nolatches;
+       flag_nomeminit = nomeminit;
        flag_nomem2reg = nomem2reg;
        flag_mem2reg = mem2reg;
        flag_lib = lib;
@@ -993,6 +1021,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);
 
@@ -1010,6 +1046,8 @@ 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);
        }
@@ -1030,13 +1068,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;
@@ -1103,6 +1142,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;