2023-11-27 03:35:29 -06:00
|
|
|
pattern ql_dsp_macc
|
2023-10-02 08:55:41 -05:00
|
|
|
// Rough sketch: (mux is optional)
|
|
|
|
//
|
|
|
|
// /-----------------------\
|
|
|
|
// | |
|
|
|
|
// \ / |
|
|
|
|
// mul ----> add -----> mux -----> ff -+---->
|
|
|
|
// | /\
|
|
|
|
// | |
|
|
|
|
// --------------
|
2023-11-27 03:35:29 -06:00
|
|
|
|
|
|
|
state <IdString> add_ba
|
|
|
|
state <IdString> mux_ab
|
|
|
|
|
2023-10-02 08:55:41 -05:00
|
|
|
// Is the output taken from before or after the FF?
|
|
|
|
state <bool> output_registered
|
2023-11-27 03:35:29 -06:00
|
|
|
|
2023-10-02 08:55:41 -05:00
|
|
|
// Is there a mux in the pattern?
|
|
|
|
state <bool> mux_in_pattern
|
|
|
|
|
|
|
|
code mux_in_pattern
|
|
|
|
mux_in_pattern = false;
|
|
|
|
branch;
|
|
|
|
mux_in_pattern = true;
|
|
|
|
endcode
|
|
|
|
|
|
|
|
// The multiplier is at the center of our pattern
|
2023-11-27 03:35:29 -06:00
|
|
|
match mul
|
|
|
|
select mul->type.in($mul)
|
2023-10-02 08:55:41 -05:00
|
|
|
// It has either two or three consumers depending on whether there's a mux
|
|
|
|
// in the pattern or not
|
2023-11-27 03:35:29 -06:00
|
|
|
select nusers(port(mul, \Y)) <= 3
|
2023-10-02 08:55:41 -05:00
|
|
|
filter nusers(port(mul, \Y)) == (mux_in_pattern ? 3 : 2)
|
2023-11-27 03:35:29 -06:00
|
|
|
endmatch
|
|
|
|
|
2023-10-02 08:55:41 -05:00
|
|
|
code output_registered
|
|
|
|
output_registered = false;
|
|
|
|
branch;
|
|
|
|
output_registered = true;
|
|
|
|
endcode
|
|
|
|
|
2023-11-27 03:35:29 -06:00
|
|
|
match add
|
|
|
|
select add->type.in($add, $sub)
|
|
|
|
choice <IdString> AB {\A, \B}
|
|
|
|
define <IdString> BA (AB == \A ? \B : \A)
|
2023-10-02 08:55:41 -05:00
|
|
|
// One input to the adder is fed by the multiplier
|
2023-11-27 03:35:29 -06:00
|
|
|
index <SigSpec> port(add, AB) === port(mul, \Y)
|
2023-10-02 08:55:41 -05:00
|
|
|
// Save the other input port, it needs to be fed by the flip-flop
|
2023-11-27 03:35:29 -06:00
|
|
|
set add_ba BA
|
2023-10-02 08:55:41 -05:00
|
|
|
// Adder has either two or three consumers; it will have three consumers
|
|
|
|
// IFF there's no mux in the pattern and the multiplier-accumulator result
|
|
|
|
// is taken unregistered
|
|
|
|
filter nusers(port(add, \Y)) == (!mux_in_pattern && !output_registered ? 3 : 2)
|
2023-11-27 03:35:29 -06:00
|
|
|
endmatch
|
|
|
|
|
|
|
|
match mux
|
2023-10-02 08:55:41 -05:00
|
|
|
if mux_in_pattern
|
2023-11-27 03:35:29 -06:00
|
|
|
select mux->type.in($mux)
|
|
|
|
choice <IdString> AB {\A, \B}
|
|
|
|
define <IdString> BA (AB == \A ? \B : \A)
|
|
|
|
index <SigSpec> port(mux, AB) === port(mul, \Y)
|
|
|
|
index <SigSpec> port(mux, BA) === port(add, \Y)
|
2023-10-02 08:55:41 -05:00
|
|
|
filter nusers(port(mux, \Y)) == (output_registered ? 2 : 3)
|
2023-11-27 03:35:29 -06:00
|
|
|
set mux_ab AB
|
|
|
|
endmatch
|
|
|
|
|
|
|
|
match ff
|
|
|
|
select ff->type.in($dff, $adff, $dffe, $adffe)
|
2023-10-02 08:55:41 -05:00
|
|
|
select param(ff, \CLK_POLARITY).as_bool()
|
|
|
|
index <SigSpec> port(ff, \D) === mux_in_pattern ? port(mux, \Y) : port(add, \Y);
|
2023-11-27 03:35:29 -06:00
|
|
|
index <SigSpec> port(ff, \Q) === port(add, add_ba)
|
2023-10-02 08:55:41 -05:00
|
|
|
filter nusers(port(ff, \Q)) == (output_registered ? 3 : 2)
|
2023-11-27 03:35:29 -06:00
|
|
|
endmatch
|
|
|
|
|
|
|
|
code
|
|
|
|
accept;
|
|
|
|
endcode
|