Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Industrial programming >> VHDL

So verknüpfen Sie Quartus Prime IP-Bibliotheken mit VUnit

Wollten Sie schon immer eine VHDL-Simulation ausführen, die einen Quartus-IP-Core über das VUnit-Verifizierungsframework enthält?

Das hatte FPGA-Ingenieur Konstantinos Paraskevopoulos im Sinn, konnte aber kein passendes Tutorial dafür finden. Glücklicherweise nutzte er sein Talent, um herauszufinden, wie und war so freundlich, es mit VHDLwhiz durch diesen Gastartikel zu teilen .

Lass uns Konstantinos das Wort geben!

Es ist oft wünschenswert, vordefinierte IPs aus dem Quartus IP-Katalog in Ihr Design zu integrieren, wenn Sie Ihr System mit VUnit simulieren. Daher zielt das folgende Tutorial darauf ab, dem Leser Kenntnisse über das Generieren, Einbinden und Verknüpfen externer Quartus-IP-Bibliotheken mit der VUnit-Umgebung zu vermitteln.

Neu bei VUnit? Sehen Sie sich dieses Tutorial an:Erste Schritte mit VUnit

Übersicht

Dieses Tutorial besteht aus drei Hauptteilen:

  1. Eine kurze Beschreibung der ausgewählten IP
  2. Erforderliche Schritte zum Generieren und Verknüpfen der entsprechenden Bibliotheken
  3. Verifizierung durch Verwendung von VUnit und Modelsim

Anforderungen

Außerdem werden grundlegende VHDL-Kenntnisse und ModelSim-Kenntnisse vorausgesetzt.

Design im Test

Für unser Szenario verwenden wir die Parallel Adder IP aus der Quartus Integer Arithmetic IP-Liste.

Unser Design akzeptiert drei 16-Bit-Eingabevektoren und gibt das addierte Ergebnis in einem 17-Bit-Vektor aus.

Schritt 1:IP generieren

Wir generieren unseren Addierer im IP-Katalogfenster, indem wir unter Bibliothek/Basisfunktionen/Arithmetik auf die parallele Addiererkomponente doppelklicken.

Nachdem wir einen Namen vergeben und unsere Komponente entsprechend unseren Anforderungen angepasst haben, klicken wir unten rechts auf die Schaltfläche HDL generieren.

An dieser Stelle erscheint ein Fenster, wie in der folgenden Abbildung dargestellt.

Hinweis: Wir müssen den Create simulation model setzen unter Simulation Abschnitt entweder zu VHDL oder Verilog, um die Simulationsdateien zu generieren, da die Standardoption keine ist. Wenn wir keinen auswählen, den given_ip_name.spd Datei wird nicht generiert, wodurch der nächste Schritt fehlschlägt.

Der obige Prozess generiert eine Datei und einen Ordner unter unserem quartus Verzeichnis:

  1. Datei:given_ip_name.ip
  2. Ordner:given_ip_name

Der Ordner beinhaltet .vhd und .v Dateien, die später in unserem run.py hinzugefügt werden müssen Skript.

Schritt 2:Generieren Sie IP-Simulationsdateien

  1. GUI: Wählen Sie Extras ➤ Simulator-Setup-Skript für IP generieren und geben Sie das Ausgabeverzeichnis im Eingabeaufforderungsfenster an
  2. CMD: Durch die Verwendung von Qsys-Befehlen können wir dieselben Dateien generieren, indem wir im Terminal den folgenden Befehl eingeben:

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

Mit einer der beiden oben genannten Methoden weisen wir Quartus an, ein Verzeichnis für jeden unterstützten Simulator zu erstellen, das ein Skript enthält, um die IP-Bibliotheken zu erstellen und zu kompilieren.

Schritt 3:Generieren und kompilieren Sie IP-Bibliotheken für Modelsim

Der nächste Schritt besteht darin, den msim_setup.tcl zu finden Skript im mentor Ordner, der im vorherigen Schritt erstellt wurde, und duplizieren Sie ihn mit dem Namen setup.tcl . Dann im setup.tcl Datei, kommentieren Sie die abgebildeten Befehle aus und setzen Sie den $QSYS_SIMDIR Variable.


# # 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
# #

Nach dem Ändern und Speichern des setup.tcl , können wir die Tcl-Datei sicher mit vsim ausführen Befehl.


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

Das erzeugt die kompilierten Bibliotheken im mentor Ordner.

Schritt 4:VUnit-Link

Nachdem die IP-Bibliotheken generiert wurden, sollten wir sie mit dem Python run.py verknüpfen Skript.

Schauen Sie sich die folgende Abbildung an, um die Verzeichnisstruktur unseres Beispiels besser zu verstehen. Die anfängliche Topologie bestand aus dem Stammordner demo , die tb , vunit , und quartus Ordner. Alle Unterordner und Dateien unter quartus Ordner werden über das Quartus-Framework generiert, nachdem ein Projekt erstellt und die Schritte 1 bis 3 abgeschlossen wurden.

Hinweis: Quartus generiert mehr Dateien und Ordner, aber das Bild unten zeigt die für uns interessanten.

Unter Verwendung dieser eindeutigen Ansicht der Topologie als Referenz können wir unseren ROOT-Pfad und den/die Pfad(e) zu den generierten Bibliotheken angeben, wie unten gezeigt.

Beachten Sie, dass sim_files ist das Verzeichnis, das wir in Schritt 2 angegeben haben, in dem der Mentor-Ordner gespeichert wurde.


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


Nach dem Erstellen einer VUnit-Instanz namens vu , können wir eine Designbibliothek für unseren VHDL-Code angeben und alle erforderlichen externen Bibliotheken verknüpfen:

# 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")

Und schließlich fügen Sie unsere Quelldateien hinzu. Diese befinden sich in drei Unterordnern unter given_ip_name Verzeichnis:

  1. parallel_add_191
  2. synth
  3. sim

Der synth und sim dirs enthalten dieselben Informationen, nämlich das Top-Level-Design unserer IP. Die Formatierung dieser Dateien ist in unserem Fall jedoch in VHDL. Sie könnten in Verilog sein, und dies hängt von der in Schritt 1 gewählten Sprache ab.

Falls unser Top-Level-Design Unterkomponenten umfasst, müssen wir auch deren Quelldateien einbeziehen. Sie befinden sich unter Unterordnern im given_ip_name Verzeichnis, z. B. parallel_add_191 Komponente in unserem Fall.

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

Testbench

Zunächst können Sie sich diesen Link ansehen, um mehr über die Grundlagen der VUnit-Testbench-Bildung zu erfahren.

Zurück zu unserer Testbench fügen wir die erforderlichen VUnit-Bibliotheken zusammen mit allen anderen Bibliotheken hinzu, die wir verwenden möchten, und definieren unsere Signale.

Hinweis: Die Prozessausführung in unserem Beispiel ist sequentiell. Somit können Steuersignale (als Flags bezeichnet ) werden verwendet, um einen Prozess darüber zu informieren, ob er beginnen oder enden soll.

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;

Anschließend instanziieren wir unseren UUT. Quartus liefert Beispiele für die Komponenteninstanziierung für VHDL und Verilog unter den Dateinamenskonventionen ip_name_inst.vhd und 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
); 

Die ersten beiden beginnenden Prozesse sind clk_process und reset_rel . Während letzteres nach dem Zurücksetzen und Fahren des reset_done ausgesetzt wird Flag auf true , der clk_process arbeitet während der gesamten Simulationszeit.

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;

Nachdem das Zurücksetzen abgeschlossen ist, können wir den test_runner aufrufen Prozess zur Durchführung unserer Tests. Außerdem bleibt der Testrunner bis zum sim_done aktiv Flag wird auf true gesetzt , die im letzten Prozess stattfindet.

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;

Schließlich die data_generator Der Prozess führt mehrere Additionen durch, indem er den drei Eingängen unseres parallelen Addierers Werte zuweist, indem er einen for verwendet Schleife.

Hinweis: Dieser Vorgang wird ausgelöst, wenn test_runner Der Prozess weist dies an, indem er start_sim einrichtet Flagge. Am Ende dieses Vorgangs wird sim_done ausgegeben Flag, das dem Testrunner befiehlt, die Simulation anzuhalten.

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;

Verifizierung

Um den Testfall auszuführen und zu überprüfen, ob alles wie erwartet funktioniert, können wir run.py ausführen script aus dem Verzeichnis, in dem es sich befindet, indem Sie einfach den folgenden Befehl im Terminal eingeben.


python ./run.py -v

Hinweis: Zur besseren Veranschaulichung in unserer Ausgabe wurde ein benutzerdefinierter Logger verwendet, der durch die Bereitstellung des ausführlichen -v sichtbar ist Möglichkeit. Da nur ein Testfall definiert ist, müssen wir außerdem keine Option bereitstellen, um ihn anzugeben.

Schließlich könnten wir zur Überprüfung unserer Ergebnisse in ModelSim den folgenden Befehl eingeben:

python ./run.py --gui

(Zum Vergrößern auf das Bild klicken)

Schlussfolgerung

Abschließend haben wir in diesem Tutorial gelernt, wie Quartus-IPs, die sich im IP-Katalog befinden, in VUnit integriert und getestet werden. Wir haben eine vordefinierte IP verwendet. Allerdings können wir auf diese Weise auch kundenspezifische IP-Pakete in unsere VUnit-Umgebung integrieren.


Sehen Sie sich dieses VUnit-Tutorial an, falls Sie es noch nicht getan haben:
Erste Schritte mit VUnit


VHDL

  1. Was ist SigFox?
  2. Erste Schritte mit VUnit
  3. So erstellen Sie eine Liste von Zeichenfolgen in VHDL
  4. So stoppen Sie die Simulation in einer VHDL-Testbench
  5. So erstellen Sie einen PWM-Controller in VHDL
  6. So erstellen Sie eine selbstüberprüfende Testbench
  7. Wie Technologie ein entscheidendes Glied in ethischen Lieferketten darstellt
  8. Maschendrahtzaunmaschine:Funktionsweise und Nutzen
  9. wie man eine hydraulische Zahnradpumpe ansaugt
  10. Wie man die Hydraulikpumpe eines Ford-Traktors ansaugt