2026/10/28 3:34:26

FPGA层次化工程入门:VHDL逻辑门结构化设计与ISE仿真综合

FPGA层次化工程入门:VHDL逻辑门结构化设计与ISE仿真综合 简介这份文档面向软件工程专业学生与FPGA入门学习者是一份数字系统设计实验报告重点围绕简单逻辑门的RTL描述、结构化电路搭建与VHDL层次化建模展开可辅助完成ISE集成环境下的基础实验、课程作业与报告整理。压缩包内仅1个docx文件大小约267KB正文按实验原理、实现步骤、测试结果和总结组织并涉及MY_AND2、MY_OR2及顶层AND_OR模块的语法检查、原理图生成与仿真验证也覆盖FPGA可编程特性、HDL编辑器使用和层次结构描述等知识点。已有345人学习适合需要参考实验流程、理解模块调用与信号连接方式的学习者。读者可据此梳理从新建工程、编写HDL代码到生成底层电路并查看测试输出的完整脉络也可借鉴其中的模块划分、端口连接与报告撰写框架用于课前预习、实验排错和课后复盘。1. 一次 FPGA 实验从“门”开始为什么第一次课就要求你搭层次化工程第一次做 FPGA 数字系统设计实验多数人的注意力会放在“写两行代码实现一个与门”上真正卡住的地方却在别处工程建在哪个目录、顶层模块是哪一个、两个门之间到底怎么连起来、综合出来的原理图为什么只有一个方块点不进去。这个实验的考点从来不是与门或门本身而是层次化工程这套组织方式——底层实体各自描述自己的行为顶层结构体只负责例化和连线VHDL 的 component 声明加 port map 把上下两层接起来。这套做法适合刚接触 fpga 开发、要交第一次实验报告的同学也适合课程设计起步阶段需要把“模块划分 顶层连线”讲清楚的人。下面按需求、架构、编码、排错、验收的顺序把这份实验拆成可以照着做的完整方案。2. 需求边界与工具选型两个逻辑门为什么要按工程规格来做2.1 把四条实验目的翻译成四份可交付物实验目的写得很“虚”熟悉简单逻辑门的 RTL 描述、创建简单电路的结构化描述、用 VHDL 创建层次结构描述、熟悉 ISE 集成环境中的 HDL 编辑器。这四条读起来像过程描述但评阅的人看的其实是产物。带过几轮这类实验之后我习惯先把目的翻译成能直接贴进报告的东西翻译完再动手效率差很多。第一条“熟悉 RTL 描述”对应两个底层源文件my_and2.vhd和my_or2.vhd每个文件里一个实体加一个结构体用并发赋值语句把真值表写出来。第二条“创建结构化描述”对应顶层文件and_or.vhd这个文件里不出现任何and、or运算符只出现 component 声明、signal 声明和三条实例化语句。第三条“用 VHDL 创建层次结构”对应的物证是 RTL 原理图里那个可以逐层双击展开的方块图它是层次关系存在的证据光有代码不算。第四条“熟悉 HDL 编辑器”最容易被敷衍过去实际对应的是语法检查通过的截图或者综合日志里那几行没有 error 的输出。这四份东西凑齐实验报告的“实现步骤”和“测试及结果”两节就自然有了内容不用临时编。这个翻译动作还决定报告的章节骨架实验原理那节写 RTL 描述和结构化描述的概念边界实现步骤那节写工程创建、编码、检查的先后顺序测试及结果那节贴原理图与波形实验总结落到层次化带来的复用价值上。每一节都有对应的物证撑着写起来不虚。2.2 为什么这门课锁定 VHDL 与 ISE 这套组合VHDL 是强类型语言端口方向、类型、位宽全部显式声明写错了编译期就拦住。这个“啰嗦”的特性恰恰是讲层次化最趁手的教具component 声明必须把被调模块的端口一字不差地抄一遍port map 必须把每一根线连到哪里写清楚学生想蒙混都蒙混不过去。换一门更宽松的语言端口不写也能跑层次关系反而讲不明白。ISE 这边真正有价值的是两个视图View RTL Schematic 给出的是与代码结构一一对应的层次图双击方块能进去看内部的与门或门View Technology Schematic 给出的是综合映射到器件原语之后的结果。两张图放在一起对比学生能直观看到“我写的结构”和“器件上真正长出来的东西”之间的差别这正是数字系统设计课想建立的直觉。工具链的一致性比工具的先进性重要得多。实验室机器装的、指导书截图上显示的、报告里贴的最好是同一套环境。我踩过一次坑本地换了另一套开发环境重新综合图形风格和指导书完全对不上答辩时被问“你这个图和指导书的差异在哪”答不上来。课程实验阶段跟着给定环境走就是最优解没什么可纠结的。2.3 工程参数怎么填器件、仿真器与顶层设置新建工程的向导里几栏需要留意。工程名和顶层模块名我一般保持一致都叫AND_OR省得后面综合时顶层对不上。路径这条特别提醒全英文、无空格、无中文综合脚本对特殊字符的容忍度很低一个中文字符就可能让整条流程中断。器件那几栏——Family、Device、Package、Speed Grade——按实验指导书给定的板卡型号填不同实验箱的芯片不一样不要照搬别人的截图。Synthesis Tool 选 XSTSimulator 选 ISimPreferred Language 选 VHDL这三项在创建工程时就定死后面改起来要么重建工程要么改属性都麻烦。顶层的设置还有一处藏在综合属性里。工程建好之后右键 Synthesize - XST 打开属性确认 Synthesis Top 指向AND_OR而不是某个底层门。这一栏设错综合出来的原理图就只有一个孤零零的方块看不到层次结构很多人到这一步以为是代码写错了其实只是顶层选错。2.4 实验边界这一版做到哪一步为止把边界划清楚报告才不会写成半成品。这一次实验的目标停在 RTL 级验证语法检查通过、综合通过、行为仿真波形与真值表一致、原理图能看到层次。引脚约束文件和下载到板子这两件事不在范围内通常的做法是留到后续实验等组合逻辑和时序逻辑都过一遍之后再碰硬件。这个边界还有个好处不用纠结板子上哪个引脚接哪个开关。第一次实验的输入输出全是虚拟的在仿真器里给激励就行报告里的“测试及结果”贴波形和原理图逻辑自洽评阅的人也看得明白。3. 总体架构设计两个底层实体加一个顶层结构体的职责划分3.1 三层职责实体管端口、结构体管行为、顶层管连线层次化工程的本质是把三件事分开对外长什么样、内部怎么干活、彼此怎么连。VHDL 里 entity 负责第一件architecture 负责第二件上层文件负责第三件。底层模块MY_AND2的 entity 只有三个端口A、B 输入Y 输出全是STD_LOGIC。它的 architecture 只有一行并发赋值Y A and B;这一行就是完整的真值表。MY_OR2完全对称只是运算符换成or。这两个模块对外只暴露端口内部怎么实现调用者不关心这就是封装。顶层的职责完全不同。AND_OR的 architecture 里不应该出现任何逻辑运算符只应该出现三类语句component 声明告诉编译器我要用哪两个模块端口长什么样、signal 声明模块之间那几根线、实例化语句把线和端口接起来。判断一个顶层写得好不好有个很直接的标准把端口连接关系遮住剩下的部分应该看不出这个电路做的是什么运算。这个划分对应到报告里就是“实验原理”那一节要讲清楚的内容RTL 描述解决单模块行为结构化描述解决模块组合层次结构是两者叠加的结果。概念讲透后面的实现步骤才有落脚点。3.2 端口与内部信号的命名约定层次化工程里最容易出问题的地方不是逻辑是名字。我一般定一条规则底层端口用单字母 A、B、Y顶层端口加语义前缀比如Y_AND、Y_OR、Y内部信号用“来源_运算”的形式比如and_ab、or_ab。这样命名的好处在 port map 那一行长出来U3 : MY_OR2 port map (A and_ab, B C, Y Y);一眼能看出第三级或门拿的是前一级与门的输出而不是某个外部输入。如果全叫sig1、sig2出波形的时候根本对不上号。还有一条内部信号必须声明成signal绝不能声明成port。顶层只对外暴露 A、B、C 三个输入和三个输出中间那两个连接点属于内部实现细节暴露出去就破坏了封装综合工具也会因为多余的端口报出警告。信号声明放在 architecture 的声明区begin之前这是硬性语法要求。3.3 顶层功能定义与真值表顶层做成什么功能直接决定要实例化几个门、用几根内部信号。我这里把AND_OR定义成两路与结果、两路或结果各引出一路输出同时把“与结果再和第三路输入做或”作为第三路输出。这样三个输入、三个输出、三个实例、两根内部信号层次结构一眼可见又不至于复杂到讲不清。ABCY_AND (A and B)Y_OR (A or B)Y ((A and B) or C)000000001001010010011011100010101011110111111111这张表在报告里有两处用途一是仿真波形对照八个时间片逐个核二是答辩时被问到“你这个 Y 到底怎么算的”指着表比划比解释代码快。表格要在动手写代码之前就定下来别等波形跑完再倒推那样很容易把错的当真。3.4 工程文件组织与层次树文件组织看着琐碎但它决定了综合工具能不能自动找到被调模块。ISE 的做法是把所有源文件都加到工程里让工具自己去匹配 entity 名和文件名。如果my_and2.vhd里的实体叫MY_AND2文件名却写成and2.vhd综合时可能报“找不到 component”排查起来很浪费时间。文件角色关键内容是否顶层my_and2.vhd底层实体entity MY_AND2 一行与运算否my_or2.vhd底层实体entity MY_OR2 一行或运算否and_or.vhd结构体顶层component 声明 signal 三条实例化是tb_and_or.vhd仿真激励可选八组输入激励 波形观察否最终形成的层次树是两层根节点AND_OR下面挂三个实例U1、U2、U3其中U1是MY_AND2U2、U3是MY_OR2。这个结构在 RTL 原理图里会原样画出来报告里贴的就是这张图。层次只有两层不是缺点第一次实验要建立的是“可以继续往下挂”的组织方式后面做计数器、状态机、分频器无非是把这棵树加高加宽。4. 编码与集成落地RTL 描述、例化语句与语法检查一条链4.1 两个底层逻辑门的 RTL 描述底层模块的代码短但每一行都有讲究写完要能对着真值表逐项解释。-- 文件一my_and2.vhd library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity MY_AND2 is Port ( A : in STD_LOGIC; -- 输入 A B : in STD_LOGIC; -- 输入 B Y : out STD_LOGIC); -- 输出 Y A and B end MY_AND2; architecture RTL of MY_AND2 is begin -- 数据流描述一条并发赋值语句即完整表达真值表 Y A and B; end RTL; -- 文件二my_or2.vhd library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity MY_OR2 is Port ( A : in STD_LOGIC; B : in STD_LOGIC; Y : out STD_LOGIC); -- 输出 Y A or B end MY_OR2; architecture RTL of MY_OR2 is begin Y A or B; end RTL;library IEEE和use IEEE.STD_LOGIC_1164.ALL这两行不是可有可无的装饰。STD_LOGIC这个类型定义在std_logic_1164包里漏掉 use 子句编译器会直接报类型未定义。初学者最常见的报错之一就出在这两行上。architecture后面跟的名字这里是RTL是自定义的同一个实体可以有多个结构体综合时通过配置指定用哪一个。单结构体工程里名字随便起都行但同一份报告里最好统一成RTL或Behavior别一个文件一个风格。并发赋值语句Y A and B;写起来像赋值实际是并发执行的描述VHDL 里所有并发语句在仿真时同时生效不存在先后顺序。这一点和过程式语言差别很大理解了这个后面看仿真波形才不会奇怪“为什么输入一变输出立刻跟着变”。4.2 顶层 AND_OR 的结构化例化顶层代码是这份实验的核心component 声明、signal 声明、port map 三样东西缺一不可。library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity AND_OR is Port ( A : in STD_LOGIC; B : in STD_LOGIC; C : in STD_LOGIC; Y_AND : out STD_LOGIC; -- A 与 B 的结果引出 Y_OR : out STD_LOGIC; -- A 或 B 的结果引出 Y : out STD_LOGIC); -- (A 与 B) 或 C end AND_OR; architecture Structural of AND_OR is -- 声明要调用的底层模块端口必须与被调实体逐字一致 component MY_AND2 Port ( A : in STD_LOGIC; B : in STD_LOGIC; Y : out STD_LOGIC); end component; component MY_OR2 Port ( A : in STD_LOGIC; B : in STD_LOGIC; Y : out STD_LOGIC); end component; -- 内部连线只在本结构体内可见不对外暴露 signal and_ab : STD_LOGIC; signal or_ab : STD_LOGIC; begin -- U1A 和 B 相与结果进内部信号 and_ab U1 : MY_AND2 port map (A A, B B, Y and_ab); -- U2A 和 B 相或结果进内部信号 or_ab U2 : MY_OR2 port map (A A, B B, Y or_ab); -- U3把 U1 的输出和 C 相或得到最终输出 Y U3 : MY_OR2 port map (A and_ab, B C, Y Y); -- 内部信号引出到输出端口 Y_AND and_ab; Y_OR or_ab; end Structural;component声明这块最容易出错。它相当于在顶层告诉编译器“有一个叫 MY_AND2 的模块端口是这样”编译器拿这份声明去和工程里my_and2.vhd的 entity 比对。两边的端口名、方向、类型必须完全一致少一个端口或者把out写成in综合时会报端口不匹配或者更隐蔽地把它当成一个黑匣子放过去原理图上出现一个没有内部结构的空方块。port map用的是命名关联写法A and_ab左边是被调模块的端口名右边是当前层次里的信号名。另一种写法是按位置关联port map (and_ab, C, Y)代码短一点但端口顺序改了就会静默接错而且检查的时候眼睛要来回对照。这类实验我一律用命名关联多敲几个字符换来的是可读性和不出错很划算。U1、U2、U3这三个实例标签也不能省。它们是层次图里节点的名字综合出来的原理图上显示的就是这三个标号报告里讲“U3 是把 U1 的输出和 C 相或”时能直接指认。三个实例都是同一种模块时必须靠标签区分否则工具也没法给你报清楚是哪一级出错。4.3 语法检查与原理图生成的操作顺序代码写完到看见原理图中间隔着几步固定操作顺序不能乱。第一步是语法检查。在 ISE 左侧的 Hierarchy 面板里选中综合项展开后双击 Check Syntax。这一步只做语法和类型检查速度快报错信息也最直接。看到绿色的勾说明通过报红就按行号回去改别急着往下走。第二步是综合。双击 Synthesize - XST工具把 VHDL 翻译成门级网表。综合过程会生成一份报告里面有几项值得看有没有 latch 被意外推断出来、有没有端口悬空、资源占用了几个查找表。这个设计太小资源数字好看不好看没意义但养成看报告的习惯后面做复杂设计时能救命。第三步是看 RTL 原理图。综合完成后双击 View RTL Schematic会弹出一个方块这就是顶层AND_OR。双击方块进去应该能看到三个实例和连接它们的线and_ab、or_ab这两根内部连线在图上画得很清楚。如果进去之后只有一个空方块或者报“无法展开”八成是 component 声明和被调实体不一致回去对端口。第四步是看底层电路。双击 View Technology Schematic看到的是映射到器件原语之后的图与门或门变成查找表加若干连线。两张图放一起对比着贴进报告“测试及结果”那一节的说服力就出来了一张证明结构设计正确一张证明能落到真实器件上。4.4 仿真激励与波形判读原理图证明结构对波形证明功能对两件事不能互相替代。ISE 里用 ISim 做行为仿真需要额外写一个测试激励文件。library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity TB_AND_OR is end TB_AND_OR; -- 测试激励没有端口 architecture Stimulus of TB_AND_OR is component AND_OR Port ( A : in STD_LOGIC; B : in STD_LOGIC; C : in STD_LOGIC; Y_AND : out STD_LOGIC; Y_OR : out STD_LOGIC; Y : out STD_LOGIC); end component; -- 激励信号必须有初值否则波形一开始全是 U signal A, B, C : STD_LOGIC : 0; signal Y_AND, Y_OR, Y : STD_LOGIC; begin DUT : AND_OR port map (A A, B B, C C, Y_AND Y_AND, Y_OR Y_OR, Y Y); stim : process begin -- 按真值表顺序遍历 8 种输入组合每种保持 20 ns A0; B0; C0; wait for 20 ns; A0; B0; C1; wait for 20 ns; A0; B1; C0; wait for 20 ns; A0; B1; C1; wait for 20 ns; A1; B0; C0; wait for 20 ns; A1; B0; C1; wait for 20 ns; A1; B1; C0; wait for 20 ns; A1; B1; C1; wait for 20 ns; wait; -- 永久挂起防止进程结束后自动重新开始 end process; end Stimulus;信号声明处的: 0是初值不写的话仿真开始时这些信号是U未初始化波形一片灰看起来像设计坏了其实是激励没给。最后那个不带条件的wait;同样关键VHDL 的 process 执行到末尾会自动从头再来没有这句激励会无限循环波形看上去乱成一团。波形判读有个稳妥办法把仿真时间轴上每 20 ns 划一格对应真值表的一行从左到右核六列输出。Y_AND只在最后两格为 1Y_OR从第四格开始为 1Y在第 2、4、6、7、8 格为 1。核完对得上功能就验完了。核不上先看是哪一个输出错再看是第几级实例的问题顺藤摸瓜比通读代码快得多。5. 避坑与常见问题排查五类最容易在第一次实验翻车的细节5.1 端口、信号与例化类问题现象一仿真波形里某个输出的逻辑和真值表对不上但代码逐行读没毛病。原因多半出在 port map 用了位置关联端口顺序记错了。比如把port map (A and_ab, B C, Y Y)写成port map (C, and_ab, Y)两个输入直接对调逻辑看起来还是“或”结果全错。解决办法是把所有实例化语句统一改成命名关联并且形成习惯只要被调模块超过两个端口一律命名关联不接受位置写法。现象二综合时报“找不到 component MY_AND2”或者原理图上出现一个空方块。原因有两类一是顶层 component 声明的端口和被调实体的 entity 不一致端口名大小写、方向、类型任何一处不同都会导致匹配失败二是被调文件根本没加到工程里工具在工程范围内搜不到这个实体。解决办法是先核对两份声明的端口列表逐行对照再检查 Hierarchy 面板里my_and2.vhd、my_or2.vhd是否都在工程文件列表下。这条排查顺序别反先查代码再查工程因为代码不一致的概率高得多。现象三综合报告里冒出“signal has multiple drivers”或者“未声明的标识符”。前者通常是同一个内部信号被两个实例的输出端口驱动逻辑上就是短路综合工具不允许后者是begin之前漏了 signal 声明或者把信号声明写到了begin之后。解决办法很直接一个内部信号只接一个输出端口需要汇总就再加一级门声明区严格放在 architecture 名和begin之间不要图省事往中间塞。5.2 工程设置与波形类问题现象四代码明明改了重新综合出来的原理图还是老样子。原因是综合结果有缓存改完源文件没有重新跑 Synthesize - XST 就直接点了 View RTL Schematic看到的还是上一次的网表。解决方式是形成一个固定顺序改代码 → Check Syntax → Synthesize - XST → View RTL Schematic四步一步不落。ISE 有时候不会自动提示源文件已变更靠人记比靠工具靠谱。现象五行为仿真跑起来波形全是 U 或者一条直线。全 U 是激励信号没给初值加了: 0就好一条直线不动多半是 process 里漏了wait;进程结束后自动重启或者wait for的时间单位写错导致所有跳变挤在 0 时刻。还有一种情况是仿真顶层选错了跑的是某个底层模块而不是TB_AND_OR波形上当然只有两根线在动。处理办法是先把仿真顶层确认一遍再回头查激励代码。这五条问题覆盖了第一次实验里绝大多数卡壳场景。真正麻烦的不是不会写而是报错信息看不懂、不知道该往哪个方向查。把“现象—原因—解决”这三段对应关系记住排查时按顺序过一遍比漫无目的地改代码高效得多。6. 验收与答辩用三张图和一张表把实验报告讲圆报告写完之后怎么自检我有一套固定流程核心就是三张图加一张表。第一张是 RTL 原理图的顶层视图证明AND_OR这个层次存在三个实例都挂在下面。第二张是双击进去之后的内部视图证明and_ab、or_ab这两根内部连线确实把 U1 的输出接到了 U3 的输入。这两张图要能相互印证顶层视图里有几个方块内部视图里就应该有几个实例数目对不上说明例化写重了或漏了。第三张是行为仿真波形横向按 20 ns 一格切开逐格对照真值表。那张真值表本身算第四份材料放在报告正文里八个输入组合一个不落。答辩被问到的问题翻来覆去就那么几类提前准备好答案能省很多临场组织语言的时间。“为什么顶层不直接写Y (A and B) or C;”——因为这次要练的是结构化描述行为描述一行就能出结果但学不到模块划分和端口连接。“component 声明能不能省”——可以VHDL-93 之后支持直接例化实体但显式声明让层次关系写在纸面上教学场景下不建议省。下面这张自检表我一般提交前逐项过一遍检查项合格标准对应物证语法检查Check Syntax 无 error综合日志截图综合顶层为 AND_OR无关键警告综合报告层次结构RTL 原理图可逐层展开顶层图 内部图器件映射Technology Schematic 能生成底层电路图功能正确波形与真值表逐格一致仿真波形 真值表文件完整三个源文件命名与实体一致工程文件列表三条最容易在答辩现场翻车的细节也都在这张表上波形和真值表对不上却解释成“仿真器误差”这种解释没人信回去重跑原理图只有一个方块说“层次在代码里”评阅的人不会去读代码图上看不见就是没有文件命名和实体名不一致被问到就只能现场解释。这三样都属于可以提前避免的错代价是十分钟的检查时间。从那以后我每次交这类实验报告前都会强制走一遍“三张图加一张表”的顺序少一张就不提交哪怕代码早就跑通了。这套流程后来做课程设计和毕业设计同样管用规模变大只是图和表的数量变多检查逻辑没变。希望帮到你。本文还有配套的精品资源点击获取