FPGA学习笔记<2>Verilog输入

一、二选一选择器是做什么的?

二选一选择器,也叫 2 选 1 多路选择器,英文是 Multiplexer,简称 MUX。

它有三个输入:

  • a:数据输入 0

  • b:数据输入 1

  • sel:选择信号

一个输出:

  • y:输出结果

逻辑关系很简单:

  • sel = 0 时,输出 y = a

  • sel = 1 时,输出 y = b

真值表如下:

sel a b y
0 0 0 0
0 0 1 0
0 1 0 1
0 1 1 1
1 0 0 0
1 0 1 1
1 1 0 0
1 1 1 1

一句话总结:

sel 等于 0 时选 asel 等于 1 时选 b

二、Vivado 2018.3 新建工程

打开 Vivado 2018.3,按下面步骤操作:

  1. 点击 Create Project

  2. 点击 Next

  3. 输入工程名,例如 mux2_1

  4. 选择工程路径,注意路径不要有中文和空格

  5. Project Type 选择 RTL Project

  6. 勾选 Do not specify sources at this time,先不添加文件

  7. 选择目标器件:

    • 如果你有开发板,选择对应芯片型号

    • 如果只是仿真学习,随便选一个即可

  8. 点击 Finish

工程创建完成后,我们就进入 Vivado 主界面。


三、添加 Verilog 设计文件

在左侧 Flow Navigator 中,找到:

Project Manager -> Add Sources

然后:

  1. 选择 Add or create design sources

  2. 点击 Next

  3. 点击 Create File

  4. File type 选择 Verilog

  5. File name 填写 mux2_1

  6. 点击 OK

  7. 点击 Finish

这时 Vivado 会生成一个 mux2_1.v 文件。双击打开它,输入下面的代码。

写法一:使用 assign,最适合小白

复制代码
module mux2_1(
    input  a,
    input  b,
    input  sel,
    output y
);

    assign y = sel ? b : a;

endmodule

解释一下:

  • module mux2_1:定义一个模块,名字叫 mux2_1

  • input a:输入端口 a

  • input b:输入端口 b

  • input sel:输入端口 sel

  • output y:输出端口 y

  • assign:连续赋值语句,常用于组合逻辑

  • sel ? b : a:三元运算符

    • sel 为 1 时,结果是 b

    • sel 为 0 时,结果是 a

所以这句话的意思就是:

如果 sel = 1y = b;否则 y = a

四、理解 Verilog 的"输入"

Verilog 模块就像一块芯片:

  • input 是芯片的输入引脚

  • output 是芯片的输出引脚

在模块内部:

  • input 只能读,不能赋值

  • output 是模块向外输出的结果

比如:

verilog

复制代码
input a;
input b;
input sel;
output y;

意思就是:

  • 外面给这个模块送进来三个信号:absel

  • 模块算出一个结果 y 送出去

在 Vivado 里"输入 Verilog 代码",其实就是:

  1. 新建 .v 文件

  2. 在文件里写 module ... endmodule

  3. 保存

  4. Vivado 自动检查语法

  5. 综合工具把你的代码翻译成硬件电路

小白要记住几个基本规则:

  • Verilog 区分大小写

  • 每条语句结尾通常要有分号 ;

  • 文件名最好和模块名一致,例如 mux2_1.v 里写 module mux2_1

  • 注释用 ///* ... */

  • 组合逻辑常用 assignalways @(*)


五、添加 Testbench 仿真文件

设计文件写完后,还需要一个测试文件,叫 Testbench。

Testbench 的作用是:

给被测模块提供输入信号,观察输出信号是否正确。

继续在 Vivado 中操作:

  1. Add Sources

  2. 选择 Add or create simulation sources

  3. 点击 Next

  4. 点击 Create File

  5. File type 选择 Verilog

  6. File name 填写 mux2_1_tb

  7. 点击 OK

  8. 点击 Finish

然后打开 mux2_1_tb.v,输入:

verilog

复制代码
`timescale 1ns / 1ps

module mux2_1_tb;

    reg a;
    reg b;
    reg sel;
    wire y;

    mux2_1 uut (
        .a(a),
        .b(b),
        .sel(sel),
        .y(y)
    );

    initial begin
        a = 0; b = 0; sel = 0;
        #10;

        a = 0; b = 1; sel = 0;
        #10;

        a = 1; b = 0; sel = 0;
        #10;

        a = 1; b = 1; sel = 0;
        #10;

        a = 0; b = 0; sel = 1;
        #10;

        a = 0; b = 1; sel = 1;
        #10;

        a = 1; b = 0; sel = 1;
        #10;

        a = 1; b = 1; sel = 1;
        #10;

        $finish;
    end

endmodule

解释一下 Testbench:

  • reg a; reg b; reg sel;

    • 因为 absel 需要在 initial 里被赋值,所以声明为 reg
  • wire y;

    • y 由被测模块输出驱动,所以用 wire
  • mux2_1 uut (...)

    • 例化被测模块

    • uut 是实例名,可以自己起

    • .a(a) 表示把 Testbench 里的 a 连接到模块的 a

  • initial begin ... end

    • 仿真开始后只执行一次
  • #10

    • 延时 10 个时间单位

    • 因为前面写了 ```timescale 1ns / 1ps``,所以是延时 10ns

  • $finish

    • 结束仿真

这段 Testbench 会把 8 种输入组合都测试一遍。


六、运行行为仿真

在 Vivado 左侧 Flow Navigator 中:

Simulation -> Run Simulation -> Run Behavioral Simulation

如果弹出窗口,点击 OK

仿真运行后,会出现波形窗口。你可以:

  1. 找到 mux2_1_tb

  2. 展开信号

  3. 观察 absely

  4. 点击 Zoom Fit 查看完整波形

预期结果:

  • sel = 0 时,y 应该等于 a

  • sel = 1 时,y 应该等于 b

如果波形正确,说明二选一选择器设计成功。


七、综合、实现和生成比特流

如果只是学习仿真,到上一步就可以了。

如果你想下载到 FPGA 开发板,还需要继续:

  1. Flow Navigator -> Synthesis -> Run Synthesis

  2. 综合完成后,选择 Run Implementation

  3. 实现完成后,选择 Generate Bitstream

  4. 生成比特流后,打开 Open Hardware Manager

  5. 连接开发板,下载程序

不过,上板之前还需要添加引脚约束文件 XDC。


八、上板时的 XDC 约束示例

不同开发板的引脚不同,下面只是示例,不能直接照抄:

tcl

复制代码
# 假设 a 接 SW0,b 接 SW1,sel 接 SW2,y 接 LED0
set_property -dict {PACKAGE_PIN P5 IOSTANDARD LVCMOS33} [get_ports a]
set_property -dict {PACKAGE_PIN P6 IOSTANDARD LVCMOS33} [get_ports b]
set_property -dict {PACKAGE_PIN P7 IOSTANDARD LVCMOS33} [get_ports sel]
set_property -dict {PACKAGE_PIN M5 IOSTANDARD LVCMOS33} [get_ports y]

注意:

  • 引脚编号必须查你开发板的原理图

  • 电平标准也要看开发板,常见是 LVCMOS33

  • 如果 LED 是低电平点亮,输出逻辑可能需要取反


九、小白常见问题

1. 为什么 Testbench 里输入用 reg,输出用 wire?

因为输入信号需要在 initialalways 里赋值,只有 reg 可以这样做。

输出信号由被测模块驱动,所以用 wire

2. 为什么设计文件里 output y 可以直接用 assign?

因为 assign 驱动的是线网类型,output y 默认就是 wire

3. 为什么 always 写法里要写 output reg y

因为 always 块中赋值的变量必须是 reg 类型。

4. 仿真波形全是红色 X 怎么办?

常见原因:

  • 输入信号没有初始化

  • 模块例化端口连接错误

  • Testbench 没有设置成仿真顶层

  • 模块名和文件名不一致

5. always @(*)always @(a or b or sel) 有什么区别?

@(*) 会自动包含所有输入信号,不容易漏写,推荐使用。


十、总结

本文完成了 FPGA 入门中非常经典的一个例子:二选一选择器。

你学会了:

  • 在 Vivado 2018.3 中新建工程

  • 添加 Verilog 设计文件

  • assignalways 两种方式实现二选一选择器

  • 理解 inputoutputwirereg

  • 编写 Testbench

  • 运行行为仿真

  • 查看波形验证功能

虽然二选一选择器很简单,但它包含了 Verilog 输入、模块定义、端口连接、组合逻辑和仿真验证的完整流程。

把这个例子练熟之后,你可以继续尝试:

  • 四选一选择器

  • 半加器、全加器

  • 计数器

  • 分频器

  • 流水灯

相关推荐
学习FPGA的电气小兴兴4 小时前
基于FPGA的CORDIC向量模式实现arctan运算,Verilog HDL实现
嵌入式硬件·fpga开发·数字信号处理·verilog·fpga·cordic·arctan
恒锐丰科技林技术员6 小时前
EG2203:一款高性价比 600V 半桥驱动芯片
经验分享·嵌入式硬件·硬件工程
hilda_jlu8 小时前
OSPI的时序
硬件工程
硬禾科技1 天前
连接世界的工程哲学
嵌入式硬件·测试工具·自动化·硬件工程
普通小毕1 天前
Verilog 异步 FIFO 设计详解:格雷码跨时钟域与空满判断
硬件工程
FPGA小迷弟1 天前
FPGA 应用技术能力的完整闭环(1-4)
fpga开发·dsp开发·fpga·sdr·无线电
深圳市恒锐丰科技杨生1 天前
EG6288 220V 三相独立半桥栅极驱动芯片|屹晶 EGmicro
嵌入式硬件·硬件工程
Eloudy1 天前
FPGA 开发与 IC 数字前端设计
fpga开发
tju新生代魔迷1 天前
Verilog HDL 学习笔记(十八)| 附录C:关键字、系统任务和编译指令
fpga开发