一、基础入门
1、整体理解
简单来说,FPGA 就是“可反复编程的逻辑器件”。
ASIC 和 FPGA 就如同印刷品和白纸
ARM 虽然有很多外设,DSP 虽然具备强大的信号运算能力,但是,ARM 能做的,DSP 能做的,FPGA 一定也都能做;而 FPGA 可以做的,ARM 不一定行,DSP 也不一定行。
FPGA 固然强大,它高高在上的成本、功耗和开发复杂性还是会让很多潜在的目标客户望而却步。
2、学习方向
“熟练”:不仅要初步了解 FPGA 是什么、能做什么等基本的理论;更重要的是要学会 HDL语言( Verilog 或 VHDL), 能够使用 EDA 工具完成 FPGA 的代码设计、 仿真验证、 时序设计(这一步相对较难一些,往往需要结合实际应用,所以往往也可以属于下一阶段)、综合和映射,能够在开发板上下载并跑例程,这可以说是完成了入门阶段。
“精通”:如何用合适的 HDL 语法风格设计出最优化的电路;对 EDA 工具的使用,也不是仅仅会了就好,而应该让 EDA 工具的不同设置功能服务于具体的设计优化;同时也应该掌握不同的板级调试手段;
“专业”:参与一个新项目,开发一款新产品。
二、逻辑设计
1、简单晶体管实现基本逻辑门电路
2、在实际工程实践中
FPGA 必须是可编程的(Programmable),意味着我们至少必须要设计一个 2 输入、1输出的可编程的电路才能够名副其实。
前面的晶体管结构的逻辑门电路中,需要 6 个晶体管实现与门和非门电路。但是用 LUT
来实现,同样只是 4 个简单的地址和数据结构就能实现。
以 Xilinx Artix7 系列 FPGA 器件为例,它使用的是 6 输入 LUT 结构。这 6 个独立的输入(称为 A1~A6)可以配置为单输出(O6)模式和双输出(O5 和 O6)模式。如图 2.29 所示,6 输入 1 输出的 LUT 内部对应着 1 个 64 个地址的存储单元。
如图 2.30 所示,5 输入 2 输出的 LUT 内部对应着 2 个 32 个地址的存储单元,输出 O5
和 O6 都有其对应的独立的 32 个地址单元。它的应用场景是一组最多 5 输入同时对应 2 个输出的情况。
3、可配置逻辑块
一颗 FPGA 内部通常都会有丰富的可配置逻辑块(Configurable Logic Block,简称 CLB),根据不同的器件规模,CLB 的数量从数千到数十万不等。如图 2.31 所示,呈矩阵排布的 CLB 就构成了最基本的 FPGA 逻辑资源的架构。
从微观角度看,如图 2.32 所示,CLB 内部主要由 2 个更小的单位 Slice 所组成,每个 Slice都有独立的高速进位链以及独立的布线通道连接到矩阵开关,通过矩阵开关可以实现 Slice与 FPGA 大布线池之间的灵活编程
所有的 slice 的这些功能块都可以用于支持逻辑、运算或 ROM 功能,此时我们称之为
SLICEL;而某些 slice 则可以支持最大 256 位数据存储的分布式 RAM 或最大 32 个 8 位宽的移位寄存器,此时我们称之为 SLICEM。这种逻辑功能和存储器功能之间的转变其实很好理解,由于 slice 内部的 4 个 LUT 本身就是一种存储器实现的结构,所以它也就理所当然的可以被轻易的设计成 ROM、RAM 或移位寄存器功能了。
线(Wires):用于连接各个不同的模块单元,FPGA 内部通常有非常丰富的预连线资源,这些连线也都是根据实际应用设计“可编程”的;
输入/输出端口(Input/Output pads):FPGA 器件与外部芯片互联的引脚。
4、Xilinx 的 Vivado 软件上的编译步骤
首先编写“HDL代码”来描述自己需要实现的电路功能;
然后在 EDA 工具中对其进行“RTL 综合”和“综合”,
“RTL 综合”将 HDL 代码转换为逻辑电路,就如前面提到过的与、或、非等一大堆门电路的各种组合;
“综合”这一步将经过“RTL 综合”后的门电路映射为 FPGA 器件的物理结构;
“实现”这一步将对 FPGA 器件进行最终的布局布线;
最后这些结果将会被转换为可以最终运行在 FPGA 器件上的二级制烧录文件。
三、Verilog语法
1、基础
1、模块声明类语法:module…endmodule
2、端口声明:input, output, inout(inout 的用法比较特殊,需要注意)
3、参数定义:parameter
4、信号类型:wire,reg 等
如图 3.1 所示,在这个简单的电路中,分别定义两个寄存器(reg)锁存当前的输入 din。
每个时钟 clk 上升沿到来时,reg 都会锁存到最新的输入数据,而 wire 就是这两个 reg 之间直接的连线。作为 input 或 inout 的信号端口只能是 wire 型,而 output 则可以是 wire 也可以是 reg。
需要特别说明的是,虽然在代码中我们可以定义信号为 wire 或 reg 类型,但是实际的电路实现是否和我们预先的一致还要看综合工具的表现。例如 reg 定义的信号通常会被综合为一个寄存器(register),但这有一个前提,就是这个 reg 信号必须是在某个由特定信号边沿敏感触发的 always 语句中被赋值。