VHDL
VUnit 검증 프레임워크를 통해 Quartus IP 코어를 포함하는 VHDL 시뮬레이션을 실행하고 싶었던 적이 있습니까?
이것이 FPGA 엔지니어인 Konstantinos Paraskevopoulos가 염두에 두었지만 적절한 튜토리얼을 찾지 못했습니다. 다행히 그는 자신의 재능을 활용하여 이 게스트 기사를 통해 VHDLwhiz와 공유하는 방법을 알아냈습니다. .
콘스탄티노스에게 한마디 합시다!
VUnit으로 시스템을 시뮬레이션할 때 Quartus IP 카탈로그에서 미리 정의된 IP를 설계에 통합하는 것이 종종 바람직합니다. 따라서 다음 튜토리얼은 독자에게 외부 Quartus IP 라이브러리를 생성, 통합 및 VUnit 환경에 연결하는 지식을 제공하는 것을 목표로 합니다.
VUnit이 처음이신가요? 이 튜토리얼을 확인하세요:VUnit 시작하기
이 튜토리얼은 세 가지 주요 부분으로 구성되어 있습니다.
또한 기본적인 VHDL 지식과 ModelSim 기술이 있다고 가정합니다.
우리 시나리오에서는 Quartus Integer Arithmetic IP 목록에서 Parallel Adder IP를 사용합니다.
우리의 디자인은 3개의 16비트 입력 벡터를 받아들이고 추가된 결과를 17비트 벡터로 출력합니다.
Library/Basic functions/Arithmetic에서 병렬 가산기 구성 요소를 두 번 클릭하여 IP 카탈로그 창에서 가산기를 생성합니다.
이름을 제공하고 필요에 따라 구성 요소를 사용자 정의한 후 오른쪽 하단에 있는 HDL 생성 버튼을 클릭합니다.
이 때 다음 그림과 같은 창이 나타납니다.
참고: Create simulation model
을 설정해야 합니다. Simulation
아래 섹션을 VHDL 또는 Verilog로 변환하여 기본 옵션이 없음이므로 시뮬레이션 파일을 생성합니다. 하나를 선택하지 않으면 given_ip_name.spd
파일이 생성되지 않아 다음 단계가 실패합니다.
위의 프로세스는 quartus
아래에 파일과 폴더를 생성합니다. 디렉토리:
given_ip_name.ip
given_ip_name
폴더에는 .vhd
이 포함됩니다. 및 .v
나중에 run.py
에 추가해야 하는 파일 스크립트.
ip-setup-simulation --quartus-project= <project's_QPF_filepath> --output-directory= <my_dir>
위의 두 가지 방법 중 하나를 사용하여 Quartus가 지원되는 각 시뮬레이터에 대해 IP 라이브러리를 생성하고 컴파일하는 스크립트를 포함하는 디렉토리를 생성하도록 지시합니다.
다음 단계는 msim_setup.tcl
를 찾는 것입니다. mentor
의 스크립트 이전 단계에서 만든 폴더를 만들고 setup.tcl
이름으로 복제합니다. . 그런 다음 setup.tcl
에서 파일에서 설명된 명령의 주석 처리를 제거하고 $QSYS_SIMDIR
을 설정합니다. 변수.
# # 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 # #
setup.tcl
변경 및 저장 후 , vsim
를 사용하여 Tcl 파일을 안전하게 실행할 수 있습니다. 명령.
vsim -c -do "do setup.tcl; quit"
mentor
에 컴파일된 라이브러리를 생성합니다. 폴더.
이제 IP 라이브러리가 생성되었으므로 python run.py
을 사용하여 링크해야 합니다. 스크립트.
예제의 디렉토리 구조를 더 잘 이해하려면 아래 그림을 확인하십시오. 초기 토폴로지는 루트 폴더 demo
로 구성되었습니다. , tb
, vunit
및 quartus
폴더. quartus
아래의 모든 하위 폴더 및 파일 폴더는 프로젝트를 생성하고 1~3단계를 완료한 후 Quartus 프레임워크를 통해 생성됩니다.
참고: Quartus는 더 많은 파일과 폴더를 생성하지만 아래 이미지는 우리가 관심을 갖는 것을 보여줍니다.
이 독특한 토폴로지 보기를 참조로 사용하여 아래와 같이 ROOT 경로와 생성된 라이브러리에 대한 경로를 지정할 수 있습니다.
sim_files
멘토 폴더가 저장된 2단계에서 지정한 디렉토리입니다.
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
vu
라는 VUnit 인스턴스를 만든 후 , VHDL 코드에 대한 디자인 라이브러리를 지정하고 필요한 외부 라이브러리를 연결할 수 있습니다.
# 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")
마지막으로 소스 파일을 추가합니다. 이는 given_ip_name
아래의 3개의 하위 폴더에 있습니다. 디렉토리:
parallel_add_191
synth
sim
synth
및 sim
dirs에는 동일한 정보, 즉 우리 IP의 최상위 디자인이 포함되어 있습니다. 그러나 우리의 경우 이러한 파일의 형식은 VHDL입니다. Verilog에 있을 수 있으며 이는 1단계에서 선택한 언어에 따라 다릅니다.
최상위 디자인에 하위 구성 요소가 포함된 경우 해당 소스 파일도 포함해야 합니다. given_ip_name
의 하위 폴더 아래에 있습니다. 디렉토리(예:parallel_add_191
) 우리의 경우 구성 요소입니다.
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()
먼저 이 링크를 확인하여 VUnit 테스트벤치 구성의 기본 사항에 대해 알아볼 수 있습니다.
테스트 벤치로 돌아가서 신호를 사용하고 정의하려는 다른 라이브러리와 함께 필요한 VUnit 라이브러리를 추가합니다.
참고: 이 예에서 프로세스 실행은 순차적입니다. 따라서 제어 신호(플래그라고 함) ) 프로세스를 시작하거나 종료할지 여부를 알리는 데 사용됩니다.
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;
다음으로 UUT를 인스턴스화합니다. Quartus는 파일 이름 규칙 ip_name_inst.vhd
에 따라 VHDL 및 Verilog에 대한 구성 요소 인스턴스화 예제를 제공합니다. 및 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 );
시작되는 처음 두 프로세스는 clk_process
입니다. 및 reset_rel
. 후자는 reset_done
을 재설정하고 구동한 후 일시 중단됩니다. 플래그를 true
로 지정 , clk_process
시뮬레이션 시간 동안 작동합니다.
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;
재설정이 완료되었으므로 test_runner
를 호출할 수 있습니다. 테스트를 실행하기 위한 프로세스입니다. 또한 테스트 실행기는 sim_done
까지 활성 상태를 유지합니다. 플래그는 true
로 구동됩니다. , 마지막 프로세스에서 발생합니다.
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;
마지막으로 data_generator
프로세스는 for
을 활용하여 병렬 가산기의 세 입력에 값을 할당하여 여러 추가를 실행합니다. 루프.
참고: 이 프로세스는 test_runner
프로세스는 start_sim
을 설정하여 그렇게 지시합니다. 깃발. 이 프로세스가 끝나면 sim_done
가 발생합니다. 플래그, 테스트 실행자에게 시뮬레이션 일시 중지 명령.
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;
테스트 케이스를 실행하고 모든 것이 예상대로 작동하는지 확인하기 위해 run.py
를 실행할 수 있습니다. 터미널에 다음 명령을 입력하기만 하면 해당 디렉토리에서 스크립트를 다운로드할 수 있습니다.
python ./run.py -v
참고: 자세한 설명을 제공하여 표시되는 출력의 더 나은 설명을 위해 맞춤 로거가 사용되었습니다. -v
옵션. 또한 하나의 테스트 케이스만 정의되어 있기 때문에 이를 지정하는 옵션을 제공할 필요가 없습니다.
마지막으로 ModelSim에서 결과를 확인하기 위해 다음 명령을 입력할 수 있습니다.
python ./run.py --gui
(이미지를 클릭하면 커집니다)
결론적으로 이 튜토리얼에서는 IP 카탈로그에 있는 Quartus IP를 VUnit에 통합하고 테스트하는 방법에 대해 배웠습니다. 미리 정의된 IP를 사용했습니다. 그러나 이러한 방식으로 패키지화된 맞춤형 IP를 VUnit 환경에 통합할 수도 있습니다.
이 VUnit 자습서를 아직 확인하지 않았다면 확인하세요.
VUnit 시작하기
VHDL
이전 자습서에서 For-Loop를 사용하여 정수 범위를 반복하는 방법을 배웠습니다. 그러나 고정된 정수 범위보다 루프를 더 자세히 제어하려면 어떻게 해야 할까요? 이를 위해 While 루프를 사용할 수 있습니다. While 루프는 테스트하는 표현식이 true로 평가되는 한 계속해서 동봉된 코드를 반복합니다. . 따라서 While-Loop는 얼마나 많은 반복이 필요한지 미리 알 수 없는 상황에 적합합니다. 이 블로그 게시물은 기본 VHDL 자습서 시리즈의 일부입니다. While 루프의 구문은 다음과 같습니다. while <
이전 자습서에서 loop을 사용하여 무한 루프를 만드는 방법을 배웠습니다. 성명. 또한 exit을 사용하여 루프에서 벗어나는 방법도 배웠습니다. 성명. 그러나 루프가 특정 횟수만큼 반복되도록 하려면 어떻게 해야 할까요? For-Loop는 이를 수행하는 가장 쉬운 방법입니다. For-Loop를 사용하면 고정된 범위의 정수 또는 열거된 항목을 반복할 수 있습니다. 현재 반복에 속하는 항목은 암시적으로 선언된 상수를 통해 루프 내에서 사용할 수 있습니다. 이 블로그 게시물은 기본 VHDL 자습서 시리즈의 일부입니다. For 루프