【IC每日一题:IC验证面试常问-3】

embedded/2024/11/14 18:35:24/

IC每日一题:IC验证面试常问-3】

    • 1.1 SV约束如何使用以及有哪几种方式?'”:=“和":/"的区别?,rand和randc的区别?如何关闭约束?
    • 1.2 代码覆盖率、功能覆盖率、SVA覆盖率都是衡量什么的;
    • 1.3 如何检查随机化是否成功?什么时候randomize()会失败?
    • 1.4 $cast在句柄转换时如何使用? 如何检查句柄是否指向有效对象?
    • 1.5 随机化的优势是什么,是不是意味着不再需要定向case了?
    • 1.6 randomize with{}中的约束与class中的约束是什么关系?
    • 1.7 什么是虚方法virtual method?虚接口virtual interface是什么以及为什么要使用虚接口?
    • 1.8 SV中的package用途是什么?如何使用?
    • 1.10 modport的用途是什么?

#1 SV相关

1.1 SV约束如何使用以及有哪几种方式?'”:=“和"😕"的区别?,rand和randc的区别?如何关闭约束?

随机化和约束是SV中写case时非常重要的点:用于限制随机变量的取值范围或满足特定的条件。约束可以应用于类(class)中的随机变量,以确保在随机化过程中生成的数值符合预期的设计要求;极大简化验证环境的编写和提高覆盖率;
约束的常见方式:
分布约束:使用dist;
条件约束:if语句, 逻辑运算符等;
区间约束:inside

约束的示例:

class Packet;rand bit [7:0] data;constraint c_data { data inside {[0:127]}; }
endclassclass Packet;rand bit [7:0] data;rand bit [1:0] mode;constraint c_data_mode { (mode == 2'b00) -> data inside {[0:31]};(mode == 2'b01) -> data inside {[32:63]};(mode == 2'b10) -> data inside {[64:95]};(mode == 2'b11) -> data inside {[96:127]}; }
endclassclass Packet;rand bit [7:0] data;constraint c_data_weight { data dist {[0:31] :/ 50, [32:63] :/ 30, [64:95] :/ 15, [96:127] :/ 5}; }
endclassclass Packet;rand bit [7:0] data;constraint c_data_set { data inside {[0:31], [64:95]}; }
endclassclass Packet;rand bit [7:0] data;rand bit enable;constraint c_data_enable { if (enable) data inside {[0:31]}; else data inside {[32:63]}; }
endclassclass UniqueConstraintExample;rand int a[];constraint c1 {a.size() == 3;  // 数组大小为 3foreach (a[i]) {a[i] inside {[1:10]};  // 每个元素在 1 到 10 之间}unique {a};  // 数组中的所有元素都是唯一的}
endclassclass CrossVariableConstraintExample;rand int a;rand int b;// 约束constraint c1 {(a + b) < 20;  // a 和 b 的和小于 20}
endclassclass SoftConstraintExample;rand int a;rand int b;// 约束constraint c1 {a < 10;  // 硬约束soft b < 5;  // 软约束}
endclass

:=: 用于直接指定变量的值或值的集合。
😕: 用于为变量的不同取值分配权重,以控制随机化过程中每个值被选中的概率。

class Packet;rand bit [7:0] data;constraint c_data { data := 8'hFF; }  // 数据必须为0xFF
endclassclass Packet;rand bit [7:0] data;constraint c_data_weight { data dist {[0:31] :/ 50, [32:63] :/ 30, [64:95] :/ 15, [96:127] :/ 5}; }
endclass

rand: 声明一个随机变量,可以取指定范围内的任意值。每次随机化时,rand变量可以取到范围内的任何值,包括之前已经取过的值。
randc: 声明一个循环随机变量,它会在指定范围内循环取值。每次随机化时,randc变量会遍历所有可能的值,直到所有值都被使用过一次

class Packet;rand bit [3:0] data; // 可以取0到15之间的任意值randc bit [2:0] control; // 可以取0到7之间的值,并且会循环取值
endclass

如何关闭约束:
disable_constraint和enable_constraint方法分别用于关闭和启用约束。constraint_mode函数用于设置约束的模式;solve方法用于临时解决约束冲突。

class Example;rand int a;rand int b;// 约束constraint c1 {a < 10;}constraint c2 {b > 5;}
endclassmodule tb;initial beginExample ex = new();// 禁用 c1 约束ex.constraint_mode(c1, 0);// 禁用 c1 约束ex.disable_constraint("c1");// 重新启用 c1 约束ex.enable_constraint("c1");// 只解决 c2 约束if (ex.randomize() with { solve c2; }) begin$display("a = %0d, b = %0d", ex.a, ex.b);end else begin$display("Randomization failed");if (ex.randomize()) begin$display("a = %0d, b = %0d", ex.a, ex.b);end else begin$display("Randomization failed");endend
endmodule

使用方法:
定义约束块:在类中定义一个约束块(constraint block),用于限制随机变量的取值范围或满足特定的条件。
应用约束:在随机化方法(如randomize())中应用约束块,以确保随机生成的值符合约束条件。

1.2 代码覆盖率、功能覆盖率、SVA覆盖率都是衡量什么的;

  • 代码覆盖率,主要由行覆盖率、条件覆盖率、fsm覆盖率、跳转覆盖率、分支覆盖率,他们是否都是运行到的,比如 fsm,是否各个状态都运行到了,然后不同状态之间的跳转是否也都运行到了。
    用途:代码覆盖率主要用于确保设计的所有代码都被充分测试;

  • 功能覆盖率的话主要是自己编写covergroup和coverpoint去覆盖我们想要覆盖的数据和地址或者其他控制信号。
    类型:
    状态覆盖率(State Coverage):测量设计的状态机中的每个状态是否被访问到。
    事务覆盖率(Transaction Coverage):测量设计中的每个事务(如总线传输)是否被覆盖到。
    交叉覆盖率(Cross Coverage):测量多个变量或参数的组合是否被覆盖到。
    序列覆盖率(Sequence Coverage):测量设计中的特定序列是否被覆盖到。
    用途:功能覆盖率主要用于确保设计的所有功能点都被充分测试,有助于发现未覆盖的功能场景,从而提高设计的功能完整性和正确性。

  • 断言覆盖率主要检测我们的时序关系是否都运行到了,比如总线的地址数据读写时序关系是否都有实现。
    类型:
    断言覆盖率(Assertion Coverage):测量每个断言是否被触发到。
    断言失败覆盖率(Assertion Failure Coverage):测量每个断言是否被触发并失败。
    断言通过覆盖率(Assertion Pass Coverage):测量每个断言是否被触发并通过

用途:主要用于总线时序关系;

1.3 如何检查随机化是否成功?什么时候randomize()会失败?

可以通过立即断言检查随机化是否成功:例如 assert(p.randomize()) 来检查p句柄指向的实例是否实例化成功
失败的可能原因:最常见的原因:1.变量对象没有声明rand或randc; 2.constraint 有冲突,无法随机出值;
1.约束冲突:
如果约束条件之间存在冲突,使得没有任何一组值能够同时满足所有的约束条件,randomize() 会失败。
例如,如果有两个约束条件 a < 5 和 a > ⅛,并且 a 的类型是 int,那么这两个约束条件之间就存在冲突,因为没有整数值能满足这两个条件。
2.无效的约束:
如果约束表达式本身是无效的或不合法的,randomize() 会失败。
例如,如果约束表达式中包含语法错误或逻辑错误,randomize() 会失败。
3.约束求解器无法找到解决方案:
在某些复杂的情况下,约束求解器可能无法找到满足所有约束条件的解决方案。
例如,如果约束条件非常复杂或涉及大量的变量,求解器可能无法在合理的时间内找到解决方案。
4.随机化次数限制:
如果设置了随机化尝试的最大次数(例如使用 set_max_randomization_tries 方法),并且在达到最大次数之前没有找到满足所有约束条件的解决方案,randomize() 会失败。

class MyClass;rand int a;rand int b;// 约束constraint c1 {a < 5;a > ⅛;  // 这里存在约束冲突}
endclassmodule tb;initial beginMyClass obj = new();// 设置最大随机化尝试次数obj.set_max_randomization_tries(1000);// 尝试随机化if (obj.randomize()) begin$display("Randomization succeeded: a = %0d", obj.a);end else begin$display("Randomization failed after 1000 tries");endend
endmodule

1.4 $cast在句柄转换时如何使用? 如何检查句柄是否指向有效对象?

判断句柄是否有效:
$cast:用于安全地将一个对象句柄从一种类型转换为另一种类型。转换成功返回 1,失败返回 0。
检查句柄是否指向有效对象:通过检查对象句柄是否为 null 来确定它是否指向一个有效的对象。

$cast(目标句柄, 源句柄);class Base;// 基类定义
endclassclass Derived extends Base;// 派生类定义
endclassmodule test;Base base_h;  // 基类句柄Derived derived_h;  // 派生类句柄initial begin// 创建一个派生类对象,并将其句柄赋值给基类句柄derived_h = new;base_h = derived_h;// 尝试将基类句柄转换为派生类句柄if ($cast(derived_h, base_h)) begin$display("Cast successful. Derived handle points to a valid object.");end else begin$display("Cast failed. Derived handle does not point to a valid object.");end// 销毁派生类对象derived_h = null;// 再次尝试转换,此时应该失败if ($cast(derived_h, base_h)) begin$display("Cast successful. Derived handle points to a valid object.");end else begin$display("Cast failed. Derived handle does not point to a valid object.");endend
endmodule

1.5 随机化的优势是什么,是不是意味着不再需要定向case了?

随机化的优势:

  • 覆盖率提高:随机化可以生成大量的随机测试用例,从而提高代码覆盖率和功能覆盖率。这有助于确保设计的所有部分都得到了充分的验证。
  • 边界情况测试:随机化可以自动生成边界情况的测试用例,这些情况在定向测试中可能容易被忽略。
    *提高验证效率:自动化:随机化可以自动化生成测试激励,减少手动编写测试用例的工作量。快速迭代:可以快速生成新的测试用例,加快验证过程,尤其是在回归测试中;
  • 更好的回归测试:后期的更好的进行回归测试,撞出bug;种子管理:通过管理随机种子,可以重现特定的测试用例,便于调试和分析;

定向case的优势:
在验证的早期阶段,定向测试可以帮助快速发现和修复明显的问题。
对于一些特定的功能或场景,定向测试可能是唯一有效的验证方法。
验证后期,针对随机化覆盖率提高不上去,需要写定向case来提高覆盖率;

1.6 randomize with{}中的约束与class中的约束是什么关系?

andomize 方法的 with {} 子句允许你在随机化过程中临时添加或覆盖类中定义的约束;允许你在不修改原有类定义的情况下,动态地改变随机化的行为;

  • 类中的约束是全局的,适用于类的所有实例和所有随机化过程。这些约束定义了类的属性在随机化时可以取的值的范围和条件。
  • randomize with {} 中的约束是局部的,只在当前的随机化过程中生效,并且可以覆盖或补充类中定义的约束; 优先级比类中的约束高;
class Packet;rand int addr;rand int data;// 类中的约束constraint c1 {addr inside {[0:255]};data inside {[0:255]};(addr + data) < 2¾;}
endclassmodule tb;initial beginPacket pkt = new();// 使用类中定义的约束进行随机化if (pkt.randomize()) begin$display("Default randomization: addr = %0d, data = %0d", pkt.addr, pkt.data);end else begin$display("Default randomization failed");end// 使用 with {} 子句临时覆盖约束if (pkt.randomize() with { addr == 10; data == 20; }) begin$display("With {} randomization: addr = %0d, data = %0d", pkt.addr, pkt.data);end else begin$display("With {} randomization failed");endend
endmodule

1.7 什么是虚方法virtual method?虚接口virtual interface是什么以及为什么要使用虚接口?

虚方法:虚方法是在类中定义的可以被子类重写(override)的方法。使用 virtual 关键字可以确保在运行时调用正确的方法版本,即使是通过基类的句柄来调用派生类的方法。这是面向对象编程中的多态性的体现。

class Base;virtual function void display();$display("Base class display");endfunction
endclassclass Derived extends Base;virtual function void display();$display("Derived class display");endfunction
endclassmodule test;Base base_h;Derived derived_h;initial beginbase_h = new;derived_h = new;base_h.display();  // 输出: Base class displayderived_h.display();  // 输出: Derived class displaybase_h = derived_h;base_h.display();  // 输出: Derived class displayend
endmodule

虚接口:虚接口是一个指向接口实例的句柄,它允许在不同的模块或类之间共享同一个接口实例。使用 virtual 关键字可以确保接口的信号在不同的模块中保持同步。虚接口通常用于连接测试平台(testbench)和设计(DUT),以便在验证环境中传递信号和控制信息。通过使用虚接口,可以避免在不同的模块中复制接口实例,从而减少代码重复,提高代码的可维护性和可重用性

// 接口定义
interface my_interface (input logic clk);logic reset;logic [7:0] data_in;logic [7:0] data_out;// 时钟边沿检测clocking cb @(posedge clk);output data_in;input  data_out;endclocking
endinterface// DUT 模块
module DUT (input logic clk, input logic reset, input logic [7:0] data_in, output logic [7:0] data_out);always_ff @(posedge clk or posedge reset) beginif (reset) begindata_out <= 8'b0;end else begindata_out <= data_in + 1;  // 一个简单的加法操作endend
endmodule// 测试平台
module tb;// 时钟和复位信号logic clk;logic reset;// 创建接口实例my_interface intf(clk);// 创建 DUT 实例并连接接口DUT dut (.clk(clk),.reset(reset),.data_in(intf.data_in),.data_out(intf.data_out));// 创建虚接口virtual my_interface vif;// 任务:初始化时钟task initialize_clock();clk = 0;forever #5 clk = ~clk;endtask// 任务:初始化复位task initialize_reset();reset = 1;#10;reset = 0;endtask// 任务:驱动数据task drive_data(input logic [7:0] data);vif.cb.data_in <= data;@(posedge clk);endtask// 任务:监测数据task monitor_data();forever @(posedge clk) begin$display("Time: %0t, Data In: %0h, Data Out: %0h", $time, vif.cb.data_in, vif.cb.data_out);endendtaskinitial begin// 初始化时钟forkinitialize_clock();join_none// 初始化复位initialize_reset();// 将接口实例赋值给虚接口vif = intf;// 启动监测任务forkmonitor_data();join_none// 驱动数据drive_data(8'hAA);drive_data(8'hBB);drive_data(8'hCC);// 停止仿真#100 $finish;end
endmodule

1.8 SV中的package用途是什么?如何使用?

package是一种将相关的类、类型定义、常量、函数和任务组织在一起的机制。它的主要用途是提供代码的封装和重用,以及避免命名冲突;

// 定义一个包
package my_package;// 类型定义typedef struct {int id;string name;} person_t;// 常量parameter int MAX_VALUE = 100;// 函数function int add(int a, int b);return a + b;endfunction// 任务task print_hello(string name);$display("Hello, %s!", name);endtask// 类class Person;int id;string name;function new(int id, string name);this.id = id;this.name = name;endfunctionfunction void display();$display("ID: %0d, Name: %s", id, name);endfunctionendclassendpackage// 导入整个包
import my_package::*;
// 导入特定的内容
import my_package::add;
import my_package::Person;module tb;initial begin// 使用包中的类型定义person_t p1;p1.id = 1;p1.name = "Alice";// 使用包中的常量$display("Max Value: %0d", MAX_VALUE);// 使用包中的函数$display("Add Result: %0d", add(5, 7));// 使用包中的任务print_hello("Bob");// 使用包中的类Person p2 = new(2, "Charlie");p2.display();end
endmodule

1.10 modport的用途是什么?

用于在接口(interface)中定义端口的方向和用途,在接口中明确指定哪些信号是输入,哪些是输出,以及哪些是双向的;主要用途是在设计中清晰地定义模块之间的信号交互。

// 定义一个接口
interface my_interface (input logic clk);logic reset;logic [7:0] data_in;logic [7:0] data_out;logic req;logic ack;// 定义 modportmodport master (input  clk,output reset,output data_in,input  data_out,output req,input  ack);modport slave (input  clk,input  reset,input  data_in,output data_out,input  req,output ack);
endinterface// 主设备模块
module Master (my_interface.master m_if);// 模块逻辑always_ff @(posedge m_if.clk or posedge m_if.reset) beginif (m_if.reset) begin// 重置逻辑end else begin// 正常逻辑m_if.req <= 1;m_if.data_in <= 8'hAA;endend
endmodule// 从设备模块
module Slave (my_interface.slave s_if);// 模块逻辑always_ff @(posedge s_if.clk or posedge s_if.reset) beginif (s_if.reset) begin// 重置逻辑s_if.ack <= 0;end else if (s_if.req) begin// 正常逻辑s_if.ack <= 1;s_if.data_out <= s_if.data_in + 1;endend
endmodule

http://www.ppmy.cn/embedded/136802.html

相关文章

创新体验触手可及 紫光展锐携手影目科技推出AI眼镜开放平台

近日&#xff0c;紫光展锐携手影目科技共同发布了搭载展锐W517芯片的影目X系列AI眼镜开放平台。这一产品的推出标志着双方在智能穿戴领域的深度协作&#xff0c;将紫光展锐的领先芯片技术与影目的产品创新相融合&#xff0c;合力打造全球智能眼镜市场的标杆产品。这一战略布局不…

动态避障-图扑自动寻路 3D 可视化

自动寻路是机器人导航的核心技术&#xff0c;其原理主要涉及机器人与环境之间的复杂信息交互与处理。在自动寻路过程中&#xff0c;机器人依靠先进的传感器系统&#xff0c;如高清摄像头、精密激光雷达和灵敏超声波装置&#xff0c;全方位感知周围环境。这些传感器能够实时捕捉…

底层视角看C语言

文章目录 main函数很普通main函数之前调用了什么main函数和自定义函数的对比变量名只为人而存在goto是循环的本质指针变量指针是一个特殊的数字汇编层面看指针数组和指针数组越界问题低端地址越界高端地址越界引用就是指针main函数很普通 main函数是第一个被调用的函数吗?在用…

使用 PageHelper 在 Spring Boot 项目中实现分页查询

目录 前言1. 项目环境配置1.1 添加 PageHelper 依赖1.2 数据库和 MyBatis 配置 2. 统一的分页响应类3. 使用 PageHelper 实现分页查询3.1 Service 层分页查询实现3.2 PageHelper 分页注意事项 4. 控制层调用示例5. 常见问题与解决方案5.1 java.util.ArrayList cannot be cast t…

微信小程序——用户隐私保护指引填写(详细版)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

【大数据测试 Elasticsearch — 详细教程及实例】

大数据测试 Elasticsearch — 详细教程及实例 1. Elasticsearch 基础概述核心概念 2. 搭建 Elasticsearch 环境2.1 安装 Elasticsearch2.2 配置 Elasticsearch 3. 大数据测试的常见方法3.1 使用 Logstash 导入大数据3.2 使用 Elasticsearch 的 Bulk API3.3 使用 Benchmark 工具…

鸿蒙UI开发——自定义UI绘制帧率

1、概 述 随着设备屏幕的不断演进&#xff0c;当前主流设备采用LTPO屏幕&#xff08;可变刷新率屏幕&#xff09;&#xff0c;此类屏幕支持在多个档位之间切换屏幕帧率。 对于快速变化的内容&#xff0c;如射击游戏&#xff0c;交互动画等&#xff0c;显示帧率越高&#xff0…

NVR小程序接入平台/设备EasyNVR多品牌NVR管理工具/设备汇聚公共资源场景方案全析

随着信息技术的飞速发展&#xff0c;视频监控已经成为现代社会安全管理和业务运营不可或缺的一部分。特别是在公共资源管理方面&#xff0c;视频监控的应用日益广泛&#xff0c;涵盖了智慧城市、智能交通、大型企业以及校园安防等多个领域。NVR小程序接入平台EasyNVR作为一款功…