Added nosync attribute and some async reset related fixes
authorClifford Wolf <clifford@clifford.at>
Mon, 25 Mar 2013 16:13:14 +0000 (17:13 +0100)
committerClifford Wolf <clifford@clifford.at>
Mon, 25 Mar 2013 16:13:14 +0000 (17:13 +0100)
README
frontends/ast/ast.h
frontends/ast/genrtlil.cc
frontends/ast/simplify.cc
passes/proc/proc_arst.cc

diff --git a/README b/README
index e86d92d4f31f139f04ed38e72db4c68cdfe90796..ab9fcd6127d5b0b17e60301cb6ff473b7566db1b 100644 (file)
--- a/README
+++ b/README
@@ -199,6 +199,12 @@ Verilog Attributes and non-standard features
   prohibits the generation of logic-loops for latches. Instead
   all not explicitly assigned values default to x-bits.
 
+- The "nosync" attribute on registers prohibits the generation of a
+  storage element. The register itself will always have all bits set
+  to 'x' (undefined). The variable may only be used as blocking assigned
+  temporary variable within an always block. This is mostly used internally
+  by yosys to synthesize verilog functions and access arrays.
+
 - In addition to the (* ... *) attribute syntax, yosys supports
   the non-standard {* ... *} attribute syntax to set default attributes
   for everything that comes after the {* ... *} statement. (Reset
index 81d29a02fd2192041685d19484fbbc5e7ca5cb40..d65851acd4a68920cad315e15f0f4e3b41a5db4a 100644 (file)
@@ -165,7 +165,7 @@ namespace AST
                void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map);
                void replace_ids(std::map<std::string, std::string> &rules);
                void mem2reg_as_needed_pass1(std::set<AstNode*> &mem2reg_set, std::set<AstNode*> &mem2reg_candidates, bool sync_proc, bool async_proc, bool force_mem2reg);
-               void mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *top_block);
+               void mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block);
                void meminfo(int &mem_width, int &mem_size, int &addr_bits);
 
                // create a human-readable text representation of the AST (for debugging)
index b12573e698799d4946d59932570cf32e76d74bdd..0654db2df59ba562aa3942c4087d3eacde35ddc2 100644 (file)
@@ -245,14 +245,14 @@ struct AST_INTERNAL::ProcessGenerator
                                RTLIL::SyncRule *syncrule = new RTLIL::SyncRule;
                                syncrule->type = child->type == AST_POSEDGE ? RTLIL::STp : RTLIL::STn;
                                syncrule->signal = child->children[0]->genRTLIL();
-                               addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to);
+                               addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true);
                                proc->syncs.push_back(syncrule);
                        }
                if (proc->syncs.empty()) {
                        RTLIL::SyncRule *syncrule = new RTLIL::SyncRule;
                        syncrule->type = RTLIL::STa;
                        syncrule->signal = RTLIL::SigSpec();
-                       addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to);
+                       addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true);
                        proc->syncs.push_back(syncrule);
                }
 
@@ -350,7 +350,7 @@ struct AST_INTERNAL::ProcessGenerator
 
        // add an assignment (aka "action") but split it up in chunks. this way huge assignments
        // are avoided and the generated $mux cells have a more "natural" size.
-       void addChunkActions(std::vector<RTLIL::SigSig> &actions, RTLIL::SigSpec lvalue, RTLIL::SigSpec rvalue)
+       void addChunkActions(std::vector<RTLIL::SigSig> &actions, RTLIL::SigSpec lvalue, RTLIL::SigSpec rvalue, bool noSyncToUndef = false)
        {
                assert(lvalue.width == rvalue.width);
                lvalue.optimize();
@@ -360,6 +360,8 @@ struct AST_INTERNAL::ProcessGenerator
                for (size_t i = 0; i < lvalue.chunks.size(); i++) {
                        RTLIL::SigSpec lhs = lvalue.chunks[i];
                        RTLIL::SigSpec rhs = rvalue.extract(offset, lvalue.chunks[i].width);
+                       if (noSyncToUndef && lvalue.chunks[i].wire && lvalue.chunks[i].wire->attributes.count("\\nosync"))
+                               rhs = RTLIL::SigSpec(RTLIL::State::Sx, rhs.width);
                        actions.push_back(RTLIL::SigSig(lhs, rhs));
                        offset += lhs.width;
                }
index 8a02cc12942516341e7a96a679b9be26049efe3e..ef06c5b032a9c71d998b061662433dff48bc5328 100644 (file)
@@ -74,7 +74,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
                                }
                        }
 
-                       mem2reg_as_needed_pass2(mem2reg_set, this, NULL, NULL);
+                       mem2reg_as_needed_pass2(mem2reg_set, this, NULL);
 
                        for (size_t i = 0; i < children.size(); i++) {
                                if (mem2reg_set.count(children[i]) > 0) {
@@ -685,6 +685,8 @@ skip_dynamic_range_lvalue_expansion:;
                                wire->port_id = 0;
                                wire->is_input = false;
                                wire->is_output = false;
+                               if (type == AST_FCALL)
+                                       wire->attributes["\\nosync"] = AstNode::mkconst_int(0, false, 0);
                                current_ast_mod->children.push_back(wire);
 
                                replace_rules[child->str] = wire->str;
@@ -957,7 +959,7 @@ void AstNode::mem2reg_as_needed_pass1(std::set<AstNode*> &mem2reg_set, std::set<
 }
 
 // actually replace memories with registers
-void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *top_block)
+void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block)
 {
        if (type == AST_BLOCK)
                block = this;
@@ -975,25 +977,15 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
                AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true)));
                wire_addr->str = id_addr;
                wire_addr->is_reg = true;
+               wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(0, false, 0);
                mod->children.push_back(wire_addr);
 
                AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
                wire_data->str = id_data;
                wire_data->is_reg = true;
+               wire_data->attributes["\\nosync"] = AstNode::mkconst_int(0, false, 0);
                mod->children.push_back(wire_data);
 
-               assert(top_block != NULL);
-               std::vector<RTLIL::State> x_bits;
-               x_bits.push_back(RTLIL::State::Sx);
-
-               AstNode *assign_addr_x = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false));
-               assign_addr_x->children[0]->str = id_addr;
-               top_block->children.insert(top_block->children.begin(), assign_addr_x);
-
-               AstNode *assign_data_x = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false));
-               assign_data_x->children[0]->str = id_data;
-               top_block->children.insert(top_block->children.begin(), assign_data_x);
-
                assert(block != NULL);
                size_t assign_idx = 0;
                while (assign_idx < block->children.size() && block->children[assign_idx] != this)
@@ -1036,10 +1028,12 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
 
                AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true)));
                wire_addr->str = id_addr;
+               wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(0, false, 0);
                mod->children.push_back(wire_addr);
 
                AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
                wire_data->str = id_data;
+               wire_data->attributes["\\nosync"] = AstNode::mkconst_int(0, false, 0);
                mod->children.push_back(wire_data);
 
                AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone());
@@ -1068,17 +1062,6 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
                cond_node->children[1]->children.push_back(assign_reg);
                case_node->children.push_back(cond_node);
 
-               if (top_block)
-               {
-                       AstNode *assign_addr_x = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false));
-                       assign_addr_x->children[0]->str = id_addr;
-                       top_block->children.insert(top_block->children.begin(), assign_addr_x);
-
-                       AstNode *assign_data_x = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false));
-                       assign_data_x->children[0]->str = id_data;
-                       top_block->children.insert(top_block->children.begin(), assign_data_x);
-               }
-
                if (block)
                {
                        size_t assign_idx = 0;
@@ -1107,11 +1090,8 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
        assert(id2ast == NULL || mem2reg_set.count(id2ast) == 0);
 
        auto children_list = children;
-       for (size_t i = 0; i < children_list.size(); i++) {
-               if (type == AST_ALWAYS && children_list[i]->type == AST_BLOCK)
-                       top_block = children_list[i];
-               children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block, top_block);
-       }
+       for (size_t i = 0; i < children_list.size(); i++)
+               children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block);
 }
 
 // calulate memory dimensions
index 62dfebaecd9918765e0b9c8361b74cf9827875cb..d0a0d864c62f9b8d5f6163f0e08c77fe80cb5b29 100644 (file)
@@ -150,6 +150,11 @@ static void proc_arst(RTLIL::Module *mod, RTLIL::Process *proc, SigMap &assign_m
                                for (auto &action : sync->actions) {
                                        RTLIL::SigSpec rspec = action.second;
                                        RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.width);
+                                       rspec.expand(), rval.expand();
+                                       for (int i = 0; i < int(rspec.chunks.size()); i++)
+                                               if (rspec.chunks[i].wire == NULL)
+                                                       rval.chunks[i] = rspec.chunks[i];
+                                       rspec.optimize(), rval.optimize();
                                        RTLIL::SigSpec last_rval;
                                        for (int count = 0; rval != last_rval; count++) {
                                                last_rval = rval;