convert integer to std_logic - vhdl

Suppose you have a loop
for i in 1 downto 0 loop
for j in 1 downto 0 loop
tS0 <= i;
But I need to convert the integer (which is natural) to std_logic. tS0 is declared as std_logic. I am only doing it one bit (0 or 1). That is, my i and j can only represent the value {0,1}.
I think I am heading to the wrong approach here. Can someone please tell me what should I do instead?
I don't think std_logic has to_unsigned method. i tried letting tS0 to be a vector (1 down to 0), and assigned like tS0(0) <= i, and etc. But it still didn't work out.
Thank you very much!

There is no need to convert from integers. You can just iterate over the std_logic datatype:
for i in std_logic range '0' to '1' loop
ts0 <= i;
end loop;

I'd write a function:
function to_std_logic(i : in integer) return std_logic is
begin
if i = 0 then
return '0';
end if;
return '1';
end function;
then use:
ts0 <= to_std_logic(i);

You will need to use a vector, either unsigned or std_logic, but it can be one bit long. ie:
signal tS0 : unsigned (0 downto 0);
...
tS0 <= to_unsigned(i, tS0'length);
...or...
signal tS0: std_logic_vector(0 downto 0);
...
tS0 <= std_logic_vector(to_unsigned(i,tS0'length);

You can do it like this. It looks a little simplier.
ts0 <= std_logic(to_unsigned(i, 1)(0));
You will build a unsigned vector by using the to_unsigned function. Then you grap the lowest bit and convert it to std_logic and then you assign it to the signal.
This is how it works fine :-).

Improving on a previous answer, you could write:
ts0 <= to_unsigned(i, 1)(0);
Provided you include the "numeric_std" library, in which that function is defined:
library IEEE;
use IEEE.numeric_std.all;
You can skip the explicit cast to "std_logic" type because the return type of "to_unsigned()" is an array of "std_logic" itself:
type UNSIGNED is array (NATURAL range <>) of STD_LOGIC;

Related

VHDL: big slv array slicing indexed by integer (big mux)

I want to slice a std_logic_vector in VHDL obtaining parts of it of fixed dimensions.
The general problem is:
din N*M bits
dout M bits
sel clog2(N) bits
Expected behaviour in an example (pseudocode): input 16 bit, want to slice it in 4 subvectors of 4bit each.
signal in: std_logic_vector(N*M-1 downto 0);
signal sel: integer;
-- with sel = 0
output <= in(N-1:0);
--with sel = 1 output <= in(2N-1:N)
-- with sel = 2
output <= in(3N-1:2N)
.....
--with sel = M-1
output <= in(M*N-1:(M-1)N)
I know a couples of way to do this, but I don't know which one is the best practice and give the best results in synthesis.
the entity
din: in std_logic_vector(15 downto 0);
dout: out std_logic_vector(3 downto 0);
sel: in std_logic_vecotor(1 downto 0)
CASE STATEMENT
case sel is
when "00" => dout <= din(3:0);
when "01" => dout <= din(7:4);
when "10" => dout <= din(11:8);
when "11" => dout <= din(15:12);
when others => ....`
It clearly implement a mux, but it's not generic at all and If the input gets big it's really hard to write and to codecover.
INTEGER INDEXING
sel_int <= to_integer(unsigned(sel));
dout <= din(4*(sel_int+1) - 1 downto 4*sel_int);
Extremely easy to write and to mantain, BUT it can have problems when the input is not a power of 2. For example, if I want to slice a 24bit vector in chunks of 4, what happen when the integer conversion of sel brings to the index 7?
A STRANGE TRADEOFF
sel_int <= to_integer(unsigned(sel));
for i in 0 to 4 generate
din_slice(i) <= din(4*(i+1)-1 downto 4*i);
end generate dout <= din_slice(sel_int);
I'm searching a solution that is general enough to be used with various input/output relationships and safe enough to be synthesized consistently everytime.
The Case statement is the only one with the Others case (that feels really safe), the other solutions rely on the slv to integer conversion and indexing that feels really comfortable but not so reliable.
Which solution would you use?
practical usecase
I have a 250bit std_logic_vector and I need to select 10 contigous bits inside of it starting from a certain point from 0 to 239. How can I do that in a way that is good for synthesis?
There is another option that is accepted by tools that allow VHDL 2008 (which includes Vivado and Prime Pro). You can use an unconstrained 2d type from a package:
type slv_array_t is array(natural range <>) of std_logic_vector; --vhdl 2008 unconstrained array type
then you can simply select which port you want. And it is as generic as you like.
library ieee;
use ieee.std_logic_1164.all;
use work.my_pkg.all;
entity mux is
generic (
N : natural;
M : natural
);
port (
sel : in natural;
ip : in slv_array_t (N-1 downto 0)(M-1 downto 0);
op : out std_logic_vector (M-1 downto 0);
);
end entity;
architecture rtl of mux is
begin
op <= ip(sel);
end architecture;
First you must extend the incoming data to be sure to have always as much bits as you need for connecting all multiplexer inputs (see the code below, process p_extend).
This will not create any logic at synthesis.
Second you must convert the resulting vector into an array, which you can access later by an index (see the code below, process p_create_array).
Again this will not create any logic at synthesis.
At last you must access this array by the select input signal (see the code below, process p_mux).
library ieee;
use ieee.std_logic_1164.all;
entity mux is
generic (
g_data_width : natural := 250;
g_slice_width : natural := 10;
g_sel_width : natural := 5;
g_start_point : natural := 27
);
port (
d_i : in std_logic_vector(g_data_width-1 downto 0);
sel_i : in std_logic_vector(g_sel_width-1 downto 0);
d_o : out std_logic_vector(g_slice_width-1 downto 0)
);
end entity mux;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
architecture struct of mux is
signal data : std_logic_vector(g_slice_width * 2**g_sel_width-1 downto 0);
type t_std_logic_slice_array is array (natural range <>) of std_logic_vector(g_slice_width-1 downto 0);
signal mux_in : t_std_logic_slice_array (2**g_sel_width-1 downto 0);
begin
p_extend: process(d_i)
begin
for i in 0 to g_slice_width * 2**g_sel_width-1 loop
if i+g_start_point<g_data_width then
data(i) <= d_i(i+g_start_point);
else
data(i) <= '0';
end if;
end loop;
end process;
p_create_array: process (data)
begin
for i in 0 to 2**g_sel_width-1 loop
mux_in(i) <= data((i+1)*g_slice_width-1 downto i*g_slice_width);
end loop;
end process;
p_mux: d_o <= mux_in(to_integer(unsigned(sel_i)));
end architecture;

How to convert std_logic to unsigned in an expression

So if wanted to assign a std_logic to a 1-bit usnigned I could just write...
signal X : unsigned(0 downto 0);
signal Y : std_logic;
X(0) <= unsigned(Y)
But what s the best way to convert a std_logic to an unsigned when used in an expression.
That is to say, without directly doing an assignment to a signal of type unsigned.
The scenario I have is this. I have two flags A and B that are signals of type std_logic.
Each flag has a strobe (A_valid , B_valid) of type std_logic that assert for 1 clock cycle each time their flag (A , B) is valid.
I have a counter (CNT) that is a signal of type unsigned that must count the number of times that either of the flags is '1'.
On any given clock cycle I must incrment CNT by 0, 1, or 2 depending on how many flags are 1.
Here is the straight forward way of doing it with an "if" statement.
signal A : std_logic;
signal A_valid : std_logic;
signal B : std_logic;
signal B_valid : std_logic;
signal CNT : unsigned;
if rising_edge(clk) then
if (A and A_valid and B and B_valid) = '1' then
CNT <= CNT + 2;
elsif (A and A_valid) = '1' then
CNT <= CNT + 1;
elsif (B and B_valid) = '1' then
CNT <= CNT + 1;
end if;
end if;
The problem with the code above is that it doesn't generalize very well since the number of cases goes up exponentially with the number of flags. For example if I had 5 flags I would have to write out 32 branches in the IF statement.
A more compact way of representing the same thing using an aggregate and a type mark is...
This is better becasue I just write one expression for each flag.
if rising_edge(clk) then
CNT <= CNT + unsigned'(0=> A AND A_valid) + unsigned'(0=> B AND B_valid);
end if;
Are there any other built-in ways (other than writing a function) to convert std_logic to unsigned in an expression in VHDL?
The easiest way is to concatenate the std_logic with a null array, yielding an array of length 1.
Cnt <= cnt + ("" & a_valid);
It should be able to work out the type from the context, otherwise you may need to qualify it with unsigned'

Direction independent slicing

I'm creating a package with some functions I often use and some functions need to take slices of their parameters. I usually use downto direction for all my signals, but sometimes signals change their direction unexpectedly, e.g., appending a zero bit (sig & '0') seems to change the direction to positive.
Is there a way to slice arrays (std_logic_vector, unsigned, signed) independent of their direction? For example how would you implement a function taking the lowest two bits? The only implementation I came up with uses an additional constant with the expected direction:
function take_two(x : std_logic_vector) return std_logic_vector is
constant cx : std_logic_vector(x'length-1 downto 0) := x;
begin
return cx(1 downto 0);
end function;
I've also tried something like x(x'low+1 downto x'low) but Quartus doesn't like this.
The question is actually not on the input, but on the required output. What do you prefer?
If you look at how functions are implemented in for instance std_logic_1164-body.vhdl, your function would similarly be something like (in a complete example):
entity e is end entity;
library ieee;
architecture a of e is
use ieee.std_logic_1164.all;
signal test : std_logic_vector(7 downto 0) := "10010110";
signal output : std_logic_vector(2 downto 0);
function slice(s: STD_LOGIC_VECTOR; u, l : natural) return STD_LOGIC_VECTOR is
alias sv : STD_LOGIC_VECTOR (s'length-1 downto 0) is s;
variable result : STD_LOGIC_VECTOR (u downto l);
begin
for i in result'range loop
result(i) := sv(i);
end loop;
return result;
end function;
begin
output <= slice(test & '0', 5, 3); -- test becomes 'to' range.
-- output still becomes "101"
end architecture;

AND all elements of an n-bit array in VHDL

lets say I have an n-bit array. I want to AND all elements in the array. Similar to wiring each element to an n-bit AND gate.
How do I achieve this in VHDL?
Note: I am trying to use re-usable VHDL code so I want to avoid hard coding something like
result <= array(0) and array(1) and array(2)....and array(n);
Thanks
Oshara
Solution 1: With unary operator
VHDL-2008 defines unary operators, like these:
outp <= and "11011";
outp <= xor "11011";
outp <= and inp; --this would be your case
However, they might not be supported yet by your compiler.
Solution 2: With pure combinational (and traditional) code
Because in concurrent code you cannot assign a value to a signal more than once, your can create a temp signal with an "extra" dimension. In your case, the output is one-bit, so the temp signal should be a 1D array, as shown below.
-------------------------------------------
entity unary_AND IS
generic (N: positive := 8); --array size
port (
inp: in bit_vector(N-1 downto 0);
outp: out bit);
end entity;
-------------------------------------------
architecture unary_AND of unary_AND is
signal temp: bit_vector(N-1 downto 0);
begin
temp(0) <= inp(0);
gen: for i in 1 to N-1 generate
temp(i) <= temp(i-1) and inp(i);
end generate;
outp <= temp(N-1);
end architecture;
-------------------------------------------
The inferred circuit is shown in the figure below.
Solution 3: With sequential code
This is simpler than solution 2, though you are now using sequential code to solve a purely combinational problem (but the hardware will be the same). You can either write a code similar to that in solution 2, but with a process and loop (the latter, in place of generate) or using a function. Because in sequential code you are allowed to assign a value to a signal more than once, the temp signal of solution 2 is not needed here.
If you have VHDL-2008 available, then reduction and is build into the
language as David Koontz and Pedroni have explained.
If you only have VHDL-2003 and prior available, then you can use a function
like:
function and_reduct(slv : in std_logic_vector) return std_logic is
variable res_v : std_logic := '1'; -- Null slv vector will also return '1'
begin
for i in slv'range loop
res_v := res_v and slv(i);
end loop;
return res_v;
end function;
You can then use the function both inside and outside functions with:
signal arg : std_logic_vector(7 downto 0);
signal res : std_logic;
...
res <= and_reduct(arg);
My favorite, non-VHDL-2008 solution is:
use ieee.std_logic_unsigned.all ; -- assuming not VHDL-2008
. . .
result <= '1' when not MyArray = 0 else '0' ;
With VHDL-2008, I recommend that you use the "and" reduction built-in (see Pedroni's post) and use the IEEE standard package "ieee.numeric_std_unsigned.all" instead of the shareware package "std_logic_unsigned".

I want to check if std_logic_vector contains negative integer

How can I check with if (...) then ... end if; construction if std_logic_vector variable holds the bits of a negative number? If it is negative, I have to assign it a zero value.
I have :
signal sum : std_logic_vector (15 downto 0);
sum<= (...);
if (...) then
sum<=x"00";
end if;
Thank you!
You cannot add two STD_LOGIC_VECTORs, because the language does not know anything about the arithmetic that it should perform. This is because, to the synthesis tool, every signal/port/variable that's declared as STD_LOGIC_VECTOR is nothing more than an array of STD_LOGIC, the multi-valued logic type. Arithmetic on such a type does not make sense.
If you want to use arithmetic on types whose interface is similar to the one exposed by STD_LOGIC_VECTOR, you should use SIGNED (for signed arithmetic) and UNSIGNED (for unsigned arithmetic) types defined in IEEE.NUMERIC_STD. In order to convert between these types, just cast them using the type names explicitly, like this :
std_logic_vector_variable := STD_LOGIC_VECTOR(unsigned_variable);
unsigned_variable := UNSIGNED(std_logic_vector_variable);
So, summing it all up - the signal sum should be declared as SIGNED, since you're obviously going to perform arithmetic on it. Then, you can freely use the comparison and arithmetic operations that you need. The resulting code should look more or less like this :
use IEEE.NUMERIC_STD.ALL;
-- entity and architecture declarations...
signal sum : SIGNED (15 downto 0);
-- inside some process...
if (sum <= 0) then sum <= 0; end if;
The quick and simple hack is to check if the most-significant-bit is 1, indicating a negative number:
result <= (others=>'0') when sum(sum'left)='1' else sum;
Or you can coerce the std_logic_vector into an appropriate type and see if it is negative:
result <= (others=>'0') when signed(sum) < 0 else sum;
Or inside of a process use an if statement instead of a selected signal assignment:
if signed(sum) < 0 then
result <= (others=>'0');
else
result <= sum;
end if;
signal sum : std_logic_vector (15 downto 0);
sum<= x"E8";
if (sum(15)='1') then
sum<=x"00";
end if;
Just check the MSB..
If MSB is 1, that means the number is negative else positive.

Resources