Improved handling of dff with async resets
authorClifford Wolf <clifford@clifford.at>
Mon, 21 Oct 2013 12:51:58 +0000 (14:51 +0200)
committerClifford Wolf <clifford@clifford.at>
Mon, 21 Oct 2013 12:51:58 +0000 (14:51 +0200)
passes/proc/proc_dff.cc
tests/simple/dff_different_styles.v

index 8e02a624ee2407d9d205c50d82ef944041db90d1..db7a59f5b2280076a0818c349aa2cacfdd6b2d9e 100644 (file)
@@ -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;
        }
 }
 
index 23d89b5dcfbe1fe3e0c447dc23781cab6b077334..db88b835e275bb07a82b5a89075cc841c0a0280e 100644 (file)
@@ -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
+