《FPGA基础知识》系列导航
本专栏专为FPGA新手打造的Xilinx平台入门指南。旨在手把手带你走通从代码、仿真、约束到生成比特流并烧录的全过程。
本篇是该系列的第三篇内容
上一篇:FPGA基础知识(二):深入理解时钟与复位-优快云博客
一 引言
在FPGA开发中,阻塞赋值(=)与非阻塞赋值(<=)的区别是每个工程师必须掌握的基础知识,但很多初学者却在这个看似简单的问题上反复犯错。本文将深入剖析两者的本质差异,帮助您从根本上理解并正确运用这两种赋值方式。
从一个经典问题说起
先来看一个简单的例子:试图交换两个变量的值
// 错误示范:使用阻塞赋值交换变量
always @(posedge clk) begin
a = b; // 立即执行
b = a; // 立即执行,但此时a已经是b的值
end
// 结果:a和b都变成了b的初始值,交换失败!
// 正确做法:使用非阻塞赋值
always @(posedge clk) begin
a <= b; // 计划执行
b <= a; // 计划执行,使用a的原始值
end
// 结果:成功交换!
二 硬件实现的本质差异
1 阻塞赋值的硬件对应
阻塞赋值描述的是组合逻辑,其行为类似于连续赋值:
// 阻塞赋值 - 组合逻辑
always @(*) begin
c = a & b; // 生成与门
d = c | e; // 生成或门,立即使用c的新值
end
硬件实现:生成多级组合逻辑电路,信号立即传播。
2 非阻塞赋值的硬件对应
非阻塞赋值描述的是时序逻辑,对应寄存器传输:
// 非阻塞赋值 - 时序逻辑
always @(posedge clk) begin
reg_a <= input_a; // 生成D触发器
reg_b <= input_b; // 生成D触发器
end
硬件实现:生成寄存器,所有更新在时钟边沿同步发生。
三 深入理解执行时机
1 阻塞赋值的"立即性"
always @(posedge clk) begin
temp = data_in + 1; // 立即计算
result = temp * 2; // 立即使用新的temp值
end
执行顺序:如同软件程序,一行行顺序执行。
2 非阻塞赋值的"计划性"
always @(posedge clk) begin
temp <= data_in + 1; // 计划更新temp
result <= temp * 2; // 使用temp的旧值!
end
执行顺序:所有右侧表达式同时计算,时钟沿统一更新左侧。
四 实际工程中的黄金法则
法则一:时序逻辑统一使用非阻塞赋值
// 正确的时序逻辑设计
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= IDLE;
count <= 8'h0;
data_out <= 8'h00;
end else begin
state <= next_state;
count <= count + 1'b1;
data_out <= processed_data;
end
end
法则二:组合逻辑使用阻塞赋值
// 正确的组合逻辑设计
always @(*) begin
case (state)
IDLE: next_state = (start) ? WORK : IDLE;
WORK: next_state = (done) ? IDLE : WORK;
default: next_state = IDLE;
end
// 多级组合逻辑
temp_data = input_a & input_b;
output_data = temp_data | input_c;
end
法则三:绝对禁止混用赋值方式
// 危险!禁止这样写!
always @(posedge clk) begin
a = b; // 阻塞赋值
c <= d; // 非阻塞赋值
// 综合工具可能报错,行为不可预测!
end
五 常见误区与调试技巧
误区一:在时序逻辑中使用阻塞赋值实现"中间变量"
// 不推荐的写法
always @(posedge clk) begin
temp = a + b; // 阻塞赋值
result <= temp * c; // 非阻塞赋值
end
// 推荐的写法
always @(posedge clk) begin
result <= (a + b) * c; // 直接表达
end
// 或者明确使用多个时钟周期
误区二:不理解非阻塞赋值的"并行性"
// 初学者常见的困惑
always @(posedge clk) begin
reg1 <= reg2; // 交换?
reg2 <= reg1; // 交换?
end
// 这实际上是并行交换,不是顺序交换!
六 调试建议
-
使用仿真工具观察信号变化时序
-
添加中间信号观察赋值时机
-
检查综合报告中的寄存器生成情况
总结
阻塞赋值与非阻塞赋值的正确使用是FPGA设计的基础,总结为三个核心要点:
-
阻塞赋值(=) 用于组合逻辑,表现为立即赋值
-
非阻塞赋值(<=) 用于时序逻辑,表现为时钟同步更新
-
绝不混用 两种赋值方式在同一always块中
掌握这一区别不仅能够避免难以调试的电路错误,更能帮助您写出清晰、可综合、易于维护的硬件描述代码。在实际项目中,建议始终遵循这一设计准则,它将为您的FPGA开发生涯奠定坚实的基础。

1100

被折叠的 条评论
为什么被折叠?



