SV常量变量

常量

全局

  • define定义宏常量
    • 全局跨文件文本常量替换

模块级

  • parameter定义可重写模块级常量
    • 编译时常量,实例化时可被覆盖
    • 支持表达式计算
1
2
3
4
5
6
7
8
9
10
11
12
module RAM #(
parameter DEPTH = 1024, // 简单常量
parameter ADDR_WIDTH = $clog2(DEPTH), // 表达式计算
parameter [7:0] INIT_VALUE = 8'hA5 // 带类型声明
) (
input logic [ADDR_WIDTH-1:0] addrs
);
localparam HIGH_BIT = ADDR_WIDTH - 1; // 派生常量
endmodule

// 实例化时覆盖参数
RAM #(.DEPTH(2048), .INIT_VALUE(8'hFF)) ram_inst();
  • localparam定义不可重写模块级常量
    • 模块内部专用常量
    • 不能被外部覆盖,常用于派生参数
1
2
3
4
5
6
7
8
9
module ALU (
input logic [7:0] a, b
);
localparam OP_ADD = 2'b00; // 操作码常量
localparam OP_SUB = 2'b01;
localparam OP_AND = 2'b10;

localparam RESULT_WIDTH = 9; // 内部计算结果位宽
endmodule

块、类级

  • const定义运行时可初始化的常量
    • 可在类、函数、initial块中使用
    • 需要显示初始化,初始化后不可变
1
2
3
4
5
6
7
8
9
10
11
12
class Packet;
const int MAX_SIZE; // 声明

function new(int size);
MAX_SIZE = size; // 在构造函数中初始化
endfunction
endclass

initial begin
const real PI = 3.1415926; // initial块常量
const byte START_ADDR = 8'h40;
end

枚举常量

  • typedef enum定义枚举常量
    • 用于定义状态机、命令码等有限值集合
    • 自动或手动赋值,提高代码可读性
1
2
3
4
5
6
7
8
9
10
11
12
typedef enum logic [2:0] {       // 显式指定底层类型
IDLE = 3'b001, // 手动赋值
START = 3'b010,
RUN = 3'b100,
ERROR = 3'b111
} state_t;

typedef enum { // 自动赋值
RED, // 0
GREEN, // 1
BLUE // 2
} color_t;

常量函数

  • 用于复杂计算生成常量值
  • 在编译时求值,只能包含常量表达式
1
2
3
4
5
6
function automatic int clog2(input int n);
return (n <= 1) ? 0 : 1 + clog2(n >> 1);
endfunction

parameter MEM_SIZE = 4096;
localparam ADDR_W = clog2(MEM_SIZE); // 计算结果为常量

静态变量

声明

  • 隐式静态变量:moduleprogram中的functiontask中声明的变量默认是静态的
  • 显示静态变量:使用static关键词显式声明

特性

  • 存储在全局数据区,固定内存位置

  • 同一个模块多次实例化时共享静态变量

    • 由于使用共享的静态存储区,这也可能导致不用线程之间窜用
  • 适用场景

    • 模块级配置参数
    • 硬件寄存器建模
    • 时序逻辑总是使用静态变量保持状态
      • 如跨多个时钟周期保持值的计数器
    • 跨时间控制语句的变量

生命周期

  • 从仿真开始(时间0)持续到仿真结束
  • 在多次触发的过程块中,只在仿真时间为0时进行一次初始化
1
2
3
4
5
6
7
8
9
10
11
module
always_ff @(posedge clk) begin
static int count = 0; // 仅仿真开始时初始化为0,声明并非执行语句,后续不再重复初始化
count <= count + 1; // 每次触发递增
end // 输出序列:1, 2, 3...(非0,1,2...)

// 等效硬件行为,更推荐
reg [31:0] counter = 0; // 综合为带初始值的寄存器
always @(posedge clk) begin
counter <= counter + 1;
end

自动变量

声明

  • 隐式自动变量:class内部的fucntiontask中声明的变量默认是自动的,initialalways中声明的变量默认也是自动的
  • 显示自动变量:使用automatic关键词显示声明
    • 建议在需要动态存储时,显式声明automatic,而非依赖隐式规则,避免混淆
1
2
3
4
5
6
7
8
9
10
//program块中显示指定自动存储方式
program automatic test();
//用检测数据何时被写入存储器任务
task wait_for_bus(input logic [31:0] addr, expect_data,
output logic success);
while (bus_addr !== addr)
@(bus_addr);
sucess = (bus_data == expect_data);
endtask
endprogram

特性

  • 存储在栈帧中,动态分配内存
  • 多实例独立,每次调用创建独立副本
  • 适用场景
    • 纯计算逻辑中使用自动变量
    • 递归函数必须使用自动变量
    • 不需要保持状态的中间变量
    • 验证环境中的临时对象

生命周期

  • 仅在作用域激活期间存在
  • 每次进入作用域时重新初始化
  • 作用域结束时销毁
  • initial中的自动变量可能在进程挂起后被回收,根据仿真器调度选项而定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
always_ff @(posedge clk) begin
int count = 0; // 错误:在always内部隐式声明自动变量
count <= count + 1; // 永远输出1
end

task calculate();
automatic int temp = 0; // 每次调用时初始化为0
temp++;
$display(temp); // 总是显示1
endtask

initial begin
automatic int delay = 10;
#delay; // 挂起delay个时间单位
// 调度器计划在($time + &delay)时唤醒这个进程
// 这里&delay为delay的内存位置,而非实际值
// 如果delay已被回收,仿真器可能无法确定何时唤醒
end

时间值

单位与精度

  • 一种方法是使用编译指示语句``timescale`。确保时延有适宜的量程和精度
    • 当采用多种``timescale`时,可能会因编译次序导致问题
    • 建议每个文件末尾都以``timescale`结束,将其恢复为公司规定的默认值
  • 另一种方式是使用timeunittimeprecision声明语句为每个模块指明时间
    • 若使用上述语句替代``timescale`,要求把它们放入每个带时延的模块中

时间参数

  • 控制时间显示格式:$timeformat(四个参数),主要影响$displaymonitor等任务中%t格式符的输出
    • 第一个参数:时间单位指数(必填),如-9对应1ns、-12对应1ps
    • 第二个参数:小数点后保留位数(默认0)
    • 第三个参数:时间值后的后缀(默认空字符串)
    • 第四个参数:时间字符串的最小宽度(默认20),自动左侧补空格
  • $time的返回值是根据所在模块的时间精度要求进行舍入的整数,$realtime的返回值则是带小数部分的完整实数
    • 在计算时延时也可以使用time trealtime r定义变量存储数据
    • 如在``timescase 1ns/100ps中,time t = 800ps以1ns存储,realtime r = 800ps`以0.8ns存储
1
2
3
4
5
6
7
8
9
10
11
module timing;
timeunit 1ns;
timeprecision 1ps;
initial begin
$timeformat(-9, 3, "ns", 8);
#1 $display("%t", $realtime); //1.000ns
#2ns $display("%t", $realtime); //3.000ns
#0.1ns $display("%t", $realtime); //3.100ns
#41ps $display("%t", $realtime); //3.141ns
end
endmodule