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:
- Eine kurze Beschreibung der ausgewählten IP
- Erforderliche Schritte zum Generieren und Verknüpfen der entsprechenden Bibliotheken
- Verifizierung durch Verwendung von VUnit und Modelsim
Anforderungen
- Quartus
- Quartus Prime herunterladen
- QSYS sollte sich in Ihrem PATH für SCHRITT 2 (CMD-Option) befinden
- Intel Modelsim
- Weitere Informationen zur kostenlosen Installation von ModelSim finden Sie in diesem Artikel
- ModelSim sollte sich in Ihrem PATH befinden
- VUnit
- In diesem Artikel erfahren Sie, wie Sie VUnit kostenlos installieren
- Python 3.6 oder höher
- Python herunterladen
- Python sollte auf Ihrem Weg sein
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:
- Datei:
given_ip_name.ip
- 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
- GUI: Wählen Sie Extras ➤ Simulator-Setup-Skript für IP generieren und geben Sie das Ausgabeverzeichnis im Eingabeaufforderungsfenster an
- 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:
parallel_add_191
synth
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
- Was ist SigFox?
- Erste Schritte mit VUnit
- So erstellen Sie eine Liste von Zeichenfolgen in VHDL
- So stoppen Sie die Simulation in einer VHDL-Testbench
- So erstellen Sie einen PWM-Controller in VHDL
- So erstellen Sie eine selbstüberprüfende Testbench
- Wie Technologie ein entscheidendes Glied in ethischen Lieferketten darstellt
- Maschendrahtzaunmaschine:Funktionsweise und Nutzen
- wie man eine hydraulische Zahnradpumpe ansaugt
- Wie man die Hydraulikpumpe eines Ford-Traktors ansaugt