M1GEO
M1GEO

Reputation: 283

VHDL signed data in std_logic_vector to unsigned data

I have an ADC (LTC1407A-1) on an FPGA board that is populating a 14-bit register with 2's compliment signed data. I want to convert this data to be unsigned:

However, whatever I try, I can't seem to get the desired result. My current section of working code for the VHDL register module is as follows:

library IEEE;
use ieee.std_logic_arith.all;
use ieee.std_logic_1164.all;

entity reg10 is
    Port ( clk : in  STD_LOGIC;                         --50MHz clock
           reset : in  STD_LOGIC;                       --asynchronous reset
           i_load : in  STD_LOGIC;                      --load signal
           i_data : in  STD_LOGIC_VECTOR (13 downto 0); --data signal
           o_data : out  STD_LOGIC_VECTOR (15 downto 0) --output data
    );
end reg10;

architecture Behavioral of reg10 is
    signal s_data : STD_LOGIC_VECTOR(9 downto 0);
    signal f_data : STD_LOGIC_VECTOR(13 downto 0);
    signal t_sign : signed (13 downto 0);
begin
    process(clk, reset)
    begin
        if reset = '1' then
            s_data <= "0000000000";
        elsif clk'event and clk = '1' then
            t_sign <= SIGNED(i_data);
            f_data <= STD_LOGIC_VECTOR(t_sign);
            s_data <= "00" & f_data(13 downto 6);
        end if;
    end process;
    o_data <= "000010" & s_data(9 downto 0);
end Behavioral;

I have done plenty of searching around and find lots of examples where the conversion can be done, but, I don't understand the correct approach to take. I have tried assigning i_data as signed, casting between variables internally, and many other recommended solutions, but all to no avail.

signal t_sign : signed (13 downto 0);
f_data <= conv_std_logic_vector(i_data, 14);

The code buffers a changing input vector, and formats the data into an output vector for a VGA controller to display.

Help appreciated. Thanks.

Upvotes: 0

Views: 5350

Answers (2)

JHBonarius
JHBonarius

Reputation: 11261

The first error is:

use ieee.std_logic_arith.all;

Don't do that. Do this:

use ieee.numeric_std.all;

The other library already treats std_logic as signed or unsigned. You shouldn't want that. Then cast from signed to std_logic_vector to unsigned. e.g.:

[signal] foo <= unsigned(std_logic_vector(signed(bar)));

however, in you case the input is already std_logic, so just cast to unsigned. It should work, unless your input representation is non-standard. (I.e. has an offset). IF it has an offset, do something like:

[signal] foo <= unsigned(std_logic_vector(signed(bar)+offset));

N.B. <= [signal] assignments are assigned at the next delta (https://en.wikipedia.org/wiki/Delta_delay). So in a process that is evaluated within one delta (i.e. without wait statements), they are not applied until after the process ends. So in you example, even though f_data is assigned by the data in t_sign the line after t_sign is assigned, t_sign will not change until the end of the process, so its change will not directly effect f_data. Instead the process will trigger on the next clk and clk'event and clk = '1' will assign f_data the new processed value t_sign. In effect each <= will insert a register in your example.

edit: I myself would probably use a cast to integer.

foo <= to_unsigned(to_integer(bar)+offset, foo'length);

Upvotes: 0

user1155120
user1155120

Reputation:

Your i_data has a range of 13 downto 0. As Brian mentioned the conversion can be accomplished by adding 8192.

8192 is "1_0000_0000_0000" as a bit_string representing binary with a length matching i_data.

That means to convert by addition you're only flipping the MSB in addition with a result the length of the longest operand. Because you're also truncating in the s_data assignment you only need 8 flip flops.

For:

signal s_data:  std_logic_vector (7 downto 0);

we could assign s_data as:

s_data <= (i_data(13) xor '1') & i_data(12 downto 6);

where the o_data assignment becomes:

o_data <= "00001000" & s_data;

Without concern for carry the addition simplifies to a single XOR gate to flip the sign converting two's complement to a binary magnitude expression.

f_data and t_data are not needed as J.H. Bonarius indicates unless two additional pipeline stages are desired.

You could also ask whether registering is needed at all when only introducing one gate delay.

If the register is eliminated:

o_data <= "00001000" & (i_data(13) xor '1') & i_data(12 downto 6);

and you can also note that at no time are 'bits' i_data(5 downto 0) used.

And because XOR with a constant '1' on one input is inversion:

o_data <= "00001000" & not i_data(13) & i_data(12 downto 6);

that operation can be logical not.

Note that an arithmetic package is not needed nor are type conversions (cast is inaccurate in VHDL, type conversion is allowed only between closely related types see IEEE Std 1076-2008 9.3.6 Type conversions).

You could also expect that synthesis would optimize adding 8192 to essentially the same result if the apparently unnecessary pipeline registers are eliminated. In a modification of your original model to add 8192, that would also imply some of those pipeline register 'bits' be optimized away.

Your design model also doesn't use i_load.

Upvotes: 1

Related Questions