09verilog延时语句
Verilog延时语句详解
📑 目录
1. 延时概述
1.1 延时的作用
延时语句是Verilog HDL中用于模拟真实硬件传播延时的重要机制,主要用于:
- 🎯 仿真验证: 模拟实际电路的时序特性
- ⏱️ 时序分析: 验证电路的时序约束
- 🔍 调试辅助: 观察信号变化的时序关系
- 📊 性能评估: 分析电路的速度特性
1.2 延时分类概览
graph TD
A[Verilog延时] --> B[连续赋值延时]
A --> C[过程语句延时]
B --> B1[普通延时 #delay]
B --> B2[惯性延时 assign #n]
B --> B3[传输延时 wire #n]
C --> C1[阻塞延时 #delay]
C --> C2[非阻塞延时 <= #delay]
C --> C3[事件控制延时 @(...)]
A --> D[延时模型]
D --> D1[最小:典型:最大]
D --> D2[上升:下降延时]
D --> D3[关断延时]
1.3 延时单位与精度
// 时间单位声明
`timescale 1ns/1ps // 时间单位1ns,精度1ps
module timing_example;
// 不同的延时表示方法
wire #1 signal1; // 1个时间单位延时
wire #1.5 signal2; // 1.5个时间单位延时
wire #(2:3:4) signal3; // 最小2ns:典型3ns:最大4ns
endmodule
2. 连续赋值延时
2.1 连续赋值延时类型
2.1.1 普通延时(Regular Delay)
module regular_delay_demo(
input wire a, b, c,
output wire y1, y2, y3
);
// 基本语法:assign #延时值 目标 = 表达式;
assign #5 y1 = a & b; // 5个时间单位延时
assign #10 y2 = a | b; // 10个时间单位延时
assign #2.5 y3 = a ^ b; // 2.5个时间单位延时
endmodule
时序波形示例:
时间: 0 5 10 15 20 25 30
a : 0 1 1 0 1 1 0
b : 0 0 1 1 1 0 0
y1 : 0 0 1 0 1 0 0 (a&b with 5ns delay)
2.1.2 隐式延时(Inertial Delay in Expression)
module inertial_delay_demo(
input wire a, b, c,
output wire result1, result2
);
// 表达式级延时
assign result1 = #3 (a & b); // 与运算后延时3ns
assign result2 = #5 (a | b) & #2 c; // 复合表达式延时
endmodule
2.1.3 声明延时(Net Declaration Delay)
module declaration_delay_demo(
input wire a, b,
output wire result
);
// 在线网声明时指定延时
wire #4 intermediate; // 声明时指定4ns延时
wire #6 final_out; // 声明时指定6ns延时
assign intermediate = a & b;
assign final_out = intermediate | a;
assign result = final_out;
endmodule
2.2 延时值的表示方法
2.2.1 单一延时值
assign #10 output_signal = input_signal; // 固定10ns延时
2.2.2 最小:典型:最大延时
module min_typ_max_delay(
input wire data_in,
output wire data_out
);
// 格式:#(min:typ:max)
assign #(1:2:3) data_out = ~data_in; // 最小1ns:典型2ns:最大3ns
// 用于不同工艺角的分析
assign #(0.8:1.0:1.2) fast_signal = data_in;
endmodule
2.2.3 上升和下降延时
module rise_fall_delay(
input wire input_signal,
output wire output_signal
);
// 格式:#(上升延时, 下降延时)
assign #(2, 3) output_signal = input_signal; // 上升2ns,下降3ns
// 三参数格式:#(上升, 下降, 关断)
assign #(1, 2, 1.5) tri_state_out = enable ? data : 1'bz;
endmodule
2.3 连续赋值延时示例
2.3.1 逻辑门延时建模
module gate_delay_model(
input wire a, b, c, d,
output wire and_out, or_out, xor_out, complex_out
);
// 模拟不同逻辑门的延时特性
assign #1.2 and_out = a & b; // 与门延时1.2ns
assign #1.5 or_out = c | d; // 或门延时1.5ns
assign #2.1 xor_out = a ^ b; // 异或门延时2.1ns
// 复合逻辑延时
assign #3.5 complex_out = (a & b) | (c ^ d); // 复合逻辑延时3.5ns
endmodule
2.3.2 多级逻辑延时
module multi_level_delay(
input wire [3:0] inputs,
output wire final_output
);
// 多级逻辑的累积延时
wire #1 level1_1, level1_2;
wire #2 level2;
wire #1.5 level3;
assign level1_1 = inputs[0] & inputs[1]; // 第一级:1ns
assign level1_2 = inputs[2] | inputs[3]; // 第一级:1ns
assign level2 = level1_1 ^ level1_2; // 第二级:2ns
assign level3 = ~level2; // 第三级:1.5ns
assign final_output = level3; // 总延时:4.5ns
endmodule
3. 过程语句延时
3.1 阻塞赋值延时
3.1.1 基本语法
module blocking_delay_demo;
reg a, b, c;
initial begin
a = 0; b = 0; c = 0;
// 延时后赋值
#5 a = 1; // 5ns后a变为1
#3 b = 1; // 再过3ns后b变为1
#2 c = a & b; // 再过2ns后c = a & b
// 总执行时间:10ns
end
endmodule
3.1.2 表达式内延时
module expression_delay_demo;
reg [7:0] data1, data2, result;
always @(posedge clk) begin
// 先计算表达式,然后延时赋值
result = #4 (data1 + data2); // 计算后延时4ns再赋值
end
endmodule
3.2 非阻塞赋值延时
3.2.1 基本用法
module nonblocking_delay_demo;
reg clk, a, b, c, d;
always @(posedge clk) begin
a <= #1 b; // 1ns后a获得b的值
b <= #2 c; // 2ns后b获得c的值
c <= #3 d; // 3ns后c获得d的值
// 所有赋值并行调度,在各自延时后生效
end
endmodule
3.2.2 流水线建模
module pipeline_with_delay(
input wire clk, rst_n,
input wire [7:0] data_in,
output reg [7:0] data_out
);
reg [7:0] stage1, stage2, stage3;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
stage1 <= #1 8'h00;
stage2 <= #1 8'h00;
stage3 <= #1 8'h00;
data_out <= #1 8'h00;
end else begin
// 流水线各级的延时
stage1 <= #0.5 data_in; // 第一级处理延时
stage2 <= #1.0 stage1 + 8'h01; // 第二级处理延时
stage3 <= #0.8 stage2 << 1; // 第三级处理延时
data_out <= #0.3 stage3; // 输出延时
end
end
endmodule
3.3 事件控制延时
3.3.1 边沿检测延时
module edge_delay_demo;
reg clk, data, delayed_data;
always begin
@(posedge clk); // 等待时钟上升沿
#2; // 延时2ns
delayed_data = data; // 然后赋值
end
// 等价写法
always @(posedge clk) begin
delayed_data <= #2 data;
end
endmodule
3.3.2 条件事件延时
module conditional_delay_demo;
reg enable, data, output_reg;
always begin
wait(enable); // 等待enable变为true
#5; // 延时5ns
output_reg = data; // 然后赋值
wait(!enable); // 等待enable变为false
end
endmodule
4. 惯性延时与传输延时
4.1 惯性延时(Inertial Delay)
4.1.1 惯性延时特性
惯性延时具有脉冲抑制特性:当输入脉冲宽度小于延时值时,输出不会改变。
module inertial_delay_example;
reg input_signal;
wire output_signal;
// 惯性延时:10ns
assign #10 output_signal = input_signal;
initial begin
input_signal = 0;
// 测试不同宽度的脉冲
#5 input_signal = 1; // 脉冲开始
#3 input_signal = 0; // 3ns宽脉冲(< 10ns)
#20 input_signal = 1; // 新的脉冲开始
#15 input_signal = 0; // 15ns宽脉冲(> 10ns)
#50 $finish;
end
endmodule
时序分析:
时间: 0 5 8 20 28 35
input: 0 1 0 1 0 0
output:0 0 0 1 1 0 (只有15ns宽的脉冲能够传输)
4.1.2 惯性延时的实际意义
module inertial_practical_example(
input wire noisy_signal,
output wire clean_signal
);
// 使用惯性延时滤除毛刺
assign #5 clean_signal = noisy_signal;
// 只有持续时间≥5ns的信号变化才会传输到输出
endmodule
4.2 传输延时(Transport Delay)
4.2.1 传输延时特性
传输延时会传输所有输入变化,无论脉冲宽度多小。
// Verilog默认是惯性延时,模拟传输延时需要特殊处理
module transport_delay_simulation(
input wire input_signal,
output reg output_signal
);
// 使用队列模拟传输延时
reg [31:0] change_queue [0:1023];
integer queue_head, queue_tail;
initial begin
queue_head = 0;
queue_tail = 0;
output_signal = input_signal;
end
// 检测输入变化
always @(input_signal) begin
// 将变化事件加入队列
change_queue[queue_tail] = $time + 10; // 10ns传输延时
queue_tail = (queue_tail + 1) % 1024;
end
// 处理延时队列
always #1 begin
if (queue_head != queue_tail &&
$time >= change_queue[queue_head]) begin
output_signal = input_signal;
queue_head = (queue_head + 1) % 1024;
end
end
endmodule
4.3 惯性延时vs传输延时对比
| 特性 | 惯性延时 | 传输延时 |
|---|---|---|
| 脉冲抑制 | ✅ 小于延时的脉冲被滤除 | ❌ 所有脉冲都传输 |
| 硬件真实性 | ✅ 更接近实际电路 | ❌ 理想化模型 |
| 毛刺滤除 | ✅ 自然滤除短毛刺 | ❌ 毛刺也会传输 |
| Verilog支持 | ✅ 默认行为 | ⚠️ 需要特殊建模 |
| 应用场景 | 数字逻辑电路 | 传输线、延时线 |
5. 延时建模类型
5.1 单路径延时
5.1.1 固定延时
module single_path_delay(
input wire a, b,
output wire y
);
// 所有输入到输出都有相同延时
assign #3 y = a & b;
endmodule
5.2 多路径延时
5.2.1 输入相关延时
module input_dependent_delay(
input wire a, b, sel,
output wire y
);
// 不同路径有不同延时
assign y = sel ? (#2 a) : (#4 b); // a路径2ns,b路径4ns
endmodule
5.2.2 状态相关延时
module state_dependent_delay(
input wire clk, data, enable,
output reg output_data
);
always @(posedge clk) begin
if (enable) begin
output_data <= #1.5 data; // 使能时1.5ns延时
end else begin
output_data <= #3.0 1'b0; // 禁能时3.0ns延时
end
end
endmodule
5.3 条件延时
5.3.1 数据相关延时
module data_dependent_delay(
input wire [7:0] data,
output wire [7:0] result
);
// 根据数据值决定延时
assign result = (data > 8'h80) ? #1 (data + 1) : // 大数据快速处理
(data > 8'h40) ? #2 (data + 1) : // 中等数据
#4 (data + 1); // 小数据慢速处理
endmodule
5.4 参数化延时
5.4.1 可配置延时模块
module configurable_delay #(
parameter DELAY_VALUE = 5,
parameter MIN_DELAY = 1,
parameter TYP_DELAY = 5,
parameter MAX_DELAY = 10
)(
input wire input_signal,
output wire output_signal
);
// 使用参数控制延时
assign #(MIN_DELAY:TYP_DELAY:MAX_DELAY) output_signal = input_signal;
endmodule
// 实例化不同延时的模块
module delay_chain;
wire sig1, sig2, sig3, sig4;
configurable_delay #(.DELAY_VALUE(2)) delay1(.input_signal(sig1), .output_signal(sig2));
configurable_delay #(.DELAY_VALUE(5)) delay2(.input_signal(sig2), .output_signal(sig3));
configurable_delay #(.DELAY_VALUE(3)) delay3(.input_signal(sig3), .output_signal(sig4));
endmodule
6. 实际应用案例
6.1 时序电路建模
6.1.1 D触发器延时建模
module d_flip_flop_with_timing(
input wire clk, d, rst_n,
output reg q, q_n
);
// 时序参数
parameter T_SETUP = 1.0; // 建立时间
parameter T_HOLD = 0.5; // 保持时间
parameter T_CQ = 2.0; // 时钟到输出延时
parameter T_RESET = 1.5; // 复位延时
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
q <= #T_RESET 1'b0;
q_n <= #T_RESET 1'b1;
end else begin
q <= #T_CQ d;
q_n <= #T_CQ ~d;
end
end
// 时序检查(仅仿真)
`ifdef TIMING_CHECK
always @(posedge clk) begin
#T_SETUP;
if ($past(d) !== d) begin
$error("Setup time violation at time %0t", $time);
end
end
always @(d) begin
if ($time > 0 && $past(clk) && ($time - $time(posedge clk)) < T_HOLD) begin
$error("Hold time violation at time %0t", $time);
end
end
`endif
endmodule
6.1.2 移位寄存器延时链
module shift_register_with_delays #(
parameter WIDTH = 8,
parameter STAGES = 4,
parameter STAGE_DELAY = 2.0
)(
input wire clk, rst_n,
input wire serial_in,
output wire serial_out,
output wire [WIDTH-1:0] parallel_out
);
reg [WIDTH-1:0] shift_stages [0:STAGES-1];
integer i;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
for (i = 0; i < STAGES; i = i + 1) begin
shift_stages[i] <= #STAGE_DELAY {WIDTH{1'b0}};
end
end else begin
// 第一级
shift_stages[0] <= #STAGE_DELAY {shift_stages[0][WIDTH-2:0], serial_in};
// 后续级联
for (i = 1; i < STAGES; i = i + 1) begin
shift_stages[i] <= #STAGE_DELAY shift_stages[i-1];
end
end
end
assign serial_out = shift_stages[STAGES-1][WIDTH-1];
assign parallel_out = shift_stages[STAGES-1];
endmodule
6.2 组合逻辑延时建模
6.2.1 多路选择器延时
module mux_with_realistic_delays #(
parameter DATA_WIDTH = 8,
parameter SEL_WIDTH = 2
)(
input wire [DATA_WIDTH-1:0] data_in [0:(1<<SEL_WIDTH)-1],
input wire [SEL_WIDTH-1:0] sel,
output wire [DATA_WIDTH-1:0] data_out
);
// 选择器延时建模
parameter SEL_DELAY = 1.5; // 选择逻辑延时
parameter DATA_DELAY = 0.8; // 数据通路延时
parameter OUTPUT_DELAY = 0.5; // 输出缓冲延时
wire [SEL_WIDTH-1:0] delayed_sel;
wire [DATA_WIDTH-1:0] selected_data;
// 选择信号延时
assign #SEL_DELAY delayed_sel = sel;
// 数据选择
assign #DATA_DELAY selected_data = data_in[delayed_sel];
// 输出缓冲
assign #OUTPUT_DELAY data_out = selected_data;
endmodule
6.2.2 算术逻辑单元(ALU)延时
module alu_with_operation_delays #(
parameter DATA_WIDTH = 8
)(
input wire [DATA_WIDTH-1:0] a, b,
input wire [2:0] op_code,
output reg [DATA_WIDTH-1:0] result,
output reg carry_out
);
// 不同操作的延时
parameter ADD_DELAY = 3.5; // 加法延时
parameter SUB_DELAY = 3.8; // 减法延时
parameter LOGIC_DELAY = 1.2; // 逻辑运算延时
parameter SHIFT_DELAY = 2.1; // 移位运算延时
always @(*) begin
carry_out = 1'b0; // 默认无进位
case (op_code)
3'b000: begin // 加法
{carry_out, result} = #ADD_DELAY (a + b);
end
3'b001: begin // 减法
{carry_out, result} = #SUB_DELAY (a - b);
end
3'b010: begin // 逻辑与
result = #LOGIC_DELAY (a & b);
end
3'b011: begin // 逻辑或
result = #LOGIC_DELAY (a | b);
end
3'b100: begin // 左移
result = #SHIFT_DELAY (a << b[2:0]);
end
3'b101: begin // 右移
result = #SHIFT_DELAY (a >> b[2:0]);
end
default: begin
result = #LOGIC_DELAY {DATA_WIDTH{1'b0}};
end
endcase
end
endmodule
6.3 存储器延时建模
6.3.1 SRAM延时模型
module sram_with_timing #(
parameter ADDR_WIDTH = 10,
parameter DATA_WIDTH = 8,
parameter MEMORY_SIZE = 1024
)(
input wire clk,
input wire [ADDR_WIDTH-1:0] addr,
input wire [DATA_WIDTH-1:0] data_in,
input wire we, oe, cs,
inout wire [DATA_WIDTH-1:0] data_bus
);
// SRAM时序参数
parameter T_AA = 10.0; // 地址访问时间
parameter T_OHA = 2.0; // 地址保持时间
parameter T_AS = 1.0; // 地址建立时间
parameter T_WC = 8.0; // 写周期时间
parameter T_OE = 3.0; // 输出使能时间
reg [DATA_WIDTH-1:0] memory [0:MEMORY_SIZE-1];
reg [DATA_WIDTH-1:0] data_out_reg;
// 读操作
always @(*) begin
if (cs && oe && !we) begin
data_out_reg = #T_AA memory[addr];
end else begin
data_out_reg = #T_OE {DATA_WIDTH{1'bz}};
end
end
// 写操作
always @(posedge clk) begin
if (cs && we && !oe) begin
memory[addr] <= #T_WC data_in;
end
end
// 三态输出控制
assign data_bus = (cs && oe && !we) ? data_out_reg : {DATA_WIDTH{1'bz}};
endmodule
7. 仿真与综合考虑
7.1 仿真中的延时
7.1.1 延时对仿真的影响
// 测试平台中的延时使用
module testbench_with_timing;
reg clk, data;
wire delayed_data;
// 被测模块
assign #5 delayed_data = data;
// 时钟生成
initial begin
clk = 0;
forever #10 clk = ~clk; // 20ns周期时钟
end
// 测试序列
initial begin
data = 0;
#25 data = 1; // 在时钟边沿之间改变
#30 data = 0; // 测试延时效果
#50 $finish;
end
// 监控信号变化
always @(data or delayed_data) begin
$display("Time=%0t: data=%b, delayed_data=%b",
$time, data, delayed_data);
end
endmodule
7.1.2 延时精度控制
// 时间尺度对延时精度的影响
`timescale 1ns/1ps // 高精度:1ns/1ps
module precision_demo;
reg signal_in;
wire signal_out;
// 精确的延时控制
assign #1.234 signal_out = signal_in; // 1.234ns延时
initial begin
signal_in = 0;
#0.5 signal_in = 1; // 0.5ns后变化
#2.0 signal_in = 0; // 2.0ns后变化
#10 $finish;
end
endmodule
7.2 综合工具对延时的处理
7.2.1 延时的可综合性
module synthesis_considerations(
input wire clk, rst_n,
input wire [7:0] data_in,
output reg [7:0] data_out
);
// ✅ 可综合:逻辑功能
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_out <= 8'h00;
end else begin
data_out <= data_in + 8'h01;
end
end
// ❌ 不可综合:延时语句
/*
always @(posedge clk) begin
data_out <= #5 data_in; // 综合工具会忽略#5
end
*/
endmodule
7.2.2 时序约束与延时
// 综合后的时序约束(SDC格式示例)
/*
# 时钟约束
create_clock -name clk -period 10.0 [get_ports clk]
# 输入延时约束
set_input_delay -clock clk -min 1.0 [get_ports data_in]
set_input_delay -clock clk -max 2.0 [get_ports data_in]
# 输出延时约束
set_output_delay -clock clk -min 0.5 [get_ports data_out]
set_output_delay -clock clk -max 1.5 [get_ports data_out]
*/
7.3 后仿真延时
7.3.1 SDF文件延时标注
// 门级网表中的延时标注
module post_synthesis_netlist(
input wire a, b,
output wire y
);
// 综合后的门级实现
AND2_X1 U1 (.A(a), .B(b), .Z(y));
// SDF文件会标注实际延时:
// (CELL (CELLTYPE "AND2_X1") (INSTANCE "U1")
// (DELAY (ABSOLUTE (IOPATH A Z (0.5:0.6:0.7)))))
endmodule
8. 最佳实践
8.1 延时使用原则
8.1.1 仿真专用延时
module simulation_only_delays(
input wire clk, data,
output reg output_data
);
// 使用条件编译控制延时
`ifdef SIMULATION
parameter CLK_TO_Q_DELAY = 2.5;
parameter SETUP_TIME = 1.0;
`else
parameter CLK_TO_Q_DELAY = 0;
parameter SETUP_TIME = 0;
`endif
always @(posedge clk) begin
output_data <= #CLK_TO_Q_DELAY data;
end
endmodule
8.1.2 参数化延时管理
module parameterized_delays #(
parameter ENABLE_DELAYS = 1,
parameter GATE_DELAY = 1.0,
parameter REG_DELAY = 2.0
)(
input wire a, b, clk,
output wire combo_out,
output reg seq_out
);
// 条件延时
generate
if (ENABLE_DELAYS) begin : with_delays
assign #GATE_DELAY combo_out = a & b;
always @(posedge clk) begin
seq_out <= #REG_DELAY a | b;
end
end else begin : no_delays
assign combo_out = a & b;
always @(posedge clk) begin
seq_out <= a | b;
end
end
endgenerate
endmodule
8.2 延时建模技巧
8.2.1 渐进式延时建模
// 第一阶段:功能验证(无延时)
module processor_stage1(
input wire clk, rst_n,
input wire [31:0] instruction,
output reg [31:0] result
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
result <= 32'h00000000;
end else begin
// 纯功能实现,无延时
result <= instruction + 32'h00000001;
end
end
endmodule
// 第二阶段:添加流水线延时
module processor_stage2(
input wire clk, rst_n,
input wire [31:0] instruction,
output reg [31:0] result
);
// 流水线寄存器
reg [31:0] decode_stage, execute_stage;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
decode_stage <= #1.5 32'h00000000;
execute_stage <= #2.0 32'h00000000;
result <= #1.0 32'h00000000;
end else begin
decode_stage <= #1.5 instruction;
execute_stage <= #2.0 decode_stage + 32'h00000001;
result <= #1.0 execute_stage;
end
end
endmodule
8.2.2 层次化延时管理
// 顶层延时配置
module timing_config;
// 全局延时参数
parameter GLOBAL_GATE_DELAY = 1.0;
parameter GLOBAL_REG_DELAY = 2.0;
parameter GLOBAL_MUX_DELAY = 1.5;
// 模块特定延时
parameter CPU_ALU_DELAY = 3.5;
parameter CPU_REG_DELAY = 2.0;
parameter MEM_ACCESS_DELAY = 10.0;
endmodule
// 使用配置的模块
module cpu_core;
import timing_config::*;
// 使用全局延时参数
assign #CPU_ALU_DELAY alu_result = operand_a + operand_b;
always @(posedge clk) begin
register_file <= #CPU_REG_DELAY new_data;
end
endmodule
8.3 调试与验证
8.3.1 延时敏感性测试
module delay_sensitivity_test;
reg clk, data;
wire output1, output2;
// 不同延时的相同逻辑
assign #2 output1 = data;
assign #5 output2 = data;
initial begin
clk = 0;
forever #10 clk = ~clk;
end
initial begin
data = 0;
// 测试短脉冲
#25 data = 1;
#3 data = 0; // 3ns脉冲
// 测试长脉冲
#20 data = 1;
#8 data = 0; // 8ns脉冲
#50 $finish;
end
// 监控延时效果
always @(data or output1 or output2) begin
$display("Time=%0t: data=%b, out1=%b, out2=%b",
$time, data, output1, output2);
end
endmodule
9. 常见问题与调试
9.1 延时相关问题
9.1.1 竞争冒险
// ❌ 问题代码:竞争条件
module race_condition_bad(
input wire a, b,
output wire y
);
wire temp;
assign temp = a & b;
assign #1 y = temp | a; // temp和a同时变化时可能产生竞争
endmodule
// ✅ 改进代码:消除竞争
module race_condition_good(
input wire a, b,
output wire y
);
wire temp;
assign #0.5 temp = a & b; // 确保temp先稳定
assign #1.5 y = temp | a; // 然后计算输出
endmodule
9.1.2 延时累积问题
// ❌ 问题:延时过度累积
module excessive_delay_bad;
wire sig1, sig2, sig3, sig4;
assign #5 sig1 = input_signal;
assign #5 sig2 = sig1;
assign #5 sig3 = sig2;
assign #5 sig4 = sig3;
// 总延时20ns,可能过长
endmodule
// ✅ 改进:合理的延时分配
module reasonable_delay_good;
wire sig1, sig2, sig3, sig4;
assign #2 sig1 = input_signal; // 输入缓冲
assign #3 sig2 = sig1; // 主要逻辑
assign #1 sig3 = sig2; // 中间级
assign #1 sig4 = sig3; // 输出缓冲
// 总延时7ns,更合理
endmodule
9.2 调试技巧
9.2.1 延时可视化
module delay_visualization;
reg input_signal;
wire [3:0] delayed_signals;
// 创建延时链用于观察
assign #1 delayed_signals[0] = input_signal;
assign #2 delayed_signals[1] = delayed_signals[0];
assign #3 delayed_signals[2] = delayed_signals[1];
assign #4 delayed_signals[3] = delayed_signals[2];
// 测试序列
initial begin
input_signal = 0;
#5 input_signal = 1;
#15 input_signal = 0;
#20 $finish;
end
// 实时监控
always @(*) begin
$display("Time=%0t: in=%b, delays=%b",
$time, input_signal, delayed_signals);
end
endmodule
9.2.2 延时验证测试台
module delay_verification_tb;
// 测试信号
reg test_input;
wire test_output;
reg expected_output;
// 被测模块(假设有5ns延时)
assign #5 test_output = test_input;
// 期望值生成(手动延时)
always @(test_input) begin
expected_output <= #5 test_input;
end
// 自检验证
always @(test_output) begin
#0.1; // 小延时确保稳定
if (test_output !== expected_output) begin
$error("Delay mismatch at time %0t: got %b, expected %b",
$time, test_output, expected_output);
end else begin
$display("Delay verification passed at time %0t", $time);
end
end
// 测试序列
initial begin
test_input = 0;
#10 test_input = 1;
#15 test_input = 0;
#10 test_input = 1;
#20 $finish;
end
endmodule
9.3 性能优化
9.3.1 延时路径优化
// 关键路径分析和优化
module critical_path_optimization(
input wire [7:0] a, b, c,
input wire sel,
output wire [7:0] result
);
// ❌ 原始实现:长关键路径
/*
wire [7:0] temp1, temp2, temp3;
assign #2 temp1 = a + b;
assign #3 temp2 = temp1 * c;
assign #2 temp3 = temp2 + a;
assign #1 result = sel ? temp3 : b;
// 总延时:8ns
*/
// ✅ 优化实现:并行处理
wire [7:0] path1, path2;
assign #4 path1 = (a + b) * c + a; // 并行计算
assign #1 path2 = b; // 简单路径
assign #2 result = sel ? path1 : path2;
// 主路径延时:6ns
endmodule
10. 进阶主题
10.1 用户定义的延时模型
10.1.1 自定义延时函数
// 自定义延时计算函数
function real calculate_delay;
input [7:0] data_width;
input [1:0] complexity;
begin
case (complexity)
2'b00: calculate_delay = data_width * 0.1; // 简单逻辑
2'b01: calculate_delay = data_width * 0.3; // 中等复杂
2'b10: calculate_delay = data_width * 0.5; // 复杂逻辑
2'b11: calculate_delay = data_width * 0.8; // 很复杂
endcase
end
endfunction
module adaptive_delay_module #(
parameter DATA_WIDTH = 8
)(
input wire [DATA_WIDTH-1:0] data_in,
input wire [1:0] operation_type,
output wire [DATA_WIDTH-1:0] data_out
);
// 使用函数计算延时
real computed_delay;
always @(*) begin
computed_delay = calculate_delay(DATA_WIDTH, operation_type);
end
// 应用计算出的延时
assign #computed_delay data_out = data_in + 1;
endmodule
10.2 统计延时建模
10.2.1 随机延时变化
module statistical_delay_model(
input wire data_in,
output reg data_out
);
real base_delay = 5.0;
real random_variation;
real actual_delay;
always @(data_in) begin
// 生成随机延时变化(±20%)
random_variation = ($random % 200 - 100) / 1000.0 * base_delay;
actual_delay = base_delay + random_variation;
// 应用随机延时
data_out <= #actual_delay data_in;
`ifdef DEBUG
$display("Time=%0t: Applied delay = %0.2f ns", $time, actual_delay);
`endif
end
endmodule
10.3 温度和电压相关延时
10.3.1 PVT (Process, Voltage, Temperature) 建模
module pvt_delay_model #(
parameter BASE_DELAY = 5.0
)(
input wire data_in,
input real voltage, // 电压 (V)
input real temperature, // 温度 (°C)
output wire data_out
);
real voltage_factor, temperature_factor, total_delay;
always @(*) begin
// 电压影响 (假设1.8V标准)
voltage_factor = 1.8 / voltage;
// 温度影响 (假设25°C标准)
temperature_factor = 1.0 + (temperature - 25.0) * 0.002;
// 计算总延时
total_delay = BASE_DELAY * voltage_factor * temperature_factor;
end
assign #total_delay data_out = data_in;
endmodule
10.4 延时的可观测性
10.4.1 延时监测模块
module delay_monitor(
input wire signal_in,
input wire signal_out,
output reg [31:0] measured_delay
);
time input_change_time, output_change_time;
// 监测输入变化
always @(signal_in) begin
input_change_time = $time;
end
// 监测输出变化并计算延时
always @(signal_out) begin
output_change_time = $time;
measured_delay = output_change_time - input_change_time;
$display("Measured delay: %0d time units at time %0t",
measured_delay, $time);
end
endmodule
🎯 总结
核心要点回顾
- 延时类型: 连续赋值延时、过程语句延时、惯性延时vs传输延时
- 延时语法:
#值、#(min:typ:max)、#(rise,fall)等多种格式 - 应用场景: 仿真建模、时序验证、硬件特性模拟
- 注意事项: 延时不可综合、仅用于仿真、合理设置避免竞争
最佳实践总结
- 🎯 仿真专用: 延时仅用于仿真,不要依赖于综合
- 📝 参数化: 使用参数控制延时,便于调整和管理
- 🔧 分层管理: 在不同抽象层次合理分配延时
- ⚡ 性能考虑: 避免过度累积延时影响仿真速度
- 🛡️ 调试辅助: 利用延时帮助理解时序关系
学习建议
- 从简单的连续赋值延时开始练习
- 理解惯性延时的脉冲抑制特性
- 练习在测试台中使用延时进行时序验证
- 学习真实电路的延时特性建模
- 掌握延时相关的调试技巧
💡 重要提醒: 延时语句是仿真建模的重要工具,但要记住它们不会被综合工具处理。在实际设计中,真实的延时由物理实现决定,需要通过时序约束来控制!

浙公网安备 33010602011771号