VHDL: use the length of an integer generic to determine number of select lines

匿名 (未验证) 提交于 2019-12-03 03:05:02

问题:

I'm trying to create a reusable barrel shifter; it takes an input array of bits and shifts them a certain number of positions (determined by another input). I want to parameterize the module so that it works for any n.

The number of select lines required is determined by n --> i.e., SHIFT_CNT = log2(NUMBITS-1)+1 in the code below. It's considered bad form in my organization (and I think overall) to have ports that are not of std_logic_vector or std_logic, so I used a std_logic_vector for the number of select lines. I need to adjust the length of the std_logic_vector based on the input generic. Is there a way to do this without using a second generic? I've seen this post, but it doesn't deal with generics. This post eliminates the generics entirely or uses the log value as the generic, which isn't as intuitive to future users (and could cause problems if the INPUT is not a power of two).

The declaration of SHIFT_CNT below is definitely incorrect; is there a way to automatically generate the length in the entity declaration without using a second generic?

entity BarrelShifter is  generic ( NUMBITS : integer :=8);                                                    Port    ( INPUT     : in   std_logic_vector (NUMBITS-1 downto 0);                           OUTPUT    : out  std_logic_vector (NUMBITS-1 downto 0);                           SHIFT_CNT : in   std_logic_vector ((NUMBITS-1)'length downto 0)                          );                                                                end BarrelShifter; 

回答1:

You can use the math library to calculate log2 and ceil of the logarit result to declare the size of SHIFT_CNT.

use IEEE.math_real.all; 

or specific functions

use IEEE.math_real."ceil"; use IEEE.math_real."log2"; 

For example you want to calculate clog2 of value a

result := integer(ceil(log2(real(a)))); 

If you just use these function to calculate paramater, your code is synthesizable (I did it).

If you don't want use it in entities, you can declare them in a library or generic with these functions.



回答2:

You can create a log2-function in a library, like this:

   function f_log2 (x : positive) return natural is       variable i : natural;    begin       i := 0;         while (2**i < x) and i < 31 loop          i := i + 1;       end loop;       return i;    end function; 

If the library is imported you may then specify the port like this:

shift_cnt : in std_logic_vector(f_log2(NUMBITS)-1 downto 0) 

It is a somewhat ugly solution, but it doesn't use any resources (since the function is pure and all the inputs are known at compile time).

I usually do this, but you may prefer specifying the log value as the generic like you're mentioning.



回答3:

Two alternative approaches:

You could work it backwards and have the generic as shift_bits - then calculate the width of the input and output vectors from that:

generic ( shift_bits: integer :=3);                                                    Port    ( INPUT     : in   std_logic_vector ((2**shift_bits)-1 downto 0);                           OUTPUT    : out  std_logic_vector ((2**shift_bits)-1 downto 0);                           SHIFT_CNT : in   std_logic_vector (shift_bits-1 downto 0)                          );  

Or treat the count as a number:

generic ( NUMBITS : integer :=8);                                                    Port    ( INPUT     : in   std_logic_vector (NUMBITS-1 downto 0);                           OUTPUT    : out  std_logic_vector (NUMBITS-1 downto 0);                           SHIFT_CNT : in   integer range 0 to numbits-1                          );   

and let the tools figure it out for you.



回答4:

When I was using the method mentioned by Khan, I encountered rounding errors. So I wrote my own versions, that are immune to rounding errors and can, in principle handle more than 32 bit. You can substitute the type of L with any Type that has a logical shift left operator.

Most of the time you want to use log2ceil which is the amount of bits required to store the given number, while log2floor can be more described as the highest bit set.

In most cases those functions are fine for synthesis as they are used for generating constants. So no hardware is inferred for them.

function log2ceil (L: POSITIVE) return NATURAL is     variable i, bitCount : natural; begin     i := L-1;     bitCount:=0;     while (i > 0) loop         bitCount := bitCount + 1;         i:=srlInteger(i,1);     end loop;     return bitCount; end log2ceil;  function log2floor (L: POSITIVE) return NATURAL is     variable i, bitCount : natural; begin     i := L;     bitCount:=0;     while (i > 1) loop         bitCount := bitCount + 1;         i:=srlInteger(i,1);     end loop;     return bitCount; end log2floor;  function srlInteger(arg: integer; s:natural) return integer is begin     return to_integer(SHIFT_RIGHT(to_UNSIGNED(ARG,32), s)); end srlInteger; 


回答5:

You can instead of inputting the NUMBITS value as 8, input it as 2 (log2(8)), then retype as below to get around the problem, your generic just won't be as clean but it is scale-able.

entity BarrelShifter is  generic ( NUMBITS : integer :=2);                                                    Port    ( INPUT     : in   std_logic_vector (((2**Nbits)-1) downto 0);                           OUTPUT    : out  std_logic_vector (((2**Nbits)-1) downto 0);                           SHIFT_CNT : in   std_logic_vector ((NUMBITS-1) downto 0)                          );                                                                end BarrelShifter; 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!