• interface中的clocking


    1. 一些概念

    • interfacemodule有类似的地方,都可以定义端口port、定义functiontask、使用initialalways
    • interface用于连接硬件(DUT)和软件(验证环境),还可以简化模块之间的连接,为模块端口提供了标准化的封装方式;
    • interface中声明clocking时钟块,可以避免delta cycle问题,通过波形上的可见延迟帮助理解仿真时序;
    • modport只是对interface中已经声明的信号再次声明方向;
    • module中可以例化module,也可以例化interfaceinterface中可以例化interface,不可以例化module

    2. 举个例子接口怎么用

    重新写一下之前的例子,以前不知道从哪抄来的,好多细节不太清楚,重新复习,还是一位加法器


    • modport用于对接口中的信号分组,并指定方向,后续模块使用接口可以直接例化modprt;
    • modprot的参数列表可以是port,也可以是clocking;
    • 对于激励产生部分simulus,验证环境要输出a、b、cin作为dut的输入;
    • 对于加法器adder,她要接收验证环境的输出作为自己的输入;
    • 对于监测器monitor,她会接收所有的端口作为自己的输入;
    • 对于一个接口中的同一个信号,比如a,她是dut的输入,又是环境的输出,这就需要用modport添加方向限制;也就是说,信号的方向对于不同的作用对象可以是不一样的

    代码如下:

    2.1. 声明接口adder_interface

    interface adder_interface(input bit clk);
      logic     a;      // declare port signal
      logic     b;
      logic     cin;
      logic     cout;
      logic     sum;
    
      clocking cp @(posedge clk);  // declare which signals are triggered at the rising edge of the clk
        output  a, b, cin;
      endclocking
    
      clocking cn @(negedge clk);  // declare which signals are triggered at the falling edge og the clk
        input   a, b, cin, cout, sum;
      endclocking
    
      modport simulus (clocking cp);
      modport adder   (input a, b, cin, output cout, sum);
      modport monitor (clocking cn);
    
    endinterface
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 在clocking cn中,利用时钟clk的下降沿触发采集输出事件,其实也是一种延迟;

    2.2. 激励的产生

    module simulus(adder_interface.simulus port);
      always @(port.cp) begin
        port.cp.a   <= $random() % 2;
        port.cp.b   <= $random() % 2;
        port.cp.cin <= $random() % 2;
      end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.3. 加法器

    module adder(adder_interface.adder port);
      assign {port.cout, port.sum} = port.a + port.b + port.cin;
    endmodule
    
    • 1
    • 2
    • 3

    3.4. 监测器

    module monitor(adder_interface.monitor mon);
      always @(mon.cn) begin
        $display("%0t: %d + %d + %d = %d %d", $time, mon.cn.a, mon.cn.b, mon.cn.cin, mon.cn.cout, mon.cn.sum);
      end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.5. 顶层文件

    `timescale 1ns/1ps;
    module top();
      bit clk = 0;
      always #10 clk = ~clk;
    
      adder_interface adder_vif(clk);  // 在test中例化接口
    
      simulus sim(adder_vif.simulus);
      adder   add(adder_vif.adder);
      monitor mon(adder_vif.monitor);
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3. 分析仿真结果

    在这里插入图片描述
    上述代码直接仿真,可以看到监测器实在时钟下降沿触发打印的,因为打印发生在always @(mon.cn)


    在实际电路中,组合逻辑都会有延迟,但是我们的仿真器不能够直接在波形上看到这个延迟时间,所有的信号都会在@(posedge clk)的时间变化,真是电路信号的变化都会在@(posedge clk)的前一点或者后一点;
    在这里插入图片描述
    vld是我们在仿真波形上看到的,信号的变化时间都是一样的,都在时钟上升沿;
    vld_acutal是实际电路的变化;
    vld_delay是我们可以clocking中指定偏移时间的结果,这样就可以直接在波形上看到这个偏差;

    4. 在clocking中设置偏移时间

    • clocking内的输入信号是对接口信号的采样,也就是dut的输出信号;
    • clocking内的输出信号是对接口信号进行驱动,也就是dut的输入信号;
    • 在clocking中用default可以设置输入输出的偏移时间;
      clocking my_if();
      	default input #1 output #2;
      endclocking
      
      • 1
      • 2
      • 3
    • clocking cp里面使用defalut仿真时报错:注意想要在clocking中添加延时,必须要指定时间单位和时间精度,否则仿真报错;
      在这里插入图片描述
      其实我在top最上面已经加了timescales 1ns/1ps,但还是报错说需要指定时间单位和精度,这是因为timescales的作用范围没有用到interface中(因为我的各个module都是在独立的.sv中),在top中将interface.sv导入进来就行;
      clocking cp @(posedge clk);  // declare which signals are triggered at the rising edge of the clk
      	default ouput #2;
        output  a, b, cin;
      endclocking
    
    • 1
    • 2
    • 3
    • 4
    `timescale 1ns/1ns;
    
    `include "adder_interface.sv"
    
    module top();
      // timeunit        1ns;
      // timeprecision   1ns;
      
      bit clk = 0;
      always #10 clk = ~clk;
    
      adder_interface adder_vif(clk);
    
      simulus sim(adder_vif.simulus);
      adder   add(adder_vif.adder);
      monitor mon(adder_vif.monitor);
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    • 对于dut来说,a、b、cin作为激励的输入来得晚,那自己的计算输出cin、cout就算的晚;也就是我延后了激励的输出,延后了simulus的输出

    • 上面的例子相当于有三个模块,激励发生部分、加法器、监测器三个模块,三个模块共用一个接口的实例adder_vif,我在工作中暂时没有遇到过这种共用的用法,基本都是一个模块用一个接口;

    • 关于clocking我在工作中暂时也没有用过,跑后仿的时候不知道需不需要查看detal cycle;

    • 上面加法器的举例,不是很好,所有的模块相当于都是硬件环境,没有做到验证环境(软件环境)和硬件环境的分离

    • 假设我想在验证环境中让dut打印时间后延,我可以在interface中的clocking中指定,也可以在验证环境中的task中手动添加延迟,规定在时钟上升沿后1ns就打印结果;

      while(1) begin
        @(posedge adder_vif.clk);
        #1ns;
        $display("%0t: %d + %d + %d = %d %d", $time, adder_vif.a, adder_vif.b, adder_vif.cin, adder_vif.cout, adder_vif.sum);
      end
      
      • 1
      • 2
      • 3
      • 4
      • 5
    • 假如我的加法器有一个工作使能信号en,只有在en拉高的情况下,加法器才会计算,并输出结果,下面有两种写法。由于en存在连续两拍都拉高的情况,所以不能用边沿检测的方法监测en,只能用电平检测;

    • 写法1:实际波形会在en拉高的下一拍,因为对输入数据的采样会以时钟上升沿前的为准;对于en信号的检查发生在一个时钟周期的结束,这有可能不是我们想要的;

      while(1) begin
        @(posedge adder_vif.clk);
        if(adder_vif.en == 1) 
          $display("%0t: %d + %d + %d = %d %d", $time, adder_vif.a, adder_vif.b, adder_vif.cin, adder_vif.cout, adder_vif.sum);
      end
      
      • 1
      • 2
      • 3
      • 4
      • 5

      在这里插入图片描述

    • 写法2:手动添加延迟,我在每一个时钟周期内去检查,这样就可以保证实时,当拍打印当拍的结果;

      while(1) begin
        @(posedge adder_vif.clk);
        #1ps;  // 手动添加延时
        if(adder_vif.en == 1) 
          $display("%0t: %d + %d + %d = %d %d", $time, adder_vif.a, adder_vif.b, adder_vif.cin, adder_vif.cout, adder_vif.sum);
      end
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      在这里插入图片描述

  • 相关阅读:
    利用星穹云Serverless云平台高效开发小程序的技术实践
    小程序Tab栏与页面滚动联动
    APP自动化之Poco框架
    [MySQL]基本介绍及安装使用详细讲解
    Thymeleaf将字符串转换为数字
    洛谷题单 Part2.2 排序算法(十种常见的排序算法)
    20230908-考题记录
    dubbo优雅关机
    K8s - 安装部署Kafka、Zookeeper集群教程(支持从K8s外部访问)
    ElasticSearch搜索引擎:常用的存储mapping配置项 与 doc_values详细介绍
  • 原文地址:https://blog.csdn.net/Bunny9__/article/details/126694013