mirror of
https://github.com/YosysHQ/yosys
synced 2026-06-19 07:16:27 +00:00
Merge 7d942b9893 into 2195277b5a
This commit is contained in:
commit
3e6497c61c
2 changed files with 77 additions and 14 deletions
|
|
@ -34,7 +34,7 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
* A multiplexer tree (mux tree) is a tree composed exclusively of muxes.
|
||||
* By mux, I mean $mux or $pmux. By port, I usually mean input port.
|
||||
* The children of a node are all the muxes driving its input ports (A, B).
|
||||
* It must be rooted in a "root mux", a mux which has multiple mux users
|
||||
* It must be rooted in a "root mux", a mux which has multiple mux port users
|
||||
* or any number of non-mux users. Only the root and leaf nodes can be
|
||||
* root muxes, not the internal nodes. Leaf nodes that are root muxes
|
||||
* are roots of "input trees".
|
||||
|
|
@ -64,10 +64,17 @@ struct OptMuxtreeWorker
|
|||
int removed_count;
|
||||
int glob_evals_left = 10'000'000;
|
||||
|
||||
struct MuxPort {
|
||||
int mux;
|
||||
// Hacky: -1 is port A, if positive then indexes B port slices (of which $mux has only one)
|
||||
int port;
|
||||
inline Hasher hash_into(Hasher h) const { h.eat(mux); h.eat(port); return h; }
|
||||
bool operator==(const MuxPort &other) const { return mux == other.mux && port == other.port; }
|
||||
};
|
||||
struct bitinfo_t {
|
||||
// Is bit directly used by non-mux cells or ports?
|
||||
bool seen_non_mux;
|
||||
pool<int> mux_users;
|
||||
pool<struct MuxPort> mux_users;
|
||||
std::optional<int> mux_driver;
|
||||
};
|
||||
|
||||
|
|
@ -94,10 +101,10 @@ struct OptMuxtreeWorker
|
|||
vector<bool> root_enable_muxes;
|
||||
pool<int> root_mux_rerun;
|
||||
|
||||
portinfo_t used_port_bit(RTLIL::SigSpec& sig, int mux_idx) {
|
||||
portinfo_t used_port_bit(RTLIL::SigSpec& sig, int mux_idx, int port_idx) {
|
||||
portinfo_t portinfo = {};
|
||||
for (int bit_idx : sig2bits(sig)) {
|
||||
bit2info[bit_idx].mux_users.insert(mux_idx);
|
||||
bit2info[bit_idx].mux_users.insert({mux_idx, port_idx});
|
||||
portinfo.input_sigs.insert(bit_idx);
|
||||
}
|
||||
return portinfo;
|
||||
|
|
@ -127,7 +134,7 @@ struct OptMuxtreeWorker
|
|||
for (int i = 0; i < GetSize(sig_s); i++) {
|
||||
RTLIL::SigSpec sig = sig_b.extract(i*GetSize(sig_a), GetSize(sig_a));
|
||||
RTLIL::SigSpec ctrl_sig = assign_map(SigSpec{sig_s[i]});
|
||||
portinfo_t portinfo = used_port_bit(sig, this_mux_idx);
|
||||
portinfo_t portinfo = used_port_bit(sig, this_mux_idx, i);
|
||||
portinfo.ctrl_sig = sig2bits(ctrl_sig, false).front();
|
||||
portinfo.const_activated = ctrl_sig.is_fully_const() && ctrl_sig.as_bool();
|
||||
portinfo.const_deactivated = ctrl_sig.is_fully_const() && !ctrl_sig.as_bool();
|
||||
|
|
@ -135,7 +142,7 @@ struct OptMuxtreeWorker
|
|||
}
|
||||
|
||||
// Analyze port A
|
||||
muxinfo.ports.push_back(used_port_bit(sig_a, this_mux_idx));
|
||||
muxinfo.ports.push_back(used_port_bit(sig_a, this_mux_idx, -1));
|
||||
|
||||
for (int idx : sig2bits(sig_y)) {
|
||||
if (bit2info[idx].mux_driver)
|
||||
|
|
@ -170,17 +177,18 @@ struct OptMuxtreeWorker
|
|||
// bit2info knows the mux users and mux drivers of bits
|
||||
// use this to tell mux2info ports about what muxes are driven by it
|
||||
for (int i = 0; i < GetSize(bit2info); i++)
|
||||
for (int j : bit2info[i].mux_users)
|
||||
for (auto &p : mux2info[j].ports) {
|
||||
if (p.input_sigs.count(i))
|
||||
if (bit2info[i].mux_driver)
|
||||
p.input_muxes.insert(*bit2info[i].mux_driver);
|
||||
for (auto muxport : bit2info[i].mux_users) {
|
||||
for (auto &p : mux2info[muxport.mux].ports) {
|
||||
if (p.input_sigs.count(i))
|
||||
if (bit2info[i].mux_driver)
|
||||
p.input_muxes.insert(*bit2info[i].mux_driver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void populate_roots() {
|
||||
// mux_to_users[i] means "set of muxes using output of mux i"
|
||||
dict<int, pool<int>> mux_to_users;
|
||||
dict<int, pool<struct MuxPort>> mux_to_users;
|
||||
// Pure root muxes (outputs seen by non-muxes)
|
||||
root_enable_muxes.resize(GetSize(mux2info));
|
||||
// All root muxes (outputs seen by non-muxes or multiple muxes)
|
||||
|
|
@ -188,8 +196,8 @@ struct OptMuxtreeWorker
|
|||
|
||||
for (auto &bi : bit2info) {
|
||||
if (bi.mux_driver)
|
||||
for (int j : bi.mux_users)
|
||||
mux_to_users[*bi.mux_driver].insert(j);
|
||||
for (auto muxport : bi.mux_users)
|
||||
mux_to_users[*bi.mux_driver].insert(muxport);
|
||||
if (!bi.seen_non_mux)
|
||||
continue;
|
||||
if (bi.mux_driver) {
|
||||
|
|
|
|||
55
tests/opt/opt_muxtree_port_reconverge.ys
Normal file
55
tests/opt/opt_muxtree_port_reconverge.ys
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
read_rtlil << EOT
|
||||
module \top
|
||||
wire input 1 \a
|
||||
wire input 2 \b
|
||||
wire output 3 \out
|
||||
wire $0\out[0:0]
|
||||
wire \y
|
||||
wire $1\out[0:0]
|
||||
wire \s
|
||||
wire \q
|
||||
wire \n_a
|
||||
|
||||
cell $mux \mux
|
||||
parameter \WIDTH 1
|
||||
connect \A 1'0
|
||||
connect \B \a
|
||||
connect \S \b
|
||||
connect \Y \y
|
||||
end
|
||||
|
||||
attribute \full_case 1
|
||||
cell $pmux \pmux
|
||||
parameter \WIDTH 1
|
||||
parameter \S_WIDTH 2
|
||||
connect \A 1'x
|
||||
connect \B { \y \y }
|
||||
connect \S { \n_a \s }
|
||||
connect \Y \q
|
||||
end
|
||||
|
||||
attribute \full_case 1
|
||||
cell $not \not
|
||||
parameter \A_SIGNED 0
|
||||
parameter \Y_WIDTH 1
|
||||
parameter \A_WIDTH 1
|
||||
connect \A \a
|
||||
connect \Y \n_a
|
||||
end
|
||||
|
||||
connect $0\out[0:0] $1\out[0:0]
|
||||
connect \s \a
|
||||
connect $1\out[0:0] \q
|
||||
connect \out \q
|
||||
end
|
||||
EOT
|
||||
# a drives out
|
||||
select -assert-any i:a %co* o:out %i
|
||||
|
||||
opt_muxtree
|
||||
# a gets optimized out
|
||||
opt_reduce
|
||||
opt_expr
|
||||
|
||||
# a no longer drives out
|
||||
select -assert-any o:out %ci* i:a %i
|
||||
Loading…
Add table
Add a link
Reference in a new issue