4. Verilog HDL基础与Nexus设计入门
Verilog HDL 是 Lattice Nexus 平台最常用的 RTL 描述语言。对初学者而言,真正需要掌握的不是语法大全,而是“哪些写法能被综合成硬件、哪些写法在 Nexus 上更省电、时钟和复位如何组织、如何把第一个 LED 闪烁工程跑通”。本节围绕这四件事展开,语法只讲与 Nexus 设计直接相关的部分。
一、Verilog 语法要点:从“描述电路”出发
Verilog 有两种建模风格:结构化描述(实例化门或模块)和行为级描述(用 always 块描述逻辑)。Nexus 工程中绝大多数代码是行为级描述,但必须牢记:always 块描述的是硬件并发行为,不是软件顺序执行。
模块是基本单元,端口方向用 input/output/inout 声明。组合逻辑用 always @(*),时序逻辑用 always @(posedge clk)。赋值语句分两类:assign 和 always 中的阻塞赋值 = 用于组合逻辑;非阻塞赋值 <= 用于时序逻辑。混用阻塞与非阻塞是新手最常见的错误来源,会导致仿真与综合结果不一致。
数据类型方面,Nexus 设计中常用 wire(连线,由 assign 或模块输出驱动)和 reg(在 always 块中被赋值的变量,综合后可能是触发器或组合逻辑)。位宽必须显式声明,例如 reg [7:0] cnt;。位宽不匹配会隐式截断或补零,容易埋下隐患。
module blink (
input wire clk, // 系统时钟
input wire rst_n, // 低电平复位
output reg led // LED 输出
);
reg [23:0] cnt;
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
cnt <= 24'd0;
else if (cnt == 24'd9_999_999)
cnt <= 24'd0;
else
cnt <= cnt + 1'b1;
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
led <= 1'b0;
else if (cnt == 24'd9_999_999)
led <= ~led;
else
led <= led;
end
endmodule
这段代码描述了一个分频计数器:每计满 10,000,000 个时钟周期翻转一次 LED。若时钟为 50 MHz,则翻转周期为 0.2 s,LED 闪烁周期约 0.4 s,肉眼可见。
二、面向 Nexus 的编码风格
Nexus 属于低功耗 FPGA 系列,其架构对时钟资源和功耗敏感。编码时应遵循几条原则:
- 时钟统一:尽量使用全局时钟网络,避免用逻辑信号作为时钟(即“门控时钟”),否则会引入毛刺并增加功耗。
- 复位同步化:异步复位、同步释放是推荐做法,可避免复位撤除时的亚稳态。
- 避免不必要的翻转:计数器位宽够用即可,多余位会持续翻转增加动态功耗。
- 组合逻辑保持简洁:Nexus 的 LUT 资源有限,复杂组合逻辑应拆分或流水化。
- 显式声明位宽和常量:如
24'd9_999_999,避免综合器推断出意外位宽。
三、时钟与复位设计
时钟和复位是数字设计的骨架。Nexus 开发板通常提供 50 MHz 或 12 MHz 晶振,经 PLL 倍频后作为系统时钟。在 Verilog 中,时钟信号只应出现在 posedge/negedge 事件中,不应参与组合逻辑运算。
复位分为异步复位和同步复位。异步复位响应快,但撤除时若靠近时钟边沿可能产生亚稳态;同步复位无此问题,但需要时钟存在才能生效。工程上常用“异步复位、同步释放”结构:
reg rst_sync1, rst_sync2;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rst_sync1 <= 1'b0;
rst_sync2 <= 1'b0;
end else begin
rst_sync1 <= 1'b1;
rst_sync2 <= rst_sync1;
end
end
// rst_sync2 作为内部同步复位使用
这样既保留了异步复位的即时性,又让复位撤除与时钟同步,降低亚稳态风险。
四、第一个 LED 闪烁工程
在 Lattice Diamond 或 Radiant 中新建工程,选择目标 Nexus 器件(如 LIFCL-40),添加上述 blink.v,再编写约束文件 blink.lpf,把 clk、rst_n、led 映射到实际引脚。约束示例:
LOCATE COMP "clk" SITE "P3" ;
IOBUF PORT "clk" IO_TYPE=LVCMOS33 ;
LOCATE COMP "rst_n" SITE "P4" ;
IOBUF PORT "rst_n" IO_TYPE=LVCMOS33 ;
LOCATE COMP "led" SITE "P5" ;
IOBUF PORT "led" IO_TYPE=LVCMOS33 ;
综合、布局布线后生成比特流,下载到开发板。若 LED 以约 0.4 s 周期闪烁,说明时钟、复位、计数器和引脚约束均正确。若 LED 常亮或常灭,优先检查复位极性、计数器比较值和引脚分配。
上图把 LED 闪烁工程拆成“时钟源—PLL—复位同步—计数器—比较器—LED 触发器—引脚输出”的信号链,并标出时钟与复位如何同步作用于各时序单元。理解这条链,就理解了 Nexus 上最基础的数字设计骨架。
cnt 是否被优化掉、比较值是否写错、复位是否一直有效。掌握以上内容后,你已经具备在 Nexus 上编写、约束、综合并下载一个基本时序逻辑工程的能力。后续更复杂的设计,都是在这条“时钟—复位—逻辑—输出”链路上扩展。