abc9_ops: still emit delay table even box has no timing
[yosys.git] / passes / techmap / dff2dffs.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 * Copyright (C) 2018 David Shah <dave@ds0.me>
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 */
20
21 #include "kernel/yosys.h"
22 #include "kernel/sigtools.h"
23
24 USING_YOSYS_NAMESPACE
25 PRIVATE_NAMESPACE_BEGIN
26
27 struct Dff2dffsPass : public Pass {
28 Dff2dffsPass() : Pass("dff2dffs", "process sync set/reset with SR over CE priority") { }
29 void help() YS_OVERRIDE
30 {
31 log("\n");
32 log(" dff2dffs [options] [selection]\n");
33 log("\n");
34 log("Merge synchronous set/reset $_MUX_ cells to create $__DFFS_[NP][NP][01], to be run before\n");
35 log("dff2dffe for SR over CE priority.\n");
36 log("\n");
37 log(" -match-init\n");
38 log(" Disallow merging synchronous set/reset that has polarity opposite of the\n");
39 log(" output wire's init attribute (if any).\n");
40 log("\n");
41 }
42 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
43 {
44 log_header(design, "Executing dff2dffs pass (merge synchronous set/reset into FF cells).\n");
45
46 bool match_init = false;
47 size_t argidx;
48 for (argidx = 1; argidx < args.size(); argidx++)
49 {
50 // if (args[argidx] == "-singleton") {
51 // singleton_mode = true;
52 // continue;
53 // }
54 if (args[argidx] == "-match-init") {
55 match_init = true;
56 continue;
57 }
58 break;
59 }
60 extra_args(args, argidx, design);
61
62 pool<IdString> dff_types;
63 dff_types.insert(ID($_DFF_N_));
64 dff_types.insert(ID($_DFF_P_));
65
66 for (auto module : design->selected_modules())
67 {
68 log("Merging set/reset $_MUX_ cells into DFFs in %s.\n", log_id(module));
69
70 SigMap sigmap(module);
71 dict<SigBit, Cell*> sr_muxes;
72 vector<Cell*> ff_cells;
73
74 for (auto cell : module->selected_cells())
75 {
76 if (dff_types.count(cell->type)) {
77 ff_cells.push_back(cell);
78 continue;
79 }
80
81 if (cell->type != ID($_MUX_))
82 continue;
83
84 SigBit bit_a = sigmap(cell->getPort(ID::A));
85 SigBit bit_b = sigmap(cell->getPort(ID::B));
86
87 if (bit_a.wire == nullptr || bit_b.wire == nullptr)
88 sr_muxes[sigmap(cell->getPort(ID::Y))] = cell;
89 }
90
91 for (auto cell : ff_cells)
92 {
93 SigSpec sig_d = cell->getPort(ID(D));
94
95 if (GetSize(sig_d) < 1)
96 continue;
97
98 SigBit bit_d = sigmap(sig_d[0]);
99
100 if (sr_muxes.count(bit_d) == 0)
101 continue;
102
103 Cell *mux_cell = sr_muxes.at(bit_d);
104 SigBit bit_a = sigmap(mux_cell->getPort(ID::A));
105 SigBit bit_b = sigmap(mux_cell->getPort(ID::B));
106 SigBit bit_s = sigmap(mux_cell->getPort(ID(S)));
107
108 SigBit sr_val, sr_sig;
109 bool invert_sr;
110 sr_sig = bit_s;
111 if (bit_a.wire == nullptr) {
112 bit_d = bit_b;
113 sr_val = bit_a;
114 invert_sr = true;
115 } else {
116 log_assert(bit_b.wire == nullptr);
117 bit_d = bit_a;
118 sr_val = bit_b;
119 invert_sr = false;
120 }
121
122 if (match_init) {
123 SigBit bit_q = cell->getPort(ID(Q));
124 if (bit_q.wire) {
125 auto it = bit_q.wire->attributes.find(ID(init));
126 if (it != bit_q.wire->attributes.end()) {
127 auto init_val = it->second[bit_q.offset];
128 if (init_val == State::S1 && sr_val != State::S1)
129 continue;
130 if (init_val == State::S0 && sr_val != State::S0)
131 continue;
132 }
133 }
134 }
135
136 log(" Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell),
137 log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type));
138
139 if (sr_val == State::S1) {
140 if (cell->type == ID($_DFF_N_)) {
141 if (invert_sr) cell->type = ID($__DFFS_NN1_);
142 else cell->type = ID($__DFFS_NP1_);
143 } else {
144 log_assert(cell->type == ID($_DFF_P_));
145 if (invert_sr) cell->type = ID($__DFFS_PN1_);
146 else cell->type = ID($__DFFS_PP1_);
147 }
148 } else {
149 if (cell->type == ID($_DFF_N_)) {
150 if (invert_sr) cell->type = ID($__DFFS_NN0_);
151 else cell->type = ID($__DFFS_NP0_);
152 } else {
153 log_assert(cell->type == ID($_DFF_P_));
154 if (invert_sr) cell->type = ID($__DFFS_PN0_);
155 else cell->type = ID($__DFFS_PP0_);
156 }
157 }
158 cell->setPort(ID(R), sr_sig);
159 cell->setPort(ID(D), bit_d);
160 }
161 }
162 }
163 } Dff2dffsPass;
164
165 PRIVATE_NAMESPACE_END