14

我正在尝试创建一个可重复使用的桶形移位器;它需要一个输入位数组并将它们移动一定数量的位置(由另一个输入确定)。我想对模块进行参数化,使其适用于任何n.

所需的选择行数由n--> 确定,即SHIFT_CNT = log2(NUMBITS-1)+1在下面的代码中。std_logic_vector在我的组织中(我认为总体而言),拥有不属于or的端口被认为是一种不好的形式std_logic,因此我使用 astd_logic_vector作为选择行的数量。我需要std_logic_vector根据输入通用调整长度。有没有办法在不使用第二个泛型的情况下做到这一点?我看过这篇文章,但它不涉及泛型。这篇文章完全消除了泛型或使用 log 值作为泛型,这对未来的用户来说不是那么直观(如果INPUT不是 2 的幂,可能会导致问题)。

下面的声明SHIFT_CNT肯定是不正确的;有没有办法在不使用第二个泛型的情况下自动生成实体声明中的长度?

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;
4

5 回答 5

21

您可以使用数学库计算对数结果的 log2 和 ceil 来声明 SHIFT_CNT 的大小。

use IEEE.math_real.all;

或特定功能

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

例如,您要计算值 a 的 clog2

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

如果你只是使用这些函数来计算参数,你的代码是可综合的 (我做到了)

如果您不想在实体中使用它,您可以在库中声明它们或使用这些函数进行泛型。

于 2012-10-06T07:18:38.397 回答
9

您可以在库中创建 log2 函数,如下所示:

   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;

如果库被导入,您可以像这样指定端口:

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

这是一个有点丑陋的解决方案,但它不使用任何资源(因为该函数是纯函数并且所有输入在编译时都是已知的)。

我通常这样做,但您可能更喜欢将日志值指定为您提到的通用值。

于 2012-10-05T17:38:45.153 回答
5

两种替代方法:

您可以向后工作并使用genericas shift_bits- 然后从中计算输入和输出向量的宽度:

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)                 
        ); 

或将计数视为一个数字:

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                 
        );  

并让工具为您解决问题。

于 2012-10-08T12:51:33.367 回答
1

您可以不将 NUMBITS 值输入为 8,而是将其输入为 2 (log2(8)),然后按如下方式重新键入以解决该问题,您的泛型不会那么干净,但它是可扩展的。

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;
于 2017-02-21T13:10:29.180 回答
0

当我使用Khan提到的方法时,我遇到了舍入错误。所以我写了我自己的版本,它不受舍入错误的影响,原则上可以处理超过 32 位。您可以将 L 的类型替换为具有逻辑左移运算符的任何类型。

大多数情况下,您希望使用 log2ceil,它是存储给定数字所需的位数,而 log2floor 可以更多地描述为最高位集。

在大多数情况下,这些函数很适合合成,因为它们用于生成常量。因此没有为它们推断硬件。

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;
于 2014-05-19T15:55:45.347 回答