diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/BDELAY.vhd b/Examples/HDL/Digital_Filtering/SSR_FIR/BDELAY.vhd
index 6cb46fb12..3ef0bc1f6 100755
--- a/Examples/HDL/Digital_Filtering/SSR_FIR/BDELAY.vhd
+++ b/Examples/HDL/Digital_Filtering/SSR_FIR/BDELAY.vhd
@@ -4,7 +4,10 @@ library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
-use work.TYPES_PKG.all;
+--CB use work.TYPES_PKG.all;
+use work.fixed_pkg.all; -- VHDL-2008 IEEE standard SFIXED type and functions
+use work.cfixed_pkg.all; -- user package, SFIXED_VECTOR, SFIXED_MATRIX and many other goodies
+--CB
entity BDELAY is
generic(SIZE:NATURAL:=1; -- SIZE has a default value of 1 and cannot be negative, this would require traveling back in time
@@ -27,6 +30,7 @@ begin
-- l2n:if (SIZE>=66 and SIZE<=65+33) or (SIZE>=130 and SIZE<=129+65+33) or (SIZE>=258 and SIZE<=257+129+65+33) or (SIZE>513) generate
l2n:if DDR and (SIZE>3) generate
signal ID:BOOLEAN:=FALSE;
+ signal OB:BOOLEAN:=FALSE;
signal T,TD,SEL:STD_LOGIC:='0';
type TBV is array(0 to SIZE/2-1) of BOOLEAN;
signal OE,OO:TBV:=(others=>FALSE); -- delay line signal is SIZE/2 in length
@@ -38,7 +42,7 @@ begin
end;
else generate
process(CLK)
- begin
+ begin
if rising_edge(CLK) then
ID<=I after 1 ps;
end if;
@@ -71,12 +75,28 @@ begin
TD<=T after 1 ps;
SEL<=TD xor T after 1 ps;
if SEL='0' then
- O<=OE(OE'high);
+ OB<=OE(OE'high);
+ -- BF O<=OE(OE'high);
else
- O<=OO(OO'high);
+ OB<=OO(OO'high);
+ -- BF O<=OO(OO'high);
end if;
end if;
end process;
+
+ --BF Added for DDR Even Filters
+ o0:if SIZE mod 2=1 generate
+ O<=OB;
+ end;
+ else generate
+ process(CLK)
+ begin
+ if rising_edge(CLK) then
+ O<=OB after 1 ps;
+ end if;
+ end process;
+ end generate;
+
end;
elsif (SIZE>=66 and SIZE<=65+33) or (SIZE>=130 and SIZE<=129+65+33) or (SIZE>=258 and SIZE<=257+129+65+33) generate
signal IO:BOOLEAN:=FALSE;
@@ -158,4 +178,4 @@ begin
O<=D(D'high);
end;
end generate;
-end TEST;
\ No newline at end of file
+end TEST;
diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/DSPx8_WRAPPER.vhd b/Examples/HDL/Digital_Filtering/SSR_FIR/DSPx8_WRAPPER.vhd
index 704c01706..a6c2a0e5d 100755
--- a/Examples/HDL/Digital_Filtering/SSR_FIR/DSPx8_WRAPPER.vhd
+++ b/Examples/HDL/Digital_Filtering/SSR_FIR/DSPx8_WRAPPER.vhd
@@ -4,7 +4,10 @@
library IEEE;
use IEEE.STD_LOGIC_1164.all;
-use work.TYPES_PKG.all;
+--CB use work.TYPES_PKG.all;
+use work.fixed_pkg.all; -- VHDL-2008 IEEE standard SFIXED type and functions
+use work.cfixed_pkg.all; -- user package, SFIXED_VECTOR, SFIXED_MATRIX and many other goodies
+--CB
library unisims_ver;
library UNISIM;
@@ -81,11 +84,11 @@ entity DSPx8_WRAPPER is
INMODE:in STD_LOGIC_VECTOR(4 downto 0):=5x"00"; -- 5-bit input: INMODE control
OPMODE:in STD_LOGIC_VECTOR(8 downto 0):=9x"035"; -- 9-bit input: Operation mode - default is P<=C+A*B
-- Data inputs: Data Ports
- A:in SFIXED; -- 30/34-bit input: A data
- B:in SFIXED; -- 18/24-bit input: B data
- C:in SFIXED; -- 48/58-bit input: C data
+ A:in SFIXED:="0"; -- 30/34-bit input: A data
+ B:in SFIXED:="0"; -- 18/24-bit input: B data
+ C:in SFIXED:="0"; -- 48/58-bit input: C data
CARRYIN:in STD_LOGIC:='0'; -- 1-bit input: Carry-in
- D:in SFIXED; -- 25/27-bit input: D data
+ D:in SFIXED:="0"; -- 25/27-bit input: D data
-- Reset/Clock Enable inputs: Reset/Clock Enable Inputs
CEA1:in STD_LOGIC:='1'; -- 1-bit input: Clock enable for 1st stage AREG
CEA2:in STD_LOGIC:='1'; -- 1-bit input: Clock enable for 2nd stage AREG
diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/Images/SSR_FIR_screen_shot.PNG b/Examples/HDL/Digital_Filtering/SSR_FIR/Images/SSR_FIR_screen_shot.PNG
old mode 100755
new mode 100644
index 36b8af84d..05076c456
Binary files a/Examples/HDL/Digital_Filtering/SSR_FIR/Images/SSR_FIR_screen_shot.PNG and b/Examples/HDL/Digital_Filtering/SSR_FIR/Images/SSR_FIR_screen_shot.PNG differ
diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/README.html b/Examples/HDL/Digital_Filtering/SSR_FIR/README.html
index 27672f0cc..c0381df55 100644
--- a/Examples/HDL/Digital_Filtering/SSR_FIR/README.html
+++ b/Examples/HDL/Digital_Filtering/SSR_FIR/README.html
@@ -5,7 +5,7 @@
-High Speed SSR FIR
+
Open Example
-This reference design can be used as a starting design point when efficient implementations of very high data rate (over 1 Gsps) Single Rate FIRs are required. This PL based design can be used in any modern AMD device - 7-Series/UltraScale/UltraScale+/Versal.
+
This reference design can be used as a starting design point when efficient implementations of very high data rate (over 1 Gsps) Single Rate FIRs are required. This PL based design can be used in any modern AMD device - 7-Series/UltraScale/UltraScale+/Versal.
-
-This Single Rate SSR FIR reference design illustrates a number of advanced Vitis Model Composer design techniques:
+
+The model now contains two functionally-equivalent FIR architectures side by side, both driven by the same stimulus. The Direct form is checked sample-by-sample against a golden floating-point reference, and the Direct and Transpose outputs are overlaid in the Output spectrum analyzer to confirm the two architectures produce equivalent results (matching to within one LSB):
-- This is a fully parameterizable design - you can control the filter order N, the number of clocks per sample SSR, the filter type (non/even/odd-symmetric), the input, output and coefficient fixed point quantization; you can set SSR and TAPS in Model Settings/Model Properties/Callbacks/InitFcnall the rest of the SSR FIR parameters can be set in the Model Composer block dialog
-- If desired, you can floorplan the DSP blocks directly from Vitis Model Composer
-- This is achieved through the use of Model Composer HDL Black Box flow, all these features are implemented in the underlying VHDL-2008 code; the reference design shows how to pass ports and parameters with generic sizes between Model Composer and VHDL code; the underlying VHDL-2008 code shows how to use arbitrary precision fixed point types, recursive component instantiations, how to instantiate DSP primitives independent of FPGA family (7-Series/UltraScale+/Versal) and floorplan them from VHDL code
-- The Vitis Model Composer design includes a top level Simulink self-checking testbench, which compares the fixed point HDL Black Box based implementation to a golden reference floating point model
-- This is a very high speed design, clock frequencies up to the maximum data sheet values of 741/891/1150 MHz in the fastest speed grade 7-Series/UltraScale+/Versal devices are possible
-- The design also shows a technique to avoid the Versal 795/824/872 MHz fMAX limitation due to SRL16 minimum pulse width spec
-- The VHDL code inside the Model Composer HDL Black Box can be instantiated stand alone in a Vivado RTL project. MATLAB and Vitis Model Composer are used here to illustrate the flow and make functional verification easier.
+DUT – Direct Form (SSR_FIR.vhd): partial products cascade from the first to the last tap through the DSP PCOUT chain. The cascade is TAPS deep.
+DUT_T – Transpose Form (TRANSPOSE_SSR_FIR.vhd): the input is broadcast to all DSPs and partial sums accumulate stage-by-stage through the DSP PREG/PCOUT registers. For SSR>1 each of the SSR lanes implements a transposed sub-FIR, so the cascade is only TAPS/SSR deep per lane.
+
+The two architectures are functionally equivalent, with outputs agreeing to within one output LSB (2^-16). Each form is independently verified against the golden floating-point reference. The two forms have different pipeline latencies (direct = TAPS+2 clocks, transpose = 3×SSR+2 clocks), so the transpose output leads the direct output in time.
+To generate code for one architecture, point the Vitis Model Composer Hub block's subsystem selection at DUT (direct) or DUT_T (transpose).
+
+The critical path of the direct form grows with TAPS (the PCOUT cascade), while the transpose form's critical path is one DSP multiply-accumulate that is independent of TAPS. This lets the transpose form close timing at high SSR and large TAPS where the direct form's cascade does not.
+
+
+
+| Property |
+Direct Form |
+Transpose Form |
+
+
+
+
+| SSR range |
+1, 2, 4, 8, 16 (2^n) |
+1, 2, 4, 8, 16 (2^n) |
+
+
+| Fmax, Versal (SSR≤4) |
+~822 MHz (device ceiling) |
+~834–841 MHz |
+
+
+| Fmax, SSR=8 |
+~670–740 MHz |
+~834 MHz |
+
+
+| Latency (SSR>1, NS) |
+TAPS + 2 |
+3×SSR + 2 |
+
+
+| PCOUT/PREG chain depth |
+TAPS hops |
+TAPS/SSR hops per lane |
+
+
+| DSP count, NS |
+SSR × TAPS |
+SSR × TAPS |
+
+
+
+Rule of thumb: use the direct form for SSR 2–4 with TAPS ≤ 64 (shorter latency, simplest dataflow); use the transpose form for SSR ≥ 8, or for TAPS > 64 at SSR = 4, or whenever a TAPS-independent (short, fixed) latency is required.
+Model configuration
+The model is parameterized through Model Settings → Model Properties → Callbacks → InitFcn:
+SSR = 8; % clocks per sample — MUST be a power of two (1,2,4,8,16,...)
+TAPS = 64; % number of FIR coefficients
+Ts = 1/SSR; % input sample time; SSR*Ts must equal the Simulink system period (1)
+FCOEFF = fir1(TAPS-1,0.25); % shared coefficient set (hardware + golden reference)
+
+Notes:
+
+SSR must be a power of two. Both cores assert this; non-power-of-2 SSR is not supported by the SSR>1 accumulation chain.
+Ts = 1/SSR keeps the buffered input frame rate aligned with the Vitis Model Composer Hub's Simulink system period so the golden-vs-DUT comparison lines up. Changing SSR automatically rescales Ts.
+- The remaining FIR parameters (input/output/coefficient fixed-point ranges, rounding, symmetry, optional DSP floorplanning) are set on the
SSRFIR Model Composer block mask inside each DUT.
-This design only works in Vivado 2022.1 or later.
Copyright (c) 2026 Advanced Micro Devices, Inc.
diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/README.md b/Examples/HDL/Digital_Filtering/SSR_FIR/README.md
index 350d1147a..eb322b546 100644
--- a/Examples/HDL/Digital_Filtering/SSR_FIR/README.md
+++ b/Examples/HDL/Digital_Filtering/SSR_FIR/README.md
@@ -1,24 +1,54 @@
-# High Speed SSR FIR
+# High Speed SSR FIR — Direct and Transpose Forms
-This reference design can be used as a starting design point when efficient implementations of very high data rate (over 1 Gsps) Single Rate FIRs are required. This PL based design can be used in any modern AMD device - 7-Series/UltraScale/UltraScale+/Versal.
+This reference design can be used as a starting design point when efficient implementations of very high data rate (over 1 Gsps) Single Rate FIRs are required. This PL based design can be used in any modern AMD device - 7-Series/UltraScale/UltraScale+/Versal.
-
+
-This Single Rate SSR FIR reference design illustrates a number of advanced Vitis Model Composer design techniques:
-- This is a fully parameterizable design - you can control the filter order N, the number of clocks per sample SSR, the filter type (non/even/odd-symmetric), the input, output and coefficient fixed point quantization; you can set SSR and TAPS in Model Settings/Model Properties/Callbacks/InitFcnall the rest of the SSR FIR parameters can be set in the Model Composer block dialog
-- If desired, you can floorplan the DSP blocks directly from Vitis Model Composer
-- This is achieved through the use of Model Composer HDL Black Box flow, all these features are implemented in the underlying VHDL-2008 code; the reference design shows how to pass ports and parameters with generic sizes between Model Composer and VHDL code; the underlying VHDL-2008 code shows how to use arbitrary precision fixed point types, recursive component instantiations, how to instantiate DSP primitives independent of FPGA family (7-Series/UltraScale+/Versal) and floorplan them from VHDL code
-- The Vitis Model Composer design includes a top level Simulink self-checking testbench, which compares the fixed point HDL Black Box based implementation to a golden reference floating point model
-- This is a very high speed design, clock frequencies up to the maximum data sheet values of 741/891/1150 MHz in the fastest speed grade 7-Series/UltraScale+/Versal devices are possible
-- The design also shows a technique to avoid the Versal 795/824/872 MHz fMAX limitation due to SRL16 minimum pulse width spec
-- The VHDL code inside the Model Composer HDL Black Box can be instantiated stand alone in a Vivado RTL project. MATLAB and Vitis Model Composer are used here to illustrate the flow and make functional verification easier.
+The model now contains **two functionally-equivalent FIR architectures side by side**, both driven by the same stimulus. The Direct form is checked sample-by-sample against a golden floating-point reference, and the Direct and Transpose outputs are overlaid in the **Output** spectrum analyzer to confirm the two architectures produce equivalent results (matching to within one LSB):
+
+- **`DUT` – Direct Form** (`SSR_FIR.vhd`): partial products cascade from the first to the last tap through the DSP `PCOUT` chain. The cascade is `TAPS` deep.
+- **`DUT_T` – Transpose Form** (`TRANSPOSE_SSR_FIR.vhd`): the input is broadcast to all DSPs and partial sums accumulate stage-by-stage through the DSP `PREG`/`PCOUT` registers. For SSR>1 each of the SSR lanes implements a transposed sub-FIR, so the cascade is only **`TAPS/SSR` deep per lane**.
+
+The two architectures are **functionally equivalent, with outputs agreeing to within one output LSB (2^-16)**. Each form is independently verified against the golden floating-point reference. The two forms have different pipeline latencies (direct = TAPS+2 clocks, transpose = 3×SSR+2 clocks), so the transpose output leads the direct output in time.
+
+To generate code for one architecture, point the **Vitis Model Composer Hub** block's subsystem selection at `DUT` (direct) or `DUT_T` (transpose).
+
+## Why two forms?
+
+The critical path of the direct form grows with `TAPS` (the `PCOUT` cascade), while the transpose form's critical path is one DSP multiply-accumulate that is **independent of `TAPS`**. This lets the transpose form close timing at high `SSR` and large `TAPS` where the direct form's cascade does not.
+
+| Property | **Direct Form** | **Transpose Form** |
+|---|---|---|
+| SSR range | 1, 2, 4, 8, 16 (2^n) | 1, 2, 4, 8, 16 (2^n) |
+| Fmax, Versal (SSR≤4) | ~822 MHz (device ceiling) | ~834–841 MHz |
+| Fmax, SSR=8 | ~670–740 MHz | ~834 MHz |
+| Latency (SSR>1, NS) | TAPS + 2 | 3×SSR + 2 |
+| PCOUT/PREG chain depth | TAPS hops | **TAPS/SSR hops per lane** |
+| DSP count, NS | SSR × TAPS | SSR × TAPS |
+
+**Rule of thumb:** use the **direct form** for SSR 2–4 with TAPS ≤ 64 (shorter latency, simplest dataflow); use the **transpose form** for SSR ≥ 8, or for TAPS > 64 at SSR = 4, or whenever a TAPS-independent (short, fixed) latency is required.
+
+## Model configuration
+
+The model is parameterized through `Model Settings → Model Properties → Callbacks → InitFcn`:
+
+```matlab
+SSR = 8; % clocks per sample — MUST be a power of two (1,2,4,8,16,...)
+TAPS = 64; % number of FIR coefficients
+Ts = 1/SSR; % input sample time; SSR*Ts must equal the Simulink system period (1)
+FCOEFF = fir1(TAPS-1,0.25); % shared coefficient set (hardware + golden reference)
+```
+
+Notes:
-This design only works in Vivado 2022.1 or later.
+- **`SSR` must be a power of two.** Both cores assert this; non-power-of-2 SSR is not supported by the SSR>1 accumulation chain.
+- **`Ts = 1/SSR`** keeps the buffered input frame rate aligned with the Vitis Model Composer Hub's Simulink system period so the golden-vs-DUT comparison lines up. Changing `SSR` automatically rescales `Ts`.
+- The remaining FIR parameters (input/output/coefficient fixed-point ranges, rounding, symmetry, optional DSP floorplanning) are set on the `SSRFIR` Model Composer block mask inside each DUT.
--------------
Copyright (c) 2026 Advanced Micro Devices, Inc.
diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/SDELAY.vhd b/Examples/HDL/Digital_Filtering/SSR_FIR/SDELAY.vhd
index 8e08543e7..0d311f7d6 100755
--- a/Examples/HDL/Digital_Filtering/SSR_FIR/SDELAY.vhd
+++ b/Examples/HDL/Digital_Filtering/SSR_FIR/SDELAY.vhd
@@ -1,212 +1,223 @@
--- Copyright (C) 2024, Advanced Micro Devices, Inc.
-
-library IEEE;
-use IEEE.STD_LOGIC_1164.all;
-use IEEE.NUMERIC_STD.ALL;
-
-use work.TYPES_PKG.all;
-
-entity SDELAY is
- generic(SIZE:NATURAL:=1; -- SIZE has a default value of 1 and cannot be negative, this would require traveling back in time
- DDR:BOOLEAN:=FALSE; -- DDR implementation for Versal -3 clock rates over 872MHz
- STYLE:STRING:="srl_reg"); -- acceptable values are "reg", "srl", "srl_reg", "reg_srl", "reg_srl_reg" or "block"
- port(CLK:in STD_LOGIC:='0'; -- an input port with a default value can be left unconnected, this could be useful when SIZE=0 (a wire)
- CLKH:in STD_LOGIC:='0'; -- half rate clock, an input port with a default value can be left unconnected, this could be useful when SIZE=0 (a wire)
- CE:in STD_LOGIC:='1'; -- clock enable, if not used can be left unconnected
--- I:in SIGNED;
--- O:out SIGNED);
- I:in SFIXED;
- O:out SFIXED);
- attribute secure_config:STRING;
- attribute secure_config of SDELAY:entity is "PROTECT";
-end SDELAY;
-
-architecture TEST of SDELAY is
- attribute syn_hier:STRING;
- attribute syn_hier of all:architecture is "hard";
- attribute srl_style:STRING;
-begin
- l2n:if DDR and (SIZE<4) generate
--- type TD is array(0 to SIZE) of SIGNED(I'range);
- type TD is array(0 to SIZE) of SFIXED(I'range);
- signal D:TD:=(others=>(others=>'0')); -- delay line signal is SIZE+1 in length
- attribute shreg_extract:STRING;
- attribute shreg_extract of D:signal is "no";
--- attribute ram_style:STRING;
--- attribute ram_style of D:signal is "registers";
- begin
- D(D'low)<=I;
- lk:for K in 1 to SIZE generate
- begin
- process(CLK)
- begin
- if rising_edge(CLK) then
- if CE='1' then
- D(K)<=D(K-1);
- end if;
- end if;
- end process;
- end generate;
--- O<=RESIZE(D(D'high),O'length);
- O<=RESIZE(D(D'high),O);
- end;
- elsif DDR and (SIZE>3) generate
- signal ID:SFIXED(I'range):=(others=>'0');
- signal T,TD,SEL:STD_LOGIC:='0';
- type TSV is array(0 to SIZE/2-1) of SFIXED(I'range);
- signal OE,OO:TSV:=(others=>(others=>'0')); -- delay line signal is SIZE/2 in length
- signal iO:SFIXED(O'range):=(others=>'0');
- attribute srl_style of OE:signal is STYLE;
- attribute srl_style of OO:signal is STYLE;
- begin
- i0:if SIZE mod 2=0 generate
- ID<=I after 1 ps;
- end;
- else generate
- process(CLK)
- begin
- if rising_edge(CLK) then
- if CE='1' then
- ID<=I after 1 ps;
- end if;
- end if;
- end process;
- end generate;
- process(CLKH)
- begin
- if rising_edge(CLKH) then
- for K in OE'low to OE'high loop
- if CE='1' then
- if K=OE'low then
- OE(K)<=ID after 1 ps;
- else
- OE(K)<=OE(K-1) after 1 ps;
- end if;
- end if;
- end loop;
- end if;
- end process;
-
- process(CLKH)
- begin
- if falling_edge(CLKH) then
- for K in OO'low to OO'high loop
- if CE='1' then
- if K=OO'low then
- OO(K)<=ID after 1 ps;
- else
- OO(K)<=OO(K-1) after 1 ps;
- end if;
- end if;
- end loop;
- end if;
- end process;
-
- process(CLKH)
- begin
- if rising_edge(CLKH) then
- T<=not T after 1 ps;
- end if;
- end process;
-
- process(CLK)
- begin
- if rising_edge(CLK) then
- TD<=T after 1 ps;
- SEL<=TD xor T after 1 ps;
- if SEL='0' then
- iO<=OE(OE'high);
- else
- iO<=OO(OO'high);
- end if;
- end if;
- end process;
- O<=iO;
- end;
- elsif (SIZE>=66 and SIZE<=65+33) or (SIZE>=130 and SIZE<=129+65+33) or (SIZE>=258 and SIZE<=257+129+65+33) generate
--- signal IO:SIGNED(I'range):=(others=>'0');
- signal IO:SFIXED(I'range):=(others=>'0');
- constant HSIZE:INTEGER:=2**(LOG2(SIZE)-1)+1;
- begin
- d2n:entity work.SDELAY generic map(SIZE=>HSIZE, -- 65/129/257
- STYLE=>STYLE)
- port map(CLK=>CLK,
- CE=>CE,
- I=>I,
- O=>IO);
- d1:entity work.SDELAY generic map(SIZE=>SIZE-HSIZE, -- 2..34/2..66/2..130
- STYLE=>STYLE)
- port map(CLK=>CLK,
- CE=>CE,
- I=>IO,
- O=>O);
- end;
- elsif l513: (SIZE>17 and SIZE<=513) generate -- infer a counter plus distributed RAM implementation
- signal A:UNSIGNED(LOG2(SIZE-1)-1 downto 0):=(others=>'0');
--- type TMEM is array(0 to 2**A'length-1) of SIGNED(I'range);
- type TMEM is array(0 to 2**A'length-1) of SFIXED(I'range);
- signal MEM:TMEM:=(others=>(others=>'0'));
- attribute ram_style:STRING;
- attribute ram_style of MEM:signal is "distributed";
--- signal iO:SIGNED(O'range):=(others=>'0');
- signal iO:SFIXED(O'range):=(others=>'0');
- begin
- process(CLK)
- begin
- if rising_edge(CLK) then
- if CE='1' then
- if A=SIZE-2 then
- A<=(others=>'0');
- else
- A<=A+1;
- end if;
- MEM(TO_INTEGER(A))<=I;
--- iO<=RESIZE(MEM(TO_INTEGER(A)),O'length);
- iO<=RESIZE(MEM(TO_INTEGER(A)),O);
- end if;
- end if;
- end process;
- O<=iO;
- end;
- elsif (SIZE>513) generate
--- signal IO:SIGNED(I'range):=(others=>'0');
- signal IO:SFIXED(I'range):=(others=>'0');
- constant HSIZE:INTEGER:=513;
- begin
- d2n:entity work.SDELAY generic map(SIZE=>HSIZE, -- 513
- STYLE=>STYLE)
- port map(CLK=>CLK,
- CE=>CE,
- I=>I,
- O=>IO);
- d1:entity work.SDELAY generic map(SIZE=>SIZE-HSIZE, -- SIZE-513
- STYLE=>STYLE)
- port map(CLK=>CLK,
- CE=>CE,
- I=>IO,
- O=>O);
- end;
- else generate -- otherwise use the behavioral implementation and the STYLE generic
--- type TD is array(0 to SIZE) of SIGNED(I'range);
- type TD is array(0 to SIZE) of SFIXED(I'range);
- signal D:TD:=(others=>(others=>'0')); -- delay line signal is SIZE+1 in length
- attribute srl_style:STRING;
- attribute srl_style of D:signal is STYLE;
- begin
- D(D'low)<=I;
- lk:for K in 1 to SIZE generate
- begin
- process(CLK)
- begin
- if rising_edge(CLK) then
- if CE='1' then
- D(K)<=D(K-1);
- end if;
- end if;
- end process;
- end generate;
--- O<=RESIZE(D(D'high),O'length);
- O<=RESIZE(D(D'high),O);
- end;
- end generate;
+-- Copyright © Advanced Micro Devices, Inc., or its affiliates. All rights reserved.
+-- Portions of this content consists of AI generated content.
+-- You may not use this software and documentation (if any) (collectively, the "Materials")
+-- except in compliance with the terms and conditions of the Software License Agreement
+-- included with the Materials or otherwise as set forth in writing and signed by you and
+-- an authorized signatory of AMD. If you do not have a copy of the Software License
+-- Agreement, contact your AMD representative for a copy. You agree that you will not
+-- reverse engineer or decompile the Materials, in whole or in part, except as allowed by
+-- applicable law.
+-- THE MATERIALS ARE DISTRIBUTED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+-- REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.all;
+use IEEE.NUMERIC_STD.ALL;
+
+use work.FIXED_PKG.all;
+use work.CFIXED_PKG.all;
+
+entity SDELAY is
+ generic(SIZE:NATURAL:=1; -- SIZE has a default value of 1 and cannot be negative, this would require traveling back in time
+ DDR:BOOLEAN:=FALSE; -- DDR implementation for Versal -3 clock rates over 872MHz
+ STYLE:STRING:="srl_reg"); -- acceptable values are "reg", "srl", "srl_reg", "reg_srl", "reg_srl_reg" or "block"
+ port(CLK:in STD_LOGIC:='0'; -- an input port with a default value can be left unconnected, this could be useful when SIZE=0 (a wire)
+ CLKH:in STD_LOGIC:='0'; -- half rate clock, an input port with a default value can be left unconnected, this could be useful when SIZE=0 (a wire)
+ CE:in STD_LOGIC:='1'; -- clock enable, if not used can be left unconnected
+-- I:in SIGNED;
+-- O:out SIGNED);
+ I:in SFIXED;
+ O:out SFIXED);
+ attribute secure_config:STRING;
+ attribute secure_config of SDELAY:entity is "PROTECT";
+end SDELAY;
+
+architecture TEST of SDELAY is
+ attribute syn_hier:STRING;
+ attribute syn_hier of all:architecture is "hard";
+ attribute srl_style:STRING;
+begin
+ l2n:if DDR and (SIZE<4) generate
+-- type TD is array(0 to SIZE) of SIGNED(I'range);
+ type TD is array(0 to SIZE) of SFIXED(I'range);
+ signal D:TD:=(others=>(others=>'0')); -- delay line signal is SIZE+1 in length
+ attribute shreg_extract:STRING;
+ attribute shreg_extract of D:signal is "no";
+-- attribute ram_style:STRING;
+-- attribute ram_style of D:signal is "registers";
+ begin
+ D(D'low)<=I;
+ lk:for K in 1 to SIZE generate
+ begin
+ process(CLK)
+ begin
+ if rising_edge(CLK) then
+ if CE='1' then
+ D(K)<=D(K-1);
+ end if;
+ end if;
+ end process;
+ end generate;
+-- O<=RESIZE(D(D'high),O'length);
+ O<=RESIZE(D(D'high),O);
+ end;
+ elsif DDR and (SIZE>3) generate
+ signal ID:SFIXED(I'range):=(others=>'0');
+ signal T,TD,SEL:STD_LOGIC:='0';
+ type TSV is array(0 to SIZE/2-1) of SFIXED(I'range);
+ signal OE,OO:TSV:=(others=>(others=>'0')); -- delay line signal is SIZE/2 in length
+ signal iO:SFIXED(O'range):=(others=>'0');
+ attribute srl_style of OE:signal is STYLE;
+ attribute srl_style of OO:signal is STYLE;
+ begin
+ i0:if SIZE mod 2=0 generate
+ ID<=I after 1 ps;
+ end;
+ else generate
+ process(CLK)
+ begin
+ if rising_edge(CLK) then
+ if CE='1' then
+ ID<=I after 1 ps;
+ end if;
+ end if;
+ end process;
+ end generate;
+ process(CLKH)
+ begin
+ if rising_edge(CLKH) then
+ for K in OE'low to OE'high loop
+ if CE='1' then
+ if K=OE'low then
+ OE(K)<=ID after 1 ps;
+ else
+ OE(K)<=OE(K-1) after 1 ps;
+ end if;
+ end if;
+ end loop;
+ end if;
+ end process;
+
+ process(CLKH)
+ begin
+ if falling_edge(CLKH) then
+ for K in OO'low to OO'high loop
+ if CE='1' then
+ if K=OO'low then
+ OO(K)<=ID after 1 ps;
+ else
+ OO(K)<=OO(K-1) after 1 ps;
+ end if;
+ end if;
+ end loop;
+ end if;
+ end process;
+
+ process(CLKH)
+ begin
+ if rising_edge(CLKH) then
+ T<=not T after 1 ps;
+ end if;
+ end process;
+
+ process(CLK)
+ begin
+ if rising_edge(CLK) then
+ TD<=T after 1 ps;
+ SEL<=TD xor T after 1 ps;
+ if SEL='0' then
+ iO<=OE(OE'high);
+ else
+ iO<=OO(OO'high);
+ end if;
+ end if;
+ end process;
+ O<=iO;
+ end;
+ elsif (SIZE>=66 and SIZE<=65+33) or (SIZE>=130 and SIZE<=129+65+33) or (SIZE>=258 and SIZE<=257+129+65+33) generate
+-- signal IO:SIGNED(I'range):=(others=>'0');
+ signal IO:SFIXED(I'range):=(others=>'0');
+ constant HSIZE:INTEGER:=2**(LOG2(SIZE)-1)+1;
+ begin
+ d2n:entity work.SDELAY generic map(SIZE=>HSIZE, -- 65/129/257
+ STYLE=>STYLE)
+ port map(CLK=>CLK,
+ CE=>CE,
+ I=>I,
+ O=>IO);
+ d1:entity work.SDELAY generic map(SIZE=>SIZE-HSIZE, -- 2..34/2..66/2..130
+ STYLE=>STYLE)
+ port map(CLK=>CLK,
+ CE=>CE,
+ I=>IO,
+ O=>O);
+ end;
+ elsif l513: (SIZE>17 and SIZE<=513) generate -- infer a counter plus distributed RAM implementation
+ signal A:UNSIGNED(LOG2(SIZE-1)-1 downto 0):=(others=>'0');
+-- type TMEM is array(0 to 2**A'length-1) of SIGNED(I'range);
+ type TMEM is array(0 to 2**A'length-1) of SFIXED(I'range);
+ signal MEM:TMEM:=(others=>(others=>'0'));
+ attribute ram_style:STRING;
+ attribute ram_style of MEM:signal is "distributed";
+-- signal iO:SIGNED(O'range):=(others=>'0');
+ signal iO:SFIXED(O'range):=(others=>'0');
+ begin
+ process(CLK)
+ begin
+ if rising_edge(CLK) then
+ if CE='1' then
+ if A=SIZE-2 then
+ A<=(others=>'0');
+ else
+ A<=A+1;
+ end if;
+ MEM(TO_INTEGER(A))<=I;
+-- iO<=RESIZE(MEM(TO_INTEGER(A)),O'length);
+ iO<=RESIZE(MEM(TO_INTEGER(A)),O);
+ end if;
+ end if;
+ end process;
+ O<=iO;
+ end;
+ elsif (SIZE>513) generate
+-- signal IO:SIGNED(I'range):=(others=>'0');
+ signal IO:SFIXED(I'range):=(others=>'0');
+ constant HSIZE:INTEGER:=513;
+ begin
+ d2n:entity work.SDELAY generic map(SIZE=>HSIZE, -- 513
+ STYLE=>STYLE)
+ port map(CLK=>CLK,
+ CE=>CE,
+ I=>I,
+ O=>IO);
+ d1:entity work.SDELAY generic map(SIZE=>SIZE-HSIZE, -- SIZE-513
+ STYLE=>STYLE)
+ port map(CLK=>CLK,
+ CE=>CE,
+ I=>IO,
+ O=>O);
+ end;
+ else generate -- otherwise use the behavioral implementation and the STYLE generic
+-- type TD is array(0 to SIZE) of SIGNED(I'range);
+ type TD is array(0 to SIZE) of SFIXED(I'range);
+ signal D:TD:=(others=>(others=>'0')); -- delay line signal is SIZE+1 in length
+ attribute srl_style:STRING;
+ attribute srl_style of D:signal is STYLE;
+ begin
+ D(D'low)<=I;
+ lk:for K in 1 to SIZE generate
+ begin
+ process(CLK)
+ begin
+ if rising_edge(CLK) then
+ if CE='1' then
+ D(K)<=D(K-1);
+ end if;
+ end if;
+ end process;
+ end generate;
+-- O<=RESIZE(D(D'high),O'length);
+ O<=RESIZE(D(D'high),O);
+ end;
+ end generate;
end TEST;
\ No newline at end of file
diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/SSR_FIR.slx b/Examples/HDL/Digital_Filtering/SSR_FIR/SSR_FIR.slx
index 42e390644..8d4406fad 100644
Binary files a/Examples/HDL/Digital_Filtering/SSR_FIR/SSR_FIR.slx and b/Examples/HDL/Digital_Filtering/SSR_FIR/SSR_FIR.slx differ
diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/SSR_FIR.vhd b/Examples/HDL/Digital_Filtering/SSR_FIR/SSR_FIR.vhd
index 9cf53d6d3..d704e9252 100755
--- a/Examples/HDL/Digital_Filtering/SSR_FIR/SSR_FIR.vhd
+++ b/Examples/HDL/Digital_Filtering/SSR_FIR/SSR_FIR.vhd
@@ -1,31 +1,91 @@
--- Copyright (C) 2024, Advanced Micro Devices, Inc.
-
+-----------------------------------------------------------------------------------------------
+-- © Copyright (C) 2024, Advanced Micro Devices, Inc. All rights reserved.
+-- This file contains confidential and proprietary information of AMD, Inc. and is
+-- protected under U.S. and international copyright and other intellectual property laws.
+-----------------------------------------------------------------------------------------------
+--
+-- Disclaimer:
+-- This disclaimer is not a license and does not grant any rights to the materials
+-- distributed herewith. Except as otherwise provided in a valid license issued to you
+-- by Xilinx, and to the maximum extent permitted by applicable law: (1) THESE MATERIALS
+-- ARE MADE AVAILABLE "AS IS" AND WITH ALL FAULTS, AND AMD HEREBY DISCLAIMS ALL
+-- WARRANTIES AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED
+-- TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR
+-- PURPOSE; and (2) AMD shall not be liable (whether in contract or tort, including
+-- negligence, or under any other theory of liability) for any loss or damage of any
+-- kind or nature related to, arising under or in connection with these materials,
+-- including for any direct, or any indirect, special, incidental, or consequential
+-- loss or damage (including loss of data, profits, goodwill, or any type of loss or
+-- damage suffered as a result of any action brought by a third party) even if such
+-- damage or loss was reasonably foreseeable or Xilinx had been advised of the
+-- possibility of the same.
+--
+-- CRITICAL APPLICATIONS
+-- AMD products are not designed or intended to be fail-safe, or for use in any
+-- application requiring fail-safe performance, such as life-support or safety devices
+-- or systems, Class III medical devices, nuclear facilities, applications related to
+-- the deployment of airbags, or any other applications that could lead to death,
+-- personal injury, or severe property or environmental damage (individually and
+-- collectively, "Critical Applications"). Customer assumes the sole risk and
+-- liability of any use of AMD products in Critical Applications, subject only to
+-- applicable laws and regulations governing limitations on product liability.
+--
+-- THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE AT ALL TIMES.
+--
+-- Contact: e-mail ben.fell@amd.com - this design is not supported by AMD
+-- Worldwide Technical Support (WTS), for support please contact the author
+-- ____ ____
+-- / /\/ /
+-- /___/ \ / Vendor: AMD Inc.
+-- \ \ \/ Version: 1.1
+-- \ \ Filename: SSR_FIR.vhd
+-- / / Date Last Modified: 23 Oct 2024
+-- /___/ /\ Date Created:
+-- \ \ / \
+-- \___\/\___\
+--
+-- Device: Any 7-Series, UltraScale or Versal AMD FPGA
+-- Author: Catalin Baetoniu
+-- Entity Name: SSR_FFT
+-- Purpose: Generic SSR Single Rate FIR, any SSR, any number of taps, non/even/odd/anti symmetric
+--
+-- Revision History:
+-- Revision 1.1 2024-Oct-23 Full VHDL-2008 version
+--------------------------------------------------------------------------------
+--
+-- Module Description:
+--
+--------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
-use work.TYPES_PKG.all;
+use work.fixed_pkg.all; -- VHDL-2008 IEEE standard SFIXED type and functions
+use work.cfixed_pkg.all; -- user package, SFIXED_VECTOR, SFIXED_MATRIX and many other goodies
entity SSR_FIR is
generic(OX,OY:INTEGER:=-2147483648; -- Coordinates of the lower left corner DSPx8, use -2147483648 if you do not want floorplanning
FAMILY:INTEGER:=3; -- use 1 for 7-series, 2 for US/US+ and 3 for Versal
DDR:BOOLEAN:=FALSE; -- DDR implementation for Versal -3 clock rates over 872MHz
- COEFFICIENT:REAL_VECTOR; -- Number of Rows=COEFFICIENT'length
+ COEFFICIENT:REAL_MATRIX; -- Number of Rows=COEFFICIENT'length
C_HIGH:INTEGER:=0;
C_LOW:INTEGER:=-17;
ROUNDING:BOOLEAN:=FALSE;
+ ANTI:BOOLEAN:=FALSE; -- for anti-symmetric filters, when ANTI=TRUE and SYMMETRY="OS" the center tap must be 0.0
SYMMETRY:STRING:="ES"); -- Filter Symmetry, use "ES" for Even-Symmetric, "OS" for Odd-Symmetric and "NS" for Non-Symmetric
port(CLK:in STD_LOGIC;
CLKH:in STD_LOGIC:='0'; -- if DDR=FALSE can be left unconnected
I:in SFIXED_VECTOR;
VI:in BOOLEAN:=TRUE;
+ CSA:in UNSIGNED:="0"; -- Coefficient Set Address, CSA'length must be equal to LOG2(COEFFICIENT'length(1))
O:out SFIXED_VECTOR;
VO:out BOOLEAN);
end SSR_FIR;
architecture TEST of SSR_FIR is
- constant SSR:INTEGER:=I'length(1); -- Number of Columns
- constant TAPS:INTEGER:=COEFFICIENT'length; -- Number of Rows
+ constant COEFFICIENT_SETS:INTEGER:=COEFFICIENT'length;
+ constant TAPS:INTEGER:=COEFFICIENT(COEFFICIENT'low)'length;
+ constant SSR:INTEGER:=I'length;
function DIL(SYMMETRY:STRING;TAPS:INTEGER) return INTEGER is
begin
if SYMMETRY="ES" then
@@ -40,19 +100,16 @@ architecture TEST of SSR_FIR is
end if;
end;
constant LDI:INTEGER:=DIL(SYMMETRY,TAPS);
--- these two type definitions overload the ones in TYPES_PKG, they are slightly different, this is a workaround for Vivado Sim VHDL-2008 limited support
- type SFIXED_VECTOR is array(INTEGER range <>) of SFIXED(I'range(2));
- type SFIXED_MATRIX is array(INTEGER range <>,INTEGER range <>) of SFIXED(I'range(2));
type AC_VECTOR is array(INTEGER range <>) of STD_LOGIC_VECTOR(FAMILY/3*4+29 downto 0);
type PC_VECTOR is array(INTEGER range <>) of STD_LOGIC_VECTOR(FAMILY/3*10+47 downto 0);
- signal SW,SE:SFIXED_MATRIX(0 to TAPS-1,0 to SSR-1);
+ signal SW,SE:SFIXED_MATRIX(0 to TAPS-1)(0 to SSR-1)(I(I'low)'range);
function LATENCY(SSR:INTEGER;SYMMETRY:STRING;TAPS:INTEGER) return INTEGER is
begin
if SSR=1 then
if SYMMETRY="ES" then
return TAPS+4;
elsif SYMMETRY="OS" then
- return TAPS+4;
+ return TAPS+4-BOOLEAN'pos(ANTI);
elsif SYMMETRY="NS" then
return TAPS+3;
else
@@ -63,7 +120,7 @@ architecture TEST of SSR_FIR is
if SYMMETRY="ES" then
return TAPS+3;
elsif SYMMETRY="OS" then
- return TAPS+3;
+ return TAPS+3-BOOLEAN'pos(ANTI);
elsif SYMMETRY="NS" then
return TAPS+2;
else
@@ -93,22 +150,39 @@ architecture TEST of SSR_FIR is
return "A";
end if;
end;
- signal II:SFIXED_VECTOR(I'range(1));
begin
assert I'length=O'length report "Ports I and O must have the same length!" severity warning;
- li:for L in I'range(1) generate
- II(L)<=GET(I,L);
- end generate;
+ assert CSA'length=MAX(LOG2(COEFFICIENT'length(1)),1) report "Inconsistent CSA length!" severity warning;
+ assert not (ANTI and SYMMETRY="NS") report "ANTI=TRUE has no effect for SYMMETRY=""NS"" - anti-symmetric pairs require ES or OS symmetry" severity warning;
+ assert SSR=1 or 2**LOG2(SSR)=SSR report "SSR must be 1 or a power of 2 - non-power-of-2 SSR causes diagonal register misalignment in the SSR>1 accumulation chain" severity failure;
+ -- For ES/OS: the SE reverse-delay index DI(-LDI-1+SSR+J) becomes invalid
+ -- when SSR > TAPS (ES) or SSR >= TAPS (OS), where TAPS=COEFFICIENT'length.
+ -- ES rule: 2*SSR <= NUM_TAPS => SSR <= COEFFICIENT'length
+ -- OS rule: 2*SSR < NUM_TAPS => SSR < COEFFICIENT'length
+ assert SYMMETRY="NS" or SSR<=TAPS-BOOLEAN'pos(SYMMETRY="OS") report "For ES: SSR must be <= NUM_TAPS/2. For OS: SSR must be < (NUM_TAPS+1)/2. Increase TAPS or use NS." severity failure;
+ -- For ES/OS, the DSP pre-adder computes D+A. D and A are both data_width bits wide,
+ -- so D+A = data_width+1 bits must fit the multiplier AD port.
+ -- FAMILY=3 (DSPx8): AD port = 27 bits → D+A ≤ 27 → data_width ≤ 26.
+ -- FAMILY=1,2 (DSP48/DSP58): AD port = 30 bits → D+A ≤ 30 → data_width ≤ 29.
+ assert SYMMETRY="NS" or I(I'low)'length <= FAMILY/3*26+(1-FAMILY/3)*29
+ report "For ES/OS: data width (I_HIGH-I_LOW+1=" & INTEGER'image(I(I'low)'length) & ") exceeds the DSP pre-adder AD port limit (" & INTEGER'image(FAMILY/3*26+(1-FAMILY/3)*29) & " bits for FAMILY=" & INTEGER'image(FAMILY) & "). Reduce I_HIGH-I_LOW to fit within the limit, or use SYMMETRY=""NS""."
+ severity failure;
+ -- For SSR>1, the DI delay buffer has depth LDI=TAPS-1. TAPS=1 gives LDI=0
+ -- (null range), which is not supported by xsim or synthesis.
+ assert SSR=1 or TAPS>=2
+ report "TAPS must be >= 2 when SSR > 1: TAPS=1 creates a null-range DI buffer (LDI=0). No practical use case exists for SSR>1 with a single-tap FIR."
+ severity failure;
i1:if SSR=1 generate
- signal DI:SFIXED(I'range(2));
+ signal DI:SFIXED(I(I'low)'range);
signal AC:AC_VECTOR(0 to TAPS);
signal PC:PC_VECTOR(0 to TAPS);
+ signal CS:UNSIGNED_VECTOR(0 to TAPS)(CSA'range):=(others=>(others=>'0'));
function DSIZE(TAPS:INTEGER;SYMMETRY:STRING) return INTEGER is
begin
if SYMMETRY="ES" then
- return 2*TAPS-1;
+ return 2*TAPS;
elsif SYMMETRY="OS" then
- return 2*TAPS-2;
+ return 2*TAPS-1;
elsif SYMMETRY="NS" then
return 0;
else
@@ -121,25 +195,41 @@ begin
DDR=>DDR)
port map(CLK=>CLK,
CLKH=>CLKH,
- I=>II(I'low),
+ I=>I(I'low),
O=>DI);
-- DSPx8 Array
AC(0)<=STD_LOGIC_VECTOR(TO_SIGNED(0,AC(0)'length));
PC(0)<=STD_LOGIC_VECTOR(TO_SIGNED(0,PC(0)'length));
- lj:for J in 0 to TAPS-1 generate
+ CS(0)<=CSA;
+ lj:for J in 0 to TAPS-1-BOOLEAN'pos(ANTI and SYMMETRY="OS") generate
+ signal ALUMODE:STD_LOGIC_VECTOR(3 downto 0);
signal INMODE:STD_LOGIC_VECTOR(4 downto 0);
signal OPMODE:STD_LOGIC_VECTOR(8 downto 0);
- signal A,D:SFIXED(I'range(2));
- signal C,P:SFIXED(LOG2(TAPS)+I'high(2)+C_HIGH+1 downto I'low(2)+C_LOW); -- must not be longer than 48/58 bits!
+ signal A,D:SFIXED(I(I'low)'range);
+ signal B:SFIXED(C_high downto C_low);
+ signal C,P:SFIXED(LOG2(TAPS)+I(I'low)'high+C_HIGH+1 downto I(I'low)'low+C_LOW); -- must not be longer than 48/58 bits!
signal CE:STD_LOGIC;
begin
- A<=II(I'low) when J=0 else (others=>'0');
- C<=TO_SFIXED(2.0**(C'low-O'low(2)-1),C) when ROUNDING and (J=0) else TO_SFIXED(0.0,C);
+ A<=I(I'low) when J=0 else (others=>'0');
+ C<=TO_SFIXED(2.0**(C'low-O(O'low)'low-1),C) when ROUNDING and (J=0) else TO_SFIXED(0.0,C);
D<=(others=>'0') when SYMMETRY="NS" else DI;
- INMODE<=5x"11" when (SYMMETRY="OS") and (J=TAPS-1) else 5x"15"; -- A1*B1 when (SYMMETRY="OS") and (K=TAPS-1) else (D+A1)*B1
- OPMODE<=9x"035" when J=0 else 9x"015"; -- PCOUT=C+(D+A)*B when J=0 else PCIN+(D+A)*B
+ ALUMODE<=4x"3" when ANTI else 4x"0";
+ INMODE<=5x"18" when ANTI and (SYMMETRY="OS") and (J=TAPS-1) else 5x"1C" when ANTI else
+ 5x"10" when (SYMMETRY="OS") and (J=TAPS-1) else 5x"14"; -- A2*B1 when (SYMMETRY="OS") and (J=TAPS-1) else (D+A1)*B1
+ OPMODE<=9x"035" when J=0 else 9x"015"; -- PCOUT=C-(D+A)*B when J=0 else PCIN-(D+A)*B
CE<='1' when VI else '0';
-
+ ia:if COEFFICIENT'length=1 generate
+ B<=TO_SFIXED(COEFFICIENT(TO_INTEGER(CS(J+1-BOOLEAN'pos(SYMMETRY="NS"))))(COEFFICIENT(COEFFICIENT'low)'low+J),C_HIGH,C_LOW);
+ CS(J+1)<=CS(J);
+ else generate
+ process(CLK)
+ begin
+ if rising_edge(CLK) then
+ B<=TO_SFIXED(COEFFICIENT(TO_INTEGER(CS(J+1-BOOLEAN'pos(SYMMETRY="NS"))))(COEFFICIENT(COEFFICIENT'low)'low+J),C_HIGH,C_LOW);
+ CS(J+1)<=CS(J);
+ end if;
+ end process;
+ end generate;
jk:entity work.DSPx8_WRAPPER generic map(X=>OX,
Y=>OY+J,
FAMILY=>FAMILY,
@@ -150,10 +240,11 @@ begin
port map (CLK=>CLK,
CEA2=>CE,
A=>A,
- B=>TO_SFIXED(COEFFICIENT(COEFFICIENT'low+J),C_HIGH,C_LOW),
+ B=>B,
C=>C,
D=>D,
ACIN=>AC(J),
+ ALUMODE=>ALUMODE,
INMODE=>INMODE,
OPMODE=>OPMODE,
PCIN=>PC(J),
@@ -161,26 +252,20 @@ begin
PCOUT=>PC(J+1),
P=>P);
-- Output Samples
- il:if J=COEFFICIENT'high generate
--- all SET calls targetting the same signal must be located in a single process!
--- SET does not work in QuestaSim!
+ il:if J=TAPS-1-BOOLEAN'pos(ANTI and SYMMETRY="OS") generate
process(P)
begin
--- SET(O,O'low,P);
- for L in O'range(2) loop
- O(O'low(1),L)<=P(L);
- end loop;
+ O(O'low)<=RESIZE(P,O(O'low));
end process;
- end generate;
+ end generate;
end generate;
end;
else generate
- signal DI:SFIXED_VECTOR(-LDI to -1):=(others=>(others=>'0'));
- signal WI,EI:SFIXED_VECTOR(1 to TAPS-1);
- signal RSW:SFIXED_MATRIX(0 to TAPS-2,0 to SSR-2):=(others=>(others=>(others=>'0')));
- signal RSE:SFIXED_MATRIX(0 to TAPS-2,1 to SSR-1):=(others=>(others=>(others=>'0')));
- type P_SFIXED_VECTOR is array(INTEGER range <>) of SFIXED(LOG2(TAPS)+I'high(2)+C_HIGH+1 downto I'low(2)+C_LOW); -- must not be longer than 48/58 bits!
- signal vP:P_SFIXED_VECTOR(0 to SSR-1);
+ signal DI:SFIXED_VECTOR(-LDI to -1)(I(I'low)'range):=(others=>(others=>'0'));
+ signal WI,EI:SFIXED_VECTOR(1 to TAPS-1)(I(I'low)'range);
+ signal RSW:SFIXED_MATRIX(0 to TAPS-2)(0 to SSR-2)(I(I'low)'range):=(others=>(others=>(others=>'0')));
+ signal RSE:SFIXED_MATRIX(0 to TAPS-2)(1 to SSR-1)(I(I'low)'range):=(others=>(others=>(others=>'0')));
+ signal vP:SFIXED_VECTOR(0 to SSR-1)(LOG2(TAPS)+I(I'low)'high+C_HIGH+1 downto I(I'low)'low+C_LOW);
begin
-- Input Data Delay Line for SSR Input Samples
process(CLK)
@@ -191,7 +276,7 @@ begin
if K<-SSR then
DI(K)<=DI(K+SSR);
else
- DI(K)<=II(I'low+K+SSR);
+ DI(K)<=I(I'low+K+SSR);
end if;
end loop;
end if;
@@ -207,12 +292,28 @@ begin
O=>WI(J));
ns:if SYMMETRY/="NS" generate
- rd:entity work.SDELAY generic map(SIZE=>J,
- DDR=>DDR)
- port map(CLK=>CLK,
- CLKH=>CLKH,
- I=>DI(-LDI-1+SSR+J),
- O=>EI(J));
+ -- Reverse delay: DI(-LDI-1+SSR+J) accesses the symmetric
+ -- counterpart sample. Guard against OOB when SSR >= TAPS_internal
+ -- (i.e. -LDI-1+SSR+J >= 0). For the degenerate center-tap case
+ -- use DI(-J) so D+B=2D; with the halved center coefficient this
+ -- gives the correct full-coefficient result. For ANTI=TRUE the
+ -- center coefficient is 0 so this path has no effect.
+ valid_rd:if (-LDI-1+SSR+J) < 0 generate
+ rd:entity work.SDELAY generic map(SIZE=>J,
+ DDR=>DDR)
+ port map(CLK=>CLK,
+ CLKH=>CLKH,
+ I=>DI(-LDI-1+SSR+J),
+ O=>EI(J));
+ end generate;
+ center_rd:if (-LDI-1+SSR+J) >= 0 generate
+ rd:entity work.SDELAY generic map(SIZE=>J,
+ DDR=>DDR)
+ port map(CLK=>CLK,
+ CLKH=>CLKH,
+ I=>DI(-J),
+ O=>EI(J));
+ end generate;
end generate;
end generate;
-- Pipelining Array Registers
@@ -221,7 +322,7 @@ begin
process(CLK)
begin
if rising_edge(CLK) then
- RSW(J,K)<=SW(J,K);
+ RSW(J)(K)<=SW(J)(K);
end if;
end process;
end generate;
@@ -231,7 +332,7 @@ begin
process(CLK)
begin
if rising_edge(CLK) then
- RSE(J,K)<=SE(J,K);
+ RSE(J)(K)<=SE(J)(K);
end if;
end process;
end generate;
@@ -240,58 +341,71 @@ begin
-- DSPx8 Array
lk:for K in 0 to SSR-1 generate
signal PC:PC_VECTOR(0 to TAPS);
+ signal CS:UNSIGNED_VECTOR(0 to TAPS)(CSA'range):=(others=>(others=>'0'));
begin
PC(0)<=STD_LOGIC_VECTOR(TO_SIGNED(0,PC(0)'length));
- lj:for J in 0 to TAPS-1 generate
+ CS(0)<=CSA;
+ lj:for J in 0 to TAPS-1-BOOLEAN'pos(ANTI and SYMMETRY="OS") generate
+ signal ALUMODE:STD_LOGIC_VECTOR(3 downto 0);
signal INMODE:STD_LOGIC_VECTOR(4 downto 0);
signal OPMODE:STD_LOGIC_VECTOR(8 downto 0);
- signal D:SFIXED(I'range(2));
+ signal D:SFIXED(I(I'low)'range);
signal C,P:SFIXED(vP(vP'low)'range);
+ signal B:SFIXED(C_high downto C_low);
begin
-- MIN/MAX workaround for QuestaSim bug
- SW(J,K)<=II(I'low+K) when J=0 else
- WI(work.TYPES_PKG.MAX(J,1)) when K=0 else
- RSW(work.TYPES_PKG.MAX(J-1,0),work.TYPES_PKG.MAX(K-1,0));
+ SW(J)(K)<=I(I'low+K) when J=0 else
+ WI(work.cfixed_pkg.MAX(J,1)) when K=0 else
+ RSW(work.cfixed_pkg.MAX(J-1,0))(work.cfixed_pkg.MAX(K-1,0));
ns:if SYMMETRY/="NS" generate
- SE(J,K)<=DI(-LDI+K) when J=0 else
- EI(work.TYPES_PKG.MAX(J,1)) when K=SSR-1 else
- RSE(work.TYPES_PKG.MAX(J-1,0),work.TYPES_PKG.MIN(K+1,SSR-1));
+ SE(J)(K)<=DI(-LDI+K) when J=0 else
+ EI(work.cfixed_pkg.MAX(J,1)) when K=SSR-1 else
+ RSE(work.cfixed_pkg.MAX(J-1,0))(work.cfixed_pkg.MIN(K+1,SSR-1));
end generate;
- C<=TO_SFIXED(2.0**(C'low-O'low(2)-1),C) when ROUNDING and (J=0) else TO_SFIXED(0.0,C);
- D<=(others=>'0') when SYMMETRY="NS" else SE(J,K);
- INMODE<=5x"11" when (SYMMETRY="OS") and (J=TAPS-1) else 5x"15"; -- A1*B1 when (SYMMETRY="OS") and (K=TAPS-1) else (D+A1)*B1
+ C<=TO_SFIXED(2.0**(C'low-O(O'low)'low-1),C) when ROUNDING and (J=0) else TO_SFIXED(0.0,C);
+ D<=(others=>'0') when SYMMETRY="NS" else SE(J)(K);
+ ALUMODE<=4x"3" when ANTI else 4x"0";
+ INMODE<=5x"13" when ANTI and (SYMMETRY="OS") and (J=TAPS-1) else 5x"1D" when ANTI else
+ 5x"11" when (SYMMETRY="OS") and (J=TAPS-1) else 5x"15"; -- A2*B1 when (SYMMETRY="OS") and (J=TAPS-1) else (D+A1)*B1
OPMODE<=9x"035" when J=0 else 9x"015"; -- PCOUT=C+(D+A)*B when J=0 else PCIN+(D+A)*B
-
+ ia:if COEFFICIENT'length=1 generate
+ B<=TO_SFIXED(COEFFICIENT(TO_INTEGER(CS(J+1-BOOLEAN'pos(SYMMETRY="NS"))))(COEFFICIENT(COEFFICIENT'low)'low+J),C_HIGH,C_LOW);
+ CS(J+1)<=CS(J);
+ else generate
+ process(CLK)
+ begin
+ if rising_edge(CLK) then
+ B<=TO_SFIXED(COEFFICIENT(TO_INTEGER(CS(J)))(COEFFICIENT(COEFFICIENT'low)'low+J),C_HIGH,C_LOW);
+ CS(J+1)<=CS(J);
+ end if;
+ end process;
+ end generate;
jk:entity work.DSPx8_WRAPPER generic map(X=>OX+K,
Y=>OY+J,
FAMILY=>FAMILY,
AMULTSEL=>AMULTSEL(SYMMETRY)) --"A" for Non-Symmetric FIR else "AD"
port map (CLK=>CLK,
- A=>SW(J,K),
- B=>TO_SFIXED(COEFFICIENT(COEFFICIENT'low+J),C_HIGH,C_LOW),
+ A=>SW(J)(K),
+ B=>B,
C=>C,
D=>D,
+ ALUMODE=>ALUMODE,
INMODE=>INMODE,
OPMODE=>OPMODE,
PCIN=>PC(J),
PCOUT=>PC(J+1),
P=>P);
-- SSR Output Samples
- il:if J=COEFFICIENT'high generate
+ il:if J=TAPS-1-BOOLEAN'pos(ANTI and SYMMETRY="OS") generate
vP(K)<=P;
end generate;
end generate;
end generate;
--- all SET calls targetting the same signal must be located in a single process!
--- SET does not work in QuestaSim!
process(vP)
begin
for K in vP'range loop
--- SET(O,O'low+K,vP(K));
- for L in O'range(2) loop
- O(O'low(1)+K,L)<=vP(K)(L);
- end loop;
+ O(O'low+K)<=RESIZE(vP(K),O(O'low+K));
end loop;
end process;
end;
@@ -303,4 +417,4 @@ begin
CLKH=>CLKH,
I=>VI,
O=>VO);
-end TEST;
\ No newline at end of file
+end TEST;
diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/SSR_FIR_TEST.vhd b/Examples/HDL/Digital_Filtering/SSR_FIR/SSR_FIR_TEST.vhd
deleted file mode 100755
index 68da4082b..000000000
--- a/Examples/HDL/Digital_Filtering/SSR_FIR/SSR_FIR_TEST.vhd
+++ /dev/null
@@ -1,77 +0,0 @@
--- Copyright (C) 2024, Advanced Micro Devices, Inc.
-
-library IEEE;
-use IEEE.STD_LOGIC_1164.ALL;
-use IEEE.NUMERIC_STD.ALL;
-
-use work.TYPES_PKG.all;
-
-library UNISIM;
-use UNISIM.VComponents.all;
-
-entity SSR_FIR_TEST is
- generic(OX,OY:INTEGER:=0; -- Coordinates of the lower left corner DSPx8, use -2147483648 if you do not want floorplanning
- FAMILY:INTEGER:=3; -- use 1 for 7-series, 2 for US/US+ and 3 for Versal
- DDR:BOOLEAN:=TRUE; -- DDR implementation for Versal -3 clock rates over 872MHz
- SSR:INTEGER:=8; -- for 8Gsps in Versal speed grade -3
--- SSR:INTEGER:=9; -- for 8Gsps in US+ speed grade -3
--- SSR:INTEGER:=11; -- for 8Gsps in 7-series speed grade -3
- COEFFICIENT:REAL_VECTOR(0 to 15):=(1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0);
--- COEFFICIENT:REAL_VECTOR(0 to 23):=(1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0,21.0,22.0,23.0,24.0);
- I_HIGH:INTEGER:=7;
- I_LOW:INTEGER:=-8;
- C_HIGH:INTEGER:=9;
- C_LOW:INTEGER:=-8;
- O_HIGH:INTEGER:=19;
- O_LOW:INTEGER:=-8;
- ROUNDING:BOOLEAN:=TRUE;
- SYMMETRY:STRING:="OS"); -- Filter Symmetry, use "ES" for Even-Symmetric, "OS" for Odd-Symmetric and "NS" for Non-Symmetric
- port(CLKIN:in STD_LOGIC;
- I:in SFIXED_VECTOR(0 to SSR-1,I_HIGH downto I_LOW);
- VI:in BOOLEAN;
- O:out SFIXED_VECTOR(0 to SSR-1,O_HIGH downto O_LOW);
- VO:out BOOLEAN);
-end SSR_FIR_TEST;
-
-architecture TEST of SSR_FIR_TEST is
- signal CLK,CLKH:STD_LOGIC;
- signal ID:SFIXED_VECTOR(0 to SSR-1,I_HIGH downto I_LOW):=(others=>(others=>'0'));
- signal VID:BOOLEAN:=FALSE;
-begin
- i1:if DDR generate
- b2:MBUFGCE_DIV port map(I=>CLKIN,
- CE=>'1',
- CLR=>'0',
- CLRB_LEAF=>'1',
- O1=>CLK,
- O2=>CLKH);
- end;
- else generate
- CLK<=CLKIN;
- CLKH<='0';
- end generate;
-
- process(CLK)
- begin
- if rising_edge(CLK) then
- ID<=I;
- VID<=VI;
- end if;
- end process;
-
- u1:entity work.SSR_FIR generic map(OX=>OX,
- OY=>OY,
- FAMILY=>FAMILY,
- DDR=>DDR,
- COEFFICIENT=>COEFFICIENT,
- C_HIGH=>C_HIGH,
- C_LOW=>C_LOW,
- ROUNDING=>ROUNDING,
- SYMMETRY=>SYMMETRY)
- port map (CLK=>CLK,
- CLKH=>CLKH,
- I=>ID,
- VI=>VID,
- O=>O,
- VO=>VO);
-end TEST;
\ No newline at end of file
diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/TRANSPOSE_SSR_FIR.vhd b/Examples/HDL/Digital_Filtering/SSR_FIR/TRANSPOSE_SSR_FIR.vhd
new file mode 100644
index 000000000..af39ae127
--- /dev/null
+++ b/Examples/HDL/Digital_Filtering/SSR_FIR/TRANSPOSE_SSR_FIR.vhd
@@ -0,0 +1,382 @@
+-- Copyright © Advanced Micro Devices, Inc., or its affiliates. All rights reserved.
+-- Portions of this content consists of AI generated content.
+-- You may not use this software and documentation (if any) (collectively, the "Materials")
+-- except in compliance with the terms and conditions of the Software License Agreement
+-- included with the Materials or otherwise as set forth in writing and signed by you and
+-- an authorized signatory of AMD. If you do not have a copy of the Software License
+-- Agreement, contact your AMD representative for a copy. You agree that you will not
+-- reverse engineer or decompile the Materials, in whole or in part, except as allowed by
+-- applicable law.
+-- THE MATERIALS ARE DISTRIBUTED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+-- REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+
+use work.FIXED_PKG.all;
+use work.CFIXED_PKG.all;
+
+-- =============================================================================
+-- TRANSPOSE_SSR_FIR_ROW
+-- One J-row sub-filter for the transpose-form SSR FIR. Instantiated SSR times
+-- from TRANSPOSE_SSR_FIR via for-generate. Keeping J as a generic constant
+-- (not a for-generate loop variable) works around an xsim VHDL-2008 bug where
+-- concurrent signal assignments and processes inside for-generate use only the
+-- first iteration value of the loop parameter. Entity instantiation port maps
+-- are evaluated correctly for every iteration, so the row is instantiated with
+-- the right J_IDX via the outer generate and handles its own K-loop internally.
+-- =============================================================================
+entity TRANSPOSE_SSR_FIR_ROW is
+ generic(J_IDX:INTEGER; -- row index (0..SSR-1)
+ OX,OY:INTEGER; -- floorplan origin; chains add K to OX
+ FAMILY:INTEGER;
+ DDR:BOOLEAN;
+ COEFFICIENT:REAL_MATRIX; -- full coefficient matrix; GET() selects K-slice
+ TAPS_G:INTEGER; -- total number of taps (passed in to size C)
+ C_HIGH:INTEGER;
+ C_LOW:INTEGER;
+ EXTRA_C_PIPELINING:BOOLEAN;
+ EXTRA_D_PIPELINING:BOOLEAN;
+ ROUNDING:BOOLEAN;
+ ANTI:BOOLEAN;
+ SYMMETRY:STRING);
+ port(CLK:in STD_LOGIC;
+ CLKH:in STD_LOGIC;
+ I:in SFIXED_VECTOR; -- full SSR-wide input
+ VI:in BOOLEAN;
+ CSA:in UNSIGNED; -- coefficient set address
+ O_J:out SFIXED); -- single sub-filter output (one lane)
+end TRANSPOSE_SSR_FIR_ROW;
+
+architecture ROW of TRANSPOSE_SSR_FIR_ROW is
+ constant SSR:INTEGER:=I'length;
+ constant D_HIGH:INTEGER:=I(I'low)'high;
+ constant D_LOW :INTEGER:=I(I'low)'low;
+ constant CH:INTEGER:=LOG2(TAPS_G)+D_HIGH+C_HIGH+2;
+ constant CL:INTEGER:=D_LOW+C_LOW;
+ -- All signals at architecture level - no for-generate local signal declarations.
+ -- K-indexed signals are 1-D arrays (SFIXED_VECTOR or UNSIGNED_VECTOR), indexed
+ -- by the lk for-generate parameter K. J_IDX is a generic constant here, so
+ -- every expression that references it is correctly evaluated in all contexts.
+ signal C :SFIXED_VECTOR(0 to SSR)(CH downto CL);
+ signal ID,RD:SFIXED_VECTOR(I'range)(D_HIGH downto D_LOW);
+ signal CP_K:SFIXED_VECTOR(0 to SSR-1)(CH downto CL)
+ :=(others=>(others=>'0'));
+ signal DD_K,BB_K:SFIXED_VECTOR(0 to SSR-1)(D_HIGH downto D_LOW)
+ :=(others=>(others=>'0'));
+ signal DO_K,BO_K:SFIXED_VECTOR(0 to SSR-1)(D_HIGH downto D_LOW);
+ signal CS:UNSIGNED_VECTOR(0 to SSR)(CSA'range):=(others=>(others=>'0'));
+
+ function GET(COEFFICIENT:REAL_MATRIX;K:INTEGER) return REAL_MATRIX is
+ constant TAPS_K:INTEGER:=COEFFICIENT(COEFFICIENT'low)'length;
+ variable RESULT:REAL_MATRIX(COEFFICIENT'range)(0 to (TAPS_K+SSR-1)/SSR-1);
+ begin
+ for J in RESULT'range loop
+ for L in RESULT(J)'range loop
+ if SSR*L+SSR-1-K >= TAPS_K then
+ RESULT(J)(L):=0.0;
+ elsif (SYMMETRY="OS") and (SSR*L+SSR-1-K=TAPS_K-1) then
+ RESULT(J)(L):=COEFFICIENT(J)(SSR*L+SSR-1-K)/2.0;
+ else
+ RESULT(J)(L):=COEFFICIENT(J)(SSR*L+SSR-1-K);
+ end if;
+ end loop;
+ end loop;
+ return RESULT;
+ end;
+
+begin
+ C(0)<=TO_SFIXED(0.0,C(0));
+
+ -- Anti+OS: center coefficient (last element of coefficient array) must be 0.0.
+ -- The GET() function applies /2.0 to the center tap; for anti-symmetric filters
+ -- the center must be zero so the pre-adder subtraction (D-B) cancels correctly.
+ assert not (ANTI and SYMMETRY="OS" and
+ COEFFICIENT(COEFFICIENT'low)(COEFFICIENT(COEFFICIENT'low)'high) /= 0.0)
+ report "TRANSPOSE_SSR_FIR_ROW: ANTI+OS center coefficient must be 0.0"
+ severity FAILURE;
+
+ -- CS cascade: one process owns ALL elements of CS (including CS(0)) to avoid
+ -- any cross-driver conflict on the unresolved UNSIGNED_VECTOR composite signal.
+ -- Having CS(0)<=CSA as a separate concurrent assignment plus a process driving
+ -- CS(1..SSR) makes xsim see the composite as having two drivers and CS(0) gets
+ -- stuck at its initial value. Absorbing CS(0)<=CSA into the same process (with
+ -- CSA in the sensitivity list so it stays combinatorial) resolves this.
+ cs_cascade:if EXTRA_C_PIPELINING generate
+ process(CLK, CSA) begin
+ CS(0)<=CSA; -- combinatorial: all CSA changes reflected immediately
+ if rising_edge(CLK) then
+ CS(1)<=CSA; -- CS(1) registered once from CSA
+ for K in 1 to SSR-1 loop
+ CS(K+1)<=CS(K);
+ end loop;
+ end if;
+ end process;
+ else generate
+ process(all) begin
+ CS(0)<=CSA;
+ CS(1)<=CSA;
+ for K in 1 to SSR-1 loop
+ CS(K+1)<=CS(K);
+ end loop;
+ end process;
+ end generate;
+
+ -- CP_K cascade: one process owns ALL elements of CP_K to avoid any
+ -- cross-driver conflict on the unresolved SFIXED_VECTOR composite signal.
+ -- CP_K(0)=C(0)=0 always; CP_K(1..SSR-1) registered when EXTRA_C_PIPELINING.
+ cp_cascade:if EXTRA_C_PIPELINING generate
+ process(CLK) begin
+ if rising_edge(CLK) then
+ for K in 0 to SSR-1 loop
+ CP_K(K)<=C(K);
+ end loop;
+ end if;
+ end process;
+ else generate
+ process(all) begin
+ for K in 0 to SSR-1 loop
+ CP_K(K)<=C(K);
+ end loop;
+ end process;
+ end generate;
+
+ -- DD_K / BB_K: registered when EXTRA_D_PIPELINING, wired otherwise.
+ -- Single process drives all SSR elements to avoid multiple-driver issues.
+ dd_bb_pipe:if EXTRA_D_PIPELINING generate
+ process(CLK) begin
+ if rising_edge(CLK) then
+ for K in 0 to SSR-1 loop
+ DD_K(K)<=ID(K+I'low);
+ BB_K(K)<=RD(K+I'low);
+ end loop;
+ end if;
+ end process;
+ else generate
+ process(all) begin
+ for K in 0 to SSR-1 loop
+ DD_K(K)<=ID(K+I'low);
+ BB_K(K)<=RD(K+I'low);
+ end loop;
+ end process;
+ end generate;
+
+ -- RD for NS symmetry: no reverse-input path, drive entire array to zero.
+ -- Handled here at architecture level (not inside the lk for-generate) so
+ -- there is exactly one driver on the unresolved SFIXED_VECTOR signal.
+ rd_ns:if SYMMETRY="NS" generate
+ RD<=(others=>(others=>'0'));
+ end generate;
+
+ -- K-loop: ONLY entity instantiations appear here.
+ -- Concurrent signal assignments and processes have been moved to architecture-level
+ -- constructs above so xsim's for-generate multiple-driver bug cannot affect them.
+ lk:for K in 0 to SSR-1 generate
+
+ -- Triangular input delay: selects and time-aligns the correct input sample
+ -- for this (J_IDX, K) filter chain. J_IDX is a generic constant so the
+ -- SIZE expression is evaluated correctly for each elaborated ROW instance.
+ sd_gen:if J_IDX=(SSR-1) generate
+ sd:entity work.SDELAY
+ generic map(SIZE=>2*K+K*BOOLEAN'pos(EXTRA_C_PIPELINING),
+ DDR=>DDR)
+ port map(CLK=>CLK,
+ CLKH=>CLKH,
+ I=>I((1+K+J_IDX) mod SSR+I'low),
+ O=>ID(K+I'low));
+ else generate
+ sd:entity work.SDELAY
+ generic map(SIZE=>1+2*K-(J_IDX+K)/(SSR-1)+K*BOOLEAN'pos(EXTRA_C_PIPELINING),
+ DDR=>DDR)
+ port map(CLK=>CLK,
+ CLKH=>CLKH,
+ I=>I((1+K+J_IDX) mod SSR+I'low),
+ O=>ID(K+I'low));
+ end generate;
+
+ -- Reverse input delay for symmetric path (ES/OS only).
+ -- NS symmetry: RD is driven to zero at architecture level above.
+ ri:if SYMMETRY="ES" generate
+ dr_gen:if J_IDX=(SSR-1) generate
+ dr:entity work.SDELAY
+ generic map(SIZE=>2*(SSR-K)-1+(SSR-K-1)*BOOLEAN'pos(EXTRA_C_PIPELINING),
+ DDR=>DDR)
+ port map(CLK=>CLK,
+ CLKH=>CLKH,
+ I=>I((1+J_IDX+K) mod SSR+I'low),
+ O=>RD(SSR-1-K+I'low));
+ else generate
+ dr:entity work.SDELAY
+ generic map(SIZE=>1+2*(SSR-K)-1-(J_IDX+K)/(SSR-1)+(SSR-K-1)*BOOLEAN'pos(EXTRA_C_PIPELINING),
+ DDR=>DDR)
+ port map(CLK=>CLK,
+ CLKH=>CLKH,
+ I=>I((1+J_IDX+K) mod SSR+I'low),
+ O=>RD(SSR-1-K+I'low));
+ end generate;
+ elsif SYMMETRY="OS" generate
+ dr:entity work.SDELAY
+ generic map(SIZE=>2*(SSR-K-1)+BOOLEAN'pos(((J_IDX+K+2) mod SSR)>J_IDX)+(SSR-K-1)*BOOLEAN'pos(EXTRA_C_PIPELINING),
+ DDR=>DDR)
+ port map(CLK=>CLK,
+ CLKH=>CLKH,
+ I=>I((J_IDX+K+2) mod SSR+I'low),
+ O=>RD(SSR-1-K+I'low));
+ end generate;
+
+ -- Accumulator chain for this (J_IDX, K) tap group.
+ jk:entity work.TRANSPOSE_SSR_FIR_CHAIN
+ generic map(OX=>OX+K,
+ OY=>OY,
+ FAMILY=>FAMILY,
+ DDR=>DDR,
+ COEFFICIENT=>GET(COEFFICIENT,K),
+ C_HIGH=>C_HIGH,
+ C_LOW=>C_LOW,
+ ROUNDING=>ROUNDING and (K=0),
+ ANTI=>ANTI,
+ SYMMETRY=>SYMMETRY,
+ FIRST_CHAIN=>K=0)
+ port map(CLK=>CLK,
+ CLKH=>CLKH,
+ DI=>DD_K(K),
+ BI=>BB_K(K),
+ CI=>CP_K(K),
+ VI=>VI,
+ CSA=>CS(K),
+ DO=>DO_K(K),
+ BO=>BO_K(K),
+ O=>C(K+1),
+ VO=>open);
+ end generate lk;
+
+ O_J<=RESIZE(C(SSR),O_J);
+
+end ROW;
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use work.FIXED_PKG.all;
+use work.CFIXED_PKG.all;
+
+-- =============================================================================
+-- TRANSPOSE_SSR_FIR
+-- Top-level SSR polyphase transpose-form FIR filter.
+-- Instantiates SSR TRANSPOSE_SSR_FIR_ROW entities via a for-generate.
+-- Only entity instantiations appear inside the for-generate (no concurrent
+-- signal assignments or processes) so xsim's for-generate evaluation bug does
+-- not affect correctness. J is passed as a generic constant J_IDX to each row.
+-- =============================================================================
+entity TRANSPOSE_SSR_FIR is
+ generic(OX,OY:INTEGER:=-2147483648; -- Coordinates of the lower left corner DSPx8, use -2147483648 if you do not want floorplanning
+ FAMILY:INTEGER:=3; -- use 1 for 7-series, 2 for US/US+ and 3 for Versal
+ DDR:BOOLEAN:=FALSE; -- DDR implementation to be used only for Versal -3 and clock rates over 872MHz
+ COEFFICIENT:REAL_MATRIX; -- Number of Coefficient Sets=COEFFICIENT'length(1), Number of Taps=COEFFICIENT'length(2)
+ C_HIGH:INTEGER:=0; -- For odd anti-symmetric filters, the center tap coefficient, COEFFICIENT(:,COEFFICIENT'high(2)) must be zero, but the redundant DSPx8 is removed
+ C_LOW:INTEGER:=-17;
+ EXTRA_C_PIPELINING:BOOLEAN:=TRUE;
+ EXTRA_D_PIPELINING:BOOLEAN:=TRUE;
+ ROUNDING:BOOLEAN:=FALSE;
+ ANTI:BOOLEAN:=FALSE; -- If even or odd symmetric, is it anti-symmetric?
+ SYMMETRY:STRING:="ES"); -- Filter Symmetry, use "ES" for Even-Symmetric, "OS" for Odd-Symmetric and "NS" for Non-Symmetric
+ port(CLK:in STD_LOGIC;
+ CLKH:in STD_LOGIC:='0'; -- if DDR=FALSE can be left unconnected
+ I:in SFIXED_VECTOR; -- for non-symmetric filters use DI as input, tie BI to zero, for symmetric filters tie DI and BI together
+ VI:in BOOLEAN:=TRUE; -- WARNING: VI must not be deasserted mid-stream.
+ -- SDELAY chains are not gated by VI; deasserting VI
+ -- after data has entered the pipeline causes permanent
+ -- misalignment between the data path and VO delay line.
+ -- There is no reset port — power-cycle to recover.
+ --CEBI,CECI,CEDI:in BOOLEAN:=TRUE;
+ CSA:in UNSIGNED:="0"; -- Coefficient Set Address, CSA'length must be equal to LOG2(COEFFICIENT'length(1))
+ O:out SFIXED_VECTOR;
+ VO:out BOOLEAN);
+end TRANSPOSE_SSR_FIR;
+
+architecture TEST of TRANSPOSE_SSR_FIR is
+ constant COEFFICIENT_SETS:INTEGER:=COEFFICIENT'length;
+ constant TAPS:INTEGER:=COEFFICIENT(COEFFICIENT'low)'length;
+ constant SSR:INTEGER:=I'length;
+ -- DSP port widths (integer division intentional; matches DSPx8_WRAPPER slv* signals)
+ constant I_WIDTH :INTEGER:=I(I'low)'high-I(I'low)'low+1; -- data bit width
+ constant C_WIDTH :INTEGER:=C_HIGH-C_LOW+1; -- coefficient bit width
+ constant A_PORT_W :INTEGER:=FAMILY/3*4+30; -- A port: 34b Versal/DSP58, 30b US+/DSP48E2
+ constant D_PORT_W :INTEGER:=27; -- D port: 27b on all families (FAMILY/2*2+25)
+ constant B_PORT_W :INTEGER:=FAMILY/3*6+18; -- B port: 24b Versal/DSP58, 18b US+/DSP48E2
+begin
+ assert I'length=O'length report "Inconsistent I and O port lengths!" severity warning;
+ assert CSA'length=MAX(LOG2(COEFFICIENT'length(1)),1) report "Inconsistent CSA length!" severity warning;
+ -- DSP port truncation guards -------------------------------------------
+ -- Coefficient maps to DSP A port (AMULTSEL="A", PREADDINSEL="B").
+ -- Exceeding A_PORT_W silently truncates coefficient MSBs -> wrong MAC results.
+ assert C_WIDTH<=A_PORT_W
+ report "TRANSPOSE_SSR_FIR: coefficient width "&INTEGER'image(C_WIDTH)
+ &"b exceeds DSP A port ("&INTEGER'image(A_PORT_W)
+ &"b on FAMILY="&INTEGER'image(FAMILY)
+ &") - reduce C_HIGH-C_LOW or target FAMILY=3 (Versal, A=34b)"
+ severity FAILURE;
+ -- Forward data maps to DSP D port (always, all filter modes; BMULTSEL="AD", B=0 for NS).
+ -- D port is 27b on all supported families. Exceeding it truncates data MSBs.
+ assert I_WIDTH<=D_PORT_W
+ report "TRANSPOSE_SSR_FIR: data width "&INTEGER'image(I_WIDTH)
+ &"b exceeds DSP D port (27b, all families) - reduce I_HIGH-I_LOW"
+ severity FAILURE;
+ -- Reverse data maps to DSP B port (ES/OS only; B is forced to 0 for NS so no risk).
+ -- B port is narrower than D: 24b Versal, 18b US+. Exceeding it truncates the
+ -- reverse pre-adder operand -> wrong ES/OS symmetric filter output.
+ assert SYMMETRY="NS" or I_WIDTH<=B_PORT_W
+ report "TRANSPOSE_SSR_FIR: data width "&INTEGER'image(I_WIDTH)
+ &"b exceeds DSP B port ("&INTEGER'image(B_PORT_W)
+ &"b on FAMILY="&INTEGER'image(FAMILY)&") for "&SYMMETRY
+ &" reverse path - reduce I_HIGH-I_LOW"
+ &" or switch to FAMILY=3 (Versal, B=24b vs US+ B=18b)"
+ severity FAILURE;
+ -- -----------------------------------------------------------------------
+
+ -- Instantiate one row sub-filter per SSR lane. Only entity instantiations
+ -- appear inside this for-generate so xsim evaluates J correctly for all
+ -- J=0..SSR-1 (xsim correctly handles for-generate for entity port maps).
+ lj:for J in SSR-1 downto 0 generate
+ jrow:entity work.TRANSPOSE_SSR_FIR_ROW
+ generic map(J_IDX => J,
+ OX => OX,
+ OY => OY+TAPS/SSR*J,
+ FAMILY => FAMILY,
+ DDR => DDR,
+ COEFFICIENT => COEFFICIENT,
+ TAPS_G => TAPS,
+ C_HIGH => C_HIGH,
+ C_LOW => C_LOW,
+ EXTRA_C_PIPELINING => EXTRA_C_PIPELINING,
+ EXTRA_D_PIPELINING => EXTRA_D_PIPELINING,
+ ROUNDING => ROUNDING,
+ ANTI => ANTI,
+ SYMMETRY => SYMMETRY)
+ port map(CLK => CLK,
+ CLKH => CLKH,
+ I => I,
+ VI => VI,
+ CSA => CSA,
+ O_J => O(J+O'low));
+ end generate lj;
+
+-- Data Valid Delay Line
+-- Latency formula (EXTRA_C=TRUE, EXTRA_D=TRUE): 2*SSR + 2 + (SSR-1) + 1 = 3*SSR + 2
+-- SSR LATENCY
+-- 1 5
+-- 2 8
+-- 3 11
+-- 4 14
+-- 5 17
+-- 6 20
+-- 8 26
+-- 10 32
+ bd:entity work.BDELAY generic map(SIZE=>2*SSR+2+(SSR-1)*BOOLEAN'pos(EXTRA_C_PIPELINING)+BOOLEAN'pos(EXTRA_D_PIPELINING),
+ DDR=>DDR)
+ port map(CLK=>CLK,
+ CLKH=>CLKH,
+ I=>VI,
+ O=>VO);
+end TEST;
diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/TRANSPOSE_SSR_FIR_CHAIN.vhd b/Examples/HDL/Digital_Filtering/SSR_FIR/TRANSPOSE_SSR_FIR_CHAIN.vhd
new file mode 100644
index 000000000..dea715736
--- /dev/null
+++ b/Examples/HDL/Digital_Filtering/SSR_FIR/TRANSPOSE_SSR_FIR_CHAIN.vhd
@@ -0,0 +1,324 @@
+-- Copyright © Advanced Micro Devices, Inc., or its affiliates. All rights reserved.
+-- Portions of this content consists of AI generated content.
+-- You may not use this software and documentation (if any) (collectively, the "Materials")
+-- except in compliance with the terms and conditions of the Software License Agreement
+-- included with the Materials or otherwise as set forth in writing and signed by you and
+-- an authorized signatory of AMD. If you do not have a copy of the Software License
+-- Agreement, contact your AMD representative for a copy. You agree that you will not
+-- reverse engineer or decompile the Materials, in whole or in part, except as allowed by
+-- applicable law.
+-- THE MATERIALS ARE DISTRIBUTED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+-- REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+
+use work.FIXED_PKG.all;
+use work.CFIXED_PKG.all;
+
+-- =============================================================================
+-- TRANSPOSE_SSR_FIR_CHAIN
+-- One K-column accumulator chain for the SSR polyphase transpose-form FIR.
+-- Instantiated SSR times from TRANSPOSE_SSR_FIR_ROW.
+--
+-- xsim workaround: concurrent signal assignments and processes inside
+-- for-generate use only the first iteration value of the loop parameter.
+-- Additionally, signal instances inside for-generate are SHARED across all
+-- iterations, causing multiple-driver conflicts (X propagation) when per-stage
+-- drivers disagree. The fix (matching what was done in TRANSPOSE_SSR_FIR_ROW)
+-- is to declare ALL signals at architecture level and drive them with a single
+-- architecture-level process or concurrent assignment. Only entity
+-- instantiations appear inside the lj:for J generate; port maps are evaluated
+-- correctly per iteration in xsim.
+-- =============================================================================
+entity TRANSPOSE_SSR_FIR_CHAIN is
+ generic(OX,OY:INTEGER:=-2147483648; -- Coordinates of the lower left corner DSPx8, use -2147483648 if you do not want floorplanning
+ FAMILY:INTEGER:=3; -- use 1 for 7-series, 2 for US/US+ and 3 for Versal
+ DDR:BOOLEAN:=FALSE; -- DDR implementation to be used only for Versal -3 and clock rates over 872MHz
+ COEFFICIENT:REAL_MATRIX; -- Number of Coefficient Sets=COEFFICIENT'length(1), Number of Taps=COEFFICIENT'length(2)
+ C_HIGH:INTEGER:=0; -- For odd anti-symmetric filters, the center tap coefficient, COEFFICIENT(:,COEFFICIENT'high(2)) must be zero, but the redundant DSPx8 is removed
+ C_LOW:INTEGER:=-17;
+ ROUNDING:BOOLEAN:=FALSE;
+ ANTI:BOOLEAN:=FALSE; -- If even or odd symmetric, is it anti-symmetric?
+ SYMMETRY:STRING:="ES"; -- Filter Symmetry, use "ES" for Even-Symmetric, "OS" for Odd-Symmetric and "NS" for Non-Symmetric
+ FIRST_CHAIN: BOOLEAN := TRUE);
+ port(CLK:in STD_LOGIC;
+ CLKH:in STD_LOGIC:='0'; -- if DDR=FALSE can be left unconnected
+ DI,BI:in SFIXED; -- for non-symmetric filters use DI as input, tie BI to zero, for symmetric filters tie DI is forward data and BI is reverse data
+ CI:in SFIXED; -- C input into the last DSPx8 in the chain, used for cascading transpose sections
+ VI:in BOOLEAN:=TRUE;
+ CEBI,CECI,CEDI:in BOOLEAN:=TRUE;
+ CSA:in UNSIGNED:="0"; -- Coefficient Set Address, CSA'length must be equal to LOG2(COEFFICIENT'length(1))
+ DO,BO:out SFIXED; -- these are not used unless you build a systolic transposed filter structure
+ O:out SFIXED;
+ VO:out BOOLEAN);
+end TRANSPOSE_SSR_FIR_CHAIN;
+
+architecture TEST of TRANSPOSE_SSR_FIR_CHAIN is
+ constant COEFFICIENT_SETS:INTEGER:=COEFFICIENT'length;
+ constant TAPS:INTEGER:=COEFFICIENT(COEFFICIENT'low)'length;
+ constant JLOW:INTEGER:=0;
+
+ -- P/C signal width (must not exceed DSP P register width of 48/58 bits)
+ constant P_HIGH : INTEGER := MAX(LOG2(TAPS)+BI'high+C_HIGH+1, O'high);
+ constant P_LOW : INTEGER := BI'low+C_LOW;
+
+ -- -------------------------------------------------------------------------
+ -- Helper functions
+ -- -------------------------------------------------------------------------
+ function BREG(SYMMETRY:STRING;ANTI:BOOLEAN;J:INTEGER) return INTEGER is
+ begin
+ if (SYMMETRY="ES") or (SYMMETRY="OS") then
+ if (SYMMETRY="OS") and FIRST_CHAIN and J=JLOW then
+ return 1;
+ elsif (SYMMETRY/="OS") and J=JLOW then
+ return 1;
+ else
+ return 2;
+ end if;
+ elsif SYMMETRY="NS" then
+ return 1;
+ else
+ assert FALSE report "SYMMETRY must be either ""ES"", ""OS"" or ""NS""!" severity warning;
+ return 0;
+ end if;
+ end;
+
+ function LATENCY(SYMMETRY:STRING;TAPS:INTEGER) return INTEGER is
+ begin
+ if SYMMETRY="ES" then
+ return 4;
+ elsif SYMMETRY="OS" then
+ return 4;
+ elsif SYMMETRY="NS" then
+ return 3;
+ else
+ assert FALSE report "SYMMETRY must be either ""ES"", ""OS"" or ""NS""!" severity warning;
+ return 0;
+ end if;
+ end;
+
+ function B_INPUT(J:INTEGER) return STRING is
+ begin
+ if J=JLOW then
+ return "DIRECT";
+ else
+ return "CASCADE";
+ end if;
+ end;
+
+ -- -------------------------------------------------------------------------
+ -- Cascade signal arrays (one entry per DSP stage, plus boundary values)
+ -- -------------------------------------------------------------------------
+ type BC_VECTOR is array(INTEGER range <>) of STD_LOGIC_VECTOR(FAMILY/3*6+17 downto 0);
+ type CS_VECTOR is array(INTEGER range <>) of UNSIGNED(LOG2(COEFFICIENT_SETS)-1 downto 0);
+ type PC_VECTOR is array(INTEGER range <>) of STD_LOGIC_VECTOR(FAMILY/3*10+47 downto 0);
+ subtype A_VECTOR is SFIXED_VECTOR(0 to COEFFICIENT'length-1)(C_HIGH downto C_LOW);
+
+ signal BC : BC_VECTOR(JLOW to TAPS);
+ signal PC : PC_VECTOR(JLOW to TAPS);
+
+ -- -------------------------------------------------------------------------
+ -- Per-stage coefficient ROM: AV_ALL(J)(coeff_set) = coefficient at tap J
+ -- ALL_AV_INIT uses a local for-loop variable (not a generate variable) so J
+ -- evaluates correctly for every iteration -> no xsim bug here.
+ -- -------------------------------------------------------------------------
+ function A_VALUE(COEFFICIENT:REAL_MATRIX;J:INTEGER) return A_VECTOR is
+ variable AV:A_VECTOR;
+ begin
+ for K in AV'range loop
+ AV(K):=TO_SFIXED(COEFFICIENT(COEFFICIENT'low+K)(COEFFICIENT(COEFFICIENT'low)'low+J),C_HIGH,C_LOW);
+ end loop;
+ return AV;
+ end;
+
+ type AV_MATRIX_T is array(INTEGER range <>) of A_VECTOR;
+
+ function ALL_AV_INIT(COEFFICIENT:REAL_MATRIX) return AV_MATRIX_T is
+ variable result : AV_MATRIX_T(JLOW to TAPS-1);
+ begin
+ for J in JLOW to TAPS-1 loop
+ result(J) := A_VALUE(COEFFICIENT, TAPS-1-J); -- transposed FIR: tap 0 at last DSP
+ end loop;
+ return result;
+ end;
+ -- Elaboration-time constant: correct coefficient per stage, all coeff sets
+ constant AV_ALL : AV_MATRIX_T(JLOW to TAPS-1) := ALL_AV_INIT(COEFFICIENT);
+
+ -- -------------------------------------------------------------------------
+ -- Static per-stage control arrays (constants, correct at elaboration time)
+ -- -------------------------------------------------------------------------
+ type OPMODE_ARR_T is array(INTEGER range <>) of STD_LOGIC_VECTOR(8 downto 0);
+ type INMODE_ARR_T is array(INTEGER range <>) of STD_LOGIC_VECTOR(4 downto 0);
+
+ function ALL_OPMODE_INIT return OPMODE_ARR_T is
+ variable result : OPMODE_ARR_T(JLOW to TAPS-1);
+ begin
+ for J in JLOW to TAPS-1 loop
+ if J = JLOW then
+ result(J) := 9x"035"; -- first: P = C + A*D (no PCIN cascade in)
+ elsif J = TAPS-1 then
+ result(J) := 9x"195"; -- last: P = C + PCIN + A*D (CI passes via C)
+ else
+ result(J) := 9x"015"; -- middle: P = PCIN + A*D
+ end if;
+ end loop;
+ return result;
+ end;
+ constant OPMODE_CONST : OPMODE_ARR_T(JLOW to TAPS-1) := ALL_OPMODE_INIT;
+
+ function ALL_INMODE_INIT return INMODE_ARR_T is
+ variable result : INMODE_ARR_T(JLOW to TAPS-1);
+ begin
+ for J in JLOW to TAPS-1 loop
+ if SYMMETRY = "NS" then
+ result(J) := 5x"07"; -- A1*D (NS: no pre-adder subtraction)
+ elsif ANTI and not ((SYMMETRY="OS") and FIRST_CHAIN and (J=JLOW)) then
+ result(J) := 5x"0D"; -- A1*(D-B2) (anti-symmetric)
+ else
+ result(J) := 5x"05"; -- A1*(D+B2) (symmetric)
+ end if;
+ end loop;
+ return result;
+ end;
+ constant INMODE_CONST : INMODE_ARR_T(JLOW to TAPS-1) := ALL_INMODE_INIT;
+
+ -- -------------------------------------------------------------------------
+ -- Architecture-level per-stage signal arrays
+ -- Declared here (NOT inside for-generate) so each array element has exactly
+ -- ONE driver -> no xsim signal-sharing / multiple-driver X propagation.
+ -- -------------------------------------------------------------------------
+ signal A_ARR : SFIXED_VECTOR(JLOW to TAPS-1)(C_HIGH downto C_LOW);
+ signal B_ARR : SFIXED_VECTOR(JLOW to TAPS-1)(BI'high downto BI'low);
+ signal C_ARR : SFIXED_VECTOR(JLOW to TAPS-1)(P_HIGH downto P_LOW);
+ signal P_ARR : SFIXED_VECTOR(JLOW to TAPS-1)(P_HIGH downto P_LOW);
+ signal CE_SIG, CEB1_SIG, CEC_SIG, CED_SIG : STD_LOGIC;
+
+begin
+ assert CSA'length=MAX(LOG2(COEFFICIENT'length(1)),1) report "Inconsistent CSA length!" severity warning;
+
+ -- Cascade boundary initial values (tie chain input to zero)
+ BC(JLOW) <= STD_LOGIC_VECTOR(TO_SIGNED(0,BC(JLOW)'length));
+ PC(JLOW) <= STD_LOGIC_VECTOR(TO_SIGNED(0,PC(JLOW)'length));
+
+ -- Clock enable signals (same for all DSP stages)
+ CE_SIG <= '1' when VI else '0';
+ CEB1_SIG <= '1' when CEBI else '0';
+ CEC_SIG <= '1' when CECI else '0';
+ CED_SIG <= '1' when CEDI else '0';
+
+ -- A_ARR: select per-stage coefficient from the elaboration-time constant AV_ALL.
+ -- Single process owns all elements; no for-generate concurrent-assignment bug.
+ ia: if CSA'length=1 generate
+ -- Combinatorial select (single coeff set or runtime-selected with 1-bit CSA).
+ -- Explicit sensitivity list instead of process(all): xsim 2025.2 may not
+ -- auto-detect SFIXED/UNSIGNED ports read through composite array indexing.
+ process(CSA) begin
+ for J in JLOW to TAPS-1 loop
+ A_ARR(J) <= AV_ALL(J)(TO_INTEGER(CSA));
+ end loop;
+ end process;
+ else generate
+ -- Registered select: pipeline CSA through one CLK stage
+ process(CLK) begin
+ if rising_edge(CLK) then
+ for J in JLOW to TAPS-1 loop
+ A_ARR(J) <= AV_ALL(J)(TO_INTEGER(CSA));
+ end loop;
+ end if;
+ end process;
+ end generate;
+
+ -- B_ARR: first stage and all NS stages get BI; remainder get 0.
+ -- Explicit sensitivity list: xsim may not auto-detect BI (SFIXED port) via process(all).
+ gen_b: process(BI) begin
+ for J in JLOW to TAPS-1 loop
+ if (J = JLOW) or (SYMMETRY = "NS") then
+ B_ARR(J) <= BI;
+ else
+ B_ARR(J) <= (others => '0');
+ end if;
+ end loop;
+ end process;
+
+ -- C_ARR: rounding constant at first stage, RESIZE(CI) at last, 0 elsewhere.
+ -- Explicit sensitivity list: xsim may not auto-detect CI (SFIXED port) via process(all),
+ -- which would cause C_ARR(TAPS-1) to be stuck at 0, breaking the inter-chain cascade.
+ gen_c: process(CI) begin
+ for J in JLOW to TAPS-1 loop
+ if ROUNDING and (J = JLOW) then
+ C_ARR(J) <= TO_SFIXED(2.0**(P_LOW+O'low-1), P_HIGH, P_LOW);
+ elsif J = TAPS-1 then
+ C_ARR(J) <= RESIZE(CI, P_HIGH, P_LOW);
+ else
+ C_ARR(J) <= TO_SFIXED(0.0, P_HIGH, P_LOW);
+ end if;
+ end loop;
+ end process;
+
+ -- Output: last DSP stage P register
+ O <= RESIZE(P_ARR(TAPS-1), O);
+
+ -- -------------------------------------------------------------------------
+ -- DSP cascade for-generate.
+ -- ONLY entity instantiations appear here; xsim evaluates entity port maps
+ -- correctly for every for-generate iteration so J-indexed signal accesses
+ -- (A_ARR(J), B_ARR(J), BC(J), PC(J), etc.) connect to the right elements.
+ -- Generic map expressions using J (BREG, B_INPUT, Y offset) also evaluate
+ -- correctly since generics are set at elaboration time.
+ -- -------------------------------------------------------------------------
+ lj: for J in JLOW to TAPS-1 generate
+ jk: entity work.DSPx8_WRAPPER
+ generic map(X => OX,
+ Y => OY+J-JLOW,
+ FAMILY => FAMILY,
+ BREG => BREG(SYMMETRY,ANTI,J),
+ BCASCREG => BREG(SYMMETRY,ANTI,J),
+ B_INPUT => B_INPUT(J),
+ PREADDINSEL => "B",
+ AMULTSEL => "A",
+ BMULTSEL => "AD")
+ port map(CLK => CLK,
+ CEB1 => CEB1_SIG,
+ CEB2 => CE_SIG,
+ CEC => CEC_SIG,
+ CED => CED_SIG,
+ A => A_ARR(J),
+ B => B_ARR(J),
+ C => C_ARR(J),
+ D => DI,
+ BCIN => BC(J),
+ INMODE => INMODE_CONST(J),
+ OPMODE => OPMODE_CONST(J),
+ PCIN => PC(J),
+ BCOUT => BC(J+1),
+ PCOUT => PC(J+1),
+ P => P_ARR(J));
+ end generate lj;
+
+ -- DO: forward-data pipeline register (used when cascading chain sections)
+ process(CLK)
+ begin
+ if rising_edge(CLK) then
+ DO <= DI;
+ end if;
+ end process;
+
+ -- BO: reverse-data shift register for cascading symmetric-filter sections
+ db: entity work.SDELAY generic map(SIZE => 2*TAPS+BREG(SYMMETRY,ANTI,0)-1,
+ DDR => DDR)
+ port map(CLK => CLK,
+ CLKH => CLKH,
+ I => BI,
+ O => BO);
+
+ -- Data Valid Delay Line
+ bd: entity work.BDELAY generic map(SIZE => LATENCY(SYMMETRY,TAPS),
+ DDR => DDR)
+ port map(CLK => CLK,
+ CLKH => CLKH,
+ I => VI,
+ O => VO);
+
+end TEST;
diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/TYPES_PKG.vhd b/Examples/HDL/Digital_Filtering/SSR_FIR/TYPES_PKG.vhd
deleted file mode 100755
index c8712fe76..000000000
--- a/Examples/HDL/Digital_Filtering/SSR_FIR/TYPES_PKG.vhd
+++ /dev/null
@@ -1,776 +0,0 @@
--- Copyright (C) 2024, Advanced Micro Devices, Inc.
-
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use ieee.math_real.all;
-use ieee.math_complex.all;
-
-package TYPES_PKG is
--- constant I_SIZE:INTEGER:=16;
--- constant C_SIZE:INTEGER:=16;
--- constant O_SIZE:INTEGER:=36;
--- type BOOLEAN_VECTOR is array(NATURAL range <>) of BOOLEAN;
--- type INTEGER_VECTOR is array(INTEGER range <>) of INTEGER;
--- type REAL_VECTOR is array(INTEGER range <>) of REAL;
--- type COMPLEX_VECTOR is array(INTEGER range <>) of COMPLEX;
--- type I_VECTOR is array(INTEGER range <>) of STD_LOGIC_VECTOR(I_SIZE-1 downto 0);
--- type O_VECTOR is array(INTEGER range <>) of STD_LOGIC_VECTOR(O_SIZE-1 downto 0);
--- type SI_VECTOR is array(INTEGER range <>) of SIGNED(I_SIZE-1 downto 0);
--- type SO_VECTOR is array(INTEGER range <>) of SIGNED(O_SIZE-1 downto 0);
--- type SI_MATRIX is array(INTEGER range <>,INTEGER range <>) of SIGNED(I_SIZE-1 downto 0);
-
- function LOG2(N:INTEGER) return INTEGER;
-
--- type REAL_VECTOR is array(INTEGER range <>) of REAL;
- type COMPLEX_VECTOR is array(INTEGER range <>) of COMPLEX;
-
- type SFIXED is array(INTEGER range <>) of STD_LOGIC;
- type SFIXED_VECTOR is array(INTEGER range <>,INTEGER range <>) of STD_LOGIC;
- type SFIXED_MATRIX is array(INTEGER range <>,INTEGER range <>,INTEGER range <>) of STD_LOGIC;
-
- type CFIXED is array(INTEGER range <>) of STD_LOGIC; -- CFIXED'high must be odd and CFIXED'low must be even
- type CFIXED_VECTOR is array(INTEGER range <>,INTEGER range <>) of STD_LOGIC; -- CFIXED'high(2) must be odd and CFIXED'low(2) must be even
- type CFIXED_MATRIX is array(INTEGER range <>,INTEGER range <>,INTEGER range <>) of STD_LOGIC; -- CFIXED'high(3) must be odd and CFIXED'low(3) must be even
-
- function MIN(A,B:INTEGER) return INTEGER;
- function MIN(A,B,C:INTEGER) return INTEGER;
- function MIN(A,B,C,D:INTEGER) return INTEGER;
- function MAX(A,B:INTEGER) return INTEGER;
- function MAX(A,B,C:INTEGER) return INTEGER;
- function MAX(A,B,C,D:INTEGER) return INTEGER;
- function MED(A,B,C:INTEGER) return INTEGER;
- function "+"(X,Y:SFIXED) return SFIXED; -- full precision add with SFIXED(MAX(X'high,Y'high)+1 downto MIN(X'low,Y'low)) result
- function "-"(X,Y:SFIXED) return SFIXED; -- full precision subtract with SFIXED(MAX(X'high,Y'high)+1 downto MIN(X'low,Y'low)) result
- function "-"(X:SFIXED) return SFIXED; -- full precision negate with SFIXED(X'high+1 downto X'low) result
- function "*"(X,Y:SFIXED) return SFIXED; -- full precision multiply with SFIXED(X'high+Y'high+1 downto X'low+Y'low) result
- function "*"(X:SFIXED;Y:STD_LOGIC) return SFIXED; -- multiply by 0 or 1 with SFIXED(X'high downto X'low) result
- function RESIZE(X:SFIXED;H,L:INTEGER) return SFIXED; -- resizes X and returns SFIXED(H downto L)
- function RESIZE(X:SFIXED;HL:SFIXED) return SFIXED; -- resizes X to match HL and returns SFIXED(HL'high downto HL'low)
- function SHIFT_RIGHT(X:SFIXED;N:INTEGER) return SFIXED; -- returns SFIXED(X'high-N downto X'low-N) result
- function SHIFT_LEFT(X:SFIXED;N:INTEGER) return SFIXED; -- returns SFIXED(X'high+N downto X'low+N) result
- function TO_SFIXED(R:REAL;H,L:INTEGER) return SFIXED; -- returns SFIXED(H downto L) result
- function TO_SFIXED(R:REAL;HL:SFIXED) return SFIXED; -- returns SFIXED(HL'high downto HL'low) result
- function TO_SFIXED(I:SIGNED;H,L:INTEGER;SHIFT:INTEGER:=0) return SFIXED; -- convert SIGNED to SFIXED(H downto L) and resize
- function TO_SFIXED(I:SIGNED;X:SFIXED;SHIFT:INTEGER:=0) return SFIXED; -- convert SIGNED to SFIXED(X'high downto X'low) and resize
- function TO_SIGNED(I:SFIXED;X:SFIXED) return SIGNED; -- resize I to X and convert to SIGNED(I'length-1 downto 0), returns SIGNED(SHIFT_RIGHT(RESIZE(I,X),X'low))
- function TO_REAL(S:SFIXED) return REAL; -- returns REAL result
- function TO_01(X:SFIXED) return SFIXED; -- get rid of Xes
--- all SET calls targetting the same signal must be located in a single process!
- function GET(A:SFIXED_VECTOR;I:INTEGER) return SFIXED; -- A(I)
- function GET(A:SFIXED_MATRIX;I,J:INTEGER) return SFIXED; -- A(I,J)
- function GET(A:SFIXED_MATRIX;I:INTEGER) return SFIXED_VECTOR; -- A(I)
- procedure SET(signal A:inout SFIXED_VECTOR;constant I:INTEGER;signal V:SFIXED); -- A(I)<=V;
- procedure SET(signal A:inout SFIXED_MATRIX;constant I,J:INTEGER;signal V:SFIXED); -- A(I,J)<=V;
- procedure SET(signal A:inout SFIXED_MATRIX;constant I:INTEGER;signal V:SFIXED_VECTOR); -- A(I)<=V;
-
- function RE(A:CFIXED) return SFIXED; -- A.RE
- function IM(A:CFIXED) return SFIXED; -- A.IM
- procedure RE(signal A:inout CFIXED;constant V:SFIXED); -- A.RE<=RESIZE(V,A.RE);
- procedure IM(signal A:inout CFIXED;constant V:SFIXED); -- A.IM<=RESIZE(V,A.IM);
- function "+"(X,Y:CFIXED) return CFIXED; -- full precision add with CFIXED(MAX(X'high,Y'high)+2 downto MIN(X'low,Y'low)) result
- function "-"(X,Y:CFIXED) return CFIXED; -- full precision subtract with CFIXED(MAX(X'high,Y'high)+2 downto MIN(X'low,Y'low)) result
- function "*"(X,Y:CFIXED) return CFIXED; -- full precision multiply with CFIXED(X'high+Y'high+2 downto X'low+Y'low) result
- function "*"(X:CFIXED;Y:SFIXED) return CFIXED; -- full precision multiply with CFIXED(X'high+Y'high downto X'low+Y'low) result
- function "*"(X:SFIXED;Y:CFIXED) return CFIXED;
- function RESIZE(X:CFIXED;H,L:INTEGER) return CFIXED; -- resizes X and returns CFIXED(RE(H downto L),IM(H downto L))
- function RESIZE(X:CFIXED;HL:CFIXED) return CFIXED; -- resizes X to match HL and returns CFIXED(RE(HL.RE'high downto HL.RE'low),IM(RE(HL.IM'high downto HL.IM'low))
- function PLUS_i_TIMES(X:CFIXED) return CFIXED; -- returns CFIXED(X'high+2 downto X'low) result
- function "-"(X:CFIXED) return CFIXED; -- full precision negate with CFIXED(X'high+2 downto X'low) result
- function MINUS_i_TIMES(X:CFIXED) return CFIXED; -- returns CFIXED(X'high+2 downto X'low) result
- function X_PLUS_i_TIMES_Y(X,Y:CFIXED;RND:CFIXED) return CFIXED; -- returns CFIXED(MAX(X'high,Y'high)+2 downto MIN(X'low,Y'low)) result
- function X_MINUS_i_TIMES_Y(X,Y:CFIXED;RND:CFIXED) return CFIXED; -- returns CFIXED(MAX(X'high,Y'high)+2 downto MIN(X'low,Y'low)) result
- function SWAP(X:CFIXED) return CFIXED; -- returns CFIXED(X'high downto X'low) result
- function CONJ(X:CFIXED) return CFIXED; -- returns CFIXED(X'high+2 downto X'low) result
- function SHIFT_RIGHT(X:CFIXED;N:INTEGER) return CFIXED; -- returns CFIXED(X'high-N downto X'low-N) result
- function SHIFT_LEFT(X:CFIXED;N:INTEGER) return CFIXED; -- returns CFIXED(X'high+N downto X'low+N) result
- function TO_CFIXED(R,I:REAL;H,L:INTEGER) return CFIXED; -- returns CFIXED(RE(H downto L),IM(H downto L)) result
- function TO_CFIXED(R,I:REAL;HL:CFIXED) return CFIXED; -- returns CFIXED(RE(HL.RE'high downto HL.RE'low),IM(RE(HL.IM'high downto HL.IM'low)) result
- function TO_CFIXED(C:COMPLEX;HL:CFIXED) return CFIXED; -- returns CFIXED(RE(HL.RE'high downto HL.RE'low),IM(RE(HL.IM'high downto HL.IM'low)) result
- function TO_CFIXED(R,I:SFIXED) return CFIXED; -- returns CFIXED(2*MAX(R'high,I'high)+1 downto 2*MIN(R'low,I'low)) result
- function TO_COMPLEX(C:CFIXED) return COMPLEX; -- returns COMPLEX result
-/*
- function TO_CFIXED_VECTOR(C:COMPLEX_VECTOR;HL:CFIXED) return CFIXED_VECTOR; -- returns CFIXED_VECTOR(RE(HL.RE'high downto HL.RE'low),IM(RE(HL.IM'high downto HL.IM'low)) result
- function TO_COMPLEX_VECTOR(C:CFIXED_VECTOR) return COMPLEX_VECTOR; -- returns COMPLEX_VECTOR result
-*/
- function "*"(R:REAL;C:COMPLEX_VECTOR) return COMPLEX_VECTOR; -- returns R*C
- function ZERO(U:UNSIGNED) return UNSIGNED; -- returns 0 with the same range as U
- function ZERO(S:SFIXED) return SFIXED; -- returns 0 with the same range as S
- function ZERO(C:CFIXED) return CFIXED; -- returns 0 with the same range as C
- function ZERO(SV:SFIXED_VECTOR) return SFIXED_VECTOR; -- returns 0 with the same range as SV
- function ZERO(CV:CFIXED_VECTOR) return CFIXED_VECTOR; -- returns 0 with the same range as CV
-
- function GET(A:CFIXED_VECTOR;I:INTEGER) return CFIXED; -- A(I)
- function GET(A:CFIXED_MATRIX;I,J:INTEGER) return CFIXED; -- A(I,J)
- function GET(A:CFIXED_MATRIX;I:INTEGER) return CFIXED_VECTOR; -- A(I)
- procedure SET(signal A:inout CFIXED_VECTOR;constant I:INTEGER;signal V:CFIXED); -- A(I)<=V;
- procedure SET(signal A:inout CFIXED_MATRIX;constant I,J:INTEGER;signal V:CFIXED); -- A(I,J)<=V;
- procedure SET(signal A:inout CFIXED_MATRIX;constant I:INTEGER;signal V:CFIXED_VECTOR); -- A(I)<=V;
-end TYPES_PKG;
-
-package body TYPES_PKG is
- function LOG2(N:INTEGER) return INTEGER is
- variable TEMP:INTEGER;
- variable RESULT:INTEGER;
- begin
- TEMP:=N;
- RESULT:=0;
- while TEMP>1 loop
- RESULT:=RESULT+1;
- TEMP:=(TEMP+1)/2;
- end loop;
- return RESULT;
- end;
-
- function MIN(A,B:INTEGER) return INTEGER is
- begin
- if AB then
- return A;
- else
- return B;
- end if;
- end;
-
- function MAX(A,B,C:INTEGER) return INTEGER is
- begin
- return MAX(MAX(A,B),C);
- end;
-
- function MAX(A,B,C,D:INTEGER) return INTEGER is
- begin
- return MAX(MAX(A,B),MAX(C,D));
- end;
-
- function MED(A,B,C:INTEGER) return INTEGER is
- begin
- return MAX(MIN(MAX(A,B),C),MIN(A,B));
- end;
-
- function "+"(X,Y:SFIXED) return SFIXED is
- variable SX,SY,SR:SIGNED(MAX(X'high,Y'high)+1-MIN(X'low,Y'low) downto 0);
- variable R:SFIXED(MAX(X'high,Y'high)+1 downto MIN(X'low,Y'low));
- begin
- for K in SX'range loop
- if KX'high-R'low then
- SX(K):=X(X'high); -- sign extend X MSBs
- else
- SX(K):=X(R'low+K);
- end if;
- end loop;
- for K in SY'range loop
- if KY'high-R'low then
- SY(K):=Y(Y'high); -- sign extend Y MSBs
- else
- SY(K):=Y(R'low+K);
- end if;
- end loop;
- SR:=SX+SY; -- SIGNED addition
- for K in SR'range loop
- R(R'low+K):=SR(K);
- end loop;
- return R;
- end;
-
- function "-"(X,Y:SFIXED) return SFIXED is
- variable SX,SY,SR:SIGNED(MAX(X'high,Y'high)+1-MIN(X'low,Y'low) downto 0);
- variable R:SFIXED(MAX(X'high,Y'high)+1 downto MIN(X'low,Y'low));
- begin
- for K in SX'range loop
- if KX'high-R'low then
- SX(K):=X(X'high); -- sign extend X MSBs
- else
- SX(K):=X(R'low+K);
- end if;
- end loop;
- for K in SY'range loop
- if KY'high-R'low then
- SY(K):=Y(Y'high); -- sign extend Y MSBs
- else
- SY(K):=Y(R'low+K);
- end if;
- end loop;
- SR:=SX-SY; -- SIGNED subtraction
- for K in SR'range loop
- R(R'low+K):=SR(K);
- end loop;
- return R;
- end;
-
- function "-"(X:SFIXED) return SFIXED is
- variable SX:SIGNED(X'high-X'low downto 0);
- variable SR:SIGNED(X'high-X'low+1 downto 0);
- variable R:SFIXED(X'high+1 downto X'low);
- begin
- for K in SX'range loop
- SX(K):=X(X'low+K);
- end loop;
- SR:=-RESIZE(SX,SR'length); -- SIGNED negation
- for K in SR'range loop
- R(R'low+K):=SR(K);
- end loop;
- return R;
- end;
-
- function "*"(X,Y:SFIXED) return SFIXED is
- variable SX:SIGNED(X'high-X'low downto 0);
- variable SY:SIGNED(Y'high-Y'low downto 0);
- variable SR:SIGNED(SX'high+SY'high+1 downto 0);
- variable R:SFIXED(X'high+Y'high+1 downto X'low+Y'low);
- begin
- for K in SX'range loop
- SX(K):=X(X'low+K);
- end loop;
- for K in SY'range loop
- SY(K):=Y(Y'low+K);
- end loop;
- SR:=SX*SY; -- SIGNED multiplication
- for K in SR'range loop
- R(R'low+K):=SR(K);
- end loop;
- return R;
- end;
-
- function "*"(X:SFIXED;Y:STD_LOGIC) return SFIXED is
- begin
- if Y='1' then
- return X;
- else
- return TO_SFIXED(0.0,X);
- end if;
- end;
-
- function RESIZE(X:SFIXED;H,L:INTEGER) return SFIXED is
- variable R:SFIXED(H downto L);
- begin
- for K in R'range loop
- if KX'high then
- R(K):=X(X'high); -- sign extend X MSBs
- else
- R(K):=X(K);
- end if;
- end loop;
- return R;
- end;
-
- function RESIZE(X:SFIXED;HL:SFIXED) return SFIXED is
- begin
- return RESIZE(X,HL'high,HL'low);
- end;
-
- function SHIFT_RIGHT(X:SFIXED;N:INTEGER) return SFIXED is
- variable R:SFIXED(X'high-N downto X'low-N);
- begin
- for K in R'range loop
- R(K):=X(K+N);
- end loop;
- return R;
- end;
-
- function SHIFT_LEFT(X:SFIXED;N:INTEGER) return SFIXED is
- variable R:SFIXED(X'high+N downto X'low+N);
- begin
- for K in R'range loop
- R(K):=X(K-N);
- end loop;
- return R;
- end;
-
- function TO_SFIXED(R:REAL;H,L:INTEGER) return SFIXED is
- variable RR:REAL;
- variable V:SFIXED(H downto L);
- begin
- assert (R<2.0**H) and (R>=-2.0**H) report "TO_SFIXED vector truncation!" severity warning;
- if R<0.0 then
- V(V'high):='1';
- RR:=R+2.0**V'high;
- else
- V(V'high):='0';
- RR:=R;
- end if;
- for K in V'high-1 downto V'low loop
- if RR>=2.0**K then
- V(K):='1';
- RR:=RR-2.0**K;
- else
- V(K):='0';
- end if;
- end loop;
- return V;
- end;
-
- function TO_SFIXED(R:REAL;HL:SFIXED) return SFIXED is
- begin
- return TO_SFIXED(R,HL'high,HL'low);
- end;
-
- function TO_SFIXED(I:SIGNED;H,L:INTEGER;SHIFT:INTEGER:=0) return SFIXED is
- variable O:SFIXED(H downto L);
- begin
- for K in O'range loop
- if KV'high then
- A(I,K)<=V(V'high); -- sign extend V MSBs
- else
- A(I,K)<=V(K);
- end if;
- end loop;
- end;
-
- procedure SET(signal A:inout SFIXED_MATRIX;constant I,J:INTEGER;signal V:SFIXED) is
- begin
- for K in A'range(3) loop
- if KV'high then
- A(I,J,K)<=V(V'high); -- sign extend V MSBs
- else
- A(I,J,K)<=V(K);
- end if;
- end loop;
- end;
-
- procedure SET(signal A:inout SFIXED_MATRIX;constant I:INTEGER;signal V:SFIXED_VECTOR) is
- begin
- for J in V'range(1) loop
- for K in A'range(3) loop
- if KV'high(2) then
- A(I,J,K)<=V(J,V'high(2)); -- sign extend V(J) MSBs
- else
- A(I,J,K)<=V(J,K);
- end if;
- end loop;
- end loop;
- end;
-
- function RE(A:CFIXED) return SFIXED is
- variable R:SFIXED(A'high/2 downto A'low/2);
- begin
- for K in R'range loop
- R(K):=A(2*K);
- end loop;
- return R;
- end;
-
- function IM(A:CFIXED) return SFIXED is
- variable R:SFIXED(A'high/2 downto A'low/2);
- begin
- for K in R'range loop
- R(K):=A(2*K+1);
- end loop;
- return R;
- end;
-
- procedure RE(signal A:inout CFIXED;constant V:SFIXED) is
- begin
- for K in A'low/2 to A'high/2 loop
- if KV'high then
- A(2*K)<=V(V'high); -- sign extend V MSBs
- else
- A(2*K)<=V(K);
- end if;
- end loop;
- end;
-
- procedure IM(signal A:inout CFIXED;constant V:SFIXED) is
- begin
- for K in A'low/2 to A'high/2 loop
- if KV'high then
- A(2*K+1)<=V(V'high); -- sign extend V MSBs
- else
- A(2*K+1)<=V(K);
- end if;
- end loop;
- end;
-
- function "+"(X,Y:CFIXED) return CFIXED is
- begin
- return TO_CFIXED(RE(X)+RE(Y),IM(X)+IM(Y));
- end;
-
- function "-"(X,Y:CFIXED) return CFIXED is
- begin
- return TO_CFIXED(RE(X)-RE(Y),IM(X)-IM(Y));
- end;
-
- function "*"(X,Y:CFIXED) return CFIXED is
- begin
- return TO_CFIXED(RE(X)*RE(Y)-IM(X)*IM(Y),RE(X)*IM(Y)+IM(X)*RE(Y));
- end;
-
- function "*"(X:CFIXED;Y:SFIXED) return CFIXED is
- begin
- return TO_CFIXED(RE(X)*Y,IM(X)*Y);
- end;
-
- function "*"(X:SFIXED;Y:CFIXED) return CFIXED is
- begin
- return TO_CFIXED(X*RE(Y),X*IM(Y));
- end;
-
- function RESIZE(X:CFIXED;H,L:INTEGER) return CFIXED is
- begin
- return TO_CFIXED(RESIZE(RE(X),H,L),RESIZE(IM(X),H,L));
- end;
-
- function RESIZE(X:CFIXED;HL:CFIXED) return CFIXED is
- begin
- return TO_CFIXED(RESIZE(RE(X),RE(HL)),RESIZE(IM(X),IM(HL)));
- end;
-
- function PLUS_i_TIMES(X:CFIXED) return CFIXED is
- begin
- return TO_CFIXED(-IM(X),RE(X));
- end;
-
- function "-"(X:CFIXED) return CFIXED is
- begin
- return TO_CFIXED(-RE(X),-IM(X));
- end;
-
- function MINUS_i_TIMES(X:CFIXED) return CFIXED is
- begin
- return TO_CFIXED(IM(X),-RE(X));
- end;
-
- function X_PLUS_i_TIMES_Y(X,Y:CFIXED;RND:CFIXED) return CFIXED is
- begin
- return TO_CFIXED(RE(X)-IM(Y)+RE(RND),IM(X)+RE(Y)+IM(RND));
- end;
-
- function X_MINUS_i_TIMES_Y(X,Y:CFIXED;RND:CFIXED) return CFIXED is
- begin
- return TO_CFIXED(RE(X)+IM(Y)+RE(RND),IM(X)-RE(Y)+IM(RND));
- end;
-
- function SWAP(X:CFIXED) return CFIXED is
- begin
- return TO_CFIXED(IM(X),RE(X));
- end;
-
- function CONJ(X:CFIXED) return CFIXED is
- begin
- return TO_CFIXED(RE(X),-IM(X));
- end;
-
- function SHIFT_RIGHT(X:CFIXED;N:INTEGER) return CFIXED is
- begin
- return TO_CFIXED(SHIFT_RIGHT(RE(X),N),SHIFT_RIGHT(IM(X),N));
- end;
-
- function SHIFT_LEFT(X:CFIXED;N:INTEGER) return CFIXED is
- begin
- return TO_CFIXED(SHIFT_LEFT(RE(X),N),SHIFT_LEFT(IM(X),N));
- end;
-
- function TO_CFIXED(R,I:REAL;H,L:INTEGER) return CFIXED is
- begin
- return TO_CFIXED(TO_SFIXED(R,H,L),TO_SFIXED(I,H,L));
- end;
-
- function TO_CFIXED(R,I:REAL;HL:CFIXED) return CFIXED is
- begin
- return TO_CFIXED(TO_SFIXED(R,HL'high/2,HL'low/2),TO_SFIXED(I,HL'high/2,HL'low/2));
- end;
-
- function TO_CFIXED(C:COMPLEX;HL:CFIXED) return CFIXED is
- begin
- return TO_CFIXED(C.RE,C.IM,HL);
- end;
-
- function TO_CFIXED(R,I:SFIXED) return CFIXED is
- constant H:INTEGER:=MAX(R'high,I'high);
- constant L:INTEGER:=MIN(R'low,I'low);
- variable C:CFIXED(2*H+1 downto 2*L);
- begin
- for K in C'low/2 to C'high/2 loop
- if KR'high then
- C(2*K):=R(R'high); -- sign extend R MSBs
- else
- C(2*K):=R(K);
- end if;
- end loop;
- for K in C'low/2 to C'high/2 loop
- if KI'high then
- C(2*K+1):=I(I'high); -- sign extend I MSBs
- else
- C(2*K+1):=I(K);
- end if;
- end loop;
- return C;
- end;
-
- function TO_COMPLEX(C:CFIXED) return COMPLEX is
- variable R:COMPLEX;
- begin
- R.RE:=TO_REAL(RE(C));
- R.IM:=TO_REAL(IM(C));
- return R;
- end;
-/*
- function TO_CFIXED_VECTOR(C:COMPLEX_VECTOR;HL:CFIXED) return CFIXED_VECTOR is
- variable R:CFIXED_VECTOR(C'range,HL'range);
- begin
- for K in C'range loop
- R(K):=TO_CFIXED(C(K),HL);
- end loop;
- return R;
- end;
-
- function TO_COMPLEX_VECTOR(C:CFIXED_VECTOR) return COMPLEX_VECTOR is
- variable R:COMPLEX_VECTOR(C'range);
- begin
- for K in C'range loop
- R(K):=TO_COMPLEX(C(K));
- end loop;
- return R;
- end;
-*/
- function "*"(R:REAL;C:COMPLEX_VECTOR) return COMPLEX_VECTOR is
- variable X:COMPLEX_VECTOR(C'range);
- begin
- for K in C'range loop
- X(K):=R*C(K);
- end loop;
- return X;
- end;
-
- function ZERO(U:UNSIGNED) return UNSIGNED is -- returns 0 with the same range as S
- begin
- return TO_UNSIGNED(0,U'length);
- end;
-
- function ZERO(S:SFIXED) return SFIXED is -- returns 0 with the same range as S
- begin
- return TO_SFIXED(0.0,S);
- end;
-
- function ZERO(C:CFIXED) return CFIXED is -- returns 0 with the same range as C
- begin
- return TO_CFIXED(0.0,0.0,C);
- end;
-
- function ZERO(SV:SFIXED_VECTOR) return SFIXED_VECTOR is -- returns 0 with the same range as SV
- variable RESULT:SFIXED_VECTOR(SV'range(1),SV'range(2));
- begin
- RESULT:=(others=>(others=>'0'));
- return RESULT;
- end;
-
- function ZERO(CV:CFIXED_VECTOR) return CFIXED_VECTOR is -- returns 0 with the same range as CV
- variable RESULT:CFIXED_VECTOR(CV'range(1),CV'range(2));
- begin
- RESULT:=(others=>(others=>'0'));
- return RESULT;
- end;
-
- function GET(A:CFIXED_VECTOR;I:INTEGER) return CFIXED is
- variable R:CFIXED(A'range(2));
- begin
- for K in R'range loop
- R(K):=A(I,K);
- end loop;
- return R;
- end;
-
- function GET(A:CFIXED_MATRIX;I,J:INTEGER) return CFIXED is
- variable R:CFIXED(A'range(3));
- begin
- for K in R'range loop
- R(K):=A(I,J,K);
- end loop;
- return R;
- end;
-
- function GET(A:CFIXED_MATRIX;I:INTEGER) return CFIXED_VECTOR is
- variable R:CFIXED_VECTOR(A'range(1),A'range(3));
- begin
- for J in R'range(1) loop
- for K in R'range(2) loop
- R(J,K):=A(I,J,K);
- end loop;
- end loop;
- return R;
- end;
-
- procedure SET(signal A:inout CFIXED_VECTOR;constant I:INTEGER;signal V:CFIXED) is
- begin
- for K in A'range(2) loop
- if KV'high then
- A(I,K)<=V(V'high+K mod 2-1); -- sign extend V.RE and V.IM MSBs
- else
- A(I,K)<=V(K);
- end if;
- end loop;
- end;
-
- procedure SET(signal A:inout CFIXED_MATRIX;constant I,J:INTEGER;signal V:CFIXED) is
- begin
- for K in A'range(3) loop
- if KV'high then
- A(I,J,K)<=V(V'high+K mod 2-1); -- sign extend V.RE and V.IM MSBs
- else
- A(I,J,K)<=V(K);
- end if;
- end loop;
- end;
-
- procedure SET(signal A:inout CFIXED_MATRIX;constant I:INTEGER;signal V:CFIXED_VECTOR) is
- begin
- for J in V'range(1) loop
- for K in A'range(3) loop
- if KV'high(2) then
- A(I,J,K)<=V(J,V'high(2)+K mod 2-1); -- sign extend V.RE and V.IM MSBs
- else
- A(I,J,K)<=V(J,K);
- end if;
- end loop;
- end loop;
- end;
-end TYPES_PKG;
\ No newline at end of file
diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/WRAPPER_SSR_FIR.vhd b/Examples/HDL/Digital_Filtering/SSR_FIR/WRAPPER_SSR_FIR.vhd
index 52d262162..23d2a2648 100755
--- a/Examples/HDL/Digital_Filtering/SSR_FIR/WRAPPER_SSR_FIR.vhd
+++ b/Examples/HDL/Digital_Filtering/SSR_FIR/WRAPPER_SSR_FIR.vhd
@@ -1,4 +1,11 @@
--- Copyright (C) 2024, Advanced Micro Devices, Inc.
+-- Copyright (C) 2026, Advanced Micro Devices, Inc.
+--
+-- Vitis Model Composer HDL Black Box wrapper for the Direct-Form SSR FIR
+-- (SSR_FIR.vhd). This wrapper adapts the System Generator / Model Composer
+-- STD_LOGIC_VECTOR black-box interface to the SFIXED_VECTOR interface of the
+-- VHDL-2008 SSR_FIR core, builds the REAL_MATRIX coefficient set from the
+-- string generic passed in by the config script, and ties the single
+-- coefficient-set address CSA to 0.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
@@ -8,18 +15,18 @@ library STD;
use STD.textio.all;
use STD.env.all;
-use work.TYPES_PKG.all;
+use work.FIXED_PKG.all; -- VHDL-2008 IEEE standard SFIXED type and functions
+use work.CFIXED_PKG.all; -- SFIXED_VECTOR, REAL_VECTOR, REAL_MATRIX and helpers
library UNISIM;
use UNISIM.VComponents.all;
entity WRAPPER_SSR_FIR is
- generic(OX,OY:INTEGER:=-1;---2147483648; -- Coordinates of the lower left corner DSPx8, use -2147483648 if you do not want floorplanning
+ generic(OX,OY:INTEGER:=-1; -- Coordinates of the lower left corner DSPx8, use -1 if you do not want floorplanning
FAMILY:INTEGER:=3; -- use 1 for 7-series, 2 for US/US+ and 3 for Versal
- DDR:BOOLEAN:=FALSE; -- use DDR=TRUE implementation only for Versal clock rates over 795MHz/824MHz/872MHz in speed grades -1/-2/-3
+ DDR:BOOLEAN:=FALSE; -- use DDR=TRUE implementation only for Versal clock rates over 795MHz/824MHz/872MHz in speed grades -1/-2/-3
SSR:INTEGER:=4;
TAPS:INTEGER:=36;
--- COEFFICIENT:REAL_VECTOR(0 to TAPS-1):=(1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0);
C:STRING:="1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0";
I_HIGH:INTEGER:=7;
I_LOW:INTEGER:=-8;
@@ -27,7 +34,7 @@ entity WRAPPER_SSR_FIR is
C_LOW:INTEGER:=-17;
O_HIGH:INTEGER:=7;
O_LOW:INTEGER:=-16;
- ROUNDING:BOOLEAN:=FALSE; -- use TRUE for rounding the output result
+ ROUNDING:BOOLEAN:=FALSE; -- use TRUE for rounding the output result
SYMMETRY:STRING:="ES"); -- Filter Symmetry, use "ES" for Even-Symmetric, "OS" for Odd-Symmetric and "NS" for Non-Symmetric
port(CLK:in STD_LOGIC;
CE:in STD_LOGIC:='1'; -- not used, for SysGen only
@@ -38,9 +45,9 @@ entity WRAPPER_SSR_FIR is
end WRAPPER_SSR_FIR;
architecture WRAPPER of WRAPPER_SSR_FIR is
- signal II:SFIXED_VECTOR(0 to SSR-1,I_HIGH downto I_LOW);
+ signal II:SFIXED_VECTOR(0 to SSR-1)(I_HIGH downto I_LOW);
signal VII:BOOLEAN;
- signal OO:SFIXED_VECTOR(0 to SSR-1,O_HIGH downto O_LOW);
+ signal OO:SFIXED_VECTOR(0 to SSR-1)(O_HIGH downto O_LOW);
signal VOO:BOOLEAN;
function REAL_value(S:STRING) return REAL is
variable R,F:REAL;
@@ -116,32 +123,32 @@ architecture WRAPPER of WRAPPER_SSR_FIR is
return R*10.0**E;
end if;
end;
- function STRING2REAL(S:STRING;N:INTEGER) return REAL_VECTOR is
- variable R:REAL_VECTOR(1 to N);
- variable P,C:INTEGER;
+ -- Parse a whitespace/comma separated coefficient string into the first N
+ -- coefficients, returned as a single-row REAL_MATRIX (one coefficient set).
+ function STRING2MATRIX(S:STRING;N:INTEGER) return REAL_MATRIX is
+ variable R:REAL_MATRIX(0 to 0)(0 to N-1);
+ variable P,CNT:INTEGER;
begin
P:=S'low;
if (S(P)='(') or (S(P)='[') then P:=P+1; end if;
- for K in R'range loop
+ for K in R(0)'range loop
while (P0
--- REAL'value() not supported in Vivado Synthesis
--- then R(K):=REAL'value(S(P to P+C-1));
- then R(K):=REAL_value(S(P to P+C-1));
- else R(K):=0.0;
+ if CNT>0
+-- REAL'value() not supported in Vivado Synthesis, use REAL_value instead
+ then R(0)(K):=REAL_value(S(P to P+CNT-1));
+ else R(0)(K):=0.0;
end if;
- P:=P+C;
+ P:=P+CNT;
end loop;
return R;
end;
--- constant COEFFICIENT:REAL_VECTOR(0 to TAPS-1):=(1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0);
- constant COEFFICIENT:REAL_VECTOR(0 to TAPS-1):=STRING2REAL(C,TAPS);
+ constant COEFFICIENT:REAL_MATRIX(0 to 0)(0 to TAPS-1):=STRING2MATRIX(C,TAPS);
signal CLK1,CLKH:STD_LOGIC;
begin
i1:if DDR generate
@@ -156,9 +163,9 @@ begin
CLK1<=CLK;
CLKH<='0';
end generate;
- ij:for J in II'range(1) generate
- ik:for K in II'range(2) generate
- II(J,K)<=I(J*II'length(2)+K-II'low(2));
+ ij:for J in 0 to SSR-1 generate
+ ik:for K in I_HIGH downto I_LOW generate
+ II(J)(K)<=I(J*(I_HIGH-I_LOW+1)+K-I_LOW);
end generate;
end generate;
VII<=VI='1';
@@ -170,17 +177,19 @@ begin
C_HIGH=>C_HIGH,
C_LOW=>C_LOW,
ROUNDING=>ROUNDING,
+ ANTI=>FALSE,
SYMMETRY=>SYMMETRY)
port map (CLK=>CLK1,
CLKH=>CLKH,
I=>II,
VI=>VII,
+ CSA=>"0",
O=>OO,
VO=>VOO);
- oj:for J in OO'range(1) generate
- ok:for K in OO'range(2) generate
- O(J*OO'length(2)+K-OO'low(2))<=OO(J,K);
+ oj:for J in 0 to SSR-1 generate
+ ok:for K in O_HIGH downto O_LOW generate
+ O(J*(O_HIGH-O_LOW+1)+K-O_LOW)<=OO(J)(K);
end generate;
end generate;
VO<='1' when VOO else '0';
-end WRAPPER;
\ No newline at end of file
+end WRAPPER;
diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/WRAPPER_SSR_FIR_config.m b/Examples/HDL/Digital_Filtering/SSR_FIR/WRAPPER_SSR_FIR_config.m
index 0e09885ca..a92eddd71 100755
--- a/Examples/HDL/Digital_Filtering/SSR_FIR/WRAPPER_SSR_FIR_config.m
+++ b/Examples/HDL/Digital_Filtering/SSR_FIR/WRAPPER_SSR_FIR_config.m
@@ -157,7 +157,8 @@ function WRAPPER_SSR_FIR_config(this_block)
% | this_block.addFile('a.vhd');
% |-------------
- this_block.addFile('TYPES_PKG.vhd');
+ this_block.addFile('fixed_pkg.vhd');
+ this_block.addFile('cfixed_pkg.vhd');
this_block.addFile('BDELAY.vhd');
this_block.addFile('SDELAY.vhd');
this_block.addFile('DSPx8_WRAPPER.vhd');
diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/WRAPPER_TRANSPOSE_SSR_FIR.vhd b/Examples/HDL/Digital_Filtering/SSR_FIR/WRAPPER_TRANSPOSE_SSR_FIR.vhd
new file mode 100644
index 000000000..8e2417cd5
--- /dev/null
+++ b/Examples/HDL/Digital_Filtering/SSR_FIR/WRAPPER_TRANSPOSE_SSR_FIR.vhd
@@ -0,0 +1,202 @@
+-- Copyright (C) 2026, Advanced Micro Devices, Inc.
+--
+-- Vitis Model Composer HDL Black Box wrapper for the Transpose-Form SSR FIR
+-- (TRANSPOSE_SSR_FIR.vhd). This wrapper adapts the System Generator / Model
+-- Composer STD_LOGIC_VECTOR black-box interface to the SFIXED_VECTOR interface
+-- of the VHDL-2008 TRANSPOSE_SSR_FIR core, builds the REAL_MATRIX coefficient
+-- set from the string generic passed in by the config script, and ties the
+-- single coefficient-set address CSA to 0.
+--
+-- The transpose form has the same external behaviour and latency as the direct
+-- form for a given filter, but its DSP PREG/PCOUT accumulation chain depth is
+-- TAPS/SSR per lane (vs TAPS in the direct form), so it closes timing at high
+-- SSR and large TAPS where the direct form's cascade does not.
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+
+library STD;
+use STD.textio.all;
+use STD.env.all;
+
+use work.FIXED_PKG.all; -- VHDL-2008 IEEE standard SFIXED type and functions
+use work.CFIXED_PKG.all; -- SFIXED_VECTOR, REAL_VECTOR, REAL_MATRIX and helpers
+
+library UNISIM;
+use UNISIM.VComponents.all;
+
+entity WRAPPER_TRANSPOSE_SSR_FIR is
+ generic(OX,OY:INTEGER:=-1; -- Coordinates of the lower left corner DSPx8, use -1 if you do not want floorplanning
+ FAMILY:INTEGER:=3; -- use 1 for 7-series, 2 for US/US+ and 3 for Versal
+ DDR:BOOLEAN:=FALSE; -- use DDR=TRUE implementation only for Versal clock rates over 795MHz/824MHz/872MHz in speed grades -1/-2/-3
+ SSR:INTEGER:=4;
+ TAPS:INTEGER:=36;
+ C:STRING:="1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0";
+ I_HIGH:INTEGER:=7;
+ I_LOW:INTEGER:=-8;
+ C_HIGH:INTEGER:=0;
+ C_LOW:INTEGER:=-17;
+ O_HIGH:INTEGER:=7;
+ O_LOW:INTEGER:=-16;
+ ROUNDING:BOOLEAN:=FALSE; -- use TRUE for rounding the output result
+ SYMMETRY:STRING:="ES"); -- Filter Symmetry, use "ES" for Even-Symmetric, "OS" for Odd-Symmetric and "NS" for Non-Symmetric
+ port(CLK:in STD_LOGIC;
+ CE:in STD_LOGIC:='1'; -- not used, for SysGen only
+ I:in STD_LOGIC_VECTOR(SSR*(I_HIGH-I_LOW+1)-1 downto 0);
+ VI:in STD_LOGIC;
+ O:out STD_LOGIC_VECTOR(SSR*(O_HIGH-O_LOW+1)-1 downto 0);
+ VO:out STD_LOGIC);
+end WRAPPER_TRANSPOSE_SSR_FIR;
+
+architecture WRAPPER of WRAPPER_TRANSPOSE_SSR_FIR is
+ signal II:SFIXED_VECTOR(0 to SSR-1)(I_HIGH downto I_LOW);
+ signal VII:BOOLEAN;
+ signal OO:SFIXED_VECTOR(0 to SSR-1)(O_HIGH downto O_LOW);
+ signal VOO:BOOLEAN;
+ function REAL_value(S:STRING) return REAL is
+ variable R,F:REAL;
+ variable E:INTEGER;
+ variable DECIMAL,NEGATIVE,EXP,NEGEXP:BOOLEAN;
+ begin
+ R:=0.0;F:=1.0;E:=0;
+ DECIMAL:=FALSE;
+ NEGATIVE:=FALSE;
+ EXP:=FALSE;
+ NEGEXP:=FALSE;
+ for K in 0 to S'length-1 loop
+ if (S(K+S'low)='E') or (S(K+S'low)='e') then
+ EXP:=TRUE;
+ elsif K=0 and S(K+S'low)='-' then
+ NEGATIVE:=TRUE;
+ elsif EXP then
+ if S(K+S'low)='-' then
+ NEGEXP:=TRUE;
+ else
+ case S(K+S'low) is
+ when '0'=>E:=E*10;
+ when '1'=>E:=E*10+1;
+ when '2'=>E:=E*10+2;
+ when '3'=>E:=E*10+3;
+ when '4'=>E:=E*10+4;
+ when '5'=>E:=E*10+5;
+ when '6'=>E:=E*10+6;
+ when '7'=>E:=E*10+7;
+ when '8'=>E:=E*10+8;
+ when '9'=>E:=E*10+9;
+ when others=>assert FALSE report "REAL number format error!" severity warning;
+ end case;
+ end if;
+ elsif DECIMAL then
+ F:=F/10.0;
+ case S(K+S'low) is
+ when '0'=>null;
+ when '1'=>R:=R+1.0*F;
+ when '2'=>R:=R+2.0*F;
+ when '3'=>R:=R+3.0*F;
+ when '4'=>R:=R+4.0*F;
+ when '5'=>R:=R+5.0*F;
+ when '6'=>R:=R+6.0*F;
+ when '7'=>R:=R+7.0*F;
+ when '8'=>R:=R+8.0*F;
+ when '9'=>R:=R+9.0*F;
+ when others=>assert FALSE report "REAL number format error!" severity warning;
+ end case;
+ else
+ case S(K+S'low) is
+ when '0'=>R:=R*10.0;
+ when '1'=>R:=R*10.0+1.0;
+ when '2'=>R:=R*10.0+2.0;
+ when '3'=>R:=R*10.0+3.0;
+ when '4'=>R:=R*10.0+4.0;
+ when '5'=>R:=R*10.0+5.0;
+ when '6'=>R:=R*10.0+6.0;
+ when '7'=>R:=R*10.0+7.0;
+ when '8'=>R:=R*10.0+8.0;
+ when '9'=>R:=R*10.0+9.0;
+ when '.'=>DECIMAL:=TRUE;
+ when others=>assert FALSE report "REAL number format error!" severity warning;
+ end case;
+ end if;
+ end loop;
+ if NEGEXP then
+ E:=-E;
+ end if;
+ if NEGATIVE then
+ return -R*10.00**E;
+ else
+ return R*10.0**E;
+ end if;
+ end;
+ -- Parse a whitespace/comma separated coefficient string into the first N
+ -- coefficients, returned as a single-row REAL_MATRIX (one coefficient set).
+ function STRING2MATRIX(S:STRING;N:INTEGER) return REAL_MATRIX is
+ variable R:REAL_MATRIX(0 to 0)(0 to N-1);
+ variable P,CNT:INTEGER;
+ begin
+ P:=S'low;
+ if (S(P)='(') or (S(P)='[') then P:=P+1; end if;
+ for K in R(0)'range loop
+ while (P0
+-- REAL'value() not supported in Vivado Synthesis, use REAL_value instead
+ then R(0)(K):=REAL_value(S(P to P+CNT-1));
+ else R(0)(K):=0.0;
+ end if;
+ P:=P+CNT;
+ end loop;
+ return R;
+ end;
+ constant COEFFICIENT:REAL_MATRIX(0 to 0)(0 to TAPS-1):=STRING2MATRIX(C,TAPS);
+ signal CLK1,CLKH:STD_LOGIC;
+begin
+ i1:if DDR generate
+ b2:MBUFGCE_DIV port map(I=>CLK,
+ CE=>'1',
+ CLR=>'0',
+ CLRB_LEAF=>'1',
+ O1=>CLK1,
+ O2=>CLKH);
+ end;
+ else generate
+ CLK1<=CLK;
+ CLKH<='0';
+ end generate;
+ ij:for J in 0 to SSR-1 generate
+ ik:for K in I_HIGH downto I_LOW generate
+ II(J)(K)<=I(J*(I_HIGH-I_LOW+1)+K-I_LOW);
+ end generate;
+ end generate;
+ VII<=VI='1';
+ u1:entity work.TRANSPOSE_SSR_FIR generic map(OX=>OX,
+ OY=>OY,
+ FAMILY=>FAMILY,
+ DDR=>DDR,
+ COEFFICIENT=>COEFFICIENT,
+ C_HIGH=>C_HIGH,
+ C_LOW=>C_LOW,
+ EXTRA_C_PIPELINING=>TRUE,
+ EXTRA_D_PIPELINING=>TRUE,
+ ROUNDING=>ROUNDING,
+ ANTI=>FALSE,
+ SYMMETRY=>SYMMETRY)
+ port map (CLK=>CLK1,
+ CLKH=>CLKH,
+ I=>II,
+ VI=>VII,
+ CSA=>"0",
+ O=>OO,
+ VO=>VOO);
+ oj:for J in 0 to SSR-1 generate
+ ok:for K in O_HIGH downto O_LOW generate
+ O(J*(O_HIGH-O_LOW+1)+K-O_LOW)<=OO(J)(K);
+ end generate;
+ end generate;
+ VO<='1' when VOO else '0';
+end WRAPPER;
diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/WRAPPER_TRANSPOSE_SSR_FIR_config.m b/Examples/HDL/Digital_Filtering/SSR_FIR/WRAPPER_TRANSPOSE_SSR_FIR_config.m
new file mode 100644
index 000000000..acb65b643
--- /dev/null
+++ b/Examples/HDL/Digital_Filtering/SSR_FIR/WRAPPER_TRANSPOSE_SSR_FIR_config.m
@@ -0,0 +1,196 @@
+
+function WRAPPER_TRANSPOSE_SSR_FIR_config(this_block)
+
+ % Vitis Model Composer HDL Black Box configuration script for the
+ % Transpose-Form SSR FIR (WRAPPER_TRANSPOSE_SSR_FIR.vhd).
+ %
+ % This is the transpose-form counterpart of WRAPPER_SSR_FIR_config.m; it
+ % shares the same mask parameter set and the same fixed_pkg/cfixed_pkg base
+ % files, and only differs in the entity name and the design source files
+ % added at the bottom.
+
+ this_block.setTopLevelLanguage('Verilog');
+
+ this_block.setEntityName('WRAPPER_TRANSPOSE_SSR_FIR');
+
+ parent = get_param(this_block.blockName,'Parent');
+maskParamNameValuePairs = get_param(parent, 'MaskWSVariables');
+
+% now step through each MASK to get the name and the evaluated value
+for i=1:length(maskParamNameValuePairs)
+ if (strcmpi(maskParamNameValuePairs(i).Name, 'OX'))
+ OX = maskParamNameValuePairs(i).Value;
+ end
+ if (strcmpi(maskParamNameValuePairs(i).Name, 'OY'))
+ OY = maskParamNameValuePairs(i).Value;
+ end
+% if (strcmpi(maskParamNameValuePairs(i).Name, 'FAMILY'))
+% FAMILY = maskParamNameValuePairs(i).Value;
+% end
+ if (strcmpi(maskParamNameValuePairs(i).Name, 'DDR'))
+ DDR = maskParamNameValuePairs(i).Value;
+ end
+ if (strcmpi(maskParamNameValuePairs(i).Name, 'SSR'))
+ SSR = maskParamNameValuePairs(i).Value;
+ end
+ if (strcmpi(maskParamNameValuePairs(i).Name, 'TAPS'))
+ TAPS = maskParamNameValuePairs(i).Value;
+ end
+ if (strcmpi(maskParamNameValuePairs(i).Name, 'COEFFICIENT'))
+ COEFFICIENT = maskParamNameValuePairs(i).Value;
+ end
+ if (strcmpi(maskParamNameValuePairs(i).Name, 'I_HIGH'))
+ I_HIGH = maskParamNameValuePairs(i).Value;
+ end
+ if (strcmpi(maskParamNameValuePairs(i).Name, 'I_LOW'))
+ I_LOW = maskParamNameValuePairs(i).Value;
+ end
+ if (strcmpi(maskParamNameValuePairs(i).Name, 'C_HIGH'))
+ C_HIGH = maskParamNameValuePairs(i).Value;
+ end
+ if (strcmpi(maskParamNameValuePairs(i).Name, 'C_LOW'))
+ C_LOW = maskParamNameValuePairs(i).Value;
+ end
+ if (strcmpi(maskParamNameValuePairs(i).Name, 'O_HIGH'))
+ O_HIGH = maskParamNameValuePairs(i).Value;
+ end
+ if (strcmpi(maskParamNameValuePairs(i).Name, 'O_LOW'))
+ O_LOW = maskParamNameValuePairs(i).Value;
+ end
+ if (strcmpi(maskParamNameValuePairs(i).Name, 'ROUNDING'))
+ ROUNDING = maskParamNameValuePairs(i).Value;
+ end
+ if (strcmpi(maskParamNameValuePairs(i).Name, 'SYMMETRY'))
+ SYMMETRY = maskParamNameValuePairs(i).Value;
+ end
+end
+
+family = this_block.getDeviceFamilyName;
+if(contains(family,"7") || strcmp(family,"zynq") || strcmp(family,"qzynq") || strcmp(family,"azynq"))
+ FAMILY = 1; % use 1 for selecting DSP48E1
+elseif(contains(family,"versal"))
+ FAMILY = 3; % use 1 for selecting DSP58
+else
+ FAMILY = 2; % use 2 for selecting DSP48E2
+end
+
+% System Generator has to assume that your entity has a combinational feed through;
+ % if not, then comment out the following line:
+ %this_block.tagAsCombinational;
+
+ this_block.addSimulinkInport('I');
+ this_block.addSimulinkInport('VI');
+
+ this_block.addSimulinkOutport('O');
+ this_block.addSimulinkOutport('VO');
+
+ VO_port = this_block.port('VO');
+ VO_port.setType('UFix_1_0');
+ VO_port.useHDLVector(false);
+
+ % -----------------------------
+ if (this_block.inputTypesKnown)
+ % do input type checking, dynamic output type and generic setup in this code block.
+
+ % (!) Port 'I' appeared to have dynamic type in the HDL -- please add type checking as appropriate;
+ % inp_width = this_block.port('I').width; % this should be SSR*(I_HIGH-I_LOW+1)
+ this_block.port('I').useHDLVector(true);
+
+ if (this_block.port('VI').width ~= 1);
+ this_block.setError('Input data type for port "VI" must have width=1.');
+ end
+
+ this_block.port('VI').useHDLVector(false);
+
+ % (!) Port 'O' appeared to have dynamic type in the HDL
+ % --- you must add an appropriate type setting for this port
+ this_block.port('O').setType(['UFix_' num2str(SSR*(O_HIGH-O_LOW+1)) '_' num2str(0)]);
+end % if(inputTypesKnown)
+ % -----------------------------
+
+ % -----------------------------
+ if (this_block.inputRatesKnown)
+ setup_as_single_rate(this_block,'CLK','CE')
+ end % if(inputRatesKnown)
+ % -----------------------------
+
+ uniqueInputRates = unique(this_block.getInputRates);
+
+ % (!) Custimize the following generic settings as appropriate. If any settings depend
+ % on input types, make the settings in the "inputTypesKnown" code block.
+ % The addGeneric function takes 3 parameters, generic name, type and constant value.
+ % Supported types are boolean, real, integer and string.
+
+
+ this_block.addGeneric('OX','INTEGER',num2str(OX));
+ this_block.addGeneric('OY','INTEGER',num2str(OY));
+ this_block.addGeneric('FAMILY','INTEGER',num2str(FAMILY));
+ if (DDR==1)
+ this_block.addGeneric('DDR','BOOLEAN','TRUE');
+ else
+ this_block.addGeneric('DDR','BOOLEAN','FALSE');
+ end
+ this_block.addGeneric('SSR','INTEGER',num2str(SSR));
+ this_block.addGeneric('TAPS','INTEGER',num2str(TAPS));
+ this_block.addGeneric('C','STRING',strcat('"',num2str(COEFFICIENT,' %.16f'),'"'));
+ this_block.addGeneric('I_HIGH','INTEGER',num2str(I_HIGH));
+ this_block.addGeneric('I_LOW','INTEGER',num2str(I_LOW));
+ this_block.addGeneric('C_HIGH','INTEGER',num2str(C_HIGH));
+ this_block.addGeneric('C_LOW','INTEGER',num2str(C_LOW));
+ this_block.addGeneric('O_HIGH','INTEGER',num2str(O_HIGH));
+ this_block.addGeneric('O_LOW','INTEGER',num2str(O_LOW));
+ if (ROUNDING==1)
+ this_block.addGeneric('ROUNDING','BOOLEAN','TRUE');
+ else
+ this_block.addGeneric('ROUNDING','BOOLEAN','FALSE');
+ end
+ this_block.addGeneric('SYMMETRY','STRING',convertStringsToChars(strcat('"',SYMMETRY,'"')));
+
+ % Add addtional source files as needed.
+ % |-------------
+ % | Add files in the order in which they should be compiled.
+ % | If two files "a.vhd" and "b.vhd" contain the entities
+ % | entity_a and entity_b, and entity_a contains a
+ % | component of type entity_b, the correct sequence of
+ % | addFile() calls would be:
+ % | this_block.addFile('b.vhd');
+ % | this_block.addFile('a.vhd');
+ % |-------------
+
+ this_block.addFile('fixed_pkg.vhd');
+ this_block.addFile('cfixed_pkg.vhd');
+ this_block.addFile('BDELAY.vhd');
+ this_block.addFile('SDELAY.vhd');
+ this_block.addFile('DSPx8_WRAPPER.vhd');
+ this_block.addFile('TRANSPOSE_SSR_FIR_CHAIN.vhd');
+ this_block.addFile('TRANSPOSE_SSR_FIR.vhd');
+ this_block.addFile('WRAPPER_TRANSPOSE_SSR_FIR.vhd');
+
+return;
+
+
+% ------------------------------------------------------------
+
+function setup_as_single_rate(block,clkname,cename)
+ inputRates = block.inputRates;
+ uniqueInputRates = unique(inputRates);
+ if (length(uniqueInputRates)==1 & uniqueInputRates(1)==Inf)
+ block.addError('The inputs to this block cannot all be constant.');
+ return;
+ end
+ if (uniqueInputRates(end) == Inf)
+ hasConstantInput = true;
+ uniqueInputRates = uniqueInputRates(1:end-1);
+ end
+ if (length(uniqueInputRates) ~= 1)
+ block.addError('The inputs to this block must run at a single rate.');
+ return;
+ end
+ theInputRate = uniqueInputRates(1);
+ for i = 1:block.numSimulinkOutports
+ block.outport(i).setRate(theInputRate);
+ end
+ block.addClkCEPair(clkname,cename,theInputRate);
+ return;
+
+% ------------------------------------------------------------
diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/cfixed_pkg.vhd b/Examples/HDL/Digital_Filtering/SSR_FIR/cfixed_pkg.vhd
new file mode 100644
index 000000000..ffa0bc71f
--- /dev/null
+++ b/Examples/HDL/Digital_Filtering/SSR_FIR/cfixed_pkg.vhd
@@ -0,0 +1,407 @@
+-- Copyright © Advanced Micro Devices, Inc., or its affiliates. All rights reserved.
+-- Portions of this content consists of AI generated content.
+-- You may not use this software and documentation (if any) (collectively, the "Materials")
+-- except in compliance with the terms and conditions of the Software License Agreement
+-- included with the Materials or otherwise as set forth in writing and signed by you and
+-- an authorized signatory of AMD. If you do not have a copy of the Software License
+-- Agreement, contact your AMD representative for a copy. You agree that you will not
+-- reverse engineer or decompile the Materials, in whole or in part, except as allowed by
+-- applicable law.
+-- THE MATERIALS ARE DISTRIBUTED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+-- REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.all;
+use IEEE.NUMERIC_STD.all;
+use IEEE.MATH_REAL.all;
+use IEEE.MATH_COMPLEX.all;
+
+package cfixed_pkg is
+ use work.fixed_pkg.all; -- VHDL-2008 fixed_pkg with no saturation, rounding or warning messages
+ -- this gives us UFIXED, SFIXED, operators and conversion functions
+
+ constant PI:REAL:=3.1415926535897932;
+-- type BOOLEAN_VECTOR is array(NATURAL range <>) of BOOLEAN;
+ type INTEGER_VECTOR is array(INTEGER range <>) of INTEGER;
+ type REAL_VECTOR is array(INTEGER range <>) of REAL;
+ type COMPLEX_VECTOR is array(INTEGER range <>) of COMPLEX;
+ type UNSIGNED_VECTOR is array(INTEGER range <>) of UNSIGNED;
+
+-- SFIXED is now the standard VHDL-2008 type defined in fixed_generic_pkg, we do not need a user defined type anymore but this is what SFIXED really is
+-- type SFIXED is array(INTEGER range <>) of STD_LOGIC; -- arbitrary precision fixed point signed number, like SIGNED but lower bound can be negative
+ type SFIXED_VECTOR is array(INTEGER range <>) of SFIXED; -- unconstrained array of SFIXED
+ type SFIXED_MATRIX is array(INTEGER range <>) of SFIXED_VECTOR; -- unconstrained 2-D array of SFIXED
+ type CFIXED is record RE,IM:SFIXED; end record; -- arbitrary precision fixed point complex signed number
+ type CFIXED_VECTOR is array(INTEGER range <>) of CFIXED; -- unconstrained array of CFIXED
+ type CFIXED_MATRIX is array(INTEGER range <>) of CFIXED_VECTOR; -- unconstrained array of CFIXED_VECTOR
+ type REAL_MATRIX is array(INTEGER range <>) of REAL_VECTOR;
+ type COMPLEX_MATRIX is array(INTEGER range <>) of COMPLEX_VECTOR;
+
+ function MIN(A,B:INTEGER) return INTEGER;
+ function MIN(A,B,C:INTEGER) return INTEGER;
+ function MIN(A,B,C,D:INTEGER) return INTEGER;
+ function MAX(A,B:INTEGER) return INTEGER;
+ function MAX(A,B,C:INTEGER) return INTEGER;
+ function MAX(A,B,C,D:INTEGER) return INTEGER;
+ function MED(A,B,C:INTEGER) return INTEGER;
+-- function TO_INTEGER(B:BOOLEAN) return INTEGER;
+
+ function "*"(X:SFIXED;Y:STD_LOGIC) return SFIXED; -- multiply by 0 or 1 with SFIXED(X'high downto X'low) result
+ function TO_SFIXED(I:SIGNED;H,L:INTEGER;SHIFT:INTEGER:=0) return SFIXED; -- convert SIGNED to SFIXED(H downto L) and resize
+ function TO_SFIXED(I:SIGNED;X:SFIXED;SHIFT:INTEGER:=0) return SFIXED; -- convert SIGNED to SFIXED(X'high downto X'low) and resize
+--redefine standard VHDL-2008 SFIXED shift function to make them full precision
+ function SHIFT_RIGHT(X:SFIXED;N:INTEGER) return SFIXED; -- returns SFIXED(X'high-N downto X'low-N) result
+ function SHIFT_LEFT(X:SFIXED;N:INTEGER) return SFIXED; -- returns SFIXED(X'high+N downto X'low+N) result
+ function TO_SFIXED_VECTOR(C:REAL_VECTOR;HL:SFIXED) return SFIXED_VECTOR; -- returns SFIXED_VECTOR(HL'high downto HL'low) result
+ function TO_REAL_VECTOR(C:SFIXED_VECTOR) return REAL_VECTOR; -- returns REAL_VECTOR result
+
+ function RE(X:CFIXED) return SFIXED; -- returns SFIXED(X'high/2 downto X'low/2) result
+ function IM(X:CFIXED) return SFIXED; -- returns SFIXED(X'high/2 downto X'low/2) result
+ function "+"(X,Y:CFIXED) return CFIXED; -- full precision add with CFIXED(MAX(X'high,Y'high)+2 downto MIN(X'low,Y'low)) result
+ function "-"(X,Y:CFIXED) return CFIXED; -- full precision subtract with CFIXED(MAX(X'high,Y'high)+2 downto MIN(X'low,Y'low)) result
+ function "*"(X,Y:CFIXED) return CFIXED; -- full precision multiply with CFIXED(X'high+Y'high+2 downto X'low+Y'low) result
+ function "*"(X:CFIXED;Y:SFIXED) return CFIXED; -- full precision multiply with CFIXED(X'high+Y'high downto X'low+Y'low) result
+ function "*"(X:SFIXED;Y:CFIXED) return CFIXED;
+ function RESIZE(X:CFIXED;H,L:INTEGER) return CFIXED; -- resizes X and returns CFIXED(RE(H downto L),IM(H downto L))
+ function RESIZE(X:CFIXED;HL:CFIXED) return CFIXED; -- resizes X to match HL and returns CFIXED(RE(HL.RE'high downto HL.RE'low),IM(RE(HL.IM'high downto HL.IM'low))
+ function PLUS_i_TIMES(X:CFIXED) return CFIXED; -- returns CFIXED(X'high+2 downto X'low) result
+ function "-"(X:CFIXED) return CFIXED; -- full precision negate with CFIXED(X'high+2 downto X'low) result
+ function MINUS_i_TIMES(X:CFIXED) return CFIXED; -- returns CFIXED(X'high+2 downto X'low) result
+ function X_PLUS_i_TIMES_Y(X,Y:CFIXED;RND:CFIXED) return CFIXED; -- returns CFIXED(MAX(X'high,Y'high)+2 downto MIN(X'low,Y'low)) result
+ function X_MINUS_i_TIMES_Y(X,Y:CFIXED;RND:CFIXED) return CFIXED; -- returns CFIXED(MAX(X'high,Y'high)+2 downto MIN(X'low,Y'low)) result
+ function SWAP(X:CFIXED) return CFIXED; -- returns CFIXED(X'high downto X'low) result
+ function CONJ(X:CFIXED) return CFIXED; -- returns CFIXED(X'high+2 downto X'low) result
+ function SHIFT_RIGHT(X:CFIXED;N:INTEGER) return CFIXED; -- returns CFIXED(X'high-N downto X'low-N) result
+ function SHIFT_LEFT(X:CFIXED;N:INTEGER) return CFIXED; -- returns CFIXED(X'high+N downto X'low+N) result
+ function TO_CFIXED(R,I:REAL;H,L:INTEGER) return CFIXED; -- returns CFIXED(RE(H downto L),IM(H downto L)) result
+ function TO_CFIXED(R,I:REAL;HL:CFIXED) return CFIXED; -- returns CFIXED(RE(HL.RE'high downto HL.RE'low),IM(RE(HL.IM'high downto HL.IM'low)) result
+ function TO_CFIXED(C:COMPLEX;HL:CFIXED) return CFIXED; -- returns CFIXED(RE(HL.RE'high downto HL.RE'low),IM(RE(HL.IM'high downto HL.IM'low)) result
+ function TO_CFIXED(R,I:SFIXED) return CFIXED; -- returns CFIXED(2*MAX(R'high,I'high)+1 downto 2*MIN(R'low,I'low)) result
+ function TO_COMPLEX(C:CFIXED) return COMPLEX; -- returns COMPLEX result
+ function TO_CFIXED_VECTOR(C:COMPLEX_VECTOR;HL:CFIXED) return CFIXED_VECTOR; -- returns CFIXED_VECTOR(RE(HL.RE'high downto HL.RE'low),IM(RE(HL.IM'high downto HL.IM'low)) result
+ function TO_COMPLEX_VECTOR(C:CFIXED_VECTOR) return COMPLEX_VECTOR; -- returns COMPLEX_VECTOR result
+ function "*"(R:REAL;C:COMPLEX_VECTOR) return COMPLEX_VECTOR; -- returns R*C
+ function LOG2(N:INTEGER) return INTEGER; -- returns ceil(log2(N))
+ function ZERO(U:UNSIGNED) return UNSIGNED; -- returns 0 with the same range as U
+ function ZERO(S:SFIXED) return SFIXED; -- returns 0 with the same range as S
+ function ZERO(C:CFIXED) return CFIXED; -- returns 0 with the same range as C
+ function ZERO(SV:SFIXED_VECTOR) return SFIXED_VECTOR; -- returns 0 with the same range as SV
+ function ZERO(CV:CFIXED_VECTOR) return CFIXED_VECTOR; -- returns 0 with the same range as CV
+end package cfixed_pkg;
+
+package body cfixed_pkg is
+ function MIN(A,B:INTEGER) return INTEGER is
+ begin
+ if AB then
+ return A;
+ else
+ return B;
+ end if;
+ end;
+
+ function MAX(A,B,C:INTEGER) return INTEGER is
+ begin
+ return MAX(MAX(A,B),C);
+ end;
+
+ function MAX(A,B,C,D:INTEGER) return INTEGER is
+ begin
+ return MAX(MAX(A,B),MAX(C,D));
+ end;
+
+ function MED(A,B,C:INTEGER) return INTEGER is
+ begin
+ return MAX(MIN(MAX(A,B),C),MIN(A,B));
+ end;
+
+-- function TO_INTEGER(B:BOOLEAN) return INTEGER is
+-- begin
+-- if B then
+-- return 1;
+-- else
+-- return 0;
+-- end if;
+-- end;
+
+ function "*"(X:SFIXED;Y:STD_LOGIC) return SFIXED is
+ begin
+ if Y='1' then
+ return X;
+ else
+ return TO_SFIXED(0.0,X);
+ end if;
+ end;
+
+ function TO_SFIXED(I:SIGNED;H,L:INTEGER;SHIFT:INTEGER:=0) return SFIXED is
+ variable O:SFIXED(H downto L);
+ begin
+ for K in O'range loop
+ if K1 loop
+ RESULT:=RESULT+1;
+ TEMP:=(TEMP+1)/2;
+ end loop;
+ return RESULT;
+ end;
+
+ function ZERO(U:UNSIGNED) return UNSIGNED is -- returns 0 with the same range as S
+ begin
+ return TO_UNSIGNED(0,U'length);
+ end;
+
+ function ZERO(S:SFIXED) return SFIXED is -- returns 0 with the same range as S
+ begin
+ return TO_SFIXED(0.0,S);
+ end;
+
+ function ZERO(C:CFIXED) return CFIXED is -- returns 0 with the same range as C
+ begin
+ return TO_CFIXED(0.0,0.0,C);
+ end;
+
+ function ZERO(SV:SFIXED_VECTOR) return SFIXED_VECTOR is -- returns 0 with the same range as SV
+ variable RESULT:SFIXED_VECTOR(SV'range)(SV(SV'low)'range);
+ begin
+ for K in SV'range loop
+ RESULT(K):=TO_SFIXED(0.0,SV(K));
+ end loop;
+ return RESULT;
+ end;
+
+ function ZERO(CV:CFIXED_VECTOR) return CFIXED_VECTOR is -- returns 0 with the same range as CV
+ variable RESULT:CFIXED_VECTOR(CV'range)(RE(CV(CV'low).RE'range),IM(CV(CV'low).IM'range));
+ begin
+ for K in CV'range loop
+ RESULT(K):=TO_CFIXED(0.0,0.0,CV(K));
+ end loop;
+ return RESULT;
+ end;
+end package body cfixed_pkg;
\ No newline at end of file
diff --git a/Examples/HDL/Digital_Filtering/SSR_FIR/fixed_pkg.vhd b/Examples/HDL/Digital_Filtering/SSR_FIR/fixed_pkg.vhd
new file mode 100644
index 000000000..2cb1318d5
--- /dev/null
+++ b/Examples/HDL/Digital_Filtering/SSR_FIR/fixed_pkg.vhd
@@ -0,0 +1,20 @@
+-- Copyright © Advanced Micro Devices, Inc., or its affiliates. All rights reserved.
+-- Portions of this content consists of AI generated content.
+-- You may not use this software and documentation (if any) (collectively, the "Materials")
+-- except in compliance with the terms and conditions of the Software License Agreement
+-- included with the Materials or otherwise as set forth in writing and signed by you and
+-- an authorized signatory of AMD. If you do not have a copy of the Software License
+-- Agreement, contact your AMD representative for a copy. You agree that you will not
+-- reverse engineer or decompile the Materials, in whole or in part, except as allowed by
+-- applicable law.
+-- THE MATERIALS ARE DISTRIBUTED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+-- REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.all;
+
+package fixed_pkg is new IEEE.fixed_generic_pkg
+ generic map(fixed_round_style=>IEEE.fixed_float_types.fixed_truncate,
+ fixed_overflow_style=>IEEE.fixed_float_types.fixed_wrap,
+ fixed_guard_bits=>2,
+ no_warning=>true);