2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include "kernel/yosys.h"
21 #include "kernel/sigtools.h"
24 PRIVATE_NAMESPACE_BEGIN
26 struct EquivMarkWorker
31 // cache for traversing signal flow graph
32 dict
<SigBit
, pool
<IdString
>> up_bit2cells
;
33 dict
<IdString
, pool
<SigBit
>> up_cell2bits
;
34 pool
<IdString
> edge_cells
, equiv_cells
;
36 // graph traversal state
37 pool
<SigBit
> queue
, visited
;
40 dict
<IdString
, int> cell_regions
;
41 dict
<SigBit
, int> bit_regions
;
47 EquivMarkWorker(Module
*module
) : module(module
), sigmap(module
)
49 for (auto cell
: module
->cells())
51 if (cell
->type
== "$equiv")
52 equiv_cells
.insert(cell
->name
);
54 for (auto &port
: cell
->connections())
56 if (cell
->input(port
.first
))
57 for (auto bit
: sigmap(port
.second
))
58 up_cell2bits
[cell
->name
].insert(bit
);
60 if (cell
->output(port
.first
))
61 for (auto bit
: sigmap(port
.second
))
62 up_bit2cells
[bit
].insert(cell
->name
);
71 while (!queue
.empty())
75 for (auto &bit
: queue
)
77 // log_assert(bit_regions.count(bit) == 0);
78 bit_regions
[bit
] = next_region
;
81 for (auto cell
: up_bit2cells
[bit
])
82 if (edge_cells
.count(cell
) == 0)
88 for (auto cell
: cells
)
90 if (next_region
== 0 && equiv_cells
.count(cell
))
93 if (cell_regions
.count(cell
)) {
94 if (cell_regions
.at(cell
) != 0)
95 region_mf
.merge(cell_regions
.at(cell
), next_region
);
99 cell_regions
[cell
] = next_region
;
101 for (auto bit
: up_cell2bits
[cell
])
102 if (visited
.count(bit
) == 0)
112 log("Running equiv_mark on module %s:\n", log_id(module
));
116 for (auto wire
: module
->wires())
117 if (wire
->port_id
> 0)
118 for (auto bit
: sigmap(wire
))
121 for (auto cell_name
: equiv_cells
)
123 auto cell
= module
->cell(cell_name
);
125 SigSpec sig_a
= sigmap(cell
->getPort("\\A"));
126 SigSpec sig_b
= sigmap(cell
->getPort("\\B"));
128 if (sig_a
== sig_b
) {
129 for (auto bit
: sig_a
)
131 edge_cells
.insert(cell_name
);
132 cell_regions
[cell_name
] = 0;
138 // marking unsolved regions
140 for (auto cell
: module
->cells())
142 if (cell_regions
.count(cell
->name
) || cell
->type
!= "$equiv")
145 SigSpec sig_a
= sigmap(cell
->getPort("\\A"));
146 SigSpec sig_b
= sigmap(cell
->getPort("\\B"));
148 log_assert(sig_a
!= sig_b
);
150 for (auto bit
: sig_a
)
153 for (auto bit
: sig_b
)
156 cell_regions
[cell
->name
] = next_region
;
160 // setting attributes
162 dict
<int, int> final_region_map
;
163 int next_final_region
= 0;
165 dict
<int, int> region_cell_count
;
166 dict
<int, int> region_wire_count
;
168 for (int i
= 0; i
< next_region
; i
++) {
169 int r
= region_mf
.find(i
);
170 if (final_region_map
.count(r
) == 0)
171 final_region_map
[r
] = next_final_region
++;
172 final_region_map
[i
] = final_region_map
[r
];
175 for (auto cell
: module
->cells())
177 if (cell_regions
.count(cell
->name
)) {
178 int r
= final_region_map
.at(cell_regions
.at(cell
->name
));
179 cell
->attributes
["\\equiv_region"] = Const(r
);
180 region_cell_count
[r
]++;
182 cell
->attributes
.erase("\\equiv_region");
185 for (auto wire
: module
->wires())
188 for (auto bit
: sigmap(wire
))
189 if (bit_regions
.count(bit
))
190 regions
.insert(region_mf
.find(bit_regions
.at(bit
)));
192 if (GetSize(regions
) == 1) {
193 int r
= final_region_map
.at(*regions
.begin());
194 wire
->attributes
["\\equiv_region"] = Const(r
);
195 region_wire_count
[r
]++;
197 wire
->attributes
.erase("\\equiv_region");
200 for (int i
= 0; i
< next_final_region
; i
++)
201 log(" region %d: %d cells, %d wires\n", i
, region_wire_count
[i
], region_cell_count
[i
]);
205 struct EquivMarkPass
: public Pass
{
206 EquivMarkPass() : Pass("equiv_mark", "mark equivalence checking regions") { }
207 void help() YS_OVERRIDE
209 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
211 log(" equiv_mark [options] [selection]\n");
213 log("This command marks the regions in an equivalence checking module. Region 0 is\n");
214 log("the proven part of the circuit. Regions with higher numbers are connected\n");
215 log("unproven subcricuits. The integer attribute 'equiv_region' is set on all\n");
216 log("wires and cells.\n");
219 void execute(std::vector
<std::string
> args
, Design
*design
) YS_OVERRIDE
221 log_header(design
, "Executing EQUIV_MARK pass.\n");
224 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
225 // if (args[argidx] == "-foobar") {
230 extra_args(args
, argidx
, design
);
232 for (auto module
: design
->selected_whole_modules_warn()) {
233 EquivMarkWorker
worker(module
);
239 PRIVATE_NAMESPACE_END