Avoid creation of bogus initial blocks for assert/assume in always @*
[yosys.git] / frontends / ast / ast.cc
index 10c7fc85bf8212809885240b1cfe5ba22825dd30..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 "kernel/log.h"
+#include "kernel/yosys.h"
 #include "libs/sha1/sha1.h"
 #include "ast.h"
 
-#include <sstream>
-#include <stdarg.h>
-#include <assert.h>
+YOSYS_NAMESPACE_BEGIN
 
 using namespace AST;
 using namespace AST_INTERNAL;
@@ -46,14 +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;
+       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;
-       RTLIL::SigSpec *genRTLIL_subst_from = NULL;
-       RTLIL::SigSpec *genRTLIL_subst_to = NULL;
+       const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
        RTLIL::SigSpec ignoreThisSignalsInInitial;
-       AstNode *current_top_block, *current_block, *current_block_child;
+       AstNode *current_always, *current_top_block, *current_block, *current_block_child;
        AstModule *current_module;
+       bool current_always_clocked;
 }
 
 // convert node types to string
@@ -67,6 +66,7 @@ std::string AST::type2str(AstNodeType type)
        X(AST_MODULE)
        X(AST_TASK)
        X(AST_FUNCTION)
+       X(AST_DPI_FUNCTION)
        X(AST_WIRE)
        X(AST_MEMORY)
        X(AST_AUTOWIRE)
@@ -76,11 +76,16 @@ std::string AST::type2str(AstNodeType type)
        X(AST_PARASET)
        X(AST_ARGUMENT)
        X(AST_RANGE)
+       X(AST_MULTIRANGE)
        X(AST_CONSTANT)
+       X(AST_REALVALUE)
        X(AST_CELLTYPE)
        X(AST_IDENTIFIER)
        X(AST_PREFIX)
+       X(AST_ASSERT)
+       X(AST_ASSUME)
        X(AST_FCALL)
+       X(AST_TO_BITS)
        X(AST_TO_SIGNED)
        X(AST_TO_UNSIGNED)
        X(AST_CONCAT)
@@ -103,6 +108,8 @@ std::string AST::type2str(AstNodeType type)
        X(AST_LE)
        X(AST_EQ)
        X(AST_NE)
+       X(AST_EQX)
+       X(AST_NEX)
        X(AST_GE)
        X(AST_GT)
        X(AST_ADD)
@@ -119,10 +126,12 @@ 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)
        X(AST_PRIMITIVE)
+       X(AST_CELLARRAY)
        X(AST_ALWAYS)
        X(AST_INITIAL)
        X(AST_BLOCK)
@@ -130,8 +139,12 @@ 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)
+       X(AST_REPEAT)
        X(AST_GENVAR)
        X(AST_GENFOR)
        X(AST_GENIF)
@@ -140,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();
@@ -162,8 +176,12 @@ 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);
+       hashidx_ = hashidx_count;
+
        this->type = type;
        filename = current_filename;
        linenum = get_line_num();
@@ -171,17 +189,23 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2)
        is_output = false;
        is_reg = false;
        is_signed = false;
+       is_string = false;
        range_valid = false;
+       range_swapped = false;
        port_id = 0;
        range_left = -1;
        range_right = 0;
        integer = 0;
+       realvalue = 0;
        id2ast = NULL;
+       basic_prep = false;
 
        if (child1)
                children.push_back(child1);
        if (child2)
                children.push_back(child2);
+       if (child3)
+               children.push_back(child3);
 }
 
 // create a (deep recursive) copy of a node
@@ -237,6 +261,12 @@ void AstNode::dumpAst(FILE *f, std::string indent)
 
        std::string type_name = type2str(type);
        fprintf(f, "%s%s <%s:%d>", indent.c_str(), type_name.c_str(), filename.c_str(), linenum);
+
+       if (id2ast)
+               fprintf(f, " [%p -> %p]", this, id2ast);
+       else
+               fprintf(f, " [%p]", this);
+
        if (!str.empty())
                fprintf(f, " str='%s'", str.c_str());
        if (!bits.empty()) {
@@ -246,7 +276,7 @@ void AstNode::dumpAst(FILE *f, std::string indent)
                                        bits[i-1] == RTLIL::S1 ? '1' :
                                        bits[i-1] == RTLIL::Sx ? 'x' :
                                        bits[i-1] == RTLIL::Sz ? 'z' : '?');
-               fprintf(f, "'(%zd)", bits.size());
+               fprintf(f, "'(%d)", GetSize(bits));
        }
        if (is_input)
                fprintf(f, " input");
@@ -259,9 +289,17 @@ void AstNode::dumpAst(FILE *f, std::string indent)
        if (port_id > 0)
                fprintf(f, " port=%d", port_id);
        if (range_valid || range_left != -1 || range_right != 0)
-               fprintf(f, " range=[%d:%d]%s", range_left, range_right, range_valid ? "" : "!");
+               fprintf(f, " %srange=[%d:%d]%s", range_swapped ? "swapped_" : "", range_left, range_right, range_valid ? "" : "!");
        if (integer != 0)
                fprintf(f, " int=%u", (int)integer);
+       if (realvalue != 0)
+               fprintf(f, " real=%e", realvalue);
+       if (!multirange_dimensions.empty()) {
+               fprintf(f, " multirange=[");
+               for (int v : multirange_dimensions)
+                       fprintf(f, " %d", v);
+               fprintf(f, " ]");
+       }
        fprintf(f, "\n");
 
        for (auto &it : attributes) {
@@ -271,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()
@@ -289,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;
@@ -303,7 +343,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
        }
 
        for (auto &it : attributes) {
-               fprintf(f, "%s" "(* %s = ", indent.c_str(), id2vl(it.first).c_str());
+               fprintf(f, "%s" "(* %s = ", indent.c_str(), id2vl(it.first.str()).c_str());
                it.second->dumpVlog(f, "");
                fprintf(f, " *)%s", indent.empty() ? "" : "\n");
        }
@@ -395,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 + "  ");
@@ -442,7 +481,11 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
                else if (bits.size() == 32)
                        fprintf(f, "%d", RTLIL::Const(bits).as_int());
                else
-                       fprintf(f, "%zd'b %s", bits.size(), RTLIL::Const(bits).as_string().c_str());
+                       fprintf(f, "%d'b %s", GetSize(bits), RTLIL::Const(bits).as_string().c_str());
+               break;
+
+       case AST_REALVALUE:
+               fprintf(f, "%e", realvalue);
                break;
 
        case AST_BLOCK:
@@ -457,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++) {
@@ -468,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");
@@ -484,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());
@@ -511,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 = "|";  }
@@ -538,6 +596,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
        if (0) { case AST_LE:           txt = "<=";  }
        if (0) { case AST_EQ:           txt = "==";  }
        if (0) { case AST_NE:           txt = "!=";  }
+       if (0) { case AST_EQX:          txt = "===";  }
+       if (0) { case AST_NEX:          txt = "!==";  }
        if (0) { case AST_GE:           txt = ">=";  }
        if (0) { case AST_GT:           txt = ">";   }
        if (0) { case AST_ADD:          txt = "+";   }
@@ -570,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
@@ -591,8 +653,12 @@ bool AstNode::operator==(const AstNode &other) const
                return false;
        if (is_signed != other.is_signed)
                return false;
+       if (is_string != other.is_string)
+               return false;
        if (range_valid != other.range_valid)
                return false;
+       if (range_swapped != other.range_swapped)
+               return false;
        if (port_id != other.port_id)
                return false;
        if (range_left != other.range_left)
@@ -649,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;
@@ -658,6 +724,42 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
        return node;
 }
 
+// create an AST node for a constant (using a string in bit vector form as value)
+AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
+{
+       AstNode *node = mkconst_str(RTLIL::Const(v).decode_string());
+       while (GetSize(node->bits) < GetSize(v))
+               node->bits.push_back(RTLIL::State::S0);
+       log_assert(node->bits == v);
+       return node;
+}
+
+// create an AST node for a constant (using a string as value)
+AstNode *AstNode::mkconst_str(const std::string &str)
+{
+       std::vector<RTLIL::State> data;
+       data.reserve(str.size() * 8);
+       for (size_t i = 0; i < str.size(); i++) {
+               unsigned char ch = str[str.size() - i - 1];
+               for (int j = 0; j < 8; j++) {
+                       data.push_back((ch & 1) ? RTLIL::S1 : RTLIL::S0);
+                       ch = ch >> 1;
+               }
+       }
+       AstNode *node = AstNode::mkconst_bits(data, false);
+       node->is_string = true;
+       node->str = str;
+       return node;
+}
+
+bool AstNode::bits_only_01()
+{
+       for (auto bit : bits)
+               if (bit != RTLIL::S0 && bit != RTLIL::S1)
+                       return false;
+       return true;
+}
+
 RTLIL::Const AstNode::bitsAsConst(int width, bool is_signed)
 {
        std::vector<RTLIL::State> bits = this->bits;
@@ -685,7 +787,7 @@ RTLIL::Const AstNode::asAttrConst()
        RTLIL::Const val;
        val.bits = bits;
 
-       if (!str.empty()) {
+       if (is_string) {
                val.flags |= RTLIL::CONST_FLAG_STRING;
                log_assert(val.decode_string() == str);
        }
@@ -710,11 +812,94 @@ bool AstNode::asBool()
        return false;
 }
 
+int AstNode::isConst()
+{
+       if (type == AST_CONSTANT)
+               return 1;
+       if (type == AST_REALVALUE)
+               return 2;
+       return 0;
+}
+
+uint64_t AstNode::asInt(bool is_signed)
+{
+       if (type == AST_CONSTANT)
+       {
+               RTLIL::Const v = bitsAsConst(64, is_signed);
+               uint64_t ret = 0;
+
+               for (int i = 0; i < 64; i++)
+                       if (v.bits.at(i) == RTLIL::State::S1)
+                               ret |= uint64_t(1) << i;
+
+               return ret;
+       }
+
+       if (type == AST_REALVALUE)
+               return uint64_t(realvalue);
+
+       log_abort();
+}
+
+double AstNode::asReal(bool is_signed)
+{
+       if (type == AST_CONSTANT)
+       {
+               RTLIL::Const val(bits);
+
+               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());
+
+               double v = 0;
+               for (size_t i = 0; i < val.bits.size(); i++)
+                       // IEEE Std 1800-2012 Par 6.12.2: Individual bits that are x or z in
+                       // the net or the variable shall be treated as zero upon conversion.
+                       if (val.bits.at(i) == RTLIL::State::S1)
+                               v += exp2(i);
+               if (is_negative)
+                       v *= -1;
+
+               return v;
+       }
+
+       if (type == AST_REALVALUE)
+               return realvalue;
+
+       log_abort();
+}
+
+RTLIL::Const AstNode::realAsConst(int width)
+{
+       double v = round(realvalue);
+       RTLIL::Const result;
+#ifdef EMSCRIPTEN
+       if (!isfinite(v)) {
+#else
+       if (!std::isfinite(v)) {
+#endif
+               result.bits = std::vector<RTLIL::State>(width, RTLIL::State::Sx);
+       } else {
+               bool is_negative = v < 0;
+               if (is_negative)
+                       v *= -1;
+               for (int i = 0; i < width; i++, v /= 2)
+                       result.bits.push_back((fmod(floor(v), 2) != 0) ? RTLIL::State::S1 : RTLIL::State::S0);
+               if (is_negative)
+                       result = const_neg(result, result, false, false, result.bits.size());
+       }
+       return result;
+}
+
 // create a new AstModule from an AST_MODULE AST node
-static AstModule* process_module(AstNode *ast)
+static AstModule* process_module(AstNode *ast, bool defer)
 {
-       assert(ast->type == AST_MODULE);
-       log("Generating RTLIL representation for module `%s'.\n", ast->str.c_str());
+       log_assert(ast->type == AST_MODULE);
+
+       if (defer)
+               log("Storing AST representation for module `%s'.\n", ast->str.c_str());
+       else
+               log("Generating RTLIL representation for module `%s'.\n", ast->str.c_str());
 
        current_module = new AstModule;
        current_module->ast = NULL;
@@ -725,99 +910,146 @@ static AstModule* process_module(AstNode *ast)
        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");
        }
 
-       while (ast->simplify(!flag_noopt, false, false, 0, -1, false)) { }
+       if (!defer)
+       {
+               while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { }
 
-       if (flag_dump_ast2) {
-               log("Dumping verilog AST after simplification:\n");
-               ast->dumpAst(NULL, "    ");
-               log("--- END OF AST DUMP ---\n");
-       }
+               if (flag_dump_ast2) {
+                       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");
-               ast->dumpVlog(NULL, "    ");
-               log("--- END OF AST DUMP ---\n");
-       }
+               if (flag_dump_vlog) {
+                       log("Dumping Verilog AST (as requested by dump_vlog option):\n");
+                       ast->dumpVlog(NULL, "    ");
+                       log("--- END OF AST DUMP ---\n");
+               }
 
-       if (flag_lib) {
-               std::vector<AstNode*> new_children;
-               for (auto child : ast->children) {
-                       if (child->type == AST_WIRE && (child->is_input || child->is_output))
-                               new_children.push_back(child);
-                       else
-                               delete child;
+               if (flag_lib) {
+                       std::vector<AstNode*> new_children;
+                       for (auto child : ast->children) {
+                               if (child->type == AST_WIRE && (child->is_input || child->is_output))
+                                       new_children.push_back(child);
+                               else
+                                       delete child;
+                       }
+                       ast->children.swap(new_children);
+                       ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
                }
-               ast->children.swap(new_children);
-               ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
-       }
 
-       ignoreThisSignalsInInitial = RTLIL::SigSpec();
+               ignoreThisSignalsInInitial = RTLIL::SigSpec();
 
-       for (auto &attr : ast->attributes) {
-               if (attr.second->type != AST_CONSTANT)
-                       log_error("Attribute `%s' with non-constant value at %s:%d!\n",
-                                       attr.first.c_str(), ast->filename.c_str(), ast->linenum);
-               current_module->attributes[attr.first] = attr.second->asAttrConst();
-       }
-       for (size_t i = 0; i < ast->children.size(); i++) {
-               AstNode *node = ast->children[i];
-               if (node->type == AST_WIRE || node->type == AST_MEMORY)
-                       node->genRTLIL();
-       }
-       for (size_t i = 0; i < ast->children.size(); i++) {
-               AstNode *node = ast->children[i];
-               if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL)
-                       node->genRTLIL();
-       }
+               for (auto &attr : ast->attributes) {
+                       if (attr.second->type != AST_CONSTANT)
+                               log_error("Attribute `%s' with non-constant value at %s:%d!\n",
+                                               attr.first.c_str(), ast->filename.c_str(), ast->linenum);
+                       current_module->attributes[attr.first] = attr.second->asAttrConst();
+               }
+               for (size_t i = 0; i < ast->children.size(); i++) {
+                       AstNode *node = ast->children[i];
+                       if (node->type == AST_WIRE || node->type == AST_MEMORY)
+                               node->genRTLIL();
+               }
+               for (size_t i = 0; i < ast->children.size(); i++) {
+                       AstNode *node = ast->children[i];
+                       if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL)
+                               node->genRTLIL();
+               }
 
-       ignoreThisSignalsInInitial.sort_and_unify();
+               ignoreThisSignalsInInitial.sort_and_unify();
 
-       for (size_t i = 0; i < ast->children.size(); i++) {
-               AstNode *node = ast->children[i];
-               if (node->type == AST_INITIAL)
-                       node->genRTLIL();
-       }
+               for (size_t i = 0; i < ast->children.size(); i++) {
+                       AstNode *node = ast->children[i];
+                       if (node->type == AST_INITIAL)
+                               node->genRTLIL();
+               }
 
-       ignoreThisSignalsInInitial = RTLIL::SigSpec();
+               ignoreThisSignalsInInitial = RTLIL::SigSpec();
+       }
 
        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;
        current_module->noopt = flag_noopt;
+       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 ignore_redef)
+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;
        flag_noopt = noopt;
+       flag_icells = icells;
+       flag_autowire = autowire;
+
+       std::vector<AstNode*> global_decls;
 
-       assert(current_ast->type == AST_DESIGN);
-       for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++) {
-               if (design->modules.count((*it)->str) != 0) {
-                       if (!ignore_redef)
-                               log_error("Re-definition of module `%s' at %s:%d!\n",
+       log_assert(current_ast->type == AST_DESIGN);
+       for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++)
+       {
+               if ((*it)->type == AST_MODULE)
+               {
+                       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);
+
+                       if (defer)
+                               (*it)->str = "$abstract" + (*it)->str;
+
+                       if (design->has((*it)->str)) {
+                               if (!ignore_redef)
+                                       log_error("Re-definition of module `%s' at %s:%d!\n",
+                                                       (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
+                               log("Ignoring re-definition of module `%s' at %s:%d!\n",
                                                (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
-                       log_error("Ignoring re-definition of module `%s' at %s:%d!\n",
-                                       (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
-                       continue;
+                               continue;
+                       }
+
+                       design->add(process_module(*it, defer));
                }
-               design->modules[(*it)->str] = process_module(*it);
+               else if ((*it)->type == AST_PACKAGE)
+                       design->verilog_packages.push_back((*it)->clone());
+               else
+                       global_decls.push_back(*it);
        }
 }
 
@@ -829,29 +1061,34 @@ AstModule::~AstModule()
 }
 
 // create a new parametric module (when needed) and return the name of the generated module
-RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters)
+RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters)
 {
-       log_header("Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", name.c_str());
+       std::string stripped_name = name.str();
+
+       if (stripped_name.substr(0, 9) == "$abstract")
+               stripped_name = stripped_name.substr(9);
+
+       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;
        flag_noopt = noopt;
+       flag_icells = icells;
+       flag_autowire = autowire;
        use_internal_line_num();
 
        std::string para_info;
-       std::vector<unsigned char> hash_data;
-       hash_data.insert(hash_data.end(), name.begin(), name.end());
-       hash_data.push_back(0);
-
        AstNode *new_ast = ast->clone();
 
        int para_counter = 0;
+       int orig_parameters_n = parameters.size();
        for (auto it = new_ast->children.begin(); it != new_ast->children.end(); it++) {
                AstNode *child = *it;
                if (child->type != AST_PARAMETER)
@@ -864,10 +1101,6 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
                        para_info += stringf("%s=%s", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id])));
                        delete child->children.at(0);
                        child->children[0] = AstNode::mkconst_bits(parameters[para_id].bits, (parameters[para_id].flags & RTLIL::CONST_FLAG_SIGNED) != 0);
-                       hash_data.insert(hash_data.end(), child->str.begin(), child->str.end());
-                       hash_data.push_back(0);
-                       hash_data.insert(hash_data.end(), parameters[para_id].bits.begin(), parameters[para_id].bits.end());
-                       hash_data.push_back(0xff);
                        parameters.erase(para_id);
                        continue;
                }
@@ -878,33 +1111,21 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
                }
        }
        if (parameters.size() > 0)
-               log_error("Requested parameter `%s' does not exist in module `%s'!\n", parameters.begin()->first.c_str(), name.c_str());
+               log_error("Requested parameter `%s' does not exist in module `%s'!\n", parameters.begin()->first.c_str(), stripped_name.c_str());
 
        std::string modname;
 
-       if (para_info.size() > 60)
-       {
-               unsigned char hash[20];
-               unsigned char *hash_data2 = new unsigned char[hash_data.size()];
-               for (size_t i = 0; i < hash_data.size(); i++)
-                       hash_data2[i] = hash_data[i];
-               sha1::calc(hash_data2, hash_data.size(), hash);
-               delete[] hash_data2;
-
-               char hexstring[41];
-               sha1::toHexString(hash, hexstring);
-
-               modname = "$paramod$" + std::string(hexstring) + name;
-       }
+       if (orig_parameters_n == 0)
+               modname = stripped_name;
+       else if (para_info.size() > 60)
+               modname = "$paramod$" + sha1(para_info) + stripped_name;
        else
-       {
-               modname = "$paramod" + name + para_info;
-       }
+               modname = "$paramod" + stripped_name + para_info;
 
-       if (design->modules.count(modname) == 0) {
+       if (!design->has(modname)) {
                new_ast->str = modname;
-               design->modules[modname] = process_module(new_ast);
-               design->modules[modname]->check();
+               design->add(process_module(new_ast, false));
+               design->module(modname)->check();
        } else {
                log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
        }
@@ -916,14 +1137,18 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
 RTLIL::Module *AstModule::clone() const
 {
        AstModule *new_mod = new AstModule;
+       new_mod->name = name;
        cloneInto(new_mod);
 
        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;
        new_mod->noopt = noopt;
+       new_mod->icells = icells;
+       new_mod->autowire = autowire;
 
        return new_mod;
 }
@@ -946,3 +1171,5 @@ void AST::use_internal_line_num()
        get_line_num = &internal_get_line_num;
 }
 
+YOSYS_NAMESPACE_END
+