Zynq基础与FPGA开发入门 - 第3节

一、数字逻辑基础:从与或非门到触发器

各位同学,咱们今天聊聊FPGA的根基——数字逻辑。说实话,我刚开始学FPGA时,总觉得这些基础电路离实际开发很远。后来做了几个项目才发现,很多bug的根源,恰恰是这些最基础的东西没搞透。

1.1 与或非门:数字世界的原子

数字电路里,与门、或门、非门就是最基本的"原子"。你想想看,再复杂的处理器,拆到最底层也就是这些门的组合。

  • 与门(AND):两个输入都为1,输出才为1。用乘法表示:Y = A · B
  • 或门(OR):只要有一个输入为1,输出就是1。用加法表示:Y = A + B
  • 非门(NOT):输入取反。Y = ¬A

我个人的小习惯:写Verilog时,我更喜欢用逻辑运算符 &、|、~ 而不是直接用门级原语。代码可读性会好很多,尤其是做复杂逻辑时。

举个实际例子。我在做某个通信接口时,需要检测一个8位总线是否全为0。用与门组合?太麻烦。直接写 assign all_zero = ~|data_bus; 一行搞定。这就是组合逻辑的魅力。

1.2 触发器:让电路记住状态

组合逻辑只能处理当前输入,但实际系统需要"记忆"。触发器就是干这个的。

最常见的D触发器,说白了就是一个"采样保持器"。时钟上升沿来的时候,它把输入D的值"拍"到输出Q上,然后保持住,直到下一个时钟沿。

避坑指南:我曾经在项目里犯过一个低级错误——把触发器的时钟和复位信号搞反了极性。结果仿真全对,上板全错。后来花了整整两天才定位到问题。记住:时钟沿和复位电平一定要和你的设计意图一致。

触发器的几个关键参数,我建议你记牢:

参数 含义 典型值
建立时间(tsu) 数据在时钟沿前必须稳定的时间 0.2~0.5 ns
保持时间(th) 数据在时钟沿后必须稳定的时间 0.1~0.3 ns
时钟到输出延迟(tco) 时钟沿到输出稳定的时间 0.3~0.8 ns

嗯,这些时序参数在Vivado的时序报告里会反复出现。你跑一次综合、实现,就能看到它们。

二、Verilog HDL基础语法:从零开始写代码

Verilog,说白了就是描述数字电路的"语言"。它不像C语言那样顺序执行,而是描述硬件结构。这个思维转变,是很多初学者最难受的地方。

2.1 模块:最小的设计单元

每个Verilog设计都以 module 开始,endmodule 结束。模块就是你的"黑盒子"——定义输入输出,内部实现功能。

module counter (
    input  wire       clk,      // 时钟
    input  wire       rst_n,    // 复位,低有效
    output reg  [3:0] count     // 4位计数器输出
);

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            count <= 4'd0;
        else
            count <= count + 1'b1;
    end

endmodule

这段代码,我估计你以后会写几百遍。一个简单的计数器,包含了时钟、复位、寄存器、赋值——这些都是FPGA设计的核心要素。

2.2 数据类型:wire 和 reg

初学者最容易搞混的就是 wire 和 reg。我直接说结论:

  • wire:组合逻辑连线。用 assign 赋值。
  • reg:寄存器或组合逻辑变量。在 always 块里赋值。

注意:reg 不一定是寄存器!在组合逻辑的 always 块里,reg 综合出来只是连线。这个坑我见过太多人踩了。判断标准很简单:看 always 块的敏感列表里有没有时钟沿。有时钟沿才是寄存器,否则就是组合逻辑。

2.3 运算符:别小看这些符号

Verilog的运算符和C语言很像,但有几个需要特别注意:

运算符 含义 示例
& 按位与 4'b1010 & 4'b1100 = 4'b1000
| 按位或 4'b1010 | 4'b1100 = 4'b1110
^ 按位异或 4'b1010 ^ 4'b1100 = 4'b0110
&& 逻辑与 用于条件判断
|| 逻辑或 用于条件判断
{} 拼接运算符 {a, b} 把a和b拼起来

我个人最常用的是拼接运算符。比如要生成一个8位的独热码,assign one_hot = 1'b1 << position; 比写一堆 case 语句方便多了。

三、组合逻辑与时序逻辑:理解本质区别

这个知识点,我建议你花点时间彻底搞懂。因为FPGA里90%的bug,都出在混淆了这两种逻辑。

3.1 组合逻辑:输入决定输出

组合逻辑的输出只取决于当前输入。没有记忆,没有时钟。典型的例子:加法器、多路选择器、译码器。

// 组合逻辑:4选1多路选择器
module mux4 (
    input  [1:0] sel,
    input  [3:0] data_in,
    output reg   data_out
);

    always @(*) begin
        case (sel)
            2'b00: data_out = data_in[0];
            2'b01: data_out = data_in[1];
            2'b10: data_out = data_in[2];
            2'b11: data_out = data_in[3];
            default: data_out = 1'b0;
        endcase
    end

endmodule

注意看,always 块的敏感列表是 @(*),表示所有输入信号变化都会触发。这就是组合逻辑的标志。

3.2 时序逻辑:时钟驱动一切

时序逻辑的输出不仅取决于当前输入,还取决于之前的状态。说白了,它有"记忆"。触发器、计数器、状态机都是时序逻辑。

// 时序逻辑:带使能的8位移位寄存器
module shift_reg (
    input  wire       clk,
    input  wire       rst_n,
    input  wire       en,
    input  wire       din,
    output reg  [7:0] dout
);

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            dout <= 8'd0;
        else if (en)
            dout <= {dout[6:0], din};  // 左移,低位补入新数据
    end

endmodule

关键区别:组合逻辑用 =(阻塞赋值),时序逻辑用 <=(非阻塞赋值)。这个规则,我建议你当成铁律来遵守。我在代码评审时,看到混用赋值方式的代码,基本都会打回去重写。

四、Vivado工程创建与仿真:动手实践

理论说完了,咱们来点实际的。Vivado是Xilinx的集成开发环境,咱们用它来创建工程、写代码、跑仿真。

4.1 创建工程

步骤很简单,但有几个细节要注意:

  1. 打开Vivado,点击 Create Project
  2. 选择 RTL Project,勾选 Do not specify sources at this time(后面再添加文件)
  3. 选择芯片型号。咱们课程用 xc7z020clg400-1(Zynq-7020)
  4. 点击 Finish,工程就创建好了

我的建议:工程命名最好有规律,比如 lab1_counter、lab2_uart。别用 test、project1 这种名字。不然三个月后你自己都找不到哪个工程是干嘛的。

4.2 添加设计文件与仿真

在工程里右键 Add Sources,选择 Add or create design sources,然后新建一个Verilog文件。把咱们刚才的计数器代码写进去。

仿真才是验证设计的核心。Vivado自带的仿真器够用,咱们写个testbench:

`timescale 1ns / 1ps

module tb_counter;

    reg  clk;
    reg  rst_n;
    wire [3:0] count;

    // 实例化被测试模块
    counter uut (
        .clk   (clk),
        .rst_n (rst_n),
        .count (count)
    );

    // 生成时钟:10ns周期,100MHz
    always #5 clk = ~clk;

    // 测试激励
    initial begin
        clk   = 0;
        rst_n = 0;
        #20;
        rst_n = 1;
        #200;
        $finish;
    end

endmodule

跑仿真时,记得在 Simulation 里选择 Run Behavioral Simulation。然后就能看到波形了。

我曾经犯过的错:仿真通过就以为设计没问题,直接上板。结果板子跑起来完全不对。后来发现是testbench里忘了给复位信号加足够的延迟。记住:仿真通过只是第一步,时序约束、上板调试才是真正的考验。

本章知识体系

下面这张图,是我自己总结的本章知识脉络。你把它存下来,学完这章后对照着回顾一遍,效果会好很多。

第1章:FPGA基础回顾 - 知识体系 数字逻辑基础 与门、或门、非门 D触发器、JK触发器 建立时间/保持时间 时序参数概念 Verilog HDL语法 module/endmodule wire与reg区别 阻塞/非阻塞赋值 运算符与表达式 逻辑设计分类 组合逻辑特点 时序逻辑特点 always @(*) vs @(posedge) = 与 <= 使用场景 Vivado工程实践 创建RTL工程 添加设计文件 编写testbench 行为仿真验证 理论 → 代码 → 仿真 → 验证,闭环学习

好了,第一章的内容就到这里。数字逻辑是FPGA的基石,Verilog是描述工具,Vivado是实践平台。这三者缺一不可。下一章咱们会深入讲Verilog的进阶语法和模块化设计,到时候见。


可可精品资料库