¿Es posible aplicar la restricción de rango STD_LOGIC_VECTOR de abajo hacia arriba?

Sé que las entidades pueden usar tipos de matriz sin restricciones (como STD_LOGIC_VECTOR) en su lista de puertos, que se dimensionarán automáticamente para que coincidan con la señal conectada en el mapa del puerto cuando se instancian (y posiblemente diferentes tamaños para cada instancia). Dentro de la entidad, los atributos como 'LENGTHy 'HIGHse pueden usar para descubrir el rango instanciado real.

Tengo un objeto de este tipo, que es un convertidor paralelo -> serie (acepta entradas de cualquier tamaño, las entradas más anchas requieren más ciclos de reloj para escupir).

¿Es posible hacer que la inferencia de rango funcione a la inversa, es decir, tener el rango especificado en un subcomponente, aplicado a una señal sin restricciones en el componente principal y propagado desde allí a otros componentes?

Más detalles:

Mi aplicación tiene una serie de subcomponentes de fuentes de datos que producen flujos de datos de varios anchos, lógica de arbitraje para muestrear y serializar estas fuentes por turnos, y convertidores paralelo->serie que realizan la serialización real y el protocolo de enlace con la lógica de arbitraje del bus.

En este momento, tengo los anchos de señal especificados como constantes en un paquete, pero esto significa que cada vez que cambia el formato de datos de transmisión, tengo que cambiar tanto el subcomponente de origen como el paquete. Realmente me gustaría que el ancho se especifique solo en el componente de origen, ya que los componentes posteriores se adaptan a cualquier ancho.

Respuestas (1)

Lo mejor es usar genéricos. Aquí hay una declaración de entidad de ejemplo para un registro de desplazamiento:

entity shift_register is
  generic (n_bits :integer := 8);
  port (clk  :std_logic;
        din  :std_logic_vector (n_bits-1 downto 0);
        dout :std_logic);
end entity shift_register;

Cuando crea una instancia de este registro de desplazamiento, lo haría así:

signal data :std_logic_vector (15 downto 0);
...
U0:  shift_register 
  generic map (n_bits => data'length)
  port map (clk, din, out);

En la entidad, definí el valor predeterminado de n_bits en 8. Cuando lo instalé, podría haber dejado el mapa genérico y luego se usaría el valor predeterminado de n_bits.

EDITAR: Para responder mejor a tu pregunta. Ir en "reversa" realmente no funciona tan bien, y lo evitaría si es posible. Pero si es necesario, siempre puede declarar algunas constantes en su paquete y usarlas más adelante. No es muy limpio, pero funciona.

Esto es exactamente lo que tengo ahora, en realidad. Y tengo que editar varios archivos cuando cambia el ancho de datos. Supongo que no hay forma de evitarlo. Es posible que pueda reorganizar las cosas y mover la creación de instancias del subcomponente paralelo-> serial dentro del componente que conoce el ancho, luego puedo pasar una interfaz serial de ancho fijo al nivel superior.
@Ben Voigt Si lo hizo bien, no debería tener que editar varios archivos cuando cambia el ancho de los datos. Mi regla para todo es: si tiene que ingresar la información más de una vez, la ingresará incorrectamente más de una vez. He hecho muchos FPGA en los que solo ingreso una parte de la información una vez y el resto del código simplemente lo resuelve.
@David: tengo un componente que proporciona los datos, algo así como parallel_out <= some_data & some_more_data & even_more_data;. Eso realmente controla qué tan ancho debe ser el puerto de salida, cuando agrego yet_more_dataa la salida, el rango de la matriz tiene que aumentar. Luego necesito una constante en un archivo de paquete, para hacer que todas las señales que enrutan esos datos coincidan con el ancho, y la necesidad de mantener eso sincronizado es lo que estoy tratando de eliminar.
@Ben Puedes hacer matemáticas con los genéricos y las constantes. Simplemente ponga esa matemática en el cálculo de sus tamaños de SLV. Algo así como "signal parallel_out :slv (some_data_bits+some_more_data_bits+even_more_bits-1 downto 0)". Recuerde: ingrese la información una vez, calcule todo lo demás.
@David: ¿Entonces ahora necesito tres constantes en lugar de una? Eso no es una mejora. Y no hay ninguna razón para que ningún componente fpga que no sea la fuente de datos conozca los tamaños de los campos individuales. (Obviamente, el microcontrolador que recibe el flujo en serie debe saberlo, pero no espero poder compartir esta información entre C y VHDL)
@Ben O no lo entiendes o no entiendo lo que dices. Y puede compartir cosas entre C y VHDL si está lo suficientemente determinado. Sí. Incluso escribí un programa que lee mi lista de conexiones de PCB y cambia los archivos VHDL y UCF para que coincidan con la PCB.
@David: Por ejemplo, un flujo de datos es el estado de la batería. El maestro I2C consulta la batería, extrae los bits de interés, los pasa a un transmisor asíncrono que maneja el encuadre, CRC, etc. para que pueda ser recibido por un periférico uC UART. Cuando mi jefe me pide tomar un par de bits adicionales, solo debería modificar la lógica para realizar un seguimiento de la transacción I2C y bloquear los bits del puerto de salida. Pero desafortunadamente, la entidad de nivel superior, que conecta el lado de la fuente (I2C) con el lado del receptor (UART), también necesita conocer el ancho de los datos paralelos.
Sin embargo, es más complicado que eso, porque los datos entrantes tienen una suma de verificación (el puerto de salida se cambia solo si la suma de verificación coincide) y los datos salientes se intercalan con un montón de otras transmisiones que compiten por el mismo UART.