亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Industrial programming >> VHDL

如何将 Quartus Prime IP 库链接到 VUnit

您是否曾经想通过 VUnit 验证框架运行包含 Quartus IP 内核的 VHDL 仿真?

这就是 FPGA 工程师 Konstantinos Paraskevopoulos 的想法,但他找不到合适的教程。幸运的是,他利用自己的才能弄清楚如何通过这篇客座文章与 VHDLwhiz 分享它 .

让我们转告康斯坦丁诺斯!

在使用 VUnit 仿真您的系统时,通常需要将 Quartus IP 目录中的预定义 IP 合并到您的设计中。因此,以下教程旨在为读者提供生成、合并和链接外部 Quartus IP 库到 VUnit 环境的知识。

对 VUnit 不熟悉?查看本教程:VUnit 入门

概述

本教程由三个主要部分组成:

  1. 所选 IP 的简要说明
  2. 生成和链接适当的库所需的步骤
  3. 使用 VUnit 和 Modelsim 进行验证

要求

它还假设具有基本的 VHDL 知识和 ModelSim 技能。

被测设计

对于我们的场景,我们使用 Quartus Integer Arithmetic IP 列表中的 Parallel Adder IP。

我们的设计接受三个 16 位的输入向量,并将相加的结果输出到一个 17 位的向量中。

第 1 步:生成 IP

我们在 IP 目录窗口中通过双击 Library/Basic functions/Arithmetic 下的并行加法器组件来生成我们的加法器。

在我们提供一个名称并根据我们的需要自定义我们的组件后,我们点击右下角的 Generate HDL 按钮。

此时会出现一个窗口,如下图所示。

注意: 我们必须设置 Create simulation model Simulation 下 部分到 VHDL 或 Verilog 以生成仿真文件,因为默认选项是无。如果我们不选择一个,given_ip_name.spd 不会生成文件,导致下一步失败。

以上过程在我们的quartus下生成了一个文件和一个文件夹 目录:

  1. 文件:given_ip_name.ip
  2. 文件夹:given_ip_name

该文件夹包含 .vhd.v 后面需要在我们的run.py中添加的文件 脚本。

第 2 步:生成 IP 模拟文件

  1. 图形界面: 选择 Tools> Generate Simulator Setup Script for IP 并在提示窗口中指定输出目录,
  2. CMD: 通过使用 Qsys 命令,我们可以通过在终端中输入以下命令来生成相同的文件:

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

使用上述两种方法之一,我们指示 Quartus 为每个支持的模拟器生成一个目录,该目录包含一个用于创建和编译 IP 库的脚本。

第 3 步:为 Modelsim 生成和编译 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 中生成已编译的库 文件夹。

第 4 步:VUnit 链接

现在已经生成了 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 下的三个子文件夹中 目录:

  1. parallel_add_191
  2. synth
  3. sim

synthsim 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 库以及我们想要使用和定义信号的任何其他库。

注意: 我们示例中的流程执行是顺序的。因此,控制信号(称为 flags ) 用于通知进程是否应该开始或终止。

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_processreset_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 flag,命令测试运行器暂停模拟。

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

  1. 什么是 SigFox?
  2. VUnit 入门
  3. 如何在 VHDL 中创建字符串列表
  4. 如何在 VHDL 测试平台中停止仿真
  5. 如何在 VHDL 中创建 PWM 控制器
  6. 如何在 VHDL 中生成随机数
  7. 如何创建自检测试平台
  8. 如何在 VHDL 中的进程中使用过程
  9. 技术如何在道德供应链中提供关键链接
  10. 链节围栏机:它的工作原理和受益者
  11. 如何启动液压齿轮泵
  12. 如何启动福特拖拉机液压泵