zoukankan      html  css  js  c++  java
  • verilog PLI简介

    0.简介

    Verilog PLI(Programming Language Interface )是一种Verilog代码调用C/C++函数的机制。它能让Verilog像调用一些系统调用(如$display/$stop/$random)一样调用用户编写的C/C++函数。PLI可以完成如下功能:

    • 功耗分析
    • 代码覆盖率工具
    • 修改Verilog仿真数据结构(如修改为更精确的延时,即sdf反标)
    • 自定义输出显示
    • 联合仿真
    • 设计的调试功能
    • 仿真分析
    • 加速仿真的C模型接口
    • Testbench建模

    为了完成上述功能,C代码需要能够访问Verilog的内部数据结构,因此Verilog PLI需要提供一些访问程序集(acc routines),此外Verilog PLI还提供了另外一组程序集:任务功能程序集(tf routines)。目前PLI有两个版本:PLI1.0和PLI2.0,PLI 2.0又叫VPI,是随着Verilog 2001一起发布的。

    1.工作原理

    1)C/C++编写函数

    2)编译并产生共享库(.DLL in Windows .so in UNIX)。一些仿真器如VCS允许静态链接。

    3)将C/C++函数细节在编译veriog代码是传递给编译器(称为链接linking)

    4)一旦链接完成,就可以像运行其他的verilog仿真一样了。

    当Verilog仿真器遇到用户定义的系统函数时,便将控制权交给PLI 程序(C/C++函数)

    2.示例-Hello World

    下面给出一个简单的示例,例子不涉及任何PLI标准函数(ACC,TF等),因此,只要使用对应仿真器连接C/C++函数即可。

    hello.c:

    #include <stdio.h> 
    
    void hello () {
      printf ("
    Hello World!
    ");
    }

    hello_pli.v

    module hello_pli ();
           
    initial begin
      $hello;
      #10 $finish;
    end
            
    endmodule

    使用如下VCS命令编译并运行:

    vcs -R -P hello.tab hello_pli.v hello.c

    hello.tab文件内容如下:

    $hello call=hello

    3.示例-PLI应用程序

    下面一个示例将简单的调用PLI系统函数实现C/C++代码对Verilog代码的数据结构的访问,并将其应用在Testbench中实现对DUT的监视。

    DUT设计为一个简单的16进制计数器,counter.v代码如下:

    `timescale 1ns/10ps
    module counter (
            input clk,
            input reset,
            input enable,
            output reg [3:0] count
            );
        
        always @(posedge clk or posedge reset)
        begin
            if(reset)
            begin
                count <=  4'b0;
            end
            else if(enable)
            begin
                count <= count+1'b1;
            end
        end
    endmodule

    编写Testbench代码 pli_counter_tb.v如下:

     1 `timescale 1ns/10ps
     2 module counter_tb();
     3  reg enable;
     4  reg reset;
     5  reg clk_reg;
     6  wire clk;
     7  wire [3:0] dut_count;
     8        
     9 initial begin
    10   enable = 0;
    11   clk_reg = 0;
    12   reset = 0;
    13   $display("%g , Asserting reset", $time);
    14   #10 reset = 1;
    15   #10 reset = 0;
    16   $display ("%g, Asserting Enable", $time);
    17   #10 enable = 1;
    18   #55 enable = 0;
    19   $display ("%g, Deasserting Enable", $time);
    20   #1 $display ("%g, Terminating Simulator", $time);
    21   #1 $finish;
    22 end
    23     
    24 always begin
    25   #5 clk_reg = !clk_reg;
    26 end
    27        
    28 assign clk = clk_reg;
    29 initial
    30 begin
    31     $dumpfile("wave.vcd");
    32     $dumpvars;
    33 end 
    34 
    35 initial begin
    36   $counter_monitor (counter_tb.clk, counter_tb.reset, counter_tb.enable, counter_tb.dut_count);
    37 end
    38 
    39 counter U(
    40 .clk (clk),
    41 .reset (reset),
    42 .enable (enable),
    43 .count (dut_count)
    44 );
    45     
    46 endmodule

    上述代码中35-37行调用用户自定义系统函数$counter_monitor,对信号进行监视并打印值,此系统函数使用C代码编写,并通过PLI进行调用。

    C代码 pli_full_example.c如下:

    #include "acc_user.h"
     
    typedef char * string;
    handle clk ;
    handle reset ;
    handle enable ;
    handle dut_count ;
    int count ;
    int sim_time;
    string high = "1";
    void counter ();
    int pli_conv (string in_string, int no_bits);
     
    void counter_monitor() {
      acc_initialize();
      clk       = acc_handle_tfarg(1);
      reset     = acc_handle_tfarg(2);
      enable    = acc_handle_tfarg(3);
      dut_count = acc_handle_tfarg(4);
      acc_vcl_add(clk,counter,null,vcl_verilog_logic);
      acc_close();
    }
        
    void counter () {
      p_acc_value value;
      sim_time = tf_gettime();
      string i_reset = acc_fetch_value(reset,"%b",value);
      string i_enable = acc_fetch_value(enable,"%b",value);
      string i_count = acc_fetch_value(dut_count,"%b",value);
      string i_clk = acc_fetch_value(clk, "%b",value);
      int size_in_bits= acc_fetch_size (dut_count);
      int tb_count = 0;
      // Counter function goes here
      if (*i_reset == *high) {
        count = 0;
        io_printf("%d, dut_info : Counter is reset
    ", sim_time);
      }
      else if ((*i_enable == *high) && (*i_clk == *high)) {
        if ( count == 15 ) {
          count = 0;
        } else {
          count = count + 1;
        }
      }
      // Counter Checker function goes checker logic goes here
      if ((*i_clk != *high) && (*i_reset != *high)) {
        tb_count = pli_conv(i_count,size_in_bits);
        if (tb_count != count) {
            io_printf("%d, dut_error : Expect value %d, Got value %d
    ", 
                sim_time, count, tb_count);
          tf_dofinish();
        } else {
            io_printf("%d, dut_info  : Expect value %d, Got value %d
    ", 
                sim_time, count, tb_count);
        }
      }
    }
    
    // Multi-bit vector to integer conversion.
    int pli_conv (string in_string, int no_bits) {
      int conv = 0;
      int i = 0;
      int j = 0;
      int bin = 0;
      for ( i = no_bits-1; i >= 0; i = i - 1) {
        if (*(in_string + i) == 49) {
          bin = 1;
        } else if (*(in_string + i) == 120) {
          io_printf ("%d, Warning : X detected
    ", sim_time);
          bin = 0;
        } else if (*(in_string + i) == 122) {
          io_printf ("%d, Warning : Z detected
    ", sim_time);
          bin = 0;
        } else {
          bin = 0;
        }
        conv = conv + (1 << j)*bin;
        j ++;
      } 
      return conv;
    }
    View Code

    因为C代码调用了PLI系统函数,所以需要包含头文件"acc_user.h",acc_user.h可以在vcs安装目录下找到,需要使用vcs命令参数指定头文件路径,

    VCS命令如下:

    vcs +v2k -R -P pli_counter.tab pli_counter_tb.v counter.v pli_full_example.c -CFLAGS "-g -l$VCS_HOME/linux/lib" +acc+3

    -CFLAG 命令参数用于向C编译器传递C编译参数,因为C代码使用了访问程序集acc routines,还需要加上 +acc+3;+v2k是因为代码使用了verilog2001语法。

    -P参数和上面例子一样,指定tab文件,不同的是,此时需要增加访问属性acc,r为读,w为写,pli_counter.tab如下:

    $counter_monitor call=counter_monitor acc=rw:*

    运行结果如下:

  • 相关阅读:
    混沌的艺术--- YChaos通过数学公式生成混沌图像
    相声段子:How Are You
    太阳崇拜---64幅由算法生成的八芒星图像
    自然的密码---36幅由算法生成的六芒星图像
    雪花六出---几幅算法生成的雪花图像,并祝大家平安夜和圣诞节快乐
    18个分形图形的GIF动画演示
    python的with用法(参考)
    彻底解决django 2.2以上版本与mysql兼容性问题(不用改源码)
    python操作MySQL数据库的三个模块
    MySql 外键约束 之CASCADE、SET NULL、RESTRICT、NO ACTION分析和作用
  • 原文地址:https://www.cnblogs.com/lkiller/p/5059939.html
Copyright © 2011-2022 走看看