Added nosync attribute and some async reset related fixes

This commit is contained in:
Clifford Wolf 2013-03-25 17:13:14 +01:00
parent 3737964809
commit 227520f94d
5 changed files with 27 additions and 34 deletions

6
README
View File

@ -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

View 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)

View 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;
}

View 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

View 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;