mirror of
https://github.com/YosysHQ/yosys
synced 2025-06-14 01:46:16 +00:00
More comments, cleanup
This commit is contained in:
parent
7de9c33931
commit
6d68972619
2 changed files with 109 additions and 42 deletions
|
@ -425,22 +425,42 @@ endcode
|
||||||
|
|
||||||
// #######################
|
// #######################
|
||||||
|
|
||||||
|
// Subpattern for matching against input registers, based on knowledge of the
|
||||||
|
// 'Q' input.
|
||||||
|
// At a high level:
|
||||||
|
// (1) Starting from a $dff cell that (partially or fully) drives the given
|
||||||
|
// 'Q' argument
|
||||||
|
// (2) Match for a $mux cell implementing synchronous reset semantics ---
|
||||||
|
// one that exclusively drives the 'D' input of the $dff, with one of its
|
||||||
|
// $mux inputs being fully zero
|
||||||
|
// (3) Match for a $mux cell implement clock enable semantics --- one that
|
||||||
|
// exclusively drives the 'D' input of the $dff (or the other input of
|
||||||
|
// the reset $mux) and where one of this $mux's inputs is connected to
|
||||||
|
// the 'Q' output of the $dff
|
||||||
subpattern in_dffe
|
subpattern in_dffe
|
||||||
arg argD argQ clock
|
arg argD argQ clock
|
||||||
|
|
||||||
code
|
code
|
||||||
dff = nullptr;
|
dff = nullptr;
|
||||||
for (auto c : argQ.chunks()) {
|
for (const auto &c : argQ.chunks()) {
|
||||||
|
// Abandon matches when 'Q' is a constant
|
||||||
if (!c.wire)
|
if (!c.wire)
|
||||||
reject;
|
reject;
|
||||||
|
// Abandon matches when 'Q' has the keep attribute set
|
||||||
if (c.wire->get_bool_attribute(\keep))
|
if (c.wire->get_bool_attribute(\keep))
|
||||||
reject;
|
reject;
|
||||||
Const init = c.wire->attributes.at(\init, State::Sx);
|
// Abandon matches when 'Q' has a non-zero init attribute set
|
||||||
if (!init.is_fully_undef() && !init.is_fully_zero())
|
// (not supported by DSP48E1)
|
||||||
reject;
|
Const init = c.wire->attributes.at(\init, Const());
|
||||||
|
if (!init.empty())
|
||||||
|
for (auto b : init.extract(c.offset, c.width))
|
||||||
|
if (b != State::Sx && b != State::S0)
|
||||||
|
reject;
|
||||||
}
|
}
|
||||||
endcode
|
endcode
|
||||||
|
|
||||||
|
// (1) Starting from a $dff cell that (partially or fully) drives the given
|
||||||
|
// 'Q' argument
|
||||||
match ff
|
match ff
|
||||||
select ff->type.in($dff)
|
select ff->type.in($dff)
|
||||||
// DSP48E1 does not support clock inversion
|
// DSP48E1 does not support clock inversion
|
||||||
|
@ -453,14 +473,12 @@ match ff
|
||||||
filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
|
filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
|
||||||
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
|
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
|
||||||
|
|
||||||
|
filter clock == SigBit() || port(ff, \CLK) == clock
|
||||||
|
|
||||||
set ffoffset offset
|
set ffoffset offset
|
||||||
endmatch
|
endmatch
|
||||||
|
|
||||||
code argQ argD
|
code argQ argD
|
||||||
{
|
|
||||||
if (clock != SigBit() && port(ff, \CLK) != clock)
|
|
||||||
reject;
|
|
||||||
|
|
||||||
SigSpec Q = port(ff, \Q);
|
SigSpec Q = port(ff, \Q);
|
||||||
dff = ff;
|
dff = ff;
|
||||||
dffclock = port(ff, \CLK);
|
dffclock = port(ff, \CLK);
|
||||||
|
@ -472,9 +490,11 @@ code argQ argD
|
||||||
// has two (ff, ffrstmux) users
|
// has two (ff, ffrstmux) users
|
||||||
if (nusers(dffD) > 2)
|
if (nusers(dffD) > 2)
|
||||||
argD = SigSpec();
|
argD = SigSpec();
|
||||||
}
|
|
||||||
endcode
|
endcode
|
||||||
|
|
||||||
|
// (2) Match for a $mux cell implementing synchronous reset semantics ---
|
||||||
|
// exclusively drives the 'D' input of the $dff, with one of the $mux
|
||||||
|
// inputs being fully zero
|
||||||
match ffrstmux
|
match ffrstmux
|
||||||
if !argD.empty()
|
if !argD.empty()
|
||||||
select ffrstmux->type.in($mux)
|
select ffrstmux->type.in($mux)
|
||||||
|
@ -506,6 +526,10 @@ code argD
|
||||||
dffrstmux = nullptr;
|
dffrstmux = nullptr;
|
||||||
endcode
|
endcode
|
||||||
|
|
||||||
|
// (3) Match for a $mux cell implement clock enable semantics --- one that
|
||||||
|
// exclusively drives the 'D' input of the $dff (or the other input of
|
||||||
|
// the reset $mux) and where one of this $mux's inputs is connected to
|
||||||
|
// the 'Q' output of the $dff
|
||||||
match ffcemux
|
match ffcemux
|
||||||
if !argD.empty()
|
if !argD.empty()
|
||||||
select ffcemux->type.in($mux)
|
select ffcemux->type.in($mux)
|
||||||
|
@ -530,16 +554,32 @@ endcode
|
||||||
|
|
||||||
// #######################
|
// #######################
|
||||||
|
|
||||||
|
// Subpattern for matching against output registers, based on knowledge of the
|
||||||
|
// 'D' input.
|
||||||
|
// At a high level:
|
||||||
|
// (1) Starting from an optional $mux cell that implements clock enable
|
||||||
|
// semantics --- one where the given 'D' argument (partially or fully)
|
||||||
|
// drives one of its two inputs
|
||||||
|
// (2) Starting from, or continuing onto, another optional $mux cell that
|
||||||
|
// implements synchronous reset semantics --- one where the given 'D'
|
||||||
|
// argument (or the clock enable $mux output) drives one of its two inputs
|
||||||
|
// and where the other input is fully zero
|
||||||
|
// (3) Match for a $dff cell (whose 'D' input is the 'D' argument, or the
|
||||||
|
// output of the previous clock enable or reset $mux cells)
|
||||||
subpattern out_dffe
|
subpattern out_dffe
|
||||||
arg argD argQ clock
|
arg argD argQ clock
|
||||||
|
|
||||||
code
|
code
|
||||||
dff = nullptr;
|
dff = nullptr;
|
||||||
for (auto c : argD.chunks())
|
for (auto c : argD.chunks())
|
||||||
|
// Abandon matches when 'D' has the keep attribute set
|
||||||
if (c.wire->get_bool_attribute(\keep))
|
if (c.wire->get_bool_attribute(\keep))
|
||||||
reject;
|
reject;
|
||||||
endcode
|
endcode
|
||||||
|
|
||||||
|
// (1) Starting from an optional $mux cell that implements clock enable
|
||||||
|
// semantics --- one where the given 'D' argument (partially or fully)
|
||||||
|
// drives one of its two inputs
|
||||||
match ffcemux
|
match ffcemux
|
||||||
select ffcemux->type.in($mux)
|
select ffcemux->type.in($mux)
|
||||||
// ffcemux output must have two users: ffcemux and ff.D
|
// ffcemux output must have two users: ffcemux and ff.D
|
||||||
|
@ -578,6 +618,10 @@ code argD argQ
|
||||||
}
|
}
|
||||||
endcode
|
endcode
|
||||||
|
|
||||||
|
// (2) Starting from, or continuing onto, another optional $mux cell that
|
||||||
|
// implements synchronous reset semantics --- one where the given 'D'
|
||||||
|
// argument (or the clock enable $mux output) drives one of its two inputs
|
||||||
|
// and where the other input is fully zero
|
||||||
match ffrstmux
|
match ffrstmux
|
||||||
select ffrstmux->type.in($mux)
|
select ffrstmux->type.in($mux)
|
||||||
// ffrstmux output must have two users: ffrstmux and ff.D
|
// ffrstmux output must have two users: ffrstmux and ff.D
|
||||||
|
@ -616,6 +660,8 @@ code argD argQ
|
||||||
}
|
}
|
||||||
endcode
|
endcode
|
||||||
|
|
||||||
|
// (3) Match for a $dff cell (whose 'D' input is the 'D' argument, or the
|
||||||
|
// output of the previous clock enable or reset $mux cells)
|
||||||
match ff
|
match ff
|
||||||
select ff->type.in($dff)
|
select ff->type.in($dff)
|
||||||
// DSP48E1 does not support clock inversion
|
// DSP48E1 does not support clock inversion
|
||||||
|
@ -632,32 +678,30 @@ match ff
|
||||||
// Check that FF.Q is connected to CE-mux
|
// Check that FF.Q is connected to CE-mux
|
||||||
filter !ffcemux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
|
filter !ffcemux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
|
||||||
|
|
||||||
|
filter clock == SigBit() || port(ff, \CLK) == clock
|
||||||
|
|
||||||
set ffoffset offset
|
set ffoffset offset
|
||||||
endmatch
|
endmatch
|
||||||
|
|
||||||
code argQ
|
code argQ
|
||||||
if (ff) {
|
SigSpec D = port(ff, \D);
|
||||||
if (clock != SigBit() && port(ff, \CLK) != clock)
|
SigSpec Q = port(ff, \Q);
|
||||||
reject;
|
if (!ffcemux) {
|
||||||
|
argQ = argD;
|
||||||
SigSpec D = port(ff, \D);
|
argQ.replace(D, Q);
|
||||||
SigSpec Q = port(ff, \Q);
|
|
||||||
if (!ffcemux) {
|
|
||||||
argQ = argD;
|
|
||||||
argQ.replace(D, Q);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto c : argQ.chunks()) {
|
|
||||||
Const init = c.wire->attributes.at(\init, State::Sx);
|
|
||||||
if (!init.is_fully_undef() && !init.is_fully_zero())
|
|
||||||
reject;
|
|
||||||
}
|
|
||||||
|
|
||||||
dff = ff;
|
|
||||||
dffQ = argQ;
|
|
||||||
dffclock = port(ff, \CLK);
|
|
||||||
}
|
}
|
||||||
// No enable/reset mux possible without flop
|
|
||||||
else if (dffcemux || dffrstmux)
|
// Abandon matches when 'Q' has a non-zero init attribute set
|
||||||
reject;
|
// (not supported by DSP48E1)
|
||||||
|
for (auto c : argQ.chunks()) {
|
||||||
|
Const init = c.wire->attributes.at(\init, Const());
|
||||||
|
if (!init.empty())
|
||||||
|
for (auto b : init.extract(c.offset, c.width))
|
||||||
|
if (b != State::Sx && b != State::S0)
|
||||||
|
reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
dff = ff;
|
||||||
|
dffQ = argQ;
|
||||||
|
dffclock = port(ff, \CLK);
|
||||||
endcode
|
endcode
|
||||||
|
|
|
@ -77,7 +77,7 @@ endcode
|
||||||
|
|
||||||
// (2) Match the driver of the 'C' input to a possible $dff cell (CREG)
|
// (2) Match the driver of the 'C' input to a possible $dff cell (CREG)
|
||||||
// (attached to at most two $mux cells that implement clock-enable or
|
// (attached to at most two $mux cells that implement clock-enable or
|
||||||
// reset functionality, using a subpattern discussed below)
|
// reset functionality, using the in_dffe subpattern)
|
||||||
code argQ ffC ffCcemux ffCrstmux ffCcepol ffCrstpol sigC clock
|
code argQ ffC ffCcemux ffCrstmux ffCcepol ffCrstpol sigC clock
|
||||||
argQ = sigC;
|
argQ = sigC;
|
||||||
subpattern(in_dffe);
|
subpattern(in_dffe);
|
||||||
|
@ -103,22 +103,41 @@ endcode
|
||||||
|
|
||||||
// #######################
|
// #######################
|
||||||
|
|
||||||
|
// Subpattern for matching against input registers, based on knowledge of the
|
||||||
|
// 'Q' input.
|
||||||
|
// At a high level:
|
||||||
|
// (1) Starting from a $dff cell that (partially or fully) drives the given
|
||||||
|
// 'Q' argument
|
||||||
|
// (2) Match for a $mux cell implementing synchronous reset semantics ---
|
||||||
|
// one that exclusively drives the 'D' input of the $dff, with one of its
|
||||||
|
// $mux inputs being fully zero
|
||||||
|
// (3) Match for a $mux cell implement clock enable semantics --- one that
|
||||||
|
// exclusively drives the 'D' input of the $dff (or the other input of
|
||||||
|
// the reset $mux) and where one of this $mux's inputs is connected to
|
||||||
|
// the 'Q' output of the $dff
|
||||||
subpattern in_dffe
|
subpattern in_dffe
|
||||||
arg argD argQ clock
|
arg argD argQ clock
|
||||||
|
|
||||||
code
|
code
|
||||||
dff = nullptr;
|
dff = nullptr;
|
||||||
for (auto c : argQ.chunks()) {
|
for (const auto &c : argQ.chunks()) {
|
||||||
|
// Abandon matches when 'Q' is a constant
|
||||||
if (!c.wire)
|
if (!c.wire)
|
||||||
reject;
|
reject;
|
||||||
|
// Abandon matches when 'Q' has the keep attribute set
|
||||||
if (c.wire->get_bool_attribute(\keep))
|
if (c.wire->get_bool_attribute(\keep))
|
||||||
reject;
|
reject;
|
||||||
Const init = c.wire->attributes.at(\init, State::Sx);
|
// Abandon matches when 'Q' has a non-zero init attribute set
|
||||||
if (!init.is_fully_undef() && !init.is_fully_zero())
|
// (not supported by DSP48E1)
|
||||||
reject;
|
Const init = c.wire->attributes.at(\init, Const());
|
||||||
|
for (auto b : init.extract(c.offset, c.width))
|
||||||
|
if (b != State::Sx && b != State::S0)
|
||||||
|
reject;
|
||||||
}
|
}
|
||||||
endcode
|
endcode
|
||||||
|
|
||||||
|
// (1) Starting from a $dff cell that (partially or fully) drives the given
|
||||||
|
// 'Q' argument
|
||||||
match ff
|
match ff
|
||||||
select ff->type.in($dff)
|
select ff->type.in($dff)
|
||||||
// DSP48E1 does not support clock inversion
|
// DSP48E1 does not support clock inversion
|
||||||
|
@ -131,14 +150,12 @@ match ff
|
||||||
filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
|
filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
|
||||||
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
|
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
|
||||||
|
|
||||||
|
filter clock == SigBit() || port(ff, \CLK) == clock
|
||||||
|
|
||||||
set ffoffset offset
|
set ffoffset offset
|
||||||
endmatch
|
endmatch
|
||||||
|
|
||||||
code argQ argD
|
code argQ argD
|
||||||
{
|
|
||||||
if (clock != SigBit() && port(ff, \CLK) != clock)
|
|
||||||
reject;
|
|
||||||
|
|
||||||
SigSpec Q = port(ff, \Q);
|
SigSpec Q = port(ff, \Q);
|
||||||
dff = ff;
|
dff = ff;
|
||||||
dffclock = port(ff, \CLK);
|
dffclock = port(ff, \CLK);
|
||||||
|
@ -150,9 +167,11 @@ code argQ argD
|
||||||
// has two (ff, ffrstmux) users
|
// has two (ff, ffrstmux) users
|
||||||
if (nusers(dffD) > 2)
|
if (nusers(dffD) > 2)
|
||||||
argD = SigSpec();
|
argD = SigSpec();
|
||||||
}
|
|
||||||
endcode
|
endcode
|
||||||
|
|
||||||
|
// (2) Match for a $mux cell implementing synchronous reset semantics ---
|
||||||
|
// exclusively drives the 'D' input of the $dff, with one of the $mux
|
||||||
|
// inputs being fully zero
|
||||||
match ffrstmux
|
match ffrstmux
|
||||||
if !argD.empty()
|
if !argD.empty()
|
||||||
select ffrstmux->type.in($mux)
|
select ffrstmux->type.in($mux)
|
||||||
|
@ -184,6 +203,10 @@ code argD
|
||||||
dffrstmux = nullptr;
|
dffrstmux = nullptr;
|
||||||
endcode
|
endcode
|
||||||
|
|
||||||
|
// (3) Match for a $mux cell implement clock enable semantics --- one that
|
||||||
|
// exclusively drives the 'D' input of the $dff (or the other input of
|
||||||
|
// the reset $mux) and where one of this $mux's inputs is connected to
|
||||||
|
// the 'Q' output of the $dff
|
||||||
match ffcemux
|
match ffcemux
|
||||||
if !argD.empty()
|
if !argD.empty()
|
||||||
select ffcemux->type.in($mux)
|
select ffcemux->type.in($mux)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue