summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README6
-rw-r--r--frontends/ast/ast.h2
-rw-r--r--frontends/ast/genrtlil.cc8
-rw-r--r--frontends/ast/simplify.cc40
-rw-r--r--passes/proc/proc_arst.cc5
5 files changed, 27 insertions, 34 deletions
diff --git a/README b/README
index e86d92d4..ab9fcd61 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 81d29a02..d65851ac 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<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)
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index b12573e6..0654db2d 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<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;
}
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 8a02cc12..ef06c5b0 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<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
diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc
index 62dfebae..d0a0d864 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;