OS:Win7 x64 EDA软件:Quartus II 13.1 FPGA平台:DE1-SOC |
用Verilog HDL不同的抽象能力设计一个一位加法器,然后用ModelSim仿真器对三中方法实现的加法器进行功能仿真(三者的功能仿真都通过,只贴出了门级实现的仿真结果),然后再将adder_description的.sof文件下载到FPGA中验证:将两个输入连接到FPGA的SW0和SW1上,输出连接到LEDR0和LEDR1上,拨动SW0和SW1观看LEDR0和LEDR1变化。
用Verilog HDL行为描述来实现这个1位加法器就是用Verilog HDL来描述1位加法器的功能:什么样的输入对应什么样的输出。
以下是描述1位加法器(无低位的进位)的功能的Verilog HDL代码:
1. module adder_description(b1, b2, s, c); 2. input b1, b2; 3. output s, c; 4. reg s, c; 5. 6. always @(b1 or b2) 7. begin 8. if (1'b0 == b1 && 1'b0 == b2) 9. begin 10. s <= 1'b0; 11. c <= 1'b0; 12. end 13. else if (1'b1 == b1 && 1'b0 == b2 || 14. 1'b0 == b1 && 1'b1 == b2 ) 15. begin 16. s <= 1'b1; 17. c <= 1'b0; 18. end 19. else if (1'b1 == b1 && 1'b1 == b2) 20. begin 21. s <= 1'b0; 22. c <= 1'b1; 23. end 24. end 25. endmodule |
想用Verilog HDL行为描述的属性来描述硬件时,只要知道硬件的功能,不用由真值表推逻辑函数。用adder_description在顶层设计文件中实例化一个1位加法器。
1. module one_bit_adder(b1, b2, s, c2); 2. input b1; 3. input b2; 4. output s; 5. output c2; 6. 7. adder_description da(b1, b2, s, c2); 8. endmodule |
然后用综合器综合输出网表文件(Processing>> Start >> Start Analysis & Synthesis),然后在网表阅读器中查看这段代码对应的硬件电路(Tools>> Netlist Viewers >> RTL(描述数据在寄存器之间流动和如何处理这些数据的模型,但在其中我们可以看到最底层的电路符号)Viewer):
点开上图的“+”号,就可以看到内部组成:
各种连接在一块的电路符号,挺复杂。对1位无进位加法器的描述是否正确,还真得需要验证。因为它比Verilog HDL门级描述的带低位进位的1位加法器要复杂得多。
用Verilog HDL门级来实现1位加法器,首先要根据1位加法器的功能发出输入/输出的真值表,然后得到逻辑函数,再对逻辑函数化简(卡诺图),对基本门表达的逻辑敏感,再有多个逻辑表达式时,必要时使各表达式中包含相同的项,以共用同一逻辑门的输出。然后就可以用Verilog HDL门级语句来实现电路(对于小型电路,不少人肯定会觉得原理图输入方式比Verilog HDL直观得多)。
以下是1位加法器的Verilog HDL门级层代码:
1. module one_bit_adder(b1, b2, c1, s, c2); 2. input b1; 3. input b2; 4. input c1; 5. output s; 6. output c2; 7. 8. wire a1, a2, x1; 9. 10. and A1(a1, b1, b2); 11. xor X1(x1, b1, b2); 12. and A2(a2, c1, x1); 13. or O1(c2, a1, a2); 14. xor X2(s, c1, x1); 15. endmodule |
在顶层设计文件中实例化one_bit_adder:
1. module n_bit_adder(b1, b2,c1,s, c2); 2. input b1; 3. input b2; 4. input c1; 5. output s; 6. output c2; 7. 8. one_bit_adder fa(b1, b2, c1, s, c2); 9. endmodule |
经综合器出来的1bit全加法器电路连接关系跟原码中表达一个样。
以下代码源自是《Verilog数字设计教程》中的一个例子:
1. module pn_bit_adder(x, y, s, c); 2. parameter n = 1; 3. 4. input[n - 1:0] x; 5. input[n - 1:0] y; 6. output[n - 1:0] s; 7. output c; 8. 9. assign {c, s} = x + y; 10. endmodule |
这段代码跟数字电路中的加法器几乎脱离了关系。不用知道1位加法器的逻辑函数甚至不用知道它的功能,只需要搜一下“Verilog加法器”就能得到关键语句“assign {c, s} = x + y”而实现n位加法器。美,但一层朦胧。
在顶层设计文件中实例化pn_bit_adder:
1. module n_bit_adder(b1, b2, s, c2); 2. input b1; 3. input b2; 4. output s; 5. output c2; 6. 7. pn_bit_adder #(1) pa(b1, b2, s, c2); 8. endmodule |
调用综合器输出网表文件并查看:
Figure4. 1bit 加法器运算符实现
图中的add0是Primitives下的一个运算符。运算符这种东西,看似不起眼,会72搬变化,其功能不容小视,但其跟电路究竟有什么对应,在网表文件中已经看不出来了。
为了求心里踏实,我们将仿真这几个1位加法器的功能,并将其下载到FPGA上,点两个灯娱乐一下。
module-endmodule是Verilog HDL描述电路的最小模块。由于生在语言中,它就必须受众多约束,不然编写综合器的人就麻烦了。Verilog的module-endmodule的使用需要按照以下格式:
module m_name(in_port, out_port, inout_port); //声明端口类型 input inport in_ports; output out_ports; inout inout_ports;
//逻辑(功能)定义 … endmodule |
声明端口类型区域专门用来声明电路模块的输入/输出端口,用的关键字就是input,output,inout;逻辑(功能)定义区不是随便怎么写都能被综合器当成逻辑功能区,必须在assign、always、或者像and、or这样的实例元件关键字下写代码才能表功能定义。不在这三种类型的关键字下写功能,综合器这一关都通不过。
以功能仿真“Verilog HDL的门级实现”加法器笔记仿真步骤。
[1] 综合“Verilog HDL的门级实现”加法器。
[2] 测试“Verilog HDL的门级实现”加法器的代码。
通过Quartus自动生成一个Testbench的模板,选择Processing-> Start -> Start Test Bench Template Writer,等待完成后打开刚才生成的Testbench,默认是保存在simulation\modelsim文件夹下的.vt格式文件。只需要列举两个被加数的所有情况就可以验证加法器是否正确,故而只需要在initial中写测试代码:
Table 1. 1位加法器门级实现测试代码
1. initial 2. begin 3. // code that executes only once 4. // insert code here --> begin 5. #100 6. c1 = 1'b0; 7. b1 = 1'b0; 8. b2 = 1'b0; 9. 10. #100 11. b1 = 1'b0; 12. b2 = 1'b1; 13. 14. #100 15. b1 = 1'b1; 16. b2 = 1'b0; 17. 18. #100 19. b1 = 1'b1; 20. b2 = 1'b1; 21. // --> end 22. $display("Running testbench"); 23. end |
#100表示延时100个时间单位(`timescale1 ps/ 1 ps前面的1ps),延时后面的代码同时执行。这里列举了两个加数的所有情况。
[3] 设置仿真软件和测试文件
在ProjectNavigator中的Hierachy界面选择顶层设计文件>> Settings >> EDA Tool Settings >> Simulation >> Toolname:ModelSim-Altera;Formatfor output netlist:VerilogHDL;在Compile test bench中选择[2]中写的测试文件
[4] 设置仿真软件目录Tools>> Options >> EDA Tool Options >> ModelSim-Altera:C:\altera\13.1\modelsim_ae\win32aloem\
[5] Tools >> Run Simulation Tool
2中指向哪里,3中就显示出相应的结果,从此次功能仿真看来,这个加法器是正确的(没验证低位进位)。经modelsim-atlrea仿真,三个加法器的功能都是对的。
在~../DE1-SoC_v.3.1.0_SystemCD/Schematic目录下打开FPGA的原理图我的是DE1-SoC_Rev_D.pdf。SW0、SW1、LEDR0、LEDR1在FPGA上的引脚分别为AB12、AC12、VC16、W16。
在QuartusII中选择Assignments >>Pin Planner,给adder_description输入输出分配引脚:
编译:Processing>> Start Compile(目的完成综合后的所有编译)。下载.sof文件到FPGA内。
一次拨动SW0和SW1按钮,得以下结果:
为了让硬件(数字)设计能够像软件设计一样,硬件描述语言(HDL)出现,Verilog HDL是众多HDL中的一个代表。语言抽象能力(足够),但决定VerilogHDL能力的还是编译器(综合器)。无综合器,Verilog HDL就成不了硬件电路更高层面的抽象层。不像二进制码,它对逻辑电平的抽象只需要一个逻辑转变。没有汇编器,汇编就不能成为机器码的助记符;没有C编译器,C就不能成为汇编的抽象层,成为更接近American语言的计算机语言。
硬件符号对硬件元件实物算第一层抽象,书上大多都用符号代替实物,用逻辑代替其功能,也很少有老师上课带实物去。学生往往需要通过这层抽象去学习到硬件的一切。
硬件语言是对硬件元件符号的直接抽象。如Verilog HDL中的and表是一个与门类型;如用Verilog HDL对一个触发器的功能进行描述……这中抽象的还原需要综合器,它将Verilog HDL还原为带连接关系的硬件符号,将这种还原输出到一个文件中,这个文件被称为网表文件,其内包含带连接关系的门、RAM等“基本”元件。
硬件名对硬件算是最高层次的抽象,也即被应用得最广的一层。当对方说出这种硬件的名字的时候,另一方需要大脑来转换这个硬件的模样、功能(还有可能需要想到怎么用VerilogHDL来实现),这种抽象岂不令人惊恐。
引用2008年的《Verilog数字系统设计教程》中的一段话:目前,用门级和RTL级抽象描述的Verilog HDL模块可以用综合器自动转换成标准的逻辑网表;用算法级描述的Verilog HDL模块,只有算术运算的离散步奏,如加法和乘法,综合器能把它转换成标准的逻辑网表;而不能综合连续的复杂运算过程,而用系统级描述的模块,目前尚未有综合器能把它转换成标准的逻辑网表,往往只用于系统仿真,即编写测试信号对已经设计的电路部分进行全面的测试和验证。
现在,综合器的功能可能有很大的提高,在完全不了解或者了解硬件儿和综合器的情况下还是可以大肆尝试去利用语言算法级和系统级抽象能力去设计电路的,因为快。