2012-10-05 20 views
10

Estoy tratando de crear una palanca de cambios reutilizable; toma una matriz de bits de entrada y los desplaza a un cierto número de posiciones (determinada por otra entrada). Quiero parametrizar el módulo para que funcione para cualquier n.VHDL: use la longitud de un entero genérico para determinar el número de líneas de selección

El número de líneas de selección requeridas está determinado por n -> es decir, SHIFT_CNT = log2(NUMBITS-1)+1 en el código siguiente. Se considera una mala forma en mi organización (y creo que en general) tener puertos que no sean de std_logic_vector o std_logic, así que utilicé un std_logic_vector para el número de líneas de selección. Necesito ajustar la longitud del std_logic_vector según la entrada genérica. ¿Hay alguna manera de hacer esto sin usar un segundo genérico? He visto this publicación, pero no trata con genéricos. La publicación This elimina completamente los genéricos o utiliza el valor de registro como genérico, que no es tan intuitivo para los usuarios futuros (y podría causar problemas si el INPUT no tiene una potencia de dos).

La declaración de SHIFT_CNT a continuación es definitivamente incorrecta; ¿Hay alguna manera de generar automáticamente la longitud en la declaración de entidad sin usar un segundo genérico?

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; 

Respuesta

7

Se puede crear una función log2 en una biblioteca, así:

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; 

Si la biblioteca es importado a continuación, puede especificar el puerto de la siguiente manera:

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

Se es una solución algo fea, pero no utiliza ningún recurso (ya que la función es pura y todas las entradas se conocen en tiempo de compilación).

Normalmente hago esto, pero puede que prefiera especificar el valor de registro como genérico como el que está mencionando.

+0

Esa era una de mis preocupaciones: no quería escribir una función que requiriera recursos de FPGA para calcular. Todavía me gustaría algo que sea totalmente autónomo si es posible (en lugar de escribir una biblioteca y luego recordar incluirlo en cualquier lugar que lo necesite) – NickD

+0

Puedo ver por qué querrías eso (yo también lo haría, ya que es tal problema común!) pero estoy bastante seguro de que no hay una manera más elegante de hacerlo. En mi empresa tenemos una biblioteca con funciones comunes como esta que importamos en todos los archivos fuente. – pc3e

13

Puede usar la biblioteca matemática para calcular log2 y el límite del resultado de logarit para declarar el tamaño de SHIFT_CNT.

use IEEE.math_real.all; 

o funciones específicas

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

Por ejemplo que desea calcular clog2 del valor de un

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

Si sólo utiliza estas funciones para calcular parámetro de, su código es sintetizable(lo hice).

Si no desea usarlo en entidades, puede declararlas en una biblioteca o genérico con estas funciones.

+0

Gracias Khanh; Hice esto como una solución provisional, y las funciones ceil y log2 de alguna manera siempre me dan un poco más. Se borró de todos modos, pero esperaba que hubiera algo más compacto que no requiriera bibliotecas o recursos adicionales de FPGA. – NickD

+0

Quiere decir que quiere piso de log2 para un poco más pequeño. Por ejemplo, el resultado de log 2 es 1.34, el límite máximo es 2 y el piso es 1. Creo que esta biblioteca requerida es estándar (estándar IEEE) y no me importa. Otro método es usar 2 parámetros para declarar. En el archivo superior, puede usar esta función. – Khanh

+0

@ user1723509, utilizando una biblioteca de la forma descrita en esta u otra respuesta (http://stackoverflow.com/a/12751341/897968) no debe usar ningún recurso FPGA adicional, ya que la salida de la función puede se resuelve durante el tiempo de compilación/síntesis. – FriendFX

3

Dos enfoques alternativos:

se puede trabajar hacia atrás y tienen la generic como shift_bits - a continuación, calcular el ancho de los vectores de entrada y salida de ese:

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

o tratar el recuento como una número:

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

y deje que las herramientas lo resuelvan.

+0

Creo que en el caso de que BITWIDTH no sea de 2 de potencia, la primera declaración no es adecuada, la segunda forma es mejor. Hice un módulo con tipo de entrada/salida de tipo entero/naturaleza, pero mi colega no aceptó. Entonces, ¿hay algún problema con esto? ¿Se obtiene el tamaño de arreglo después de la síntesis? – Khanh

0

Cuando estaba usando el método mencionado por Khan, encontré errores de redondeo. Así que escribí mis propias versiones, que son inmunes a los errores de redondeo y que, en principio, pueden manejar más de 32 bits. Puede sustituir el tipo de L con cualquier Tipo que tenga un operador de desplazamiento lógico a la izquierda.

La mayor parte del tiempo desea utilizar log2ceil, que es la cantidad de bits necesarios para almacenar el número dado, mientras que log2floor se puede describir más como el conjunto de bits más alto.

En la mayoría de los casos, esas funciones son adecuadas para la síntesis ya que se utilizan para generar constantes. Entonces no se infiere ningún hardware para ellos.

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

Usted puede en vez de introducir el valor NUMBITS como 8, de entrada como 2 (log2 (8)), vuelva a escribir la siguiente manera a evitar el problema, el genérico no será tan limpio, pero es escalable.

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; 
Cuestiones relacionadas