Modelsim自动化仿真脚本(TCL)——简单实例

目录

[1. Modelsim与TCL脚本的关系](#1. Modelsim与TCL脚本的关系)

2.实验文件

2.1设计文件

2.2仿真测试文件

[2.3. 脚本文件](#2.3. 脚本文件)

[3. 实验步骤](#3. 实验步骤)

[3.1. 创建文件夹](#3.1. 创建文件夹)

[3.2. 指定路径](#3.2. 指定路径)

[3.3. 创建工程](#3.3. 创建工程)

[3.4. 运行命令](#3.4. 运行命令)

[3.4. 实验效果](#3.4. 实验效果)


1. Modelsim与TCL脚本的关系

TCL(Tool Command Language)是一种脚本编程语言,由John Ousterhout在1988年开发。TCL是一种通用的、高级的、解释执行的脚本语言,它特别适合用于快速原型开发、测试、自动化任务以及GUI开发。TCL语言设计简单,易于学习和使用,它具有可扩展性,可以通过添加库来扩展其功能。

ModelSim是由Mentor Graphics(现在是Siemens EDA的一部分)开发的一款行业标准的硬件描述语言(HDL)仿真工具。它支持多种HDL语言,包括VHDL、Verilog和SystemVerilog,用于验证数字电路和系统的设计。

TCL脚本与ModelSim的关系在于,ModelSim提供了对TCL脚本的支持,使得用户可以使用TCL脚本来控制仿真环境、运行仿真、管理项目、处理结果等。通过编写TCL脚本,用户可以自动化ModelSim的许多操作,提高工作效率,实现复杂的测试流程,以及进行批量处理。例如,用户可以编写TCL脚本来自动化测试套件的执行,收集和分析仿真结果,甚至修改仿真参数并重新运行仿真,从而实现更加高效的验证流程。

2.实验文件

2.1. 设计文件

`timescale  1ns/1ns

module  complex_fsm(
    input   wire    sys_clk         ,   //系统时钟50MHz
    input   wire    sys_rst_n       ,   //全局复位
    input   wire    pi_money_one    ,   //投币1元
    input   wire    pi_money_half   ,   //投币0.5元
                    
    output  reg     po_money        ,   //po_money为1时表示找零
                                        //po_money为0时表示不找零
    output  reg     po_cola             //po_cola为1时出可乐
                                        //po_cola为0时不出可乐
);

//----------------------------------------------------------------------
//parameter define
//只有五种状态,使用独热码
parameter   IDLE     = 5'b00001;
parameter   HALF     = 5'b00010;
parameter   ONE      = 5'b00100;
parameter   ONE_HALF = 5'b01000;
parameter   TWO      = 5'b10000;

//wire  define
wire    [1:0]   pi_money;
//reg   define
reg     [4:0]   state;


//----------------------------------------------------------------------
//maincode
//pi_money:为了减少变量的个数,我们用位拼接把输入的两个1bit信号拼接成1个2bit信号。投币方式可以为:不投币(00)、投0.5元(01)、投1元(10),每次只投一个币
assign pi_money = {pi_money_one, pi_money_half};

//第一段状态机,描述当前状态state如何根据输入跳转到下一状态
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        state <= IDLE;  //任何情况下只要按复位就回到初始状态
    else	case(state)
                IDLE    : if(pi_money == 2'b01)   //判断一种输入情况
                              state <= HALF;
                          else    if(pi_money == 2'b10)//判断另一种输入情况
                              state <= ONE;
                          else
                              state <= IDLE;
    
                HALF    : if(pi_money == 2'b01)
                              state <= ONE;
                          else    if(pi_money == 2'b10)
                              state <= ONE_HALF;
                          else
                              state <= HALF;
    
                ONE     : if(pi_money == 2'b01)
                              state <= ONE_HALF;
                          else    if(pi_money == 2'b10)
                              state <= TWO;
                          else
                              state <= ONE;
    
                ONE_HALF: if(pi_money == 2'b01)
                              state <= TWO;
                          else    if(pi_money == 2'b10)
                              state <= IDLE;
                          else
                              state <= ONE_HALF;
    
                TWO     : if((pi_money == 2'b01) || (pi_money == 2'b10))
                              state <= IDLE;
                          else
                              state <= TWO;
        //如果状态机跳转到编码的状态之外也回到初始状态
                default :       state <= IDLE;
            endcase

//第二段状态机,描述当前状态state和输入pi_money如何影响po_cola输出
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        po_cola <= 1'b0;
    else    if((state == TWO && pi_money == 2'b01) || (state == TWO && 
          pi_money == 2'b10) || (state == ONE_HALF && pi_money == 2'b10))
        po_cola <= 1'b1;
    else
        po_cola <= 1'b0;

//第二段状态机,描述当前状态state和输入pi_money如何影响po_money输出
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n ==	1'b0)
        po_money <= 1'b0;
    else if((state == TWO) && (pi_money == 2'b10))
        po_money <= 1'b1;
    else
        po_money <= 1'b0;

endmodule

2.2. 仿真测试文件

关于随机数可参考:Modelsim怎样在测试平台文件中快捷使用随机数?-CSDN博客

`timescale  1ns/1ns

module  tb_complex_fsm();

//----------------------------------------------------------------------
//reg   define
reg         sys_clk;
reg         sys_rst_n;
reg         pi_money_one;
reg         pi_money_half;
reg         random_data_gen;

//wire  define
wire        po_cola;
wire        po_money;
//----------------------------------------------------------------------
//初始化系统时钟、全局复位
initial begin
    sys_clk    = 1'b1;
    sys_rst_n <= 1'b0;
    #20
    sys_rst_n <= 1'b1;
end

//sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50MHz
always  #10 sys_clk = ~sys_clk;

//random_data_gen:产生非负随机数0、1
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        random_data_gen <= 1'b0;
    else
        random_data_gen <= {$random} % 2;

//pi_money_one:模拟投入1元的情况
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        pi_money_one <= 1'b0;
    else
        pi_money_one <= random_data_gen;

//pi_money_half:模拟投入0.5元的情况
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        pi_money_half <= 1'b0;
    else
        pi_money_half <= ~random_data_gen;  //取反是因为一次只能投一个币,即pi_money_one和pi_money_half不能同时为1

//------------------------------------------------------------
//将RTL模块中的内部信号引入到Testbench模块中进行观察打印
wire    [4:0]   state    = complex_fsm_inst.state;
wire    [1:0]   pi_money = complex_fsm_inst.pi_money;

initial begin
    $timeformat(-9, 0, "ns", 6);
    $monitor("@time %t: pi_money_one=%b pi_money_half=%b pi_money=%b state=%b po_cola=%b po_money=%b", $time, pi_money_one, pi_money_half, pi_money, state, po_cola, po_money);
end
//------------------------------------------------------------
complex_fsm complex_fsm_inst(
    .sys_clk        (sys_clk        ),  //input     sys_clk
    .sys_rst_n      (sys_rst_n      ),  //input     sys_rst_n
    .pi_money_one   (pi_money_one   ),  //input     pi_money_one
    .pi_money_half  (pi_money_half  ),  //input     pi_money_half
                    
    .po_cola        (po_cola        ),  //output    po_money
    .po_money       (po_money       )   //output    po_cola
);  

endmodule

2.3. 脚本文件

  1. `quit -sim` :退出仿真,如果当前modelsim中具有仿真运行,可以将其中止并退出仿真界面。

2)`.main clear ` :清除modelsim Transcript中的内容

3)`vlog "../src*.v" `:vlog为编译的意思,则../src/*.v代表路径。因为FPGA设计文件在src中,所以需要用../退到上一级文件夹,再选择src/*.v(即该文件夹下的所有.v文件)。如果不需要全部编译,也可以指定文件(vlog "../src/complex_fsm.v)。

  1. `vsim`:这是ModelSim/QuestaSim的仿真命令,用于启动仿真。

5)`-t ns`这个选项指定了仿真的时间单位。在这个例子中,`-t ns`表示时间单位是纳秒(nanoseconds)。

6)`-voptargs=+acc`:这个选项用于传递参数给仿真优化工具(vopt)。`+acc`是一个特定的参数,它启用了额外的信号可访问性,这通常用于波形查看或交互式调试。`+acc`选项会使得更多的信号在仿真中可见,这可能会影响仿真的性能,因为需要跟踪更多的信号。

7)`work.tb_complex_fsm`: 这部分指定了要仿真的测试台(testbench)。`work`是ModelSim/QuestaSim中默认的库名,`tb_complex_fsm`是测试台的名字。在ModelSim/QuestaSim中,所有编译好的设计和测试台都存储在一个名为"work"的库中,除非你在编译时指定了其他的库名。

8)`add wave -driver {tb_complex_fsm}`:这条命令在波形显示中添加一个分隔线,用以区分不同的信号组。`{tb_complex_fsm}`是分隔线的标签。

9)`add wave tb_complex_fsm/*`: 这条命令将`tb_complex_fsm`测试台中所有的信号添加到波形显示中。``是一个通配符,表示添加所有信号。

10)`add wave -divider {complex_fsm}`: 这条命令在波形显示中添加一个分隔线,用以区分不同的信号组。`{complex_fsm}`是分隔线的标签。

11)`add wave -radix decimal tb_complex_fsm/complex_fsm_inst/*`: 这条命令将`tb_complex_fsm/complex_fsm_inst/`下的所有信号添加到波形显示中,并且设置这些信号的显示基数为十进制。这意味着这些信号的值将以十进制形式显示,而不是默认的二进制或十六进制。

12)`virtual function {(vir_new_signal)tb_complex_fsm/complex_fsm_inst/state} new_state`:这条命令创建了一个虚拟信号`new_state`,它是基于`tb_complex_fsm/complex_fsm_inst/state`信号的函数。这里的`vir_new_signal`可能是一个自定义的函数,用于处理`state`信号并生成`new_state`虚拟信号。

13)`add wave -color red -itemcolor blue tb_complex_fsm/complex_fsm_inst/new_state`: 这条命令将虚拟信号`new_state`添加到波形显示中,并设置该信号的波形颜色为红色,信号项的颜色为蓝色。

#---------------------------------------------------------------------
#基础配置
quit -sim
.main clear

#---------------------------------------------------------------------
#包含文件
vlog "../src/*.v"
vlog "*.v"
#开始仿真
vsim -t ns -voptargs=+acc work.tb_complex_fsm

#---------------------------------------------------------------------
# 添加虚拟类型
virtual    type {
{01 IDLE}
{02 HALF}
{04 ONE}
{08 ONE_HALF}
{16 TWO}
} vir_new_signal

#----------------------------------------------------------------------
#添加波形
add wave -divider {tb_complex_fsm} 

add wave tb_complex_fsm/*
add wave -divider {complex_fsm_inst}
add wave -radix decimal tb_complex_fsm/complex_fsm_inst/* 
virtual    function {(vir_new_signal)tb_complex_fsm/complex_fsm_inst/state} new_state
add wave  -color red  -itemcolor blue  tb_complex_fsm/complex_fsm_inst/new_state

configure wave -timelineunits us
#----------------------------------------------------------------------
#运行
run 10us

3. 实验步骤

3.1. 创建文件夹

按照如图方式创建modelsim_test、src、sim三个文件夹,并将FPGA设计文件和测试平台文件和自动化脚本放入如图文件夹

3.2. 指定路径

打开软件更改Change Directory路径为3.1.的sim文件夹

3.3. 创建工程

3.4. 运行命令

3.4. 实验效果

相关推荐
上理考研周导师6 小时前
第二章 虚拟仪器及其构成原理
fpga开发
flashman9117 小时前
python在word中插入图片
python·microsoft·自动化·word
FPGA技术实战7 小时前
《探索Zynq MPSoC》学习笔记(二)
fpga开发·mpsoc
2401_8576226617 小时前
SpringBoot健身房管理:敏捷与自动化
spring boot·后端·自动化
力姆泰克17 小时前
看电动缸是如何提高农机的自动化水平
大数据·运维·服务器·数据库·人工智能·自动化·1024程序员节
BPM_宏天低代码17 小时前
低代码 BPA:简化业务流程自动化的新趋势
运维·低代码·自动化
bigbig猩猩18 小时前
FPGA(现场可编程门阵列)的时序分析
fpga开发
IT-民工2111018 小时前
CI/CD 实践总结
运维·ci/cd·自动化
_.Switch20 小时前
Serverless架构与自动化运维
运维·python·缓存·自动化·运维开发