From: Clifford Wolf Date: Mon, 21 Oct 2013 12:51:58 +0000 (+0200) Subject: Improved handling of dff with async resets X-Git-Tag: yosys-0.2.0~454 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d61699843fc3ecab9c484d911f43877e9a7a9d3d;p=yosys.git Improved handling of dff with async resets --- diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc index 8e02a624e..db7a59f5b 100644 --- a/passes/proc/proc_dff.cc +++ b/passes/proc/proc_dff.cc @@ -147,6 +147,7 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce) while (1) { RTLIL::SigSpec sig = find_any_lvalue(proc); + bool free_sync_level = false; if (sig.width == 0) break; @@ -160,6 +161,8 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce) RTLIL::SyncRule *sync_edge = NULL; RTLIL::SyncRule *sync_always = NULL; + std::map> many_async_rules; + for (auto sync : proc->syncs) for (auto &action : sync->actions) { @@ -167,8 +170,12 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce) continue; if (sync->type == RTLIL::SyncType::ST0 || sync->type == RTLIL::SyncType::ST1) { - if (sync_level != NULL && sync_level != sync) - log_error("Multiple level sensitive events found for this signal!\n"); + if (sync_level != NULL && sync_level != sync) { + // log_error("Multiple level sensitive events found for this signal!\n"); + many_async_rules[rstval].insert(sync_level); + rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.width); + } + rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.width); sig.replace(action.first, action.second, &rstval); sync_level = sync; } @@ -191,6 +198,46 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce) action.first.remove2(sig, &action.second); } + if (many_async_rules.size() > 0) + { + many_async_rules[rstval].insert(sync_level); + if (many_async_rules.size() == 1) + { + sync_level = new RTLIL::SyncRule; + sync_level->type = RTLIL::SyncType::ST1; + sync_level->signal = NEW_WIRE(mod, 1); + sync_level->actions.push_back(RTLIL::SigSig(sig, rstval)); + free_sync_level = true; + + RTLIL::SigSpec inputs, compare; + for (auto &it : many_async_rules[rstval]) { + inputs.append(it->signal); + compare.append(it->type == RTLIL::SyncType::ST0 ? RTLIL::State::S1 : RTLIL::State::S0); + } + assert(inputs.width == compare.width); + + RTLIL::Cell *cell = new RTLIL::Cell; + cell->name = NEW_ID; + cell->type = "$ne"; + cell->parameters["\\A_SIGNED"] = RTLIL::Const(false, 1); + cell->parameters["\\B_SIGNED"] = RTLIL::Const(false, 1); + cell->parameters["\\A_WIDTH"] = RTLIL::Const(inputs.width); + cell->parameters["\\B_WIDTH"] = RTLIL::Const(inputs.width); + cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1); + cell->connections["\\A"] = inputs; + cell->connections["\\B"] = compare; + cell->connections["\\Y"] = sync_level->signal; + mod->add(cell); + + many_async_rules.clear(); + } + else + { + rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.width); + sync_level = NULL; + } + } + ce.assign_map.apply(insig); ce.assign_map.apply(rstval); ce.assign_map.apply(sig); @@ -200,7 +247,7 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce) sig.optimize(); if (sync_always) { - if (sync_edge || sync_level) + if (sync_edge || sync_level || many_async_rules.size() > 0) log_error("Mixed always event with edge and/or level sensitive events!\n"); log(" created direct connection (no actual register cell created).\n"); mod->connections.push_back(RTLIL::SigSig(sig, insig)); @@ -210,18 +257,26 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce) if (!sync_edge) log_error("Missing edge-sensitive event for this signal!\n"); - if (!rstval.is_fully_const() && !ce.eval(rstval)) + if (many_async_rules.size() > 0) + { + log_error("Multiple async resets for different values (feature under construction)!\n"); + } + else if (!rstval.is_fully_const() && !ce.eval(rstval)) { log("WARNING: Async reset value `%s' is not constant!\n", log_signal(rstval)); gen_dffsr(mod, insig, rstval, sig, sync_edge->type == RTLIL::SyncType::STp, sync_level && sync_level->type == RTLIL::SyncType::ST1, sync_edge->signal, sync_level->signal, proc); - } else + } + else gen_dff(mod, insig, rstval.chunks[0].data, sig, sync_edge->type == RTLIL::SyncType::STp, sync_level && sync_level->type == RTLIL::SyncType::ST1, sync_edge->signal, sync_level ? &sync_level->signal : NULL, proc); + + if (free_sync_level) + delete sync_level; } } diff --git a/tests/simple/dff_different_styles.v b/tests/simple/dff_different_styles.v index 23d89b5dc..db88b835e 100644 --- a/tests/simple/dff_different_styles.v +++ b/tests/simple/dff_different_styles.v @@ -50,3 +50,42 @@ always @(posedge clk or negedge arst) begin end endmodule +module dffa4(clk, arst1, arst2, arst3, d, q); +input clk, arst1, arst2, arst3, d; +output reg q; +always @(posedge clk, posedge arst1, posedge arst2, negedge arst3) begin + if (arst1) + q <= 0; + else if (arst2) + q <= 0; + else if (!arst3) + q <= 0; + else + q <= d; +end +endmodule + +module dffsr1(clk, arst, d, q); +input clk, arst, d; +output reg q; +always @(posedge clk, posedge arst) begin + if (arst) + q <= d^d; // constant expression -- but the frontend optimizer does not know that.. + else + q <= d; +end +endmodule + +// module dffsr2(clk, preset, clear, d, q); +// input clk, preset, clear, d; +// output reg q; +// always @(posedge clk, posedge preset, posedge clear) begin +// if (preset) +// q <= 1; +// else if (clear) +// q <= 0; +// else +// q <= d; +// end +// endmodule +