第1章:FPGA基础语法回顾
各位同学,欢迎来到《FPGA雷达信号处理加速实战教程》。我是你们的老朋友,一个在FPGA和雷达信号处理领域摸爬滚打了十几年的工程师。
这一章,咱们不急着上硬菜。先花点时间,把FPGA设计最核心的语法和概念捋一遍。你可能会觉得基础,但说实话,我见过太多项目翻车,都是因为基础不牢。咱们稳扎稳打,后面才能飞得起来。
1.1 Verilog与VHDL:我该选哪个?
这是个老生常谈的问题。我个人习惯用Verilog,因为它语法更灵活,写起来快,尤其在处理雷达信号这种大规模数据流时,代码量能少不少。但VHDL也有它的优势,比如类型检查更严格,适合大型团队协作。
不过,你想想看,现在主流的FPGA厂商(Xilinx、Intel)的IP核和参考设计,大部分都提供Verilog版本。所以,我建议初学者从Verilog入手。咱们课程里也统一用Verilog。
说白了,语言只是工具。核心是你能不能把硬件逻辑想清楚。
1.2 组合逻辑与时序逻辑:一个都不能少
这是FPGA设计的基石。我刚开始学的时候,也经常搞混。咱们用最直白的话说清楚。
组合逻辑
输出只取决于当前的输入。没有记忆功能。就像一根导线,输入变了,输出立刻跟着变。
举个例子,一个简单的与门:
// Verilog 组合逻辑示例
assign y = a & b;
这段代码综合出来就是一个与门。a和b变了,y马上变。没有时钟,没有寄存器。
时序逻辑
输出不仅取决于当前输入,还取决于之前的状态。它有记忆功能。靠时钟沿来触发更新。
最常见的时序逻辑就是D触发器:
// Verilog 时序逻辑示例
always @(posedge clk) begin
q <= d;
end
这里,q只在时钟上升沿才更新为d的值。其他时间,q保持不变。
1.3 状态机设计:控制逻辑的灵魂
状态机,说白了就是控制逻辑的大脑。它决定了你的电路在什么时候该干什么事。
我遇到过不少新手,写状态机喜欢用一大堆if-else嵌套,最后代码自己都看不懂了。我的建议是:用三段式状态机。清晰、稳定、好维护。
三段式状态机的写法:
- 第一段: 时序逻辑,描述状态跳转。
- 第二段: 组合逻辑,描述下一个状态的条件。
- 第三段: 时序逻辑,描述每个状态下的输出。
看个例子,一个简单的数据包检测状态机:
// 三段式状态机示例
// 第一段:状态跳转
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
current_state <= IDLE;
else
current_state <= next_state;
end
// 第二段:次态逻辑
always @(*) begin
case (current_state)
IDLE: begin
if (data_in == 8'hAA)
next_state = HEADER;
else
next_state = IDLE;
end
HEADER: begin
if (data_in == 8'h55)
next_state = DATA;
else
next_state = IDLE;
end
DATA: begin
if (byte_count == 10)
next_state = IDLE;
else
next_state = DATA;
end
default: next_state = IDLE;
endcase
end
// 第三段:输出逻辑
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_valid <= 1'b0;
byte_count <= 4'd0;
end else begin
case (current_state)
IDLE: begin
data_valid <= 1'b0;
byte_count <= 4'd0;
end
HEADER: begin
data_valid <= 1'b0;
byte_count <= 4'd0;
end
DATA: begin
data_valid <= 1'b1;
byte_count <= byte_count + 1;
end
endcase
end
end
1.4 同步设计与异步设计:别让时钟域成为你的噩梦
这是FPGA设计里最容易出问题的地方,没有之一。尤其是在雷达信号处理中,多个时钟域并存是常态。
同步设计
所有寄存器都在同一个时钟沿下工作。简单、可靠、时序分析容易。这是我们的首选。
异步设计
信号跨时钟域传输。比如,一个信号从100MHz的时钟域传到200MHz的时钟域。如果不做处理,大概率会出现亚稳态,导致数据错误。
处理跨时钟域,最常用的方法就是打两拍(双级同步器):
// 异步信号同步化
always @(posedge clk_dst or negedge rst_n) begin
if (!rst_n) begin
sync_reg1 <= 1'b0;
sync_reg2 <= 1'b0;
end else begin
sync_reg1 <= async_signal;
sync_reg2 <= sync_reg1;
end
end
assign sync_signal = sync_reg2;
这里,async_signal是来自另一个时钟域的信号。经过两级寄存器同步后,sync_signal就可以安全地在clk_dst时钟域使用了。
1.5 本章小结
好了,这一章咱们把FPGA设计最核心的语法和概念过了一遍。组合逻辑、时序逻辑、状态机、同步异步设计,这些都是基本功。你想想看,后面我们要做的雷达信号处理,无论是FFT、数字下变频还是脉冲压缩,本质上都是这些基础元素的组合。
下一章,咱们开始进入正题,聊聊雷达信号处理的基本流程。到时候,你会发现,这些基础语法会反复用到。
嗯,今天就到这里。有什么问题,咱们课后交流。