I am trying to implement an adder tree for 8 bit signed numbers using VHDL and recursion. The code works well if there is not overflow or underflow. The problem starts when I am trying to write logic to take care of saturation, the internal signals are all X so the logic to take care of saturation does not work.
I have seen that the values of internal signals like "addr_i" are undefined both on Vivado simulator and on Modelsim
Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;
-- Package Declaration Section
package def_pkg is
type add_arr_unc is array (integer range <>) of signed(7 downto 0);
end package def_pkg;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;
use work.def_pkg.all;
entity adder_tree_se is
port (
clk : in std_logic;
a : in add_arr_unc;
res : out signed(7 downto 0)
);
end adder_tree_se;
architecture Behavioral of adder_tree_se is
component adder_tree_se
port (
clk : in std_logic;
a : in add_arr_unc;
res : out signed(7 downto 0)
);
end component;
alias arrInput : add_arr_unc (0 TO a'Length-1) IS a;
signal LowOp : signed(7 downto 0);
signal HiOp : signed(7 downto 0);
signal arrInput_s: signed(7 downto 0);
signal add_i : signed(8 downto 0);
signal Output_s : signed(7 downto 0);
begin
add_i <= (LowOp(7) & LowOp) + (HiOp(7) & HiOp); -- addition with sign extension
add_pr : process(clk)
begin
if(rising_edge(clk)) then
Output_s <= add_i(7 downto 0);
arrInput_s <= arrInput(0);
end if;
end process add_pr;
GeneralCase:
if arrInput'Length > 1 generate
LowerTree: adder_tree_se
port map (
clk => clk,
a => arrInput (0 TO arrInput'Length/2-1),
res => LowOp
);
UpperTree: adder_tree_se
port map (
clk => clk,
a => arrInput (arrInput'Length/2 TO arrInput'Length-1),
res => HiOp
);
PullItAllTogether:
res <= Output_s;
end generate;
BaseCase:
if arrInput'Length = 1 generate
PassThrough: res <= arrInput_s;
end generate;
end Behavioral;
-
\$\begingroup\$ Interesting problem, it seems some sense of underflow/overflow needs to be passed up. Also what should happen when LowerTree underflows and UpperTree overflows. If you add tracking for the sense of overflow is it more complex than just maintaining the extra bits and then checking for underflow/overflow at the end with a full precision number. \$\endgroup\$Jim Lewis– Jim Lewis2023年05月27日 20:55:55 +00:00Commented May 27, 2023 at 20:55
1 Answer 1
In VHDL you can define the initial state of any signal when its declared.
signal LowOp : signed(7 downto 0) := "00000000" ;--binary initializer
signal HiOp : signed(7 downto 0) := X"00" ;--hex initializer
signal arrInput_s: signed(7 downto 0) := (others => '0') ;--aggregate initializer
signal add_i : signed(8 downto 0) := (others => '1') ;--aggregate initializer
signal Output_s : signed(7 downto 0) := (0 => '1', others => '0');--aggregate initializer
This works both in simulation, and on may types of FPGAs. This includes all Xilinx FPGAs (which is like 90% of the market). The Vivado tools also support this for both simulation and synthesis.
You can even do this for signals on your port definitions to create default values when the signals are not connected. If they are connected, then whatever they are being driven with will of course overrided the default.