【quartus】基于原理图输入法的4位全加器层次化设计与实现
1. 从零开始:为什么选择原理图输入法?
如果你刚开始接触数字电路设计,或者正在学习像《数字逻辑》这样的课程,面对一堆门电路和真值表,是不是感觉有点抽象,不知道如何把书本上的知识变成电脑里能跑起来的电路?我刚开始学的时候也是这样,总觉得Verilog或者VHDL这些硬件描述语言门槛有点高,一堆代码写出来,心里还是没底,不知道最终生成的电路到底长啥样。这时候,Quartus的原理图输入法简直就是救星。
你可以把它想象成电子版的“搭积木”。我们不用写一行代码,而是直接在软件里找到需要的“积木块”——也就是与门、或门、非门、异或门这些基本逻辑门,然后用“导线”把它们按照逻辑关系连接起来。你画出来的图,就是最终的电路结构,一目了然。这对于理解半加器、全加器这种基础组合逻辑电路的内部工作原理,有不可替代的直观优势。你每画一条线,都对应着硬件里一根真实的连线,这种“所见即所得”的体验,能帮你把抽象的逻辑代数(比如S=A⊕B,Cout=AB)和具体的物理电路牢牢绑定在一起。
所以,这次我们不用写代码,就用手动“搭积木”的方式,从最基础的一位半加器开始,像盖房子一样,一层一层地构建出一个4位全加器。这个过程就是层次化设计的精髓:先造好砖块(半加器),再用砖块砌成一面墙(全加器),最后用四面墙组成一个房间(4位全加器)。这种方法不仅思路清晰,调试起来也特别方便,哪个“砖块”出了问题,就单独检查哪个,非常适合初学者来建立数字系统的整体设计观。我当年就是通过这个实验,才真正搞懂了进位链是怎么一回事。
2. 基石:亲手绘制一位半加器
万事开头难,但我们得从最简单的开始。半加器是加法器的最小单元,它只考虑两个一位二进制数相加,不考虑来自低位的进位。它的功能很简单:输入两个数A和B,输出一个和S,以及一个向高位的进位Cout。
它的真值表只有四行,我们一起来看:
| A | B | S (和) | Cout (进位) |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 0 |
| 1 | 0 | 1 | 0 |
| 1 | 1 | 0 | 1 |
从真值表我们可以推导出逻辑表达式:和S等于A异或B (S = A ⊕ B),进位Cout等于A与B (Cout = A & B)。看,这就是我们搭积木的图纸:我们需要一个异或门(XOR)和一个与门(AND)。
现在,打开Quartus Prime(我这里以18.1 Lite版为例,版本不同但核心操作一致)。第一步,创建工程:File -> New Project Wizard。跟着向导走,给工程起个明白的名字,比如OneHalfAdder。存放路径建议用一个干净的文件夹,避免文件混乱。到选择器件型号那一步,对于初学者做功能仿真来说,具体型号影响不大,你可以像我一样,在Device Family里选Cyclone IV E,然后在Available devices里选一个引脚数适中的,比如EP4CE6E22C8。如果只是学习,直接选Auto device selected by the Fitter让软件自动选也行,但养成指定器件的习惯对以后做实际板级调试有好处。
工程建好后,我们开始画原理图。File -> New,选择Block Diagram/Schematic File,点击OK,就打开了一个空白的绘图页面。右侧的Symbol Tool(或者按快捷键Ctrl+Shift+S)是我们的积木盒子。双击空白处,会弹出元件库窗口。在Libraries下,展开primitives -> logic,这里存放着所有基础逻辑门。找到xor(异或门)和and2(2输入与门),分别点击OK,把它们放到绘图区。
放好元件后,接下来是连线。选择左侧工具栏的Orthogonal Node Tool(直角连线工具),像用画笔一样,从门的输出引脚拖拽到另一个门的输入引脚。我们需要定义输入输出端口。同样在Symbol Tool里,在primitives -> pin下找到input和output,拖两个input出来,分别命名为A和B;拖两个output出来,分别命名为S和Cout。然后,按照逻辑表达式S = A xor B和Cout = A and B,用导线把A、B连接到两个门的输入端,再把门的输出端连接到对应的输出端口上。画完后的原理图应该非常整洁:两个输入引脚,经过一个异或门输出S,经过一个与门输出Cout。
画好了不等于成功了,必须编译检查。点击上方工具栏那个紫色的三角形(Start Compilation),或者按Ctrl+L。如果下方Messages窗口没有显示红色的Error,只有一些警告(Warning),那恭喜你,电路画对了。警告通常关于引脚未分配,仿真时可以先忽略。为了后续步骤,我们还需要把这个半加器封装成一个“积木块”。File -> Create/Update -> Create Symbol Files for Current File,软件就会生成一个.bsf的符号文件。这个文件就是我们自己制作的“新积木”,在后面的设计里可以像调用库里的门电路一样直接调用它,这就是层次化设计的关键一步。
3. 升级:用两个半加器组装一位全加器
有了半加器这块好砖,我们就可以砌墙了。全加器比半加器更实用,因为它考虑了来自低位的进位Cin,是构成多位加法器的真正核心。它的真值表有八行,表达了三个数(A, B, Cin)相加的所有情况。
全加器的逻辑表达式稍微复杂一点:S = A ⊕ B ⊕ Cin, Cout = (A & B) | ((A ⊕ B) & Cin)。直接用一个异或门和一个与或门组合也能实现,但今天我们用更体现层次化设计思想的方法:用两个半加器和一个或门来实现一个全加器。
怎么实现呢?我来拆解一下。第一步,用第一个半加器把A和B相加,得到一个部分和(记为Sum1 = A ⊕ B)和一个部分进位(记为Carry1 = A & B)。第二步,用第二个半加器把这个部分和Sum1与来自低位的进位Cin相加,得到最终的和S = Sum1 ⊕ Cin,以及第二个部分进位Carry2 = Sum1 & Cin。那么,向高位的总进位Cout什么时候为1呢?要么是A和B同时为1(即Carry1=1),要么是Sum1和Cin同时为1(即Carry2=1)。所以,Cout = Carry1 OR Carry2。看,我们只需要两个半加器和一个或门,就完美实现了全加器功能。
在Quartus里,我们新建一个工程OneFullAdder。关键操作来了:如何调用我们刚才做好的半加器“积木块”?你需要把上一个工程OneHalfAdder里生成的两个文件:.bdf(原理图文件)和.bsf(符号文件),复制到OneFullAdder的工程目录下。然后在OneFullAdder的原理图页面,再次打开Symbol Tool。这次,在Libraries的顶部,你会发现一个Project目录,点开它,里面赫然躺着一个名叫OneHalfAdder的元件!把它拖出来,连续拖两个,它们就是我们自制的半加器模块。
再从库primitives -> logic里拖一个or2(2输入或门)出来。接着,放置三个input引脚,命名为A, B, Cin;两个output引脚,命名为S, Cout。现在开始像搭乐高一样连接:将A和B接到第一个半加器的输入;将第一个半加器的和输出S连接到第二个半加器的A输入,将Cin连接到第二个半加器的B输入;第二个半加器的和输出S,就是全加器的最终和输出S。然后,将第一个半加器的进位输出Cout,和第二个半加器的进位输出Cout,一起接到或门的两个输入端,或门的输出就是全加器的总进位Cout。连接完成后,仔细检查一遍线路,确保没有漏连或多连。编译通过后,同样记得Create Symbol Files for Current File,为我们的一位全加器也生成一个符号文件,以备后用。
4. 集成:构建4位全加器并完成仿真验证
终于到了最后一步,把我们做好的多位全加器“墙”拼成一个“房间”——4位全加器。一个4位全加器,本质上就是四个一位全加器串联起来,低位的进位输出Cout连接到高位的进位输入Cin,形成一个行波进位链。这种结构非常直观,虽然速度不是最快(因为进位要一位一位传上去),但最适合我们理解层次化设计。
新建工程FourFullAdder。这里有个非常重要的坑,我当年就踩过:你需要把前两个工程生成的所有必要文件都拷贝过来。具体来说,需要OneHalfAdder.bsf, OneHalfAdder.bdf, OneFullAdder.bsf, OneFullAdder.bdf。少一个,Quartus在编译时就会报错,提示找不到某个模块的定义,就像你搭积木时少了一块关键零件。把它们都放进工程目录后,在原理图页面的Symbol Tool的Project目录下,你应该能看到OneFullAdder这个元件了。
我们需要四个OneFullAdder实例。拖出四个来,整齐排列好。放置输入输出引脚:我们需要4组A[3..0]和B[3..0]作为加数,一个Cin作为最低位的进位输入;输出则是4位的和S[3..0],以及一个最高位的进位输出Cout。在Quartus里,总线(多位线)的绘制很方便。对于A和B,你可以放一个input引脚,然后双击它,在Pin name(s)里直接输入A[3..0],软件会自动识别这是一根4位宽的线。用同样的方法创建B[3..0]和S[3..0]。
连线时,为了清晰,我们通常用总线模式。选择Orthogonal Bus Tool(总线工具),画一条粗线代表总线。然后,用Orthogonal Node Tool(细线工具)从总线上引出分支连接到模块的单个引脚上。你需要分别将A[3], A[2], A[1], A[0]连接到从高到低四个全加器的A输入端,B信号同理。最关键的是进位链的连接:最低位全加器(比如对应A[0]和B[0]的那一个)的Cin接外部输入Cin;它的Cout连接到次低位全加器的Cin;依次类推,像串糖葫芦一样连上去;最高位全加器的Cout则连接到外部输出Cout。四个全加器的S输出端,则分别连接到输出总线S[3..0]的对应分支上。
电路连接完毕,编译通过后,激动人心的仿真验证环节来了。我们通过仿真给电路输入不同的信号,看看它的输出是否符合加法器的预期。File -> New,选择University Program VWF(Vector Waveform File,矢量波形文件)。在仿真文件左侧空白处双击,添加所有需要观察的节点:A, B, Cin, S, Cout。对于A和B这种多位信号,软件会默认以总线形式显示,你也可以右键选择显示为Unsigned Decimal(无符号十进制数),这样看起来更直观。
接下来设置输入信号。比如,我们想测试A=5(二进制0101),B=10(二进制1010),Cin=1的情况。计算一下:5+10+1=16,二进制是10000,所以理论上S应该输出0000,Cout输出1。在波形界面,选中A信号的一段区域,在左侧工具栏点击Overwrite Clock或Overwrite Value,可以设置其值。你可以设置A在0时刻值为5,B为10,Cin为1。为了全面测试,我们还可以设置一段时间让A和B变化,比如让A从0递增到15,B固定为某个值,观察输出变化。
设置好输入后,保存波形文件。然后点击Tools -> Run Simulation Tool -> RTL Simulation,Quartus就会启动ModelSim(如果你安装了的话)进行仿真。稍等片刻,仿真波形图就会显示出来。你就能清晰地看到,随着输入的变化,输出S和Cout是否严格按照二进制加法规则变化。如果发现结果不对,就要回到原理图,仔细检查连线和模块调用是否有误。这个仿真调试的过程,是数字电路设计中最有成就感也最能加深理解的一环。当你看到仿真结果与理论计算完全吻合时,就意味着你这个从门电路开始、亲手搭建的4位全加器,真正地设计成功了。
更多推荐
所有评论(0)