Reputation: 283
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:
-8192 to 8191
0 to 16383
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
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
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