39
\$\begingroup\$

I built a mod-16 counter, and the output result is a INTEGER (all the examples I saw used INTEGER).

I built a hex-to-7-segment-display decoder, and its input is a STD_LOGIC_VECTOR (wrote it that way because it was easy to map out the truth table).

I'd like to connect the output of the counter to the input of the decoder, but I get 'type mismatch' errors when trying to compile in QuartusII.

Is there a way to convert from a INTEGER type to a STD_LOGIC_VECTOR type in a VHDL listing?

\$\endgroup\$

7 Answers 7

31
\$\begingroup\$

As others said, use ieee.numeric_std, never ieee.std_logic_unsigned, which is not really an IEEE package.

However, if you are using tools with VHDL 2008 support, you can use the new package ieee.numeric_std_unsigned, which essentially makes std_logic_vector behave like unsigned.

Also, since I didn't see it stated explicitly, here's actual code example to convert from an (unsigned) integer to an std_logic_vector:

use ieee.numeric_std.all;
...
my_slv <= std_logic_vector(to_unsigned(my_int, my_slv'length));
\$\endgroup\$
17
\$\begingroup\$

As LoneTech says, use ieee.numeric_std is your friend. You can convert a std_logic_vector to an integer, but you'll have to cast it as signed or unsigned first (as the compiler has no idea which you mean). VHDL is a strongly typed language. I've written more on this subject on my blog

Fundamentally, I'd change your 7seg converter to take in an integer (or actually a natural, given that it's only going to deal with positive numbers) - the conversion is then a simple array lookup. Set up a constant array with the conversions in and just index into it with the integer you use on the entity as an input.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks for this. I appreciate your comments very much. I was in a TA position of sorts, learning VHDL to help a prof get started who was a little shakey on programming concepts. I'm going to pass on your info to him - the textbook we used didn't delve into VHDL 'morality' questions. \$\endgroup\$
    – J. Polfer
    Commented Nov 17, 2010 at 15:41
  • 1
    \$\begingroup\$ It is less of a 'morality' issue than it is a guarantee of consistency. The numeric_std lib is a real standard instituted by the IEEE, while the std_logic_unsigned library was made up by a vendor, and adopted in the industry without any real formal definition. There is no guarantee of cross-vendor compatibility with the non-standard libs, though it typically works fine. It is good form to move on to the standard now though. \$\endgroup\$
    – MattG
    Commented Sep 28, 2011 at 18:57
4
\$\begingroup\$

To convert an integer to std_logic_vector you have several options. Using numeric_std:

vect <= std_logic_vector( to_unsigned( your_int, vect'length));

or

vect <= std_logic_vector( to_signed( your_int, vect'length));

Using std_logic_arith:

vect <= conv_std_logic_vector( your_int, vect'length);

std_logic_arith is a not an ieee standard, but most tools compile it into the IEEE library and it is widely used.

\$\endgroup\$
3
\$\begingroup\$

As the main answer says, the recommended method is as follows:

use ieee.numeric_std.all;
...
my_slv <= std_logic_vector(to_unsigned(my_int, my_slv'length));

However, I would like to elaborate about why this is recommended, and why VHDL has such a seemingly convoluted way of converting integers into std_logic_vectors.

It comes down to how these types are viewed by the tools.

A standard_logic_vector is literally a bunch of 1s or 0s. I have 10001. What number is this? Well, it depends. Is it signed or unsigned? Ths SLV doesn't know or care. How many bits? Well, how long is your SLV?

An integer is signed, and usually 32 bits (if i remember correctly).

Stage 1: Make my integer shorter, and unsigned. That's this part:

to_unsigned(my_int, my_slv'length));

"I have this integer, I want it to be unsigned, and I want it to fit into the length of my SLV."

Stage 2: Then, take those bits and use them to drive the my_slv.

my_slv <= std_logic_vector(...)

"Take these bits, and use them to drive my slv"

(A note on terminology. A <= B in VHDL is read out loud as "A is driven by B")

Combined, this gets you:

my_slv <= std_logic_vector(to_unsigned(my_int, my_slv'length));

When coming from a traditional programming background, it's very easy to get stuck in a programming way of thinking. But in VHDL the code you write has physical implications in hardware. Knowing why this method works and is recommended is one step closer to thinking about what you're writing in hardware terms.

Bonus tip: functions prefixed by to_ are ones that shorten/change the operands. They make them unsigned or a certain length or both. This is why to_unsigned requires you to specify the length. The functions without to_ (straight std_logic_vector(...) in this example) are used when types are directly compatible already. "Take these bits and stuff them in this type, no modifications required". These don't have a length argument because both sides are already the same. So when constructing things like this, I don't need to look it up, I just think about how I'm changing the data.

\$\endgroup\$
1
\$\begingroup\$

You may be interested in using the types unsigned and signed from ieee.numeric_std. They're compatible with std_logic_vector, but have a numeric interpretation (binary or 2-complement). There's also the option to put such an interpretation on std_logic_vector, but this is not recommended.

\$\endgroup\$
1
\$\begingroup\$

For VHDL 2019

VHDL-2019 example of conversion from integer to std_logic_vector on EDA Playground.

You can simply do:

slv <= std_logic_vector(to_signed(i));

Or as a function for both signals and variables:

function ConvertToSlv(constant i: in integer) return TResult of std_logic_vector is
    variable result: TResult;
begin
    result := std_logic_vector(to_signed(i, result'length));
    return result;
end function;

Usage

signal int: integer := -5;
signal nat: natural := 5;
signal sig1: std_logic_vector(7 downto 0);
signal sig2: std_logic_vector(15 downto 0);
...
variable var1: std_logic_vector(7 downto 0);
variable var2: std_logic_vector(15 downto 0);
...
sig1 <= ConvertToSlv(int);
sig2 <= ConvertToSlv(nat);
...
var1 := ConvertToSlv(int);
var2 := ConvertToSlv(nat);

For previous versions of VHDL

Write conversion procedures that ensure we read the length attribute of the signal or variable we are modifying, something like this:

For signals:

procedure ConvertToSlvSig(constant i: in integer; signal slv: out std_logic_vector) is
begin
    slv <= std_logic_vector(to_signed(i, slv'length));
end procedure;

For variables:

procedure ConvertToSlvVar(constant i: in integer; variable slv: out std_logic_vector) is
begin
    slv := std_logic_vector(to_signed(i, slv'length));
end procedure;

Usage:

signal int: integer := -5;
signal nat: natural := 5;
signal sig1: std_logic_vector(7 downto 0);
signal sig2: std_logic_vector(15 downto 0);
...
variable var1: std_logic_vector(7 downto 0);
variable var2: std_logic_vector(15 downto 0);
...
ConvertToSlvSig(int, sig1);
ConvertToSlvSig(nat, sig2);

ConvertToSlvVar(int, var1);
ConvertToSlvVar(nat, var2);

This prevents bugs such as:

the_wrong_slv <= std_logic_vector(to_unsigned(int, the_right_slv'length));
\$\endgroup\$
0
\$\begingroup\$

Let's say that your 4-bit counter had an INTEGER output SOME_INTEGER, and you wanted to convert it to a 4-bit STD_LOGIC_VECTOR

SOME_VECTOR <= conv_std_logic_vector(SOME_INTEGER, 4);

You can also use this to initialize vectors with meaningful numbers

SOME_VECTOR <= conv_std_logic_vector(9, 4); -- instead of "1001"

I think you may need to add "use IEEE.STD_LOGIC_ARITH.ALL;" and/or STD_LOGIC_UNSIGNED.

The complementary operation is conv_integer(vector). I like to use this when I do comparisons. So I might declare

constant SOME_CONSTANT : integer := 999;

And then, later, I can use this in an if statement

if (conv_integer(SOME_VECTOR)=SOME_CONSTANT)
  then OTHER_VECTOR <= (others => '0');
end if;

EDIT: You shouldn't need to declare the variable as an Integer. Try changing the declaration to std_logic_vector instead. The + and - operators work on std_logic_vectors.

\$\endgroup\$
4
  • 3
    \$\begingroup\$ Please don't do this! Use numeric_std (see LoneTech's and my answers) \$\endgroup\$ Commented Nov 17, 2010 at 14:46
  • \$\begingroup\$ If you have a better way to do it, that's fine, but my suggestion works so I think your down-vote was unnecessary. I have used std_logic_arith for years and I never had any problems with it. I think fears about vendors changing their implementations are unfounded; what vendor in their right mind will risk breaking their customers' designs? \$\endgroup\$
    – ajs410
    Commented Nov 17, 2010 at 19:15
  • 1
    \$\begingroup\$ You already have an answer to what vendor will willfully put vendor specific stuff in IEEE's namespace. It remains crude, particularly when dealing with signed and unsigned values. \$\endgroup\$ Commented Nov 19, 2010 at 2:36
  • \$\begingroup\$ "The + and - operators work on std_logic_vectors." AFAIK, they don't work, unless I misunderstand your meaning. it's usually necessary to cast to a type that holds signed/unsigned data first. \$\endgroup\$
    – stanri
    Commented Jan 24, 2018 at 19:46

Not the answer you're looking for? Browse other questions tagged or ask your own question.