【SystemVerilog学习笔记】2-SystemVerilog 声明的位置

本文介绍了SystemVerilog中的包管理、编译单元声明、未命名语句块中的声明及仿真时间精度设置等内容。重点讲解了如何使用包来共享类型定义,并提供了具体的编码实践指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


SystemVerilog:

  • 拓展了Verilog的声明空间
  • 增强了定义仿真时间单位的能力

2.1 包 Package

 Verilog要求局部声明,但是SystemVerilog中的typedef的用户类型希望在多个模块使用。

2.1.1 Package的定义

 功能:主要是为了使多个模块共享 typedef 定义的用户类型。
 格式:

package PACKAGE_NAME
	//可综合的结构
	//1 parameter、localparam
	//2 const
	//3 typedef
	//4 task  function
	//5 import
	//6 操作符定义重载
	//不可综合的结构
	//全局变量声明、静态task、静态function
endpackage

 按照上面的格式定义一个名为definitions的package:

//example_2_3
package definitions;
	typedef enum { ADD, SUB, MUL } opcodes_t;
	typedef struct {
​    	logic [31:0] a, b;
​    	opcodes_t opcode; 
  	} instruction_t;
function automatic [31:0] multiplier (input [31:0] a,b);
​    return a * b;
endfunction
endpackage

注意:package中的parameter不能重新定义。因为它不是模块实例的一部分。

2.1.2 Package的引用

 方法:以引用example_2_3中的package definitions为例。

  1. 作用域解析操作符“::”直接引用
module ALU (
  	input definitions::instruction_t I_IW,
  	input logic clock,
  	output logic [31:0] result
);
always_ff @( posedge clock ) 
begin
  	case (IW.opcode)
​    	definitions::ADD : result = IW.a + IW.b;
​    	definitions::SUB : result = IW.a - IW.b;
​    	definitions::MUL : result = definitions::multiplier(IW.a, IW.b);
​    default: ;
  	endcase
end
endmodule
  1. 将特定子项导入
module ALU (
  	input definitions::instruction_t I_IW,
  	input logic clock,
  	output logic [31:0] result
);
import definitions::ADD;
import definitions::SUB;
import definitions::MUL;
import definitions::multiplier;
always_ff @( posedge clock ) 
begin
  	case (IW.opcode)
​    	ADD : result = IW.a + IW.b;
​    	SUB : result = IW.a - IW.b;
​    	MUL : result = definitions::multiplier(IW.a, IW.b);
​    default: ;
  	endcase
end
endmodule

注意:只导入枚举类型的定义(opcodes_t)并不会导入该定义使用的元素(ADD、SUB与MUL)。

  1. 用通配符将特定子项导入
module ALU (
  	input definitions::instruction_t I_IW,
  	input logic clock,
  	output logic [31:0] result
);
import definitions::*;
always_ff @( posedge clock ) 
begin
  	case (IW.opcode)
​    	ADD : result = IW.a + IW.b;
​    	SUB : result = IW.a - IW.b;
​    	MUL : result = definitions::multiplier(IW.a, IW.b);
​    default: ;
  	endcase
end
endmodule

注意:使用通配符(*)时,只有实际使用的子项(ADD、SUB与MUL)才会被真正导入。

  1. 将子项导入$unit声明域中

2.1.3 synthesis指导

  • 为了能够综合,包中定义的task和function必须声明为 automatic ,并且不能包好static变量。
  • 综合不支持包中的变量声明。
    说明:自动任务和函数每次调用时才会分配独立的副本,其他如变量等则为所有模块共享,这种不通过端口传递数据的模块间通信是不可综合的。

2.2 $unit 编译单元声明

 编译单元(unit):同时编译的所有文件。
 编译单元域($unit 域):编译单元在package、module、接口和程序块的外部的声明域。
 编译单元域可以包含:

  1. 时间单位和精度声明
  2. 变量声明
  3. net声明
  4. 常量声明
  5. 用户定义类型数据声明
  6. 任务和函数定义
    注意:$unit域的声明不是全局的。全局声明无论源文件单独还是同时编译,都会被所有模块共享;$unit域的声明只作用于同时编译的源文件.

2.2.1 编码建议

  1. 不要再$unit中进行任何声明,而应在package内。
  2. 必要时可以将package导入到$unit中。

2.2.2 SystemVerilog标识符搜索优先级

  1. Verilog标准定义的局部声明。
  2. 通配符导入的包中的声明。
  3. $unit中的声明。
  4. 设计层次中的声明。

2.2.3 源代码顺序

注意:数据标识符和类型标识符必须在引用前声明,否则为声明的标识符将被隐式声明为net类型(通常为wire)。

2.2.4 将package导入$unit的编码原则

 可在模块声明之前将包导入到$unit域中,比如“2.1.2 Package的引用”中import语句位置换到module外。
注意

  • 按照搜索优先级,import语句必须出现在包中子项被引用之前。
  • 多个文件同时编译只有一个 u n i t 域 , 多 个 文 件 单 独 编 译 有 多 个 不 同 的 unit域,多个文件单独编译有多个不同的 unitunit域,导入的包对其他$unit域不可见。
  • 将同样的包导入同一$unit域是非法,在包中利用条件编译避免重复导入。包文件用`include编译命令间接传递。
`ifndef DFFS_DONE
  	`define DFFS_DONE
package definitions;
  	typedef enum { ADD, SUB, MUL } opcodes_t;
  	typedef struct {
​    	logic [31:0] a, b;
​    	opcodes_t opcode; 
  	} instruction_t;
  	function automatic [31:0] multiplier (input [31:0] a,b);
​    	return a * b;
  	endfunction
endpackage
import definitions::*;
`endif

 design file:xxx.v

`include "definitions.pkg"

注意:包中的变量被所有导入变量的设计块或测试块共享。包中的变量、静态任务和函数都不可综合。

2.2.5 综合指导

 编译单元域中声明的可综合结构:

  1. typedef用户定义类型
  2. automatic function
  3. automatic task
  4. parameter、localparam常量
  5. package导入
    注意:最好不要在$unit声明任务、函数和参数,当分开编译时,这些内容对模块不可见。
    说明:自动任务和函数的存储区再每次调用时才会实际分配,存储区独立才能保证综合前仿真行为和综合后行为相同。

2.3 未命名语句块中的声明

 verilog允许在命名的begin…end或fork…join块中声明局部变量,并且可以用包含块名的层次路径引用局部变量。
 SystemVerilog还允许在未命名块中声明局部变量,由于没有层次路径,局部变量不能在局部范围以外的任何地方引用。

2.4 仿真时间和精度

 与verilog一样,在遇到`timescale后,指定的时间单位和精度一直保持有效到下一条`timescale语句。
 SystemVerilog可以直接给时间值指定时间单位:

forever #5ns clock = ~clock;

注意:时间值和时间单位之间不允许有空格。
 SystemVerilog增加关键字timeunit和timeprecision使时间单位和精度作为模块定义的一部分。

module chip (
...
);
 timeunit 1ns;
 timeprecision 10ps;
 ... 
endmodule

说明:timeunit和timeprecision可以在$unit声明,但是必须先于其他任何声明。
 时间单位和精度搜索优先级:

  1. 时间值自带的单位。
  2. 模块、接口和程序块内部指定的时间单位和精度。
  3. 父级模块或者接口的时间精度和单位。
  4. 模块编译时有效的`timescale定义的时间单位和精度。
  5. $unit中定义的时间单位和精度。
  6. 仿真器默认的时间单位和精度。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ChipWeaver

觉得有用的话点个赞吧 :)

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值