SV学习(5)——类和对象、类的成员

本文深入解析了类和对象在Verilog SystemVerilog中的概念,涵盖了对象创建、句柄传递、销毁、静态变量与方法,以及面向对象编程在验证环境中的优势。比较了Verilog例化与SV class的区别,以及类、结构体和模块的异同。

1. 类和对象概述

  • class类:包含成员变量和方法,是软件盒子
  • object对象:类的实例
  • handle句柄(指针):用来指向对象的指针
  • property属性(变量):在类中声明的存储数据的变量
  • method方法:类中使用task或function定义方法,处理自身或外部传入的数据

2. 声明类并创建对象

class Transaction;
	bit [31: 0] addr, crc, data[8];
	
	function void display;
		$display ("Transaction: %h", addr);
	endfunction: display
	
	function void calc_crc;
		crc = addr ^ data.xor;
	endfunction: calc_crc
	
endclass: Transaction

initial	begin
	Transaction tr;	// 声明句柄
	tr = new();		// 创建对象
end
  • 创建对象,开辟新的内存空间,用来存放新的成员变量和方法
  • 创建对象时,会调用构建函数(可自定义),不需要返回值,隐式的返回例化后的对象指针
  • 创建对象的动作时动态的,可以在仿真过程中发生

3. 句柄的传递

Transaction t1, t2;
t1 =  new();
t2 = t1;
t1 = new();

在这里插入图片描述

4. 对象的销毁

  • 没有句柄指向的对象就会被销毁,空间被收回
  • SV不能回收一个被句柄引用的对象,即同一个对象被多个句柄指向,必须清除所有句柄才能销毁对象

5. 句柄的使用

  • 句柄可以用来创建多个对象,也可以前后指向不同对象

    Transaction t1, t2;
    t1 =  new();
    t2 = t1;
    t1 = new();
    t2 = null;	// 将t2赋值为‘空’,即不指向任何对象,此时指针‘悬空’,悬空的指针很‘危险’
    
  • 可以通过句柄来使用对象中的成员变量或者成员方法

    Transaction t;
    t = new();
    t.addr = 32'h42;
    t.display();// 调用对象的成员方法
    

6. 静态变量

  • class中声明的变量默认为动态变量,声明周期始于对象创建,终于对象销毁

  • static声明class中变量为静态,声明周期始于编译阶段,贯穿于整个仿真阶段

  • 静态变量var的引用:class::car、object.var

  • 类的所有对象共享一个静态变量

    class Transaction;
    	static itn count = 0;
    	int id;
    	
    	function new ();
    		id = count++;
    	endfunction
    	
    endclass: Transaction
    
    initial	begin
    	Transaction t1, t2;
    	t1 = new();	// id = 0, count = 1
    	t2 = new();	// id = 1, count = 2
    	$display("Second id = %d, count = %0d", t2.id, t2.count);	// 同 Transaction::count	
    end
    

7. 静态方法

  • class中声明的方法默认是动态的,可以用static修改为静态方法
  • 静态方法内可以声明并使用动态变量,但是不能使用类的动态成员变量

在调用静态方法时,可能并没有创建具体的对象,也因此没有为动态成员变量开辟空间,因此在静态方法中使用类的动态成员变量是禁止的,可能会造成内存泄漏,但是静态方法可以使用类的静态变量,因为静态方法和静态变量在编译阶段就已经分配好了空间。

class Transaction;
	static Congif cfg;
	static int count = 0;
	int id;
	
	// 通过静态方法来操作静态变量
	static function void display_statics();
		$display("Transaction cfg.mode = %s, count = %0d", cdf.mode.name(), count);
	endfunction
	
endclass: Transaction

initial	begin
	Congif cfg;
	Transaction::cfg = cfg;			// 静态变量赋值
	Transaction::display_statics();	// 调用静态方法
end

8. 验证为什么需要OOP面向对象

  • 验证环境的不同组件功能和所需要处理的数据内容是不相同
  • 不同环境的同一类型的组件其所具备的功能数据内容是相似
  • 基于以上两点,验证世界的各个组件角色明确、功能分立,使用面向对象编程于验证世界的构建原则十分符合

9. 一些差别对比

9.1. Verilog的例化和SV class例化的差别:

  • 两者共同点在于使用想用的模板来创建内存实例
  • 不同点在于Verilog的例化是静态的,即在编译链接时玩车个,而SV class例化是动态的,可以在任意时间点发生,使得类的例化方式更加灵活和节省空间
  • Verilog中没有句柄的概念,即只能通过层次化的索引方式A.B.sigX,而SV class通过句柄可以将对象的指针赋予其他句柄,使得操作更加灵活

9.2. 类与结构体的异同

  • 二者本身都可以定义数据成员
  • 类变量在声明之后,需要构造函数才会创建对象实体,而struct在变量声明时就开辟内存
  • 类除了可以声明数据变量,还可以声明方法,而struct不行
  • 根本上看,struct是一种数据结构,而class包含了数据成员以及针对这些成员们操作的方法

9.3. 类与模块的异同

  • 从数据和方法定义而言,二者都可以作为封闭的容器来定义和存储
  • 从例化来看,模块必须在仿真一开始就确定是否应该被例化,类的变量在仿真的任何时段都可以被构造(开辟内存)创建新对象。硬件部分必须在仿真一开始就确定下来,即module和其内部过程块、变量都应该是静态的;而软甲部分,即类的部分可以在仿真任何阶段声明并创建出新的对象
  • 从封装性来看,模块内的变量和方法是对外部公共(public)开放的,而类可以根据需要确定外部访问的权限是否是默认的公共类型、或者受保护类型(protected)还是私有类型(local)
  • 从继承性来看,模块没有任何的继承性,即无法在原有module基础上进行新module功能的扩展,而继承性是类的一大特点
### SystemVerilog 策略的使用方法示例 #### 封装、继承与多态的应用 在SystemVerilog中,面向对象编程(OOP)的概念被广泛应用。OOP的核心特性包括封装、继承以及多态[^1]。 - **封装**:通过将数据成员(属性)操作这些数据的方法组合在一起形成一个独立单元——即。 - **继承**:允许创建新的基于已存在的,从而重用代码并扩展功能。 - **多态**:不同型的对象可以调用相同名称的方法而表现出不同的行为模式。 对于策略模式而言,在SystemVerilog里可以通过定义接口(interface class),让多个派生实现该接口中的抽象函数来达到目的;这样做的好处是可以灵活切换算法而不影响其他部分逻辑结构。 #### 定义策略基及具体策略子 下面是一个简单的例子展示如何利用上述概念构建一个基本框架: ```systemverilog // 声明一个虚拟接口作为所有策略的基础模板 virtual class Strategy; pure virtual function void execute(); endclass : Strategy // 实现具体的加法运算策略 class AddStrategy extends Strategy; function new(); super.new(); endfunction // 覆盖父中的execute()方法完成特定任务 function void execute(); $display("Executing Addition..."); endfunction endclass : AddStrategy // 实现减法运算的具体策略 class SubtractStrategy extends Strategy; function new(); super.new(); endfunction // 同样覆盖execute() function void execute(); $display("Executing Subtraction..."); endfunction endclass : SubtractStrategy ``` 在此基础上还可以进一步设计上下文(Context)环境用于管理当前所使用的策略实例: ```systemverilog class Context; protected Strategy strat; // 设置新策略 function set_strategy(Strategy s); this.strat = s; endfunction // 执行选定策略的操作 task perform_operation(); if(strat != null) strat.execute(); else $fatal("No strategy has been selected."); endtask endclass : Context ``` 最后编写一段测试脚本来验证整个机制的工作情况: ```systemverilog module tb; initial begin Context ctx = new(); // 初始设置为Addition策略 ctx.set_strategy(new AddStrategy()); ctx.perform_operation(); // 更改为Subtraction策略再执行一次 ctx.set_strategy(new SubtractStrategy()); ctx.perform_operation(); #10ns; // 模拟延时结束仿真过程 $finish; end endmodule : tb ``` 当运行这段程序时将会依次打印出两条消息:“Executing Addition... Executing Subtraction...”,这表明成功实现了动态改变算法的行为方式。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值