简介面向数字逻辑与EDA课程学习者及FPGA入门者的两份实验报告合集围绕LiberoSoc软件仿真验证与实验箱硬件测试两条实践路径展开。内容涵盖LiberoSoc工程创建、Verilog HDL基本门电路与组合/时序电路描述、仿真激励设置、波形结果分析以及74HC系列门电路、74HC148编码器、74HC4511译码显示、74HC161计数器的接线测试、LED与逻辑笔状态判定、输入输出状态表和综合实验设计读者可据此理解从代码编写、功能验证到硬件核对的完整流程。报告含实验目的、仪器元器件、实验原理、数据记录与问题讨论等栏目结构较完整并附思考题便于复盘使用对课程实验归档与考前复习也有参考意义。资源包为1个docx文档约1.43MB便于查阅、打印和二次整理。已有938人学习适合需要补齐实验报告、熟悉EDA工具操作与数字逻辑验证思路的学生参考。1. 两份实验报告拆开看数字逻辑设计仿真怎么从 LiberoSoc 一路走到实验箱拿到这份资源的人多半卡在同一个地方LiberoSoc 里 Verilog 代码跑通了波形也漂亮可一换到实验箱上接线74HC00 的输出死活不动。这套实验报告把两件事绑在了一起——先用 EDA 工具做数字逻辑设计仿真再回到实验箱上验证同一批 74 系列芯片中间夹着 74HC148、74HC4511、74HC161 三片组合与时序器件的完整真值表记录还留了六片基本门的模块代码和测试平台。它适合正在上数字逻辑与 EDA 设计课、既要交报告又想真搞懂流程的人软件侧有能直接跑的源码硬件侧有引脚级接线与 LED、逻辑笔判读方法连综合实验里 SmartDesign 的连线思路都没省略。下面按我复现时的顺序拆先讲工程怎么建再讲 testbench 怎么写最后落到上板时那些仿真器不会告诉你的坑。2. LiberoSoc 工程落地从新建工程到六片 74HC 的 Verilog 建模2.1 器件先定代码后写工程向导里的三个必选项很多人打开 LiberoSoc 第一件事就是 File → New Project → 一路 Next器件那一步随手选个默认值等综合报告出来才发现资源利用率和同学对不上。实验报告要交综合结果截图器件、封装、速度等级三项不一致两台机器跑出来的 LUT 数量和时序余量就是两套数评审一眼能看出来。我一般的顺序是先把课程或实验箱指定的目标器件确认清楚再回头建工程。新建工程的路径里有两个坑值得提前说。一是工程目录不要带中文和空格LiberoSoc 在调用综合与仿真脚本时会拼绝对路径中文路径在部分版本上直接报脚本执行失败错误信息还指向一个不相干的文件查起来非常费劲。二是 HDL 类型选 Verilog仿真工具选外部仿真器常见做法是 ModelSim这样波形窗口的功能比内置仿真器完整后面调波形、加光标、导图片都方便。工程建好之后源文件组织建议按「一个芯片一个文件」来HC00.v、HC02.v、HC04.v、HC08.v、HC32.v、HC86.v再加一个tb_all.v放测试平台。这样综合的时候可以把单个模块设成 top单独看一片门的资源占用报告里每片门配一张综合截图逻辑清晰。测试平台文件记得在工程里标记为 simulation-only否则综合工具会尝试去综合它报一堆「initial 块不可综合」的警告把真正的错误淹掉。2.2 六片 74HC 的 Verilog 建模位宽向量是这份报告最省事的地方这套代码里最值得学的一个细节是端口位宽的选择input [4:1] a, b;而不是一位一位地写。原因很实在——74HC00、74HC02、74HC08、74HC32、74HC86 都是四路二输入门一片封装里正好四个独立门74HC04 是六反相器所以它用[6:1]。位宽直接对应封装内的门数一次仿真就把四个或六个门全测了不用为每一路单独写一个实例。// 74HC00 四路二输入与非门y ~(a b) module HC00( input wire [4:1] a, input wire [4:1] b, output wire [4:1] y ); assign y ~(a b); endmodule // 74HC02 四路二输入或非门y ~(a | b) module HC02( input wire [4:1] a, input wire [4:1] b, output wire [4:1] y ); assign y ~(a | b); endmodule // 74HC04 六反相器y ~a module HC04( input wire [6:1] a, output wire [6:1] y ); assign y ~a; endmodule // 74HC08 四路二输入与门y a b module HC08( input wire [4:1] a, input wire [4:1] b, output wire [4:1] y ); assign y a b; endmodule // 74HC32 四路二输入或门y a | b module HC32( input wire [4:1] a, input wire [4:1] b, output wire [4:1] y ); assign y a | b; endmodule // 74HC86 四路二输入异或门y a ^ b module HC86( input wire [4:1] a, input wire [4:1] b, output wire [4:1] y ); assign y a ^ b; endmodule逐段说明一下。assign是连续赋值描述的是组合逻辑综合出来就是一级查找表和真实门电路的传播延迟没有对应关系但对验证逻辑功能完全够用。六个模块全部用assign没有一处always这是刻意的门电路级别的功能用不着过程块用always (*)反而容易漏分支推出锁存器。位运算符号的对应关系要记牢——~是按位取反、|、^分别是按位与、或、异或与非门写成~(a b)外层的取反不能少括号也不能省写成~a b就变成了「非 a 与 b」是完全另一个函数。参数上唯一需要留意的是端口方向。原文里 HC04 的两个端口写作大写A、Y其余模块写小写a、b、yVerilog 本身区分大小写只要模块内一致就没问题但混着写容易在例化时打错。我倾向于全小写只给时钟、复位这类信号加_n后缀表示低有效读代码时一眼能分辨极性。2.3 综合前的检查清单这五项对不上报告分数直接打折代码写完不等于能综合。下面这张表是我每次交报告前必过一遍的五项里任意一项出问题综合要么报错要么跑出来一个和预期完全不同的电路。检查项常见错误写法后果正确做法模块名与例化名一致定义module HC86例化写74HC86 u1(...)编译报 Unknown module typeVerilog 标识符不能以数字开头模块名和例化名统一需要前缀就用G_74HC86这类字母开头形式端口位宽匹配定义[4:1] y测试平台声明wire y高位被截断波形只看到最低位误判功能正确测试平台里 wire 声明与端口位宽完全一致组合逻辑分支完整always (*) if (x) y 1;综合出锁存器报警告功能随时序漂移用assign或在always里补全else输出驱动唯一同一个y既 assign 又在 always 里赋值多驱动综合报错或综合出线与逻辑一个输出只保留一种驱动方式Top 模块设置把测试平台设成 top综合工具去综合 initial 块报一堆不可综合警告综合前手动指定目标模块为 top测试平台标 simulation-only第一项就是原文里真实存在的坑HC86 的测试平台里例化写成了74HC86 u1(a,b,y);而模块定义是module HC86。这在 ModelSim 里会直接报找不到模块新手看到「Unknown module type」经常以为是库没编折腾半天。记住一条Verilog 标识符必须以字母或下划线开头芯片型号当前缀时一定要加字母。3. 测试平台与波形让仿真真的能抓出错误而不是走过场3.1 把一段 testbench 拆开initial 块、延迟与移位激励测试平台写得好不好直接决定这次仿真有没有验证价值。原文给的激励模式很有代表性一个输入固定另一个输入用左移的方式逐位扫一遍四个位并行一次跑完四组输入组合。timescale 1ns/1ns // 时间单位 1ns时间精度 1ns module tb_HC00(); reg [4:1] a; reg [4:1] b; wire [4:1] y; // 推荐用命名连接端口顺序变了也不会错连 HC00 u1(.a(a), .b(b), .y(y)); initial begin a 4b0000; b 4b0001; #15 b b 1; // 15ns 后 b 0010 #15 b b 1; // 30ns 后 b 0100 #15 b b 1; // 45ns 后 b 1000 a 4b1111; b 4b0001; #15 b b 1; #15 b b 1; #15 b b 1; #10 $stop; // 留一小段观察时间后停止仿真 end endmodule拆开看几个点。timescale 1ns/1ns是编译指令前面必须有反引号它决定了#15到底代表多长——前一个数是时间单位后一个数是精度两个都写 1ns 意味着延迟可以精确到 1ns波形窗口横轴一格就是 1ns。reg和wire的区别在这里体现得很直接测试平台里被赋值的信号声明为reg被测模块的输出接wire写反了编译就过不去。#15是绝对延迟意思是「从当前仿真时刻再往后推 15ns」不是相对上一条语句的时间点重新计时。initial 块里的语句顺序执行所以四条#15累计出 45ns 的激励长度。b b 1是左移一位最高位被挤出去最低位补 0所以0001 → 0010 → 0100 → 1000正好把一个「1」从最低位推到最高位四路门里每一路都轮到一次高电平。例化那一行我改成了命名连接.a(a)。原文用的是位置连接HC00 u1(a,b,y);功能上没差别但只要有人调整了模块端口顺序位置连接会静默错连——不报错波形却是错的这种问题最难查。命名连接多敲几个字符省下的是半小时的抓头。3.2 激励覆盖率向量化测试的边界在哪刚才那段激励只测了a 0000和a 1111两种取值。对单个门来说输入 a 只有 0 和 1 两种可能看起来覆盖全了但对四位向量来说a 0101、a 1010这些中间态一次都没出现。如果哪位同学把assign y ~(a b)手滑写成assign y ~a b在这组激励下会不会暴露算一下a0000 时~(ab)恒为 1111而~a b等于1111 b也就是 b 本身。b 从 0001 扫到 1000输出跟着变波形上确实不同——所以这个错误能抓到。但如果错写成assign y ~(a | b)与非写成或非a0000 时两个式子都等于~ba1111 时~(ab)是~b而~(a|b)恒为 0000也能抓到。真正的盲区在更隐蔽的错误上比如把位选写错、把某一位单独取反。想彻底放心用穷举激励最干脆timescale 1ns/1ns module tb_HC00_exhaustive(); reg [4:1] a, b; wire [4:1] y; integer i, j; HC00 u1(.a(a), .b(b), .y(y)); initial begin for (i 0; i 16; i i 1) begin for (j 0; j 16; j j 1) begin a i[3:0]; b j[3:0]; #10; end end $stop; end endmoduleinteger是 32 位整数i[3:0]取低四位赋给四位的 a正好遍历 0 到 15。内外两层循环一共 256 组输入每组持续 10ns总仿真时间 2.56μs跑完不到一秒。256 组乘以四路并行等于把四输入二输出门的所有组合过了一遍这种覆盖率拿去交报告评审挑不出毛病。代价是波形窗口里信号跳得太密截图时要配合后面的分组和光标技巧否则一片糊。3.3 波形截图不是截屏白底、量程、光标三件事实验报告要求把波形窗口背景设成白色再截图这不是形式主义。深色背景打印出来是一片黑信号名和波形叠在一起基本看不清白底黑线在纸质报告上对比度最高。ModelSim 里的操作是右键波形区 → Wave Window Properties把背景改成白色信号颜色保持默认的绿黄配色就够。具体截图时要控三件事。第一是时间轴量程用 Zoom Full 让整段激励刚好铺满窗口不要留大段空白也不要截断最后一个跳变沿——评审看的就是跳变是否发生在预期时刻。第二是信号分组把输入信号放一组、输出信号放一组组间加分隔线四路向量展开成y[4]、y[3]、y[2]、y[1]单独显示这样一眼能看出哪一路先变。第三是关键跳变处加光标ModelSim 里点波形区的 Add Cursor拖到某个上升沿窗口下方会显示精确时刻截图时把这个时间读数一起截进去等于给报告附了一个证据。截图要素具体做法为什么背景波形区属性改白色打印对比度评审可读量程Zoom Full覆盖完整激励周期避免空白占比过大或截断跳变沿信号顺序输入在上、输出在下向量展开因果关系一目了然光标停在关键跳变沿显示精确时刻证明延迟和逻辑关系符合预期标题文件名或窗口标题注明芯片型号六张截图混在一起时不会认错截图这一步最容易被当成走过场但它是报告里唯一能证明「我确实跑过」的材料。我见过有同学六张波形图用的是同一次仿真的截图只改了文件名结果 HC04 的图上出现了六路信号之外的两输入端口一眼被看出来。每片门单独建工程、单独跑仿真、单独截图麻烦十分钟省掉的是返工。4. 组合与时序器件对齐74HC148、4511、161 的仿真用例与实测数据4.1 74HC148优先编码与使能链先看 GS 和 EO 再看输出74HC148 是八线到三线优先编码器八个输入 I7 到 I0 全部低有效优先级 I7 最高。输出 A2A1A0 是低有效反码——意思是输入 I7 有效时输出 000输入 I0 有效时输出 111跟直觉正好拧着这是真值表最容易填错的地方。除了八个输入和三个输出它还有三根控制线EI 是使能输入低有效GS 是组信号只要有任何一路输入有效就拉低EO 是使能输出在所有输入都无效且 EI 有效时拉低专门用于级联扩展。module HC148( input wire [7:0] I, // I7~I0低有效输入 input wire EI, // 使能输入低有效 output reg [2:0] A, // A2~A0低有效反码输出 output reg GS, // 组信号低有效 output reg EO // 使能输出低有效 ); always (*) begin if (EI) begin A 3b111; GS 1b1; EO 1b1; // 未使能全部无效 end else begin casez (I) 8b0???????: A 3b000; // I7 优先 8b10??????: A 3b001; 8b110?????: A 3b010; 8b1110????: A 3b011; 8b11110???: A 3b100; 8b111110??: A 3b101; 8b1111110?: A 3b110; 8b11111110: A 3b111; // I0 最低优先 default: A 3b111; // 无有效输入 endcase GS (I 8hFF) ? 1b1 : 1b0; EO (I 8hFF) ? 1b0 : 1b1; end end endmodulecasez里的?表示通配所以8b10??????匹配的是「I7 为 1、I6 为 0」这一个条件其余位随便。这个写法比嵌套 if 清晰得多也直接对应真值表的行。GS 和 EO 的互斥关系要注意有有效输入时 GS0、EO1无有效输入且 EI0 时 GS1、EO0EI1 时两者都是 1。实验时如果发现 GS 一直是高先查 EI 有没有拉低再查输入是不是全接成了高电平。上板实测时八个输入用拨码开关模拟按键开关一端接 GND、一端接输入脚同时每个输入脚加 10kΩ 上拉到 VCC。不按的时候是稳定的高电平按下去变低逻辑正好对上低有效的定义。常见错误是只接开关不加上拉CMOS 输入悬空读数全凭运气。4.2 74HC4511LT、BI、LE 三个控制脚的优先级决定你看到什么74HC4511 是 BCD 到七段锁存译码驱动器共阴数码管专用。输入是四位 BCD 码 D3D2D1D0输出是 a 到 g 七段高电平点亮。它比纯译码器多了三个控制脚优先级从高到低是 LT灯测试低有效、BI消隐低有效、LE锁存使能高有效。LT 拉低时无视一切输入七段全亮显示「8」BI 拉低时七段全灭LE 拉高时锁存当前数据输入变化不影响输出。LTBILE输入 D3~D0七段输出 abcdefg显示0XXX11111118灯测试10XX0000000无显示消隐1100000111111001100001011000011100010110110121100011111100131100100011001141100101101101151100110101111161100111111000071101000111111181101001111101191101010~11110000000无显示非法 BCD这张表是填实验报告表 8 的依据。段码顺序是 a 对应最高位、g 对应最低位共阴数码管低电平灭、高电平亮所以显示 0 的时候 a 到 f 亮、g 灭写成1111110。填表时最常犯的错是把共阴当共阳段码整体取反结果整张表全错。实验报告里那道思考题「如果要同时显示 4 个数字应如何处理」答案不在译码器本身而在扫描。LN3461Ax 是 4 位共阴数码管内部四位共用同一组 a 到 g 段线只有公共端位选是分开的。做法是用一个计数器产生位选信号轮流给四位公共端送低电平同时把对应位的 BCD 码送到 4511 的输入端。每位点亮时间约 1~2ms整体刷新率超过 100Hz人眼就看不到闪烁。这里有个隐含条件4511 的 LE 必须配合扫描时序使用否则数据在切换瞬间会被锁存到错误的位上。4.3 74HC161清零法与置数法的差别就一个字——同步74HC161 是四位同步二进制计数器带异步清零 MR低有效、同步置数 PE低有效、两个计数使能 CEP 和 CET、进位输出 TC。做成十进制计数器有两条路实验报告要求两种都写差别全在「什么时候归零」。清零法的思路是让它自然数到 101010检测到这个状态立刻拉低 MR异步清零。异步的意思是清零不等待时钟沿状态一到就生效。module cnt10_async( input wire clk, input wire rst_n, output reg [3:0] q, output wire tc ); // 数到 10 立即拉低异步清零端 wire mr_n rst_n ~(q 4d10); always (posedge clk or negedge mr_n) begin if (!mr_n) q 4d0; // 异步清零不等时钟沿 else q q 1b1; end assign tc (q 4d9); // 进位输出在 9 时有效 endmodule置数法的思路是用同步置数端 PE数到 9 时把 PE 拉低下一个时钟上升沿把 0000 同步装进去。module cnt10_sync( input wire clk, input wire rst_n, output reg [3:0] q, output wire tc ); always (posedge clk or negedge rst_n) begin if (!rst_n) q 4d0; else if (q 4d9) q 4d0; // 下一个时钟沿同步归零 else q q 1b1; end assign tc (q 4d9); endmodule两者在波形上的区别非常直观。清零法的 q 会短暂出现1010然后立刻跳回0000这段「10」的持续时间只有一个门延迟仿真里把时间轴放大到 1ns 一格才看得见示波器上基本抓不到但如果后面直接驱动 4511译码器会在那一瞬间解出一个非法 BCD 并输出全灭数码管上表现为极短的一次闪烁。置数法的 q 严格在 0 到 9 之间循环1001之后直接是0000没有任何中间态。对比项清零法置数法归零时机异步状态一到立即生效同步等下一个时钟上升沿是否出现 1010出现持续一个门延迟不出现数码管表现可能有一次极短闪烁稳定无闪烁报告里怎么画时序图要画出 1010 的窄脉冲只画 0~9 循环推荐场景对毛刺不敏感的场合直接驱动译码显示的场合时序图按状态序列画就行时钟画等间距方波q 在每个上升沿后变化依次标出 0000 到 1001清零法要在 1001 之后补一个宽度极窄的 1010 再回到 0000并在旁边标注「异步清零毛刺」。这张图是报告里区分度最高的部分画对了说明真理解了两者的差别。4.4 实验箱侧怎么对齐LED、逻辑笔和那根不能悬空的输入线仿真跑通只是第一步实验箱上还有一套自己的规矩。74HC 系列是 CMOS 工艺输入阻抗极高引脚悬空时电压不确定输出会乱跳。所有未使用的输入脚必须接固定电平——要么接 VCC要么接 GND不能空着。这条在仿真里完全体现不出来是最典型的「仿真过、上板挂」。判断输出电平有两种方法。一是把输出接实验箱的 LED 指示位灯亮为高电平逻辑 1灯灭为低电平逻辑 0。二是用逻辑笔功能区直接测。两种方法的差别在于 LED 有位选和驱动电路测的是整条通路的电平逻辑笔测的是引脚本身的电平排查「芯片输出正常但 LED 不亮」这类问题时逻辑笔更有用。接线时注意 14 脚 DIP 封装的电源脚位置缺口朝左左下角是 1 脚右下角是 7 脚接 GND左上角是 14 脚接 VCC。插反了通电芯片基本就废了。共阴数码管的公共端接 GND段脚串 330Ω 到 1kΩ 限流电阻直接接会被拉低电压导致亮度异常甚至损坏。5. 避坑与排查仿真跑通、上板就挂的五个典型翻车现场5.1 编译阶段模块名和例化名对不上现象ModelSim 编译测试平台报Unknown module type: 74HC86工程里明明有HC86.v。原因测试平台例化时写了74HC86 u1(a,b,y);而被测模块定义是module HC86。Verilog 的标识符规则要求首字符必须是字母或下划线数字开头的名字不合法编译器把它当成一个不存在的模块类型。这个错误在原文的 HC86 测试平台里是真实存在的其余五片的例化名都和模块名一致唯独这一片多写了型号前缀。解决把例化改成HC86 u1(.a(a), .b(b), .y(y));模块名和例化名保持一致。如果确实想在名字里保留型号统一加字母前缀比如G_74HC86但要注意模块定义和例化两处都得改。排查这类问题的习惯是先看报错里的模块名再去源文件里搜module关键字两个名字逐字符比对大小写也算。5.2 仿真阶段波形一条直线或者跳变全挤在 0 时刻现象一跑完仿真波形窗口里所有信号都是平的没有任何跳变。 原因漏了timescale编译指令或者 initial 块里所有赋值都没有加延迟。没有延迟的话所有语句在仿真时刻 0 一次性执行完最终值直接覆盖中间过程一条都不留。 解决文件头补上timescale 1ns/1ns每条激励之间加#10或#15末尾加$stop或$finish让仿真停在合适的位置而不是一直跑到默认上限。现象二向量化激励跑完波形看起来很漂亮报告交上去被判「验证不充分」。 原因激励只覆盖了a 0000和a 1111两种极值中间的 0101、1010、0011 这些组合一次没出现。对于按位运算的门电路某些位选错误在这种激励下不会暴露。 解决换成两层 for 循环的穷举激励遍历 0 到 15 的所有组合或者至少补上a 4b1010、a 4b0101两组交替模式。穷举的仿真时间很短几百纳秒到几微秒没有理由省这一步。5.3 上板阶段输入悬空和异步清零毛刺现象一实验箱通电74HC00 的输入开关全断开输出 LED 忽亮忽灭用手碰一下芯片旁边的线灯的状态跟着变。 原因拨码开关断开时输入端处于悬空状态CMOS 输入阻抗极高引脚电压受分布电容和人体感应影响处于不确定区输出自然乱跳。仿真器里输入永远有确定的 0 或 1所以这个现象在仿真中完全不会出现。 解决每个输入脚加一个 10kΩ 上拉电阻到 VCC低有效输入或下拉到 GND高有效输入开关另一端接相反电平。这样断开时是稳定的一种电平闭合时是另一种中间没有悬空态。实验箱上通常已经内置了上拉或下拉接线前先确认避免重复加电阻把电平拉死。现象二74HC161 用清零法做十进制计数器仿真波形正常上板后数码管在 9 跳 0 的瞬间闪一下或者译码器偶尔显示一个奇怪的字符。 原因异步清零产生的 1010本文还有配套的精品资源点击获取