I have a vector and I want to divide it by two in 2 complement. I did the following but I am not sure at all if this is good or not. Any help if this is correct or not?
Data_in :in std_logic_vector(15 downto 0) ;
Data_out :out std_logic_vector(15 downto 0) ;
-- these vectors in 16 it
variable tmp : integer ;
tmp := conv_integer(Data_in ) / 2 ;
Data_out <= conv_std_logic_vector (tmp,8);
-------- i will add these lines so the question would be posted
-- come on :((((((((((((((((((((
thanks in advance !
Any help if this is correct or not?
It's not correct. The reason is due to a semantic error that would show up during simulation (not shown here, the question lacking a Minimal, Complete and Verifiable example).
Data_out <= conv_std_logic_vector (tmp,8);
The length of the expression on the right hand side is determined by the second parameter to conv_std_logic_vector (the 8). There is a requirement when simulating that there is an element in the effective value for each element of the target signal. (IEEE Std 1076-2008 14.7.3.4 Signal update, para 2, b)). You'd get a simulation error.
Correcting that in your snippet would be passing the correct length:
Data_out <= conv_std_logic_vector (tmp, 16);
Without a Minimal, Complete and Verifiable example it's not possible to determine if you've made another error.
Type INTEGER has a minimum range (the actual range is implementation dependent, see 5.2.3.2 Predefined integer types where the minimum range is –2147483647 to +2147483647. No VHDL synthesis tools support wider range integer values. For binary values falling within that range there's nothing wrong with using conversion to integer and dividing by 2.
Historically you could use shifts for powers of two division.
Juergen's comment suggests shifting right one bit and preserving the sign would look like:
Data_out <= Data_in(15) & Data_in(15 downto 1);
That works fine for numbers 0 or greater. For numbers less it rounds down odd numbers due to two's complement representation. That can be overcome by adjusting the shift input, adding 1 to odd negative dividend values:
if Data_in(15) = '1' and Data_in(0) = '1' then -- odd negative numbers
Data_out <= SHIFT_RIGHT (Data_in + 1, 1);
else
Data_out <= Data_in(15) & Data_in(15 downto 1); -- SHIFT_RIGHT(Data_In, 1)
end if;
(Data_in and Data_out are type signed, along with function SHIFT_RIGHT from IEEE package numeric_std.)
VHDL synthesis tools generally can divide by powers of two. For example using IEEE package numeric_std:
Data_out <= std_logic_vector(signed(Data_in) / 2);
Where the std_logic_vector value is treated as a two's complement value (type signed). The synthesized logic implements this without an actual divider.
Xilinx Vivado (see UG901 Synthesis) supports VHDL division by powers of two for static right operands as here. See Table 5-10 VHDL Constructs and Support Status in the user guide).
Note: Synopsys packages are referred to as legacy packages in the Vivado user guide. Synthesis tools have evolved to deal with division since Synopsys released their std_logic_arith, std_logic_unsigned and std_logic_signed packages. The IEEE provides standard numeric packages that include division operators for std_logic_1164 based array types.
Code examples:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity signed_div_2 is
end entity;
architecture foo of signed_div_2 is
signal Data_in: signed (15 downto 0) := (1 => '0', others => '1');
signal Data_out: signed (15 downto 0);
function to_string (inp: signed) return string is
variable image_str: string (1 to inp'length);
alias input_str: signed (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) :=
character'VALUE(std_ulogic'IMAGE(input_str(i)));
end loop;
return image_str;
end function;
begin
process
begin
report LF & HT & "Data_in = " & to_string (Data_in) &
" (" & integer'image(to_integer(Data_in)) & ")";
Data_out <= Data_in(15) & Data_in(15 downto 1);
wait for 0 ns; -- so Data_out is updated
report LF & "By right shift (wrong)" & LF & HT &
"Data_out = " & to_string (Data_out) &
" (" & integer'image(to_integer(Data_out)) & ")";
Data_out <= Data_in / 2;
wait for 0 ns; -- wait for update
report LF & "Signed divide by 2" & LF & HT &
"Data_out = " & to_string (Data_out) &
" (" & integer'image(to_integer(Data_out)) & ")";
if Data_in(15) = '1' and Data_in(0) = '1' then -- odd negative numbers
Data_out <= SHIFT_RIGHT (Data_in + 1, 1);
else
Data_out <= Data_in(15) & Data_in(15 downto 1);
end if;
wait for 0 ns; -- wait for update
report LF & "By adjusted right shift" & LF & HT &
"Data_out = " & to_string (Data_out) &
" (" & integer'image(to_integer(Data_out)) & ")";
wait; -- once only
end process;
end architecture;
The types of Data_in and Data_out have been changed to signed to avoid numerous type conversions. Simulating the model gives:
ghdl -r signed_div_2 signed_div_2.vhdl:25:9:@0ms:(report note): Data_in = 1111111111111101 (-3) signed_div_2.vhdl:29:9:@0ms:(report note): By right shift (wrong) Data_out = 1111111111111110 (-2) signed_div_2.vhdl:34:9:@0ms:(report note): Signed divide by 2 Data_out = 1111111111111111 (-1) signed_div_2.vhdl:43:9:@0ms:(report note): By adjusted right shift Data_out = 1111111111111111 (-1)
The first Data_out report for shifting without adjustment shows that the result is wrong.
The second Data_out report is uses signed divide by 2 and is correct.
The third Data_out report uses the adjustment for odd negative values to give the correct result. The adjustment implements a carry tree in synthesis, all it's right operand bits are static and carry trees are optimally implemented in FPGAs.
For legacy packages or applications not being able to use the division operator and requiring adjusted shifting the SHIFT_RIGHT function from numeric_std can be replaced by the SHR function from package std_logic_arith, the to_integer function would be similarly replaced by CONV_INTEGER and the to_signed function replaced by CONV_SIGNED.
The to_string function is predefined in -2008 compliant VHDL tools. Included here to support older simulators.