summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2013-10-21 14:51:58 +0200
committerClifford Wolf <clifford@clifford.at>2013-10-21 14:51:58 +0200
commitd61699843fc3ecab9c484d911f43877e9a7a9d3d (patch)
treea763ae52dbe44c6c8995050dc2d749ad03f6552d
parent56ea2306764e1363688e0f9e1146f98bd48d3037 (diff)
Improved handling of dff with async resets
-rw-r--r--passes/proc/proc_dff.cc65
-rw-r--r--tests/simple/dff_different_styles.v39
2 files changed, 99 insertions, 5 deletions
diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc
index 8e02a624..db7a59f5 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<RTLIL::SigSpec, std::set<RTLIL::SyncRule*>> 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 23d89b5d..db88b835 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
+