VHDL: используйте длину целочисленного общего для определения количества выделенных строк

Я пытаюсь создать многоразовый баррель; он принимает входной массив бит и сдвигает их на определенное количество позиций (определяется другим входом). Я хочу параметризовать модуль, чтобы он работал для любого n.

Количество требуемых строк выбора определяется в n → i.e., SHIFT_CNT = log2(NUMBITS-1)+1 в приведенном ниже коде. Он считал плохую форму в моей организации (и, я думаю, в целом), чтобы иметь порты, которые не относятся к std_logic_vector или std_logic, поэтому я использовал std_logic_vector для количества выбранных строк. Мне нужно отрегулировать длину std_logic_vector на основе общего ввода. Есть ли способ сделать это, не используя второй общий? Я видел этот пост, но он не касается дженериков. Это сообщение полностью исключает генерики или использует значение журнала как общее, что не так интуитивно для будущих пользователей (и может вызвать проблемы, если INPUT не является мощность двух).

Декларация 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;

Ответ 1

Вы можете использовать математическую библиотеку для вычисления log2 и ceil результата логарифма, чтобы объявить размер SHIFT_CNT.

use IEEE.math_real.all;

или конкретные функции

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

Например, вы хотите вычислить clog2 значения a

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

Если вы просто используете эту функцию для вычисления paramater, ваш код синтезируется (я сделал это).

Если вы не хотите использовать его в объектах, вы можете объявить их в библиотеке или обобщенном с помощью этих функций.

Ответ 2

Вы можете создать функцию 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)

Это несколько уродливое решение, но оно не использует никаких ресурсов (поскольку функция чиста и все входы известны во время компиляции).

Обычно я это делаю, но вы можете указать значение журнала как общее, как вы упоминаете.

Ответ 3

Два альтернативных подхода:

Вы можете работать в обратном направлении и иметь generic как 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                 
        );  

и инструменты помогут вам разобраться.

Ответ 4

Когда я использовал метод, упомянутый Хан, я столкнулся с ошибками округления. Поэтому я написал свои собственные версии, которые невосприимчивы к ошибкам округления и могут, в принципе, обрабатывать более 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;

Ответ 5

Вместо того, чтобы вводить значение 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;