systemverilog声明的位置

  1. 包 package

为什么引入包?

在verilog中,变量、任务和函数的声明都在module..endmodule之间,声明的对象都是局部的。不能全局声明。如果一个声明在多个设计块中用到,必须在每个块中声明。

Systemverilog可以使用typedef用户自定义类型,会在多个模块中使用这个类型,verilog需要在多个模块中使用这个类型。引入了包的概念。

1.1 包的定义

可以使多个模块共享用户自定义类型。在package和endpackage之间定义。

包中可综合的结构有

①paramater和 localparam 常量定义(不能被重新定义,在包中,parameter和localparam是相同的)

②const变量定义

③typedef用户定义

④task和function定义

⑤从其他包中import语句

⑥操作符重载定义

package definitions;
    parameter VERSION = '1.1';
    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

1.2 引用包的内容

①使用作用域解析操作符 “::”

可以通过包的名称直接引用包,选择包中特定的定义或声明

module ALU(
    input definitions::instruction_t IW,
    input logic clock,
    output logic[31:0] result
);

always_ff @(posedge clock)
    case(IW.code)
    definitions::ADD:result=IW.a + IW.b;
    definitions::SUB:result=IW.a - IW.b;
    definitions::MUL:result=definitions::multiplier(IW.a,IW.b);
    endcase
endmodule

当包中的一项或者多项在模块中多次引用,每次显式地引用包的名称太麻烦。

②导入包中的特定子项

import语句导入特定子项。

import definitions::ADD;
import definitions::multiplier;

case(IW.code)
    ADD:result = IW.a + IW.b;
    MUL:result = multiplier(IW.a,IW.b);
endcase

但是导入枚举类型并不导入里面的元素。

例如:import definitions::opcode_t;会使用户定义的类型opcode_t在模块中可见,但是它不会时其使用的枚举元素可见。每个枚举元素必须显式导入。

为此,使用通配符导入更实用。

③包中子项的通配符导入

import definations::*

通配符导入并不能自动导入包中所有内容(只有在模块或接口中实际使用的子项才会被真正导入,没被引用的包中的定义和声明不会被导入)

import definition::*;

always_comb 
    case(IW.opcode)
        ADD:result=;
    endcase

对于模块端口IW,包名必须显式引用,因为不能在module和端口定义之间加入一个import语句。

可以使用$unit声明域

综合:

为了能够综合,包中定义的任务和函数必须声明为automatic,并且不能包含静态变量。

  1. $unit编译单元声明

编译单元是同时编译的所有源文件,为软件工具提供了一种对整个设计的各个子块单独编译的方法。

sv允许在包、模块、接口和程序块的外部进行声明,扩展了verilog的声明域。外部声明在“编译单元域”(不可综合!!!)

编辑单元(unit):同时编译的所有文件

编辑单元域($unit域):编译单元在package\module\接口和程序块外部的声明域

编译单元域包含:

(1)时间单位和精度声明

(2)变量声明

(3)net声明

(4)常量声明

(5)用户定义数据类型

(6)任务和函数定义

///外部声明/
parameter VERSION = "1.2a";   //外部常量
reg  resetN = 1;  //外部变量(低有效)
typedef struct packes{  //外部用户定义类型
        reg [31:0] address;
        reg [31:0] data;
        reg [31:0] opcode;
}instruction_word_t;

function automatic int log2 (input int n);//外部函数
    if (n <= 1) return (1);
    log2 = 0;
    while( n > 1)
    begin
        n = n/2;
        log2++;
    end
    return(log2);
endfunction

/模块定义
//用外部声明定义端口类型
module register(
        output instruction_word_t q,
        input instruction_word_t d,
        input wire clock
);

always @(posedge clock ,negedge resetN)
    if(!resetN)  q <= 0;//使用外部复位
    else            q <= d;
endmodule

注:外部编译单元域声明不是全局的

SV的编译单元域只作用于同时编译的源文件。每次编译源文件,就创建一个唯一针对此次编译的编译单元域。

2.1编码建议

①不要在$unit中进行任何声明,而应在package内。

②必要时可以将package导入到$unit中。

  1. 未命名语句块中的声明

verilog中允许在命名的begin...end 和 fork...join块中声明局部变量。

局部变量声明的通常用法是声明一个临时变量进行循环控制。避免了对同名但用途不同的模块级变量的无意访问。

3.1 未命名块中的局部变量

可以在未命名块中声明变量,被隐藏起来,不会被块以外的代码读取和修改。

  1. 仿真时间单位和精度

4.1 verilog编译指令

`timescale 1ns/10ps

4.2 包含时间单位的时间值

SV扩展了Verilog语言,可以给时间值指定时间单位

forever #5ns clock=~clock;

4.3 范围级时间单位和精度

SV允许指定局部性的时间单位和精度,作为模块、接口或程序块的一部分,而不是作为软件工具的指令。

timeunit和timeprecision语句必须在其他任何声明或语句之前、紧随模块,必须先于其他任何声明。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值