cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
Observer
Observer
754 Views
Registered: ‎04-03-2020

Converting an integer into unsigned

Jump to solution

Hi,

    I am receiving some SPI data from an ADC and I save it in an unsigned (15 downto 0). I convert this into an integer (because later on, I have to do some arithmetic operations on it) and then convert this back to another unsigned (15 downto 0).

    I wrote the VHDL code inside a component, I define the spi_mcu_miso as an input which is an integer:

port(
spi_mcu_miso        : in  integer);

     Then, I defined an unsigned:

signal data_out     : unsigned (15 downto 0);

   Finally, I convert the integer into unsigned:

data_out <= conv_unsigned(spi_mcu_miso,16);

    And I receive the following warnings in the synthesis:

 

[Synth 8-3331] design MCU_SPI has unconnected port spi_mcu_miso[30]

....

[Synth 8-3331] design MCU_SPI has unconnected port spi_mcu_miso[16]

It sounds like the spi_mcu_miso has 32 bits and I am ignoring 16 of them. I run the FPGA with this code, it works well and I do not see any problem for now.

 

My questions:

  • Should I be concerned about this? I am personally a fan of having minimal warnings in the code.
  • I was doing the exact same thing in my Top.vhd module and it did not give me any warning. I started seeing this problem when I moved these commands to a component. Do you think this is causing the problem?

Thanks for your help!

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

In case you find more information useful:

I am getting data from an ADC, then I have to do some multiplications on the data so, I prefer to convert it to integer (which works well); here is how I do that

spi_mcu_miso <= conv_integer(spi_adc1_miso);

The above commands do not give me any warning.

The next step is converting the integer into a bitstream that I can SPI to an MCU.

0 Kudos
1 Solution

Accepted Solutions
Highlighted
Voyager
Voyager
661 Views
Registered: ‎06-20-2012

@Mason1 

You said "It sounds like the spi_mcu_miso has 32 bits and I am ignoring 16 of them".

In VHDL integer have 32 bits but you only use 16.

data_out <= conv_unsigned(spi_mcu_miso,16);

It may or may not be fine depending on your design.

== If this was helpful, please feel free to give Kudos, and close if it answers your question ==

View solution in original post

16 Replies
Highlighted
710 Views
Registered: ‎01-22-2015

@Mason1 

Here are some thoughts that may solve your problem and some rules that I use when writing VHDL that have kept me out of trouble.

  1. You can do math with unsigned and signed types when using IEEE.NUMERIC_STD.ALL.  That is, you don't need to convert to the integer type in order to do math.

  2. Don't use integer types unless you absolutely need them (which is rare).  If you do use an integer type then constrain the range of the integer as shown in the following example.
    signal bit_cnt : integer range 0 to 7;
  3. We must often go "thru" the integer type when converting between other types.  The nice diagram <here> is pasted on the wall near my computer and I use it often.   The example below shows how we must go "thru" integer to convert a unsigned type to a signed type.  
    signal us8 : unsigned(7 downto 0);
    signal s9 : signed(8 downto 0);
    --
    --convert 8-bit unsigned, us8, to 9-bit signed, s9
    s9 <= to_signed(to_integer(us8),9);
  4. When doing a type conversion that requires you to go "thru" the integer type, you don't actually need to declare a signal of type integer (as shown by my example above).

  5. I recall when we were sorta restricted to use only std_logic and std_logic_vector types for component ports.  I still mostly do this, but sometimes I now use the unsigned and signed types for component ports.  I don't use the integer type for ports

  6. Do your type conversions inside a VHDL clocked process, using VHDL variables rather than signals if needed.

 

So, to answer your questions, "unconnected port" warnings should be investigated.  Sometimes it means that some bits of the port are not being used by the VHDL component and have therefore been optimized out (ie. removed) by synthesis - but we should still investigate and try to understand why.

Try using the unsigned type for everything shown in your example code and see what effect this has on the synthesis warnings.

Cheers,
Mark

 

 

Highlighted
Voyager
Voyager
662 Views
Registered: ‎06-20-2012

@Mason1 

You said "It sounds like the spi_mcu_miso has 32 bits and I am ignoring 16 of them".

In VHDL integer have 32 bits but you only use 16.

data_out <= conv_unsigned(spi_mcu_miso,16);

It may or may not be fine depending on your design.

== If this was helpful, please feel free to give Kudos, and close if it answers your question ==

View solution in original post

Highlighted
Scholar
Scholar
583 Views
Registered: ‎08-01-2012

My notes:

You dont show the whole code, and the posted warnings does not relate to any of the posted code. The warning relates to MCU_SPI , but the code only has spi_mcu_miso and data_out signal names.

Dont use integers for top level ports.

When you use an integer on ports, it can sometimes be good to constrain it to prevent extra bits being created during synthesis. Remember, integers will need to be converted to a bit-type in the real design:

signal int_sig : integer range 0 to 255; -- will be an 8 bit integer

Finally, Just delete std_logic_arith from your code. Its not a standard package. Use ieee.numeric_std instead (as its the correct standard). If you keep with std_logic_arith Ill guarantee you'll get a "two types visible" error in future. Just stop using it now.

Highlighted
Voyager
Voyager
575 Views
Registered: ‎06-20-2012

@richardhead 

"The warning relates to MCU_SPI , but the code only has spi_mcu_miso and data_out signal names."

MCU_SPI is the entity, spi_mcu_miso is the port.

== If this was helpful, please feel free to give Kudos, and close if it answers your question ==
Highlighted
Observer
Observer
509 Views
Registered: ‎04-03-2020

Temporary post:

I guess I can find multiple answers within these very detailed responses; I will try every single of these and then wrap up this topic. I guess I do not need others to spend more time on this. Thanks!

0 Kudos
Highlighted
Observer
Observer
469 Views
Registered: ‎04-03-2020

markg@prosensing.com wrote:

@Mason1 

Here are some thoughts that may solve your problem and some rules that I use when writing VHDL that have kept me out of trouble.

  1. You can do math with unsigned and signed types when using IEEE.NUMERIC_STD.ALL.  That is, you don't need to convert to the integer type in order to do math.

  2. Don't use integer types unless you absolutely need them (which is rare).  If you do use an integer type then constrain the range of the integer as shown in the following example.
    signal bit_cnt : integer range 0 to 7;
  3. We must often go "thru" the integer type when converting between other types.  The nice diagram <here> is pasted on the wall near my computer and I use it often.   The example below shows how we must go "thru" integer to convert a unsigned type to a signed type.  
    signal us8 : unsigned(7 downto 0);
    signal s9 : signed(8 downto 0);
    --
    --convert 8-bit unsigned, us8, to 9-bit signed, s9
    s9 <= to_signed(to_integer(us8),9);
  4. When doing a type conversion that requires you to go "thru" the integer type, you don't actually need to declare a signal of type integer (as shown by my example above).

  5. I recall when we were sorta restricted to use only std_logic and std_logic_vector types for component ports.  I still mostly do this, but sometimes I now use the unsigned and signed types for component ports.  I don't use the integer type for ports

  6. Do your type conversions inside a VHDL clocked process, using VHDL variables rather than signals if needed.

 

So, to answer your questions, "unconnected port" warnings should be investigated.  Sometimes it means that some bits of the port are not being used by the VHDL component and have therefore been optimized out (ie. removed) by synthesis - but we should still investigate and try to understand why.

Try using the unsigned type for everything shown in your example code and see what effect this has on the synthesis warnings.

Cheers,
Mark

 

 



Fantastic!

  • Doing math with unsigned is a GREAT idea. I ended up using this method. It just increases the length, like I multiply a 16-bits by 1 and the result has 30 bits. I can take care of this easily.
  • I am changing a lot of my signals to variables. Really making my code very neat and easy to debug. Also, I guess this helps me with keeping signals from unnecessarily going into the fabric and occupy traces that I might need in the future.

Thanks!

0 Kudos
Highlighted
Scholar
Scholar
459 Views
Registered: ‎08-01-2012

"I am changing a lot of my signals to variables. Really making my code very neat and easy to debug. Also, I guess this helps me with keeping signals from unnecessarily going into the fabric and occupy traces that I might need in the future."

I highly recommend you DONT do this. Variables or signals can still produce identical logic. But using only variables can get you into real traps. using a variable does not save any logic at all and may give you timing problems if you do certain things.

Here is an example - with signals it ALWAYS produces 3 registers in a shift register:

process(clk)
begin
  if rising_edge(clk) then
    b <= a;
    a <= ip;
    op <= b; 

   -- always 3 regs - a -> b > op 
  end if;
end process;

With variables, then assignment order is important, and can cause you an unseen headache:

process(clk)
  variable a, b : std_logic;
begin
  if rising_edge(clk) then
   a :=  ip;
   b := a;
   op := b;

   -- Here ip -> op is a single register

    -- version 2 - this now matches the signal version 3 registers
    op := b;
    b := a;
    a := ip;
  end if;
end process;
Highlighted
Observer
Observer
447 Views
Registered: ‎04-03-2020

@richardhead wrote:

My notes:

You dont show the whole code, and the posted warnings does not relate to any of the posted code. The warning relates to MCU_SPI , but the code only has spi_mcu_miso and data_out signal names.

Dont use integers for top level ports.

When you use an integer on ports, it can sometimes be good to constrain it to prevent extra bits being created during synthesis. Remember, integers will need to be converted to a bit-type in the real design:

signal int_sig : integer range 0 to 255; -- will be an 8 bit integer

Finally, Just delete std_logic_arith from your code. Its not a standard package. Use ieee.numeric_std instead (as its the correct standard). If you keep with std_logic_arith Ill guarantee you'll get a "two types visible" error in future. Just stop using it now.


Sorry for not providing enough information. MCU_SPI is in fact the component that the convert command is located inside. So,

  • Limiting the integer range is a great idea. I did it for all the integers I am using right now.
  • I refrain from using integer type on ports, based on what markg@prosensing.com said, I use unsigned and do not convert.
  • Appreciate your comment on using IEEE.NUMERIC_STD.ALL

Thanks!

0 Kudos
Highlighted
Observer
Observer
445 Views
Registered: ‎04-03-2020

@richardhead wrote:

"I am changing a lot of my signals to variables. Really making my code very neat and easy to debug. Also, I guess this helps me with keeping signals from unnecessarily going into the fabric and occupy traces that I might need in the future."

I highly recommend you DONT do this. Variables or signals can still produce identical logic. But using only variables can get you into real traps. using a variable does not save any logic at all and may give you timing problems if you do certain things.

Here is an example - with signals it ALWAYS produces 3 registers in a shift register:

process(clk)
begin
  if rising_edge(clk) then
    b <= a;
    a <= ip;
    op <= b; 

   -- always 3 regs - a -> b > op 
  end if;
end process;

With variables, then assignment order is important, and can cause you an unseen headache:

process(clk)
  variable a, b : std_logic;
begin
  if rising_edge(clk) then
   a :=  ip;
   b := a;
   op := b;

   -- Here ip -> op is a single register

    -- version 2 - this now matches the signal version 3 registers
    op := b;
    b := a;
    a := ip;
  end if;
end process;

"With variables, then assignment order is important"

Did not know about this! Glad you told me about it. I still want to move some simple parameters like counters inside my processes, but will be careful about making mistakes like the one you've mentioned here. Thanks!

 

0 Kudos
Highlighted
408 Views
Registered: ‎01-22-2015

@Mason1 

I am changing a lot of my signals to variables. Really making my code very neat and easy to debug.

I feel that a little balance to Richard's comments about using VHDL variables is needed.  As you say, making code neat and understandable, is a good reason to use variables.

In the VHDL code example below, I show how two 8-bit std_logic_vector signals are added together and the result is stored in a 16-bit std_logic_vector.   I wanted to do this in one clock cycle (so, I can't use a bunch of VHDL signals), but I also want my code readable (so, I used the VHDL variables, tmp1 and tmp2).

 

    signal slv1,slv2 : std_logic_vector(7 downto 0);
    signal slv3 : std_logic_vector(15 downto 0);

    P1: process(CLK1) 
        variable tmp1 : unsigned(7 downto 0);
        variable tmp2 : unsigned(15 downto 0);           
    begin 
        if rising_edge(CLK1) then
            tmp1 := unsigned(slv1) + unsigned(slv2);  --do the math, result is 8-bit
            tmp2 := to_unsigned(to_integer(tmp1),16); --convert 8-bit result to 16-bit 
            slv3 <= std_logic_vector(tmp2);           --convert 16-bit unsigned to slv
        end if;           
    end process P1;

 


There are other ways to do what is done in my example code.  However, the point of my example is to show how the use of variables can make VHDL coding neater and more understandable.

Cheers,
Mark

Highlighted
Voyager
Voyager
389 Views
Registered: ‎06-20-2012

Just another usefull example with variable.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
---------- count the number of '1' ----------
entity CONT4 is
PORT(A : in std_logic_vector(3 downto 0);
Y: out std_logic_vector(2 downto 0)
);
end CONT4;
architecture LOOP_BEH of CONT4 is
begin
process(A)
variable tmp : unsigned(2 downto 0);
begin
tmp := "000" ;
for I in 3 downto 0 loop
if(A(I)= '1' ) then
tmp := tmp + 1;
end if ;
end loop ;
Y <= std_logic_vector(tmp) ;
end process;
end LOOP_BEH;
== If this was helpful, please feel free to give Kudos, and close if it answers your question ==
Highlighted
Observer
Observer
363 Views
Registered: ‎04-03-2020

markg@prosensing.com wrote:

@Mason1 

I am changing a lot of my signals to variables. Really making my code very neat and easy to debug.

I feel that a little balance to Richard's comments about using VHDL variables is needed.  As you say, making code neat and understandable, is a good reason to use variables.

In the VHDL code example below, I show how two 8-bit std_logic_vector signals are added together and the result is stored in a 16-bit std_logic_vector.   I wanted to do this in one clock cycle (so, I can't use a bunch of VHDL signals), but I also want my code readable (so, I used the VHDL variables, tmp1 and tmp2).

 

 

    signal slv1,slv2 : std_logic_vector(7 downto 0);
    signal slv3 : std_logic_vector(15 downto 0);

    P1: process(CLK1) 
        variable tmp1 : unsigned(7 downto 0);
        variable tmp2 : unsigned(15 downto 0);           
    begin 
        if rising_edge(CLK1) then
            tmp1 := unsigned(slv1) + unsigned(slv2);  --do the math, result is 8-bit
            tmp2 := to_unsigned(to_integer(tmp1),16); --convert 8-bit result to 16-bit 
            slv3 <= std_logic_vector(tmp2);           --convert 16-bit unsigned to slv
        end if;           
    end process P1;

 

 


There are other ways to do what is done in my example code.  However, the point of my example is to show how the use of variables can make VHDL coding neater and more understandable.

Cheers,
Mark


Mark, thanks for your explanations. This is another aspect of variables that I might use in the near future, as I should be doing multiplications and summations. Thanks for your time and the illustrative example!

0 Kudos
Highlighted
Observer
Observer
362 Views
Registered: ‎04-03-2020

@calibra wrote:

Just another usefull example with variable.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
---------- count the number of '1' ----------
entity CONT4 is
PORT(A : in std_logic_vector(3 downto 0);
Y: out std_logic_vector(2 downto 0)
);
end CONT4;
architecture LOOP_BEH of CONT4 is
begin
process(A)
variable tmp : unsigned(2 downto 0);
begin
tmp := "000" ;
for I in 3 downto 0 loop
if(A(I)= '1' ) then
tmp := tmp + 1;
end if ;
end loop ;
Y <= std_logic_vector(tmp) ;
end process;
end LOOP_BEH;

Great! Quick question, is the for loop done after four clocks or just a single clock? My understanding is that it happens after four clocks, I am juts asking to double check it. Thanks!

0 Kudos
Highlighted
Scholar
Scholar
361 Views
Registered: ‎08-01-2012

markg@prosensing.com 

You do have to be a bit careful. Your example does the expansion to 16 bits after the add. So 0x80 + 0x80 will result in 0x0000 (8 bit result with no carry, expanded to 16. Personally, I would jus write this:

slv3 <= resize(unsigned(slv1), 16) + unsigned(slv2);

or remove type conversion altogether with VHDL 2008:

use ieee.numeric_std_unsigned.all; -- vhdl 2008

slv <= resize(slv1, slv'length) + slv2;

The addition works as the "+" function expands all values to the longest operand before the sum operation. Hence everything done at 16 bits.

But I agree variables can be useful for clarity.

Highlighted
Scholar
Scholar
352 Views
Registered: ‎08-01-2012

@Mason1 

In that example, no clocks are involved at all. Hence it is just a binary decode counting the number of bits in A. This code is functionally identical:

 

with A select
  Y <= "000" when "000",
       "001" when "001" | "010" | "100",
       "010" when "011" | "110" |  "101",
       "011" when "111",
       "XXX" when others;  -- pass through meta cases in simulation. Removed in synthesis.
Highlighted
Voyager
Voyager
348 Views
Registered: ‎06-20-2012

@Mason1 

For loop is always combinatorial.

In fact it is unrolled.

This is the design elaborated and synthesized.

 

== If this was helpful, please feel free to give Kudos, and close if it answers your question ==
X2.PNG
X1.PNG