VCS使用以及命令行调试

最近在学习VCS,现将VCS的一些使用心得记录下来。

VCSsynopsys的仿真verilog的仿真器。基于linux系统。有命令行模式和图形化模式。图形化模式是用的dve

以串口verilog代码使用为例,进行VCS使用说明。

简要说明下该串口功能。该串口工作在波特率为115200,无奇偶检验位。一位停止位。当使能信号有效,就将8位数据发送出去,输出结束后,在将该数据读回来。即自发自收。

测试代码如下:

module ceshi_uart_test;
    // Inputs
    reg clk;
    reg rst_n;
    reg [7:0] in_data;
    reg w_en;
    // Outputs
    wire [7:0] data;
    wire tx_free;
    wire rx_free;
// Instantiate the Unit Under Test (UUT)
ceshi_uart uut (
   .clk(clk),
   .rst_n(rst_n),
   .in_data(in_data),
   .w_en(w_en),
   .data(data),
   .tx_free(tx_free),
   .rx_free(rx_free)
);
   always #1 clk = ~clk;
   initial begin
      // Initialize Inputs
      clk = 0;
      rst_n = 0;
      in_data = 8'h53;
      w_en = 0;
      // Wait 100 ns for global reset to finish
      #100 rst_n = 1;
      #50  w_en = 1;
      #5   w_en = 0;
      @(tx_free)
      #50  w_en = 1;
      #5   w_en = 0;           
      #100  $finish;
   end
endmodule

 

顶层模块代码:

module ceshi_uart(
         input clk,
         input rst_n,
         input [7:0] in_data,
         input w_en,
                           
         output [7:0] data,
         output tx_free,
         output rx_free                       
);
         wire  band_tick;
         wire  [1:0] rx_state;
         wire  [1:0] tx_state;
         wire        txd_data;
bandrate_generate     //波特率产生模块。产生波特率时钟的16倍时钟
    #(
       .bandrate(19200)    //波特率
     )bandrate_generate_1
     (
       .clk(clk),
       .rst_n(rst_n),
       .state(rx_state|tx_state),
       .band_tick(band_tick)
    );

uart_rx uart_rx_1 (     //接收模块
       .clk(clk),
       .rst_n(rst_n),
       .rxd_data(txd_data),
       .band_tick(band_tick),
       .free(rx_free),
       .data(data),
       .rx_state(rx_state)
);

uart_tx uart_tx_1(    //发送模块
       .clk(clk),
       .rst_n(rst_n),
       .w_en(w_en),
       .band_tick(band_tick),
       .send_data(in_data),
       .free(tx_free),
       .txd_data(txd_data),
       .tx_state(tx_state)
);
endmodule

波特率产生模块

module bandrate_generate
   #(
       parameter bandrate = 9600
     )
     (
       input clk,
       input rst_n,
       input [1:0] state,                
       output band_tick
    );
//此处initial语句是可以综合的,因为是预先计算的。
/************* initial the bandrate    *******************/     
   reg[9:0] bandrate_number ;
   initial  begin
      case( bandrate )
         4800:
             bandrate_number = 650;
         9600:                 
             bandrate_number = 325;
         14400:
             bandrate_number = 216;        
         19200:
             bandrate_number = 162;        
         38400:  
             bandrate_number = 80;
         56000:
             bandrate_number = 55;                            
         115200:
             bandrate_number = 26;
         default:
             bandrate_number = 352;
         endcase
   end
/************* end initial bandrate ****************/
    localparam idle = 2'd0;
 
    reg[9:0] bandrate_cnt ;
    always@( posedge clk ) begin
       if( !rst_n )
          begin
              bandrate_cnt <= 0;
          end
       else
          begin
              if( state == idle || bandrate_cnt == bandrate_number )
                  bandrate_cnt <= 0;
              else
                  bandrate_cnt <= bandrate_cnt + 1'b1;
              end
    end 
    assign band_tick = (bandrate_cnt ==  bandrate_number);
endmodule

接收模块代码:

module uart_rx(
       //input signal
       input clk,
       input rst_n,
       input rxd_data,
       input band_tick,
                    
       //output signal
       output reg free,
       output reg [7:0] data,
       output [1:0] rx_state,
       output reg finish
);
     localparam idle    = 2'd0;
     localparam start   = 2'd1;
     localparam receive = 2'd2;
     localparam stop    = 2'd3;
 
     reg [1:0] state;
     reg [1:0] state_next;
     reg [7:0] rx_data;
     reg [7:0] rx_data_next;
     reg [3:0] n_reg;
     reg [3:0] n_next;
     reg [3:0] cnt_reg;
     reg [3:0] cnt_next;
          
     always@( posedge clk ) begin
        if( !rst_n )
            begin
                 state <= idle;
                 n_reg <= 0;
                 cnt_reg <= 0;
                 rx_data <= 0;
            end
        else
            begin
                 state <= state_next;
                 n_reg <= n_next;
                 cnt_reg <= cnt_next;
                 rx_data <= rx_data_next;
            end
        end
          
     always@ *  begin
        n_next = n_reg;
        cnt_next = cnt_reg;
        state_next = state;
        rx_data_next = rx_data;
        finish = 0;
        free = 0;
        case( state )
            idle:
                begin
                   free = 1;
                   if( ~rxd_data )
                      begin
                         state_next = start;
                         cnt_next = 0;
                      end
                end
            start:
                begin
                   if( band_tick )
                      if( cnt_reg == 15 )
                          begin
                             state_next = receive;
                             rx_data_next = 0;
                             cnt_next = 0;
                             n_next = 0;
                          end
                      else
                          cnt_next = cnt_reg + 1'b1;
                 end
            receive:
                 begin
                    if( band_tick )
                        begin
                           if( cnt_reg == 7 )
                                rx_data_next = {rxd_data,rx_data[7:1]};
                           if( cnt_reg == 15 )
                                begin
                                   cnt_next = 0;
                                   if( n_reg == 7 )
                                      begin
                                         state_next = stop;
                                      end
                                   else
                                      n_next = n_reg + 1'b1;
                                end
                           else
                                cnt_next = cnt_reg + 1'b1;
                        end
                  end
            stop:
                  begin
                      if( band_tick )
                          if( cnt_reg == 15 )
                              begin
                                  cnt_next = 0;
                                  state_next = idle;
                                  finish = 1;
                              end
                          else
                              cnt_next = cnt_reg + 1'b1;
                   end
            default:
                   state_next = idle;
        endcase
    end
          
    always@( posedge clk ) begin
       if( !rst_n )
           data <= 0;
       else
           begin
               if( state == stop )
                    data <= rx_data;
               else
                    data <= data;
           end
    end
          
    assign rx_state = state;
endmodule

发送数据模块

module uart_tx (
    input clk,
    input rst_n,
    input w_en,
    input [7:0] send_data,
    input band_tick,
    
    output reg free,
    output reg txd_data,
    output [1:0] tx_state                
);
    // define serial_port state
    localparam idle    = 2'd0;
    localparam start   = 2'd1;
    localparam send    = 2'd2;
    localparam done    = 2'd3;
 
    reg [1:0] state;
    reg [1:0] state_next;
    reg [3:0] n_reg;
    reg [3:0] n_next;
    reg [3:0] cnt_reg;
    reg [3:0] cnt_next;
 
          
    always@( posedge clk ) begin
        if( !rst_n )
            begin
                state <= idle;
                n_reg <= 0;
                cnt_reg <= 0;
            end
        else
            begin
                state <= state_next;
                n_reg <= n_next;
                cnt_reg <= cnt_next;
            end
    end
                
    always@ *  begin
        state_next = state;
        n_next = n_reg;
        cnt_next = cnt_reg;
        free = 0;
        case( state )
            idle:
                begin
                    txd_data = 1;
                    free = 1;
                    if( w_en )
                        begin
                            state_next = start;
                        end
                end
            start:
                begin
                    txd_data = 0;
                    if( band_tick )
                        begin
                            if( cnt_reg == 15 )
                                begin
                                    state_next = send;
                                    n_next = 0;
                                    cnt_next = 0;
                                end
                            else
                                begin
                                    cnt_next = cnt_reg + 1'b1;
                                end
                        end
                end
            send:
                begin              
                    txd_data = send_data[n_reg];
                    begin
                        if( band_tick )
                            begin
                                if( cnt_reg == 15 )
                                    begin
                                        cnt_next = 0;
                                        if( n_reg == 7 )
                                            state_next = done;
                                        else
                                           n_next = n_reg + 1'b1;
                                    end
                                else
                                    cnt_next = cnt_reg + 1'b1;
                            end
                    end
                end
            done:
                begin
                    txd_data = 1;
                    if( band_tick )
                        begin
                            if( cnt_reg == 15 )
                                begin
                                    cnt_next = 0;
                                    state_next = idle;
                                end
                                else
                                    cnt_next = cnt_reg + 1'b1;
                        end
                end
            default:
                state_next = idle;
        endcase
    end
    assign tx_state = state;
endmodule

一、VCS仿真

下面开始进行VCS仿真。

VCS要使用图形化界面,必须得先编译得到vpd文件,才能用图形化界面看波形。

首先是编译verilog文件。

主要命令如下

                        vcs        verilog文件         [-y 搜索路径  +libext+.v  -debug_all –ncli]

其中 []中的选项是可选的。

  -y 搜索路径   指定搜索目录

  +libext+.v       指定搜索后缀为.v的文件

  -debug_all     是调试用的,如果要进行调试,就要加这个命令。

  -ncli                 是命令行ncli调试。

以上是主要的可选项,其余的自行百度。

clip_image002

我的文件目录如上所示,测试代码在当前目录下,其余的调用的模块代码在rtl目录下。

所以,要编译。用如下命令:

             vcs  ceshi_uart_test.v  -y ./rtl +libext.+v

就进行编译了。-y的作用就是指定搜索路径,因为有可能我们的verilog代码不都是在当前目录下,而是在一个文件夹里面。这样就可以用-y指定该文件夹,这样vcs编译的时候,就会去该目录下去寻找verilog文件。而+libext+.v是指在该搜索路径下,将顶层模块中用到的例化模块都给包括进来。

如果所有的verilog文件都在当前目录下,那么可直接执行

  vcs  a.v b.v c.v ……  (注意,testbench要放在最前面,因为testbench中有`timescale

 

如果只是 vcs ceshi_uart_test.v –y ./rtl  就会有如下错误

clip_image004

提示测试文件中的例化模块找不到。 

 

image

编译完成后,会在当前目录下,生成一个simv文件。 这个文件是一个可执行文件,执行这个文件,就可以看到我们的仿真结果。

 

命令是   ./simv

clip_image008

因为在testbench中没有写显示内容,所以仿真结果是看不到显示结果的。

可以用dve查看波形。

命令        ./simv     -gui

clip_image010

可以看到会有错误,这是因为没有生成vpd文件。VCSdve是执行vpd文件的。直接 vcs verilog文件 是不会产生vpd文件的。要加一个-debug_all或者-debug或者-debug_pp 命令。不过推荐用-debug_all,因为这个可以加断点。

即         vcs  ceshi_uart_test.v  -y ./rtl +libext.+v  -debug_all

然后再执行           ./simv -gui

 

image

就打开了dve。同时在当前目录下,产生了inter.vpd文件。

接下来的操作和一般的verilog仿真软件是一样的。选中信号加入到波形中,然后开始仿真。就可以看到波形了。

clip_image014

   点击运行仿真

clip_image016

就可以看到波形了。

 

二、命令行调试

接下来是命令行调试。

命令行调试不用看波形,用命令,执行仿真,观看信号。命令行仿真是在ucli中进行的。所以在编译命令中,要加入-ucli

使用命令行调试,可在testbench中加入$stop语句。这样仿真可以在该处停下来,这样可以查看各个信号的值。

如我再testbench中加入两个$stop语句。

clip_image018

执行命令 vcs  ceshi_uart_test.v  -y ./rtl +libext.+v  -debug_all –ucli –R

-R 表示编译后立即执行。

不加这个选项   那执行完上个命令后,在执行命令./simv -ucli 才启动ucli调试。

image

显示ucli就表示进入ucli调试了。

ucli中有一些常用命令,

scope  显示当前的顶层模块

       scope u1 就表示进入到当前顶层模块的u1模块,同时将u1模块设置为顶层模块 

       scope -up 回到目前顶层模块的上一层。

scope可以用来选择不同的模块,以此来显示不同的信号。因为show是显示当前顶层的信号以及子模块

 

show 显示当前顶层模块的信号以及子模块

     show    -value   信号 -radix hex/bin/dec   显示信号的值  以特定的进制显示。

 

run  运行仿真

     run  一直运行,直到遇到$stop或者设置的断点

     run  time   运行多少时间停止(不推荐)

     run  -posedge 信号  运行到信号的上升沿停止

     run  -negedge 信号  运行到信号的下降沿停止

     run  -change  信号  信号有变化时停止

 

stop 设置断点

     stop  显示断点

     stop  -posedge 信号  在信号的上升沿设置断点

     stop  -negedge 信号  在信号的下降沿设置断点

     stop  -condition  {信号表达式}  信号表达式为真的地方设置断点

     stop  -delete 断点值   删除断点值的断点

 

restart  重新开启ucli调试模式

 

-h  帮助命令

    命令后面接 –h  显示当前命令的帮助

      scope –h 显示

clip_image022

 接下来就开始调试

clip_image024

首先scope命令,显示当前顶层为ceshi_uart_test,即我们的testbench模块。

第二个命令 show 显示当前模块下有哪些信号和子模块。可看出,有7个信号,和一个子模块uut。即我们例化的uart_top模块。

第三个命令 show -value 显示信号的值,以16进制显示,因为还没有开始运行,所以信号的值都是x。不定值。

第四个命令 scope uut 进入到uut子模块。当前的顶层模块为uut

第五个命令 show 显示当前顶层模块uut的信号以及子模块,这里有11个信号,3个子模块。

执行scope -up 回到顶层模块。

clip_image026

第六个命令 run命令 56行有$stop,所以在该处,仿真暂停。

第七个命令 show命令  显示信号的值  因为有些值还没有初始化,所以显示为x

第八个命令 show命令  显示子模块uut中的信号。调用模块中的信号是用 . 调用的。

clip_image027

第九个命令  设置断点1  clk的上升沿设置断点1

第十个命令  设置断点2  clk的下降沿设置断点2

第十一个命令 设置断点3  rst1 设置断点3

第十二个命令 显示断点  设置了三个断点,这里就显示3个断点

第十三个命令 删除断点2  删除在clk下降沿设置的断点2

第十四个命令 显示断点  删除掉了断点2  这里就显示断点13

 

断点设置好后,接下来就runshow 看信号就可以了。

使用restart可以重新开始调试。即仿真时刻回到0时刻。

每次show -value 比较麻烦,可以使用 alias var show -value var代替show -value

如果show -value 信号  就可以 var  信号

 

以上就是我目前学习到VCS的一些使用心得。当然VCS还有其他的一些命令,由于还没有接触到,这里也没有提到。

 

此条目发表在IC分类目录,贴了标签。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。