Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Industrial programming >> VHDL

Cómo vincular las bibliotecas IP de Quartus Prime a VUnit

¿Alguna vez ha querido ejecutar una simulación VHDL que incluya un núcleo IP de Quartus a través del marco de verificación de VUnit?

Eso es lo que tenía en mente el ingeniero de FPGA Konstantinos Paraskevopoulos, pero no pudo encontrar un tutorial adecuado para ello. Afortunadamente, usó su talento para descubrir cómo hacerlo y tuvo la amabilidad de compartirlo con VHDLwhiz a través de este artículo invitado. .

¡Démosle la palabra a Konstantinos!

A menudo es deseable incorporar direcciones IP predefinidas del catálogo de direcciones IP de Quartus en su diseño al simular su sistema con VUnit. Por lo tanto, el siguiente tutorial tiene como objetivo proporcionar al lector conocimientos sobre cómo generar, incorporar y vincular bibliotecas IP de Quartus externas al entorno VUnit.

¿Nuevo en VUnit? Consulte este tutorial:Primeros pasos con VUnit

Resumen

Este tutorial consta de tres partes principales:

  1. Una breve descripción de la IP seleccionada
  2. Pasos necesarios para generar y vincular las bibliotecas adecuadas
  3. Verificación utilizando VUnit y Modelsim

Requisitos

También supone tener conocimientos básicos de VHDL y habilidades de ModelSim.

Diseño bajo prueba

Para nuestro escenario, utilizamos la IP del sumador paralelo de la lista de IP aritmética de enteros de Quartus.

Nuestro diseño acepta tres vectores de entrada de 16 bits y genera el resultado agregado en un vector de 17 bits.

Paso 1:Generar IP

Generamos nuestro sumador en la ventana del catálogo de IP haciendo doble clic en el componente del sumador paralelo en Biblioteca/Funciones básicas/Aritmética.

Después de proporcionar un nombre y personalizar nuestro componente según nuestras necesidades, hacemos clic en el botón Generar HDL en la parte inferior derecha.

En este punto, aparecerá una ventana, como se muestra en la siguiente figura.

Nota: Debemos configurar el Create simulation model bajo el Simulation sección a VHDL o Verilog para generar los archivos de simulación ya que la opción predeterminada es ninguno. Si no elegimos uno, el given_ip_name.spd no se generará el archivo, lo que provocará un error en el siguiente paso.

El proceso anterior genera un archivo y una carpeta bajo nuestro quartus directorio:

  1. Archivo:given_ip_name.ip
  2. Carpeta:given_ip_name

La carpeta contiene .vhd y .v archivos que deben agregarse más tarde en nuestro run.py guión.

Paso 2:generar archivos de simulación de IP

  1. GUI: Seleccione Herramientas ➤ Generar secuencia de comandos de configuración del simulador para IP y especifique el directorio de salida en la ventana de solicitud,
  2. CMD: Al utilizar los comandos de Qsys, podemos generar los mismos archivos escribiendo en la terminal el siguiente comando:

ip-setup-simulation --quartus-project= <project's_QPF_filepath>
--output-directory= <my_dir>

Usando uno de los dos métodos anteriores, le indicamos a Quartus que genere un directorio para cada simulador compatible que contenga un script para crear y compilar las bibliotecas IP.

Paso 3:generar y compilar bibliotecas IP para Modelsim

El siguiente paso es encontrar el msim_setup.tcl guión en el mentor carpeta creada por el paso anterior y duplicarla con el nombre setup.tcl . Luego, en el setup.tcl archivo, elimine los comentarios de los comandos ilustrados y configure el $QSYS_SIMDIR variables.


# # QSYS_SIMDIR is used in the Quartus-generated IP simulation script to
# # construct paths to the files required to simulate the IP in your Quartus
# # project. By default, the IP script assumes that you are launching the
# # simulator from the IP script location. If launching from another
# # location, set QSYS_SIMDIR to the output directory you specified when you
# # generated the IP script, relative to the directory from which you launch
# # the simulator.
# #
 set QSYS_SIMDIR <script generation output directory>
# #
# # Source the generated IP simulation script.
 source $QSYS_SIMDIR/mentor/msim_setup.tcl
# #
# # Set any compilation options you require (this is unusual).
# set USER_DEFINED_COMPILE_OPTIONS <compilation options>
# set USER_DEFINED_VHDL_COMPILE_OPTIONS <compilation options for VHDL>
# set USER_DEFINED_VERILOG_COMPILE_OPTIONS <compilation options for Verilog>
# #
# # Call command to compile the Quartus EDA simulation library.
 dev_com
# #
# # Call command to compile the Quartus-generated IP simulation files.
 com
# #

Después de modificar y guardar el setup.tcl , podemos ejecutar con seguridad el archivo Tcl usando el vsim comando.


vsim -c -do "do setup.tcl; quit"

Eso genera las bibliotecas compiladas en el mentor carpeta.

Paso 4:enlace de VUnit

Ahora que se han generado las bibliotecas de IP, debemos vincularlas mediante el run.py de python guión.

Consulte la figura a continuación para comprender mejor la estructura de directorios de nuestro ejemplo. La topología inicial constaba de la carpeta raíz demo , el tb , vunit y quartus carpetas Todas las subcarpetas y archivos bajo el quartus La carpeta se genera a través del marco Quartus después de crear un proyecto y completar los pasos 1 a 3.

Nota: Quartus genera más archivos y carpetas, pero la imagen de abajo muestra los que nos interesan.

Usando esta vista distinta de la topología como referencia, podemos especificar nuestra ruta ROOT y la(s) ruta(s) a las bibliotecas generadas, como se muestra a continuación.

Tenga en cuenta que sim_files es el directorio que especificamos en el paso 2 donde se ha almacenado la carpeta del mentor.


from vunit import VUnit
from os.path 
import join, dirname, abspath
# ROOT
root = join(dirname(__file__), '../')
# Path to generated libraries
path_2_lib = '/quartus/sim_files/mentor/libraries/'
# ROOT


Después de crear una instancia de VUnit llamada vu , podemos especificar una biblioteca de diseño para nuestro código VHDL y vincular las bibliotecas externas requeridas:

# Create VUnit instance by parsing command line arguments
vu = VUnit.from_argv()
# create design's library
my_lib = vu.add_library('my_lib')
# Link external library
vu.add_external_library("parallel_adder", root + path_2_lib + "parallel_adder")

Y finalmente, agregue nuestros archivos fuente. Estos se encuentran en tres subcarpetas bajo el given_ip_name directorio:

  1. parallel_add_191
  2. synth
  3. sim

El synth y sim dirs contienen la misma información, es decir, el diseño de nivel superior de nuestra IP. Sin embargo, el formateo de estos archivos en nuestro caso es en VHDL. Podrían estar en Verilog, y esto depende del idioma elegido en el paso 1.

En caso de que nuestro diseño de nivel superior implique subcomponentes, también debemos incluir sus archivos fuente. Se encuentran en subcarpetas en el given_ip_name directorio, como  el parallel_add_191 componente en nuestro caso.

 
my_lib.add_source_files(join(root,'quartus','parallel_adder','sim','parallel_adder.vhd'))
my_lib.add_source_files(join(root,'quartus','parallel_adder','parallel_add_191','sim','parallel_adder_parallel_add_191_oh4guxa.vhd'))
my_lib.add_source_files(join(root,'tb','tb_demo.vhd'))
testbench = my_lib.entity("tb_demo") 
vu.main()

Banco de pruebas

Para empezar, puede consultar este enlace para conocer los conceptos básicos de la formación del banco de pruebas VUnit.

Volviendo a nuestro banco de pruebas, agregamos las bibliotecas VUnit necesarias junto con cualquier otra biblioteca que nos gustaría emplear y definir nuestras señales.

Nota: La ejecución del proceso en nuestro ejemplo es secuencial. Por lo tanto, las señales de control (conocidas como banderas ) se utilizan para notificar un proceso si comenzará o terminará.

library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
library vunit_lib;
context vunit_lib.vunit_context;

entity tb_demo is 
generic ( runner_cfg : string:= runner_cfg_default); 
end tb_demo;
architecture sim of tb_demo is
constant clk_period : time := 10 ns;
signal clk : std_logic := '0';
signal rst : std_logic := '0';
-- INPUTS
signal data_a : std_logic_vector(0 to 15):= (others => '0');
signal data_b : std_logic_vector(0 to 15):= (others => '0');
signal data_c : std_logic_vector(0 to 15):= (others => '0');
-- OUTPUTS
signal result : std_logic_vector(0 to 16);
-- CONTROL FLAGS
signal reset_done :boolean := false;
signal sim_done   :boolean := false;
signal start_sim  :boolean := false;

A continuación, instanciamos nuestra UUT. Quartus proporciona ejemplos de creación de instancias de componentes para VHDL y Verilog bajo las convenciones de nombre de archivo ip_name_inst.vhd y ip_name_inst.v .

begin 
-- Unit Under Test 
UUT : entity work.parallel_adder
port map ( 
data0x => data_a, -- parallel_add_input.data0x 
data1x => data_b, --                   .data1x 
data2x => data_c, --                   .data2x 
result => result  -- parallel_add_output.result
); 

Los primeros dos procesos que comienzan son clk_process y reset_rel . Mientras que este último se suspende después de reiniciar y conducir el reset_done marcar a true , el clk_process opera durante todo el tiempo de simulación.

clk_process : process
begin 
  clk <= '1';
  wait for clk_period/2;
  clk <= '0'; 
  wait for clk_period/2; 
end process clk_process;

reset_rel : process
begin
  rst <= '1'; 
  wait for clk_period*2; 
  wait until rising_edge(clk); 
  rst <= not rst; 
  reset_done <= true; 
  wait; 
end process reset_rel;

Ahora que se ha realizado el reinicio, podemos invocar el test_runner proceso para ejecutar nuestras pruebas. Además, el corredor de prueba permanece activo hasta el sim_done la bandera se conduce a true , que tiene lugar en el último proceso.

test_runner : process
begin
  test_runner_setup(runner, runner_cfg);
  wait until reset_done and rising_edge(clk);

  iterate : while test_suite loop
    start_sim <= true;
    if run("test_case_1") then
      info ("Start");
      info (running_test_case);
      wait until sim_done;
    end if;
  end loop;
  test_runner_cleanup(runner);
end process test_runner;

Finalmente, el data_generator El proceso ejecuta varias sumas asignando valores a las tres entradas de nuestro sumador paralelo utilizando un for bucle.

Nota: Este proceso se activa cuando test_runner proceso lo indica configurando el start_sim bandera. Mientras que al final de este proceso, levanta el sim_done marca, ordenando al corredor de prueba que pause la simulación.

data_generator : process 
  constant tag2 : log_level_t := new_log_level("INFO", fg => blue, bg => black, style => bright);
  variable a,b,c,d : integer; 
begin 
  wait until start_sim;
   wait until rising_edge(clk); 
   show(display_handler, tag2);
   if running_test_case = "test_case_1" then
     for i in 0 to 10 loop
       data_a <= std_logic_vector(to_unsigned(i+10,data_a'length));
       data_b <= std_logic_vector(to_unsigned(i+20,data_a'length));
       data_c <= std_logic_vector(to_unsigned(i+30,data_a'length)); 
       wait until rising_edge(clk); 
       a := to_integer(unsigned(data_a)); 
       b := to_integer(unsigned(data_b)); 
       c := to_integer(unsigned(data_c)); 
       d := to_integer(unsigned(result)); 
       log( integer'image(a) &" + "& integer'image(b) &" + "& integer'image(c) 
          &" = "& integer'image(d), tag2); 
     end loop;
   end if; 
   sim_done <= true;
end process data_generator;

Verificación

Para ejecutar el caso de prueba y verificar que todo funciona como se esperaba, podemos ejecutar el run.py script del directorio en el que se encuentra simplemente escribiendo en la terminal el siguiente comando.


python ./run.py -v

Nota: Se ha utilizado un registrador personalizado para una mejor ilustración en nuestra salida que es visible al proporcionar el -v detallado opción. Además, dado que solo se define un caso de prueba, no tenemos que proporcionar una opción para especificarlo.

Finalmente, para verificar nuestros resultados en ModelSim, podríamos escribir el siguiente comando:

python ./run.py --gui

(Click en la imagen para agrandarla)

Conclusión

Para concluir, aprendimos en este tutorial sobre cómo incorporar y probar las IP de Quartus que residen en el catálogo de IP a VUnit. Empleamos una IP predefinida. Sin embargo, también podemos integrar IP personalizadas empaquetadas de esta manera en nuestro entorno VUnit.


Mira este tutorial de VUnit si aún no lo has hecho:
Cómo empezar con VUnit


VHDL

  1. ¿Qué es SigFox?
  2. Primeros pasos con VUnit
  3. Cómo crear una lista de cadenas en VHDL
  4. Cómo detener la simulación en un banco de pruebas VHDL
  5. Cómo crear un controlador PWM en VHDL
  6. Cómo generar números aleatorios en VHDL
  7. Cómo crear un banco de pruebas de autocomprobación
  8. Cómo la tecnología proporciona un vínculo crucial en las cadenas de suministro éticas
  9. Máquina de esgrima de eslabones de cadena:cómo funciona y el beneficiario
  10. cómo cebar la bomba hidráulica de engranajes
  11. cómo cebar la bomba hidráulica de un tractor ford