Vivado Block Design实战:图形化构建三位四选一多路选择器

📅 2026/8/1 13:43:56
Vivado Block Design实战:图形化构建三位四选一多路选择器
1. 项目缘起从原理图到Block Design的跨越如果你刚开始接触FPGA开发或者刚从单片机、数字电路设计转过来那么“三位四选一多路选择器”这个实验你大概率是用原理图Schematic的方式完成的。在Vivado里拖几个逻辑门AND、OR、NOT和输入输出端口I/O Port然后用线Net连起来编译、仿真、上板一气呵成。这确实是最直观、最贴近我们数字电路课本认知的方式。但今天我想和你聊聊另一种更高效、更贴近现代FPGA设计流程的方法——使用Vivado的Block Design块设计。为什么我要专门写一篇关于用Block Design实现这个“简单”电路的文章因为在我看来这个实验是理解Vivado高层次设计工具链的绝佳跳板。当你还在用原理图“画”电路时你本质上是在进行门级设计这和二十年前用Protel画PCB原理图区别不大。而Block Design则是Vivado IP IntegratorIP集成器的核心它让你从“连线”升级到“搭积木”。你不再关心一个与非门内部有几个晶体管而是关心“我这里需要一个多路选择器IP核”、“那里需要一个计数器IP核”然后把它们像乐高一样连接起来。这种设计思想的转变对于后续进行复杂的、包含处理器如MicroBlaze、Zynq ARM的SoC设计至关重要。三位四选一多路选择器功能很简单有4组3位宽的输入数据假设叫A[2:0], B[2:0], C[2:0], D[2:0]一个2位宽的选择信号Sel[1:0]以及一个3位宽的输出Y[2:0]。根据Sel的值00, 01, 10, 11输出Y分别等于A, B, C, D。用Verilog写可能就是一句assign Y (Sel 2‘b00) ? A : (Sel 2’b01) ? B : ...。但今天我们不用写代码也不用画门电路就用纯图形化的Block Design来实现它并深入理解背后的每一个步骤和细节。2. Block Design核心概念与工作环境搭建在开始动手之前我们必须先统一思想理解Block Design到底是什么以及它和传统原理图设计的本质区别。你可以把Block Design理解为一个“系统级画布”。在这个画布上你放置的不是一个一个的逻辑门而是一个一个具有明确功能和接口的“块”Block这些块就是IP核Intellectual Property Core。IP核可以是Xilinx官方提供的如数学运算、存储器、接口控制器也可以是你自己用HDLVerilog/VHDL封装好的模块甚至是来自第三方的成熟设计。Block Design的核心优势在于抽象和复用。它通过标准的接口协议如AXI4、AXI4-Lite、AXI4-Stream来连接各个IP核设计师无需关心IP核内部的实现细节只需关注其对外提供的功能接口和时序。这极大地提高了设计效率降低了连接错误的风险并且使得整个系统的架构一目了然。对于我们的多路选择器虽然看起来“杀鸡用牛刀”但正是通过这个简单例子我们能无压力地熟悉整个Block Design的创建、配置、连接和导出流程。注意使用Block Design并不意味着完全取代HDL编码。在实际项目中两者是相辅相成的。算法核心、定制逻辑通常用HDL实现并封装成IP核然后在Block Design中与处理器、外设控制器等系统级IP进行集成。接下来我们搭建工作环境。首先确保你安装了Vivado Design Suite建议使用2018.3及以后版本界面和流程相对稳定。启动Vivado后我们创建一个新项目点击“Create Project”向导。项目类型选择“RTL Project”并勾选“Do not specify sources at this time”。因为我们完全使用图形化设计暂时不需要添加HDL文件。选择对应的FPGA器件型号例如对于学习板可能是Artix-7系列的xc7a35tftg256-1等。这一步很重要它决定了后续可用的IP核库。完成项目创建。项目创建好后在左侧的“Flow Navigator”面板中找到“IP INTEGRATOR”栏目点击其中的“Create Block Design”。这时会弹出一个对话框让你为这个Block Design命名并指定设计目录。我们可以命名为mux_4x1_3bit。确认后Vivado会打开一个空白的Diagram图表窗口这就是我们的主设计画布。同时左侧的“Sources”窗口下在“Design Sources”里会出现一个mux_4x1_3bit.bd文件这就是Block Design的源文件。所有我们的图形化操作最终都会保存到这个.bd文件中。3. 寻找与定制核心IPUtility Vector Logic的应用我们的目标是实现一个3位宽、4选1的多路选择器。在Vivado的IP Catalog中并没有一个直接叫“Mux 4:1”的IP核。那该怎么办这里就需要一点设计思维的转换。我们需要的核心功能是“数据选择”而Vivado提供了一个非常基础且强大的IP核家族——Utility Vector Logic。这个IP核可以实现基本的位逻辑操作如与、或、非、异或等但它有一个隐藏的强大功能可以通过配置实现一个多路选择器。在Diagram窗口的空白处右键选择“Add IP...”或者在左侧的“IP INTEGRATOR”面板点击“”号。这会打开IP Catalog窗口。在搜索框输入“Utility Vector Logic”然后双击它一个该IP的实例就会被添加到画布上。默认添加的util_vector_logic实例实现的是一个2输入的逻辑与AND操作这显然不是我们想要的。接下来是关键的一步配置这个IP核。双击画布上的util_vector_logic_0模块会打开它的配置窗口Re-customize IP。我们需要关注几个关键参数Operation: 这是核心。下拉菜单里并没有直接的“MUX”。但是仔细看有一个选项叫“MUX”。是的Utility Vector LogicIP支持多路复用功能。选择“MUX”。C_SIZE: 这个参数定义了数据通路的位宽。我们的数据是3位宽所以这里要设置为3。Input Ports: 当你选择Operation为MUX后输入端口配置会发生变化。对于一个C_SIZEN的MUX它会生成一个N位宽的Op1输入、一个N位宽的Op2输入以及一个1位宽的Sel输入。但是这是一个2选1的MUX它只有两个数据输入通道Op1和Op2一个选择信号Sel0时选Op1Sel1时选Op2。我们需要的是4选1。如何用2选1的MUX搭建4选1这是数字电路的基础知识通过级联。一个4选1多路选择器可以用三个2选1多路选择器来实现。具体结构是第一级两个MUX分别从四路输入中两两选出一路第二级一个MUX从第一级输出的两路中选出一路作为最终输出。选择信号Sel[1:0]中Sel[0]最低位控制第一级的两个MUXSel[1]最高位控制第二级的MUX。因此我们需要在画布上添加三个Utility Vector LogicIP核并将它们的Operation都配置为“MUX”C_SIZE都配置为3。我们可以分别将它们重命名为mux_stage1_ab,mux_stage1_cd,mux_stage2_final以便于区分。重命名的方法是选中IP实例在右侧的“Block Properties”窗口中找到“Name”字段进行修改。4. 构建完整数据通路IP核连接与外部端口创建现在画布上有三个配置好的MUX IP核了但它们还是孤立的方块。我们需要用“线”把它们连接起来并引出对外的输入输出端口。首先处理输入数据。每个MUX IP核有两个3位宽的输入端口Op1和Op2。我们需要为整个系统创建4个3位宽的输入端口A, B, C, D和1个2位宽的选择端口Sel。在Diagram窗口的空白处右键选择“Create Port...”。会弹出端口创建对话框Port name: 输入A。Direction: 选择Input。Type: 选择Bus。MSB/LSB: MSB填2 LSB填0。这定义了一个从第2位到第0位的3位宽总线。 点击“OK”一个名为A的输入端口就会出现在画布上。重复这个过程创建输入端口B[2:0],C[2:0],D[2:0]以及选择端口Sel[1:0]Direction为Input Type为Bus MSB1, LSB0。接着创建输出端口。同样“Create Port...”命名为YDirection为OutputType为BusMSB2, LSB0。现在开始连接第一级MUX连接将端口A连接到mux_stage1_ab的Op1端口。将端口B连接到mux_stage1_ab的Op2端口。将端口C连接到mux_stage1_cd的Op1端口。将端口D连接到mux_stage1_cd的Op2端口。选择信号Sel是一位但我们有两位。我们需要将Sel总线拆开。这里有一个小技巧Sel是一个2位总线Sel[0]是第0位。我们可以直接拖拽Sel端口的一条线到mux_stage1_ab的Sel端口Vivado会自动弹出“Make Connection”对话框让你选择连接哪一位。选择Bit 0。对mux_stage1_cd的Sel端口也做同样操作连接Sel的Bit 0。这样第一级的两个MUX都由选择信号的最低位Sel[0]控制。第二级MUX连接将mux_stage1_ab的Res结果输出端口连接到mux_stage2_final的Op1端口。将mux_stage1_cd的Res端口连接到mux_stage2_final的Op2端口。将Sel总线的Bit 1最高位连接到mux_stage2_final的Sel端口。这样当Sel[1]0时输出第一级中Sel[0]选出的AB中的一路当Sel[1]1时输出第一级中Sel[0]选出的CD中的一路。这就完整实现了4选1的逻辑。最后将mux_stage2_final的Res输出端口连接到系统的输出端口Y。连接完成后你的Diagram应该是一个清晰的树状结构四个输入汇聚到两个第一级MUX它们的输出汇聚到第二级MUX最终输出到Y。选择信号Sel的两位分别控制着不同层级的MUX。这时候你可以点击Diagram工具栏上的“Regenerate Layout”通常是一个环形箭头图标让Vivado自动优化一下布局使连线更清晰。提示在连接总线到单个位宽的端口时如Sel[0]到SelVivado的自动连接有时会不太直观。如果直接拖拽不成功你可以先点击源端口如Sel然后将鼠标移动到目标端口如MUX的Sel附近当出现一个带加号的链图标时再点击在弹出菜单中选择具体的位进行连接。这是一个非常实用的技巧在连接复杂总线时经常用到。5. 设计验证生成HDL包装与行为仿真图形化设计完成后它只是一张“图”。FPGA工具链最终需要的是HDL网表。因此我们需要将Block Design“转换”成工具可以理解的格式。这一步叫做“生成输出产品”Generate Output Products。在Diagram窗口上方的工具栏或者左侧“Flow Navigator”中“IP INTEGRATOR”下的“Block Design”节点右键选择“Generate Block Design”。Vivado会执行一系列操作检查设计完整性、为Block Design生成顶层的HDL包装文件Wrapper、为各个IP核生成对应的综合/实现网表。这个过程可能会花一点时间。生成成功后在“Sources”窗口的“Design Sources”下你会看到mux_4x1_3bit.bd下面多出了一个子项mux_4x1_3bit_wrapper。这是一个Verilog或VHDL文件取决于你的项目设置它就是整个Block Design对外的“黑盒子”接口。你可以双击打开它查看里面实例化了你的.bd模块并将我们创建的端口A, B, C, D, Sel, Y暴露出来。这个wrapper文件就是我们需要在更高层次调用的顶层模块。接下来进行仿真验证功能是否正确。我们创建一个简单的测试平台Testbench。在“Sources”窗口的“Simulation Sources”上右键选择“Add Sources” - “Add or create simulation sources” - “Create File”。创建一个名为tb_mux_4x1_3bit的Verilog测试文件。在测试文件中我们需要实例化mux_4x1_3bit_wrapper模块并编写测试逻辑。一个基础的测试脚本应该遍历所有可能的输入组合4组3位输入共12位数据理论上2^124096种组合但我们可以简化主要测试选择功能。更实际的方法是我们固定几组有代表性的输入数据然后遍历4种选择状态。timescale 1ns / 1ps module tb_mux_4x1_3bit(); reg [2:0] A_tb, B_tb, C_tb, D_tb; reg [1:0] Sel_tb; wire [2:0] Y_tb; // 实例化设计顶层 mux_4x1_3bit_wrapper uut ( .A(A_tb), .B(B_tb), .C(C_tb), .D(D_tb), .Sel(Sel_tb), .Y(Y_tb) ); initial begin // 初始化输入 A_tb 3b001; B_tb 3b010; C_tb 3b100; D_tb 3b111; Sel_tb 2b00; // 遍历选择信号 #100 Sel_tb 2b00; #100 Sel_tb 2b01; #100 Sel_tb 2b10; #100 Sel_tb 2b11; // 再换一组输入测试 #100; A_tb 3b101; B_tb 3b110; C_tb 3b000; D_tb 3b011; Sel_tb 2b00; #100 Sel_tb 2b01; #100 Sel_tb 2b10; #100 Sel_tb 2b11; #100 $finish; end endmodule保存测试文件后在左侧“Flow Navigator”的“SIMULATION”下点击“Run Simulation” - “Run Behavioral Simulation”。Vivado会编译仿真库并启动仿真。在打开的仿真波形窗口你需要手动将uut实例化模块下的所有信号A_tb, B_tb, C_tb, D_tb, Sel_tb, Y_tb添加到波形图中。然后重新运行仿真Restart - Run All。观察波形验证当Sel_tb变化时Y_tb的输出是否严格对应A_tb,B_tb,C_tb,D_tb。例如当Sel_tb2‘b10时Y_tb应等于C_tb3’b100。通过波形验证是确保逻辑功能正确的关键一步。6. 综合、实现与上板调试仿真通过后就可以进行综合Synthesis和实现Implementation了这是将逻辑设计映射到具体FPGA器件资源的过程。在“Flow Navigator”的“PROGRAM AND DEBUG”栏目下直接点击“Generate Bitstream”。Vivado会自动依次执行综合、实现和比特流生成。这个过程时间较长期间会进行逻辑优化、布局布线等操作。生成比特流过程中有两点需要特别关注资源利用率报告综合完成后可以在“Open Synthesized Design”中查看资源使用情况。对于我们这个设计三个3位宽的2选1MUX消耗的应该是LUT查找表资源。一个6输入LUTArtix-7系列可以实现任意6输入1输出的逻辑函数。我们的每个MUX3位宽本质上需要3个独立的2选1选择器。每个2选1选择器的逻辑是Y (Sel D1) | (~Sel D0)这是一个3输入1输出的函数完全可以用一个6输入LUT实现实际上可能更少。因此整个设计预计消耗9个LUT3个MUX * 3位。你可以通过报告验证这个估算理解图形化设计最终是如何映射到硬件资源的。I/O规划我们的设计有输入输出端口但还没有指定它们具体对应FPGA芯片的哪个物理引脚。在上板之前必须进行引脚约束。点击“Open Synthesized Design”或“Open Implemented Design”然后在顶部菜单栏选择“Window” - “I/O Ports”。会打开I/O端口窗口列出所有顶层端口。你需要根据你的FPGA开发板原理图将A[0],A[1],A[2]...Y[2]以及Sel[0],Sel[1]分配到具体的芯片引脚号Package Pin并设置正确的I/O标准如LVCMOS33 3.3V LVTTL。例如你可以将Sel[1:0]分配到两个拨码开关对应的引脚将A[2:0]等输入分配到按键或通过代码产生将Y[2:0]分配到三个LED灯对应的引脚。约束完成后需要重新运行“Generate Bitstream”。比特流生成成功后连接好FPGA开发板和下载器点击“Open Hardware Manager”连接设备然后“Program device”将生成的.bit文件下载到FPGA中。上板后通过拨动拨码开关改变Sel值观察LED灯代表Y输出的状态是否与输入可以通过固定接高电平或低电平的引脚来模拟A/B/C/D的不同值和选择逻辑相符。这是最终的硬件验证。7. 进阶思考封装自定义IP与设计复用通过以上步骤我们已经用Block Design完成了一个功能完整的多路选择器。但我们可以更进一步。想象一下如果我在另一个更大的系统中需要用到这个“三位四选一多路选择器”模块难道要重新画一遍吗当然不是。Vivado允许我们将Block Design或者任何HDL模块封装成自定义的IP核加入到IP Catalog中以便在其他项目中像使用官方IP一样直接调用。具体操作如下在当前项目中在“Sources”窗口右键点击你的mux_4x1_3bit.bd文件选择“Create HDL Wrapper”确保wrapper已更新。然后在顶部菜单栏选择“Tools” - “Create and Package New IP...”。按照向导选择“Package your current project”然后下一步。在“Package IP”窗口中你需要指定IP的输出目录、版本、名称等信息。最关键的一步是在“Compatibility”页面确保IP支持你的FPGA器件家族。在“Review and Package”页面点击“Package IP”。Vivado会打开一个新的临时项目来封装IP。封装完成后这个自定义IP就被保存在本地IP仓库了。以后在新的Vivado项目中你只需要在“Settings” - “IP” - “Repository”中添加你保存IP的目录然后在IP Catalog中搜索你命名的IP例如“my_mux_4x1_3bit”就可以像添加其他IP一样直接拖入新的Block Design中使用。这实现了设计成果的最大化复用。实操心得封装自定义IP时务必仔细检查自动生成的“端口与接口”Ports and Interfaces以及“地址映射”Address Map如果有时钟或总线接口。对于我们这个纯组合逻辑的MUX接口很简单。但对于包含寄存器、时钟、复位信号的模块Vivado可能会尝试推断出AXI等接口需要手动调整或确认。良好的IP封装是构建模块化、可复用FPGA系统的基础。8. Block Design设计方法评析与避坑指南回顾整个流程我们用一种“图形化编程”的方式实现了一个数字电路。这种方法利弊都很明显。优势直观可视系统架构一目了然特别适合连接关系复杂的系统集成比如连接处理器、DMA、存储器控制器等。减少错误基于IP核和标准接口避免了手动编写HDL时容易出现的连线错误、位宽不匹配等问题。提升效率对于使用大量标准IP如Xilinx的LogiCORE IP的设计图形化连接比手动实例化并配置参数要快得多。便于团队协作Block Design.bd文件可以很清晰地展示系统框图方便沟通。劣势与陷阱抽象泄漏对于纯组合逻辑或简单的时序逻辑使用Block Design可能显得臃肿。像本例用一句Verilogassign语句就能完成的事情我们用了三个IP核和一堆连线。这增加了设计的间接性。调试复杂性当设计出现问题时你需要深入生成的HDL网表或综合后的原理图进行调试不如直接阅读自己写的RTL代码直观。版本控制.bd文件是XML格式的虽然可读但直接进行diff和merge比较困难不如纯文本的HDL代码友好。对IP核的依赖设计被绑定在特定的IP核版本和配置上。如果IP核更新或配置变更需要重新生成和验证。常见坑点与解决方案IP核锁相有时在重新打开项目或升级Vivado后IP核会显示“锁住”Locked状态提示需要升级或重新生成。这是因为IP核的生成输出产品.xci文件与当前Vivado版本或设置不兼容。解决方法在Block Design上右键选择“Report IP Status”然后根据提示“Upgrade Selected”或“Re-run Generation”。接口连接错误连接总线时位宽不匹配是常见错误。务必仔细检查每个端口的位宽。Vivado通常会用红色波浪线标出错误连接。时钟与复位处理本例是纯组合逻辑没有时钟。但在绝大多数Block Design中时钟和复位网络是核心。必须确保时钟信号从时钟生成器Clocking Wizard正确分配到所有需要时钟的IP核并且复位信号是同步的、满足时序要求的。一个最佳实践是使用“Processor System Reset”这类IP来生成稳定的系统复位。仿真模型缺失有些IP核尤其是一些高速接口IP的仿真模型可能需要额外的License或者编译步骤。如果仿真时遇到找不到模块的错误需要检查该IP是否支持行为仿真或者是否需要编译仿真库。我个人在实际操作中的体会是Block Design是Vivado工具链中面向“系统集成”的利器而非“底层逻辑设计”的最佳选择。对于算法模块、状态机、定制数据处理流水线我依然倾向于使用Verilog/VHDL进行精确描述。然后将这些模块封装成带AXI-Lite或AXI-Stream接口的IP核最后在Block Design这个“顶层装配车间”里将它们与CPU、DDR控制器、以太网MAC等大型IP核连接起来。这种“自底向上设计自顶向下集成”的模式兼顾了灵活性和效率。所以不要把Block Design看作替代HDL的工具而应视其为HDL模块的“集成框架”和“连接器”。从这个小实验开始掌握它未来当你面对Zynq或Versal这类包含处理器的异构平台时你会感谢今天在这些基础步骤上花费的时间。