Hoe Quartus Prime IP-bibliotheken aan VUnit te koppelen
Heb je ooit een VHDL-simulatie willen uitvoeren met een Quartus IP-kern via het VUnit-verificatieraamwerk?
Dat was wat FPGA-ingenieur Konstantinos Paraskevopoulos in gedachten had, maar hij kon er geen geschikte tutorial voor vinden. Gelukkig gebruikte hij zijn talent om erachter te komen hoe en was zo vriendelijk om het te delen met VHDLwhiz via dit gastartikel .
Laten we Konstantinos het woord geven!
Het is vaak wenselijk om vooraf gedefinieerde IP's uit de Quartus IP-catalogus in uw ontwerp op te nemen bij het simuleren van uw systeem met VUnit. Daarom is de volgende tutorial bedoeld om de lezer kennis te geven van het genereren, opnemen en koppelen van externe Quartus IP-bibliotheken aan de VUnit-omgeving.
Nieuw bij VUnit? Bekijk deze tutorial:Aan de slag met VUnit
Overzicht
Deze tutorial bestaat uit drie hoofdonderdelen:
- Een korte beschrijving van het geselecteerde IP
- Vereiste stappen om de juiste bibliotheken te genereren en te koppelen
- Verificatie door gebruik te maken van VUnit en Modelsim
Vereisten
- Kwartus
- Quartus Prime downloaden
- QSYS zou in uw PATH moeten staan voor STAP 2 (CMD-optie)
- Intel Modelsim
- Raadpleeg dit artikel voor informatie over het gratis installeren van ModelSim
- ModelSim zou in je PATH moeten staan
- VUnit
- Raadpleeg dit artikel voor informatie over het gratis installeren van VUnit
- Python 3.6 of hoger
- Python downloaden
- Python zou op je pad moeten zitten
Het veronderstelt ook basiskennis van VHDL en ModelSim-vaardigheden.
Ontwerp wordt getest
Voor ons scenario gebruiken we de Parallel Adder IP uit de Quartus Integer Arithmetic IP-lijst.
Ons ontwerp accepteert drie 16-bits invoervectoren en voert het toegevoegde resultaat uit in een 17-bits vector.
Stap 1:Genereer IP
We genereren onze opteller in het IP-catalogusvenster door te dubbelklikken op de parallelle optellercomponent onder Bibliotheek/Basisfuncties/Rekenen.
Nadat we een naam hebben gegeven en onze component hebben aangepast op basis van onze behoeften, klikken we rechtsonder op de knop HDL genereren.
Op dit punt verschijnt een venster, zoals weergegeven in de volgende afbeelding.
Opmerking: We moeten de Create simulation model
. instellen onder de Simulation
sectie naar VHDL of Verilog om de simulatiebestanden te genereren, aangezien de standaardoptie geen is. Als we er geen kiezen, de given_ip_name.spd
bestand wordt niet gegenereerd, waardoor de volgende stap mislukt.
Het bovenstaande proces genereert een bestand en een map onder onze quartus
map:
- Bestand:
given_ip_name.ip
- Map:
given_ip_name
De map bevat .vhd
en .v
bestanden die later in onze run.py
. moeten worden toegevoegd schrift.
Stap 2:Genereer IP-simulatiebestanden
- GUI: Selecteer Tools ➤ Genereer Simulator Setup Script voor IP en specificeer de uitvoermap in het promptvenster,
- CMD: Door Qsys-opdrachten te gebruiken, kunnen we dezelfde bestanden genereren door de volgende opdracht in de terminal te typen:
ip-setup-simulation --quartus-project= <project's_QPF_filepath> --output-directory= <my_dir>
Met behulp van een van de twee bovenstaande methoden instrueren we Quartus om een map te genereren voor elke ondersteunde simulator die een script bevat om de IP-bibliotheken te maken en te compileren.
Stap 3:Genereer en compileer IP-bibliotheken voor Modelsim
De volgende stap is het vinden van de msim_setup.tcl
script in de mentor
map gemaakt door de vorige stap en dupliceer deze met de naam setup.tcl
. Dan, in de setup.tcl
bestand, verwijder de commentaar bij de geïllustreerde commando's en stel de $QSYS_SIMDIR
. in variabel.
# # 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 # #
Na het wijzigen en opslaan van de setup.tcl
, kunnen we het Tcl-bestand veilig uitvoeren met behulp van de vsim
commando.
vsim -c -do "do setup.tcl; quit"
Dat genereert de gecompileerde bibliotheken in de mentor
map.
Stap 4:VUnit-link
Nu de IP-bibliotheken zijn gegenereerd, moeten we ze koppelen met behulp van de python run.py
schrift.
Bekijk de onderstaande afbeelding om de directorystructuur van ons voorbeeld beter te begrijpen. De initiële topologie bestond uit de hoofdmap demo
, de tb
, vunit
, en quartus
mappen. Alle submappen en bestanden onder de quartus
map worden gegenereerd via het Quartus-framework na het maken van een project en het voltooien van stap 1 tot 3.
Opmerking: Quartus genereert meer bestanden en mappen, maar de afbeelding hieronder toont de bestanden die voor ons interessant zijn.
Door deze duidelijke weergave van de topologie als referentie te gebruiken, kunnen we ons ROOT-pad en de paden naar de gegenereerde bibliotheken specificeren, zoals hieronder weergegeven.
Merk op dat sim_files
is de map die we in stap 2 hebben opgegeven waar de mentormap is opgeslagen.
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
Na het maken van een VUnit-instantie met de naam vu
, kunnen we een ontwerpbibliotheek voor onze VHDL-code specificeren en alle vereiste externe bibliotheken koppelen:
# 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")
En tot slot, voeg onze bronbestanden toe. Deze bevinden zich in drie submappen onder de given_ip_name
map:
parallel_add_191
synth
sim
De synth
en sim
dirs bevatten dezelfde informatie, namelijk het ontwerp op het hoogste niveau van onze IP. De opmaak van deze bestanden is in ons geval echter in VHDL. Ze kunnen in Verilog staan, en dit hangt af van de gekozen taal bij stap 1.
Als ons ontwerp op het hoogste niveau subcomponenten bevat, moeten we ook hun bronbestanden opnemen. Ze bevinden zich onder submappen in de given_ip_name
directory, zoals de parallel_add_191
component in ons geval.
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()
Testbank
Om te beginnen kun je deze link bekijken om meer te weten te komen over de basisprincipes van VUnit-testbench-formatie.
Terug naar onze testbank voegen we de benodigde VUnit-bibliotheken toe, samen met elke andere bibliotheek die we zouden willen gebruiken en definiëren onze signalen.
Opmerking: De procesuitvoering in ons voorbeeld is sequentieel. Dus stuursignalen (aangeduid als vlaggen ) worden gebruikt om een proces te melden of het zal beginnen of eindigen.
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;
Vervolgens instantiëren we onze UUT. Quartus levert voorbeelden van componentinstantiatie voor VHDL en Verilog onder de bestandsnaamconventies ip_name_inst.vhd
en 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 );
De eerste twee processen die beginnen zijn clk_process
en reset_rel
. Terwijl de laatste wordt onderbroken na het resetten en besturen van de reset_done
markeer naar true
, de clk_process
werkt gedurende de hele simulatietijd.
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;
Nu de reset is voltooid, kunnen we de test_runner
. aanroepen proces voor het uitvoeren van onze tests. Verder blijft de testloper actief tot de sim_done
vlag wordt gestuurd naar true
, die plaatsvindt in het laatste proces.
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;
Eindelijk, de data_generator
proces voert verschillende toevoegingen uit door waarden toe te kennen aan de drie ingangen van onze parallelle opteller door gebruik te maken van een for
lus.
Opmerking: Dit proces wordt geactiveerd wanneer de test_runner
proces instrueert dit door de start_sim
. in te stellen vlag. Aan het einde van dit proces verhoogt het de sim_done
vlag, die de testloper opdracht geeft om de simulatie te pauzeren.
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;
Verificatie
Om de testcase uit te voeren en te controleren of alles werkt zoals verwacht, kunnen we de run.py
. uitvoeren script uit de map waarin het zich bevindt door simpelweg de volgende opdracht in de terminal te typen.
python ./run.py -v
Opmerking: Er is een aangepaste logger gebruikt voor een betere illustratie in onze uitvoer die zichtbaar is door de uitgebreide -v
te leveren keuze. Omdat er slechts één testcase is gedefinieerd, hoeven we bovendien geen optie te bieden om deze te specificeren.
Ten slotte, om onze resultaten in ModelSim te verifiëren, kunnen we het volgende commando typen:
python ./run.py --gui
(Klik op de afbeelding om deze groter te maken)
Conclusie
Tot slot hebben we in deze tutorial geleerd hoe je Quartus IP's die zich in de IP-catalogus bevinden, in VUnit kunt opnemen en testen. We hebben een vooraf gedefinieerd IP-adres gebruikt. We kunnen echter ook verpakte aangepaste IP's op deze manier integreren in onze VUnit-omgeving.
Bekijk deze VUnit-zelfstudie als je dat nog niet hebt gedaan:
Aan de slag met VUnit
VHDL
- Wat is SigFox?
- Aan de slag met VUnit
- Een lijst met strings maken in VHDL
- Simulatie stoppen in een VHDL-testbench
- Een PWM-controller maken in VHDL
- Hoe willekeurige getallen te genereren in VHDL
- Hoe maak je een zelfcontrolerende testbank aan
- Hoe technologie een cruciale schakel vormt in ethische toeleveringsketens
- Chain Link Fencing Machine:hoe het werkt en de begunstigde
- hydraulische tandwielpomp vullen
- hoe de hydraulische pomp van een ford-tractor te vullen