From 227520f94d5fe0eb983889b61ed9b72640f1b4f4 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 25 Mar 2013 17:13:14 +0100 Subject: [PATCH] Added nosync attribute and some async reset related fixes --- README | 6 ++++++ frontends/ast/ast.h | 2 +- frontends/ast/genrtlil.cc | 8 +++++--- frontends/ast/simplify.cc | 40 ++++++++++----------------------------- passes/proc/proc_arst.cc | 5 +++++ 5 files changed, 27 insertions(+), 34 deletions(-) diff --git a/README b/README index e86d92d4f..ab9fcd612 100644 --- 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 diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 81d29a02f..d65851acd 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -165,7 +165,7 @@ namespace AST void expand_genblock(std::string index_var, std::string prefix, std::map &name_map); void replace_ids(std::map &rules); void mem2reg_as_needed_pass1(std::set &mem2reg_set, std::set &mem2reg_candidates, bool sync_proc, bool async_proc, bool force_mem2reg); - void mem2reg_as_needed_pass2(std::set &mem2reg_set, AstNode *mod, AstNode *block, AstNode *top_block); + void mem2reg_as_needed_pass2(std::set &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) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index b12573e69..0654db2df 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -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 &actions, RTLIL::SigSpec lvalue, RTLIL::SigSpec rvalue) + void addChunkActions(std::vector &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; } diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 8a02cc129..ef06c5b03 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -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 &mem2reg_set, std::set< } // actually replace memories with registers -void AstNode::mem2reg_as_needed_pass2(std::set &mem2reg_set, AstNode *mod, AstNode *block, AstNode *top_block) +void AstNode::mem2reg_as_needed_pass2(std::set &mem2reg_set, AstNode *mod, AstNode *block) { if (type == AST_BLOCK) block = this; @@ -975,25 +977,15 @@ void AstNode::mem2reg_as_needed_pass2(std::set &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 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 &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 &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 &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 diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc index 62dfebaec..d0a0d864c 100644 --- a/passes/proc/proc_arst.cc +++ b/passes/proc/proc_arst.cc @@ -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; -- 2.30.2