FPGA编程入门(半加器,1位全加器和4位全加器的实现)

目录



一、Verilog编程入门

1.1 门电路入门练习

(1)与门

本题要求使用 Verilog 语言描述一个模块,实现与门的作用。

从第 4 题开始,是用 Verilog 描述各种 “门”,这也就是 Verilog 硬件描述语言中,描述二次的由来。描述就是我们用 Verilog 的语法,通过写下几句代码来实现一个电路。从最简单的门到 CPU 都可以使用 HDL 描述。

题目给出的模块如下图,有三个 wire : a,b 以及 out。a,b 信号已经由模块的输入端口驱动,但图中黑色的部分中,wire out 还没有被任何信号驱动。本题要写一个 assign 语句,使 a,b 信号经过与门的输出驱动 wire out 信号。

显然,assign 语句的实现和前一题非常接近,只是增加了一个输入信号。和前一题不同的是,我们在这里强调了信号是被驱动(drive)的,被驱动的含义可以理解为,该信号的取值取决于另一个连接到它的信号的值,该信号的值随着另一个信号的值改变而改变。下图中模块的输入端口 input wire 被外部连接到模块的信号所驱动。assign 语句映射到具体的硬件上,就是产生了信号的驱动,由右值驱动左值。

说道 assign,一个 wire 信号不能被多个信号同时驱动(当一个信号说往东,另一个信号说往西,两个信号还要同时驱动我时,我到底该往哪?另一个方面,一个没有驱动者(driver)的信号的值会处于未定义的状态,好在综合器一般会免费给他安排一个,将其信号值驱动为 0.

在这里插入图片描述

代码:

module top_module( 
    input a, 
    input b, 
    output out );
   	assign out=a&b;

endmodule

结果:
在这里插入图片描述

(2)或非门

本题要求使用 Verilog 实现一个 NOR 门,注意这里其实是或非门,而不是更常见的异或门,或非门是或门的输出取反。

assign 语句将某个值赋予 wire 信号,这个 value 可以是常量,也可以是一个复杂的逻辑表达式,综合器会综合出相应的逻辑门实现。assign 语句代表的始终是连续赋值,因为当输入信号改变时,输出信号会重新“计算”。和一个逻辑门的工作方式相同,输入改变,输出对应改变。

在这里插入图片描述

代码:

module top_module( 
    input a, 
    input b, 
    output out );
    assign out=~(a|b);
endmodule

结果:

在这里插入图片描述

(3)同或门

XNor 的中文是什么,其实应该是同或门。

我们首先复习下数电,同或门 (XNor Gate) 是异或门 (Nor Gate) 的取反输出。异或门的输入输出可以概括为:(输入)相同(输出)为 0 ,不同为 1 。

在这里插入图片描述

代码:

module top_module( 
    input a, 
    input b, 
    output out );
    assign out = ~(a^b);
endmodule

结果:

在这里插入图片描述

1.2 组合电路入门练习

(1)Declaring wires

之前电路足够简单,我们能直接表示出输入输出信号的逻辑关系,但如果电路变得复杂,那么我们就需要一些中间信号来帮助我们简化描述电路的难度。

定义中间信号的语法格式为

wire foo ;

信号定义语句需要放置于模块的 body 中,就好比 C 语言中,你的中间临时变量需要定义在 main 函数函数体中。模块的 body 指的就是 module 和 endmodule 中间的部分。

这里建议先定义信号,再使用信号,就像 C 语言中一样。原则上,你可以在任何位置定义你的信号,使用前使用后都可以,正如之前的课程中说的那样,语句的顺序对于 Verilog 来说没有关系。但有些仿真工具需要你在使用信号之前定义信号,So,你就这么来吧。

实现下图中的模块。首先创建两个中间信号将与门和或门连接起来,信号的名字随你的便,但好的名字往往影响一个信号的一生,若干年后,你还能依稀记起当年定义这个信号的峥嵘岁月。

注意,与门的输出信号也就是或门的输入信号,所以你不需要再定义或门的输入信号。再提醒一下,信号只能被一个信号驱动,但能驱动多个信号。

按照下图中的逻辑关系,你的代码应该有 4 个 assign 语句,对应四个逻辑门,或者说模块。

在这里插入图片描述

代码:

`default_nettype none
module top_module(
    input a,
    input b,
    input c,
    input d,
    output out,
    output out_n   ); 
	wire	and_1 = a & b;
    wire	and_2 = c & d;
    wire	or_1  = and_1 | and_2;
    assign	out   = or_1;
    assign	out_n = ~or_1;
endmodule

结果:
在这里插入图片描述

(2)7458芯片

本题要实现个稍稍复杂的电路:数电芯片 7458 。它有 10 个输入信号,2 个输出信号。你可以选择对每个输出信号,使用一个 assign 语句,也可以先产生第一级逻辑门输出的 4 个中间信号。有时间的话,两种方式都可以尝试下。
在这里插入图片描述

代码:

module top_module ( 
    input p1a, p1b, p1c, p1d, p1e, p1f,
    output p1y,
    input p2a, p2b, p2c, p2d,
    output p2y );
    assign p1y = (p1a & p1b & p1c) | (p1d & p1e & p1f);
    assign p2y = (p2a & p2b) | (p2d & p2c);
endmodule

结果:
在这里插入图片描述

(3)7420 chip

7420 chip是拥有两组4输入的与非门芯片,本练习需要构造一个与7420 chip功能一样的电路,拥有8个输入与2个输出。
在这里插入图片描述

代码:

module top_module
    (
        input  p1a, p1b, p1c, p1d,
        output p1y,
        input  p2a, p2b, p2c, p2d,
        output p2y
    );

    assign p1y = ~(p1a & p1b & p1c & p1d);
    assign p2y = ~(p2a & p2b & p2c & p2d);

endmodule

结果:
在这里插入图片描述

1.3 时序电路入门练习

(1)D flip-flop (Dff)

接下来的题目是属于触发器,锁存器的专题。我们会从用 Verilog 实现基础 D 触发器开始,学习触发器这一数字电路中最重要的电路之一。
在这里插入图片描述

D 触发器是一个电路,存储 1bit 数据,并定期地根据触发器的输入(d)更新这 1 bit 数据,更新通常发生在时钟上升沿(clk)。存储的数据会通过输出管脚(q)输出。

t1时刻: d -> 0

t2时刻: clk->1 上升沿到来,触发器存储的数据变成 0,输出 q 保持为存储的值:0,直到下一个时钟上升沿到来。

t3时刻: d -> 1(d:我变了),q 仍保持 0 不动摇(时钟沿还没来呢)

t4时刻: clk->1 上升沿到来,q->1(q:时钟沿来了,我该变身了)

绝大多数时候,我们不会在 Verilog 代码中显示例化一个触发器(作者没这么做过,但应该是可以做的),我们在时钟敏感的 always 块中的语句一般都会被综合工具转换为相应的触发器。

D 触发器可以认为是一个触发器和一段最简单的组合逻辑块(blob :想表达逻辑块的时候用我,别用 block)的组合。其中组合逻辑块仅仅是一段 wire。(q 直接输出了触发器的存储值)

代码:

module top_module (
    input clk,    // Clocks are used in sequential circuits
    input d,
    output reg q );//

    // Use a clocked always block
    //   copy d to q at every positive edge of clk
    //   Clocked always blocks should use non-blocking assignments
    always@(posedge clk) begin
        q <= d;
    end
endmodule

结果:
在这里插入图片描述

在每个时钟上升沿,输出 q 的值变为输入 d 的值。我们在 always 块中的语句就会被综合工具转换为触发器。这里使用 clk,q,d 对应于触发器的三个端口,反应了转换的对应关系。

(2)D flip-flops (Dff8)

实现 8 个 D 触发器,听上去好像很累的样子,实则 Verilog 语言的抽象帮助我们省去不少麻烦。输入 a,b 的位宽变为 8 位,但 always 块中的语句与上一题完全相同。

综合工具根据位宽,综合出了 8 个 D 触发器。一般没有八位触发器的说法。这里反映了综合工具能分析代码,生成相应的触发器电路,其实综合器还能将复杂得多的语句转为相应的电路。
代码:

module top_module (
    input clk,
    input [7:0] d,
    output [7:0] q
);
    always@(posedge clk) begin
    	q <= d;
    end
endmodule

结果:
在这里插入图片描述

(3)DFF with reset (Dff8r)

在上题的 8 个 D 触发器基础上,这题我们要给触发器配上同步复位端口。

什么同步复位?当时钟上升沿到来时,如果同步复位端有效(本题中复位高电平有效,即 reset),那么任凭你触发器此前输出或者输入的是 0,是 1,输出一律变为 0。

复位电路对于那些经常需要恢复到初始状态的电路是必要的,复位相较于断电重新加载程序恢复到初始状态的速度要快得多。但也有一些电路则不需要复位设计。(作者也是有所耳闻那些不需要复位的电路,平常自己还是会加上复位电路)

代码:

module top_module (
input clk,
input reset,
input [7:0] d,
output [7:0] q
);
always@(posedge clk) begin
q <= (~{8{reset}} & d);
end
endmodule

从语法的角度来说,reset 实现就是加一个 if 语句判断 reset 是否有效,有效就将输出 q 置为 0 。

但从电路的角度来说,电路的角度往往更加重要,是使用一个带有复位端的 D 触发器 fdr,另一种 D 触发器单元。

结果:
在这里插入图片描述

二、Logisim进行仿真设计

2.1 认识全加器

2.1.1 半加器

半加器是指对输入的两个一位二进制数相加(A与B),输出一个结果位(SUM)和进位(C),没有进位的输入加法器电路,是一个实现一位二进制数的加法电路。

真值表

被加数a加数a和s进位c
0000
0110
1010
1101

逻辑表达式
根据上述的真值表,当A和B相同时SUM为0,否则为1;逻辑关系属于异或;当A和B同时为1时,C等于1,其余都为零,逻辑关系为与。
所以我们可以得到如下的逻辑表达式:
在这里插入图片描述

逻辑电路图
在这里插入图片描述

2.1.2 全加器

全加器是指对输入的两个二进制数相加(A与B)同时会输入一个低位传来的进位(Ci-1),得到和数(SUM)和进位(Ci);一位全加器可以处理低位进位,并输出本位加法进位。多个一位全加器进行级联可以得到多位全加器。常用二进制四位全加器74LS283。

真值表

被加数a加数b低进位cin和s进位cout
00000
00110
01010
10010
11001
01101
10101
11111

逻辑表达式
由全加器的定义理解我们可以知道当Ai和Bi异或后再与Ci-1进行异或得到SUMi,结合真值表,我们可以知道当Ai、Bi、Ci-1只要有两个以上的1是进位Ci就等于1;所以只需要每两变量求与,结果再求或就可以满足要求。由此我们可以得到最常用的逻辑表达式:

在这里插入图片描述

逻辑电路图
根据逻辑表达式绘制两种逻辑电路图如下:

在这里插入图片描述

2.2 Logisim完成一个1位全加器的设计并测试

2.2.1 先设计设计一个1位半加器电路

采用异或门和与门结合设计一个简单的半加器:

在这里插入图片描述

2.2.2 在半加器电路基础上,实现一位全加器电路

在设计全加器时,因为会有三个数进行运算,因此可以简化为先进行两个输入数的运算,再进行其和与进位数的运算,即两次1bit运算。同时,在计算结果时,除了结果数,还要提出进位数供下一位计算。因此,在Logisim中,我们可以采用两个半加器相结合的方式设计一个全加器,参考如下:
在这里插入图片描述

三、基于Quartus进行实验并仿真

3.1 输入原理图实现1位加法器

创建工程项目过程:
启动 Quartus软件,选择File->New Project Wizard
在这里插入图片描述

填写工程名称:
在这里插入图片描述

选择第一个,直接Next
在这里插入图片描述

这个界面不用管,直接next
在这里插入图片描述

根据使用的FPGA,进行选择芯片系列及类型
在这里插入图片描述

直接next
在这里插入图片描述

完成工程创建,点击finish
在这里插入图片描述

3.1.1 半加器原理图输入

(1)绘制过程实现

首先选择File->New,进入后选择Block Diagram/Schematic File
在这里插入图片描述

选择元件
在这里插入图片描述

添加输入输出,完成效果:

在这里插入图片描述

保存文件,并编译
通过tool->Netlist Viewers->RTL Viewer,查看电路图
在这里插入图片描述

(2)仿真实现

创建一个向量波形文件,选择菜单项 File→New->VWF

在这里插入图片描述

出现这个页面后,双击左侧空白处
在这里插入图片描述

出现这个弹窗,点击Node Finder
在这里插入图片描述

然后添加进来,点击ok
在这里插入图片描述

最后出现波形:
在这里插入图片描述

随便编辑一下信号
在这里插入图片描述

保存文件并启动功能仿真,出现错误,别慌,进行仿真配置,选择tool->launch simulation library complier
在这里插入图片描述

在这里插入图片描述

(3)仿真结果

重新测试仿真:

功能仿真结果:
在这里插入图片描述

时序仿真结果:
在这里插入图片描述

通过仿真结果,可以发现得到的结果与真值表中是相吻合的。

3.1.2 全加器原理图输入

利用半加器元件实现全加器

(1)将设计项目设置为可调用的元件

在打开半加器原理图文件half_adder.bdf的情况下,选择菜中File中的Create/Update→CreateSymbolFilesforCurrentFile项,即可将当前文件h_adder.bdf变成一个元件符号存盘,以待在高层次设计中调用

在这里插入图片描述

(2)绘制过程实现

首先选择File->New,进入后选择Block Diagram/Schematic File
在这里插入图片描述

选择元件
在这里插入图片描述

添加输入输出,完成效果
在这里插入图片描述

保存文件,并编译
通过tool->Netlist Viewers->RTL Viewer,查看电路图
在这里插入图片描述

(3)仿真实现

创建一个向量波形文件,选择菜单项 File→New->VWF
在这里插入图片描述

跟半加器同理添加信号,然后编辑信号
在这里插入图片描述

保存文件并启动功能仿真,出现错误,进行仿真配置,选择tool->launch simulation library complier(同理半加器)

(4)仿真测试结果

功能仿真结果
在这里插入图片描述

时序仿真结果
在这里插入图片描述
通过仿真结果,可以发现得到的结果与真值表中是相吻合的。

四、Verilog编程实现1位加法器

创建Verilog文件

在这里插入图片描述

4.1 代码实现

module full_adder(
	//输入信号,ain表示被加数,bin表示加数,cin表示低位向高位的进位
	input ain,bin,cin,
	//输出信号,cout表示向高位的进位,sum表示本位的相加和
	output reg cout,sum

);
reg s1,s2,s3;
always @(ain or bin or cin) begin
	sum=(ain^bin)^cin;//本位和输出表达式
	s1=ain&cin;
	s2=bin&cin;
	s3=ain&bin;
	cout=(s1|s2)|s3;//高位进位输出表达式
end
endmodule

保存并编译文件
通过tool->Netlist Viewers->RTL Viewer,查看电路图
在这里插入图片描述

4.2 仿真实现

创建一个向量波形文件,选择菜单项 File→New->VWF
在这里插入图片描述

同理添加信号并编辑信号
在这里插入图片描述

功能仿真结果
在这里插入图片描述

时序仿真结果
在这里插入图片描述

通过仿真结果,可以发现得到的结果与真值表中是相吻合的。

五、下载测试

5.1 1位全加器测试

(1)点击引脚配置

在这里插入图片描述

(2)配置引脚

使用3个SW作为输入信号,2个LED作为输出信号
在这里插入图片描述

(3)原理图

在这里插入图片描述

(4)代码下载

代码下载到FPGA板子上
在这里插入图片描述

(5)测试结果

a为,b为1,输入的cin为1,则s=1,进位cout=1,其他测试也通过

在这里插入图片描述

六、四位全加器(实验重点)

6.1 四位全加器的原理图设计

同理将一位全加器设置为可调用的元件,然后设计出原理图

(1)原理图

在这里插入图片描述

(2)RTL电路图如下

在这里插入图片描述

(3)仿真测试

设置信号:
在这里插入图片描述

(4)仿真结果

功能仿真结果
在这里插入图片描述

时序仿真结果
在这里插入图片描述

6.2 四位全加器的Verilog编程实现

(1)创建文件:

在这里插入图片描述

(2)代码实现

//数据流描述4位全加器
module four_adder1(
    	input[3:0] a,b,
    	output[3:0] s,
    	output cout,
    	input cin
);

assign{cout,s} = a+b+cin;
endmodule

(3)RTL电路图

编译代码得到的RTL电路图
在这里插入图片描述

(4)上板烧录

引脚选择
在这里插入图片描述

引脚在板子上的位置对应关系:
在这里插入图片描述

实物图:

在这里插入图片描述

(5)测试结果(重点检验)

此次测试的板子LED1电压不稳定,始终保持亮状态,测试中我们忽略

(1)b3为1,其余为0,结果为1 0 0 0 ,SW7为1,LED4亮,无进位,测试成功
在这里插入图片描述

(2)a3和b3为1,其余为0,结果为1 0 0 0 0,SW3和SW7为1,LED0亮,有进位,cout=1,测试成功

在这里插入图片描述

(3)b2为1,其余为0,结果为0 1 0 0,SW6为1,LED3亮,无进位,测试成功
在这里插入图片描述
结果为跟其真值表相吻合。nice!


总结

这次实验内容很多,基本上是全新的知识点(对于大二没有学过模电数电的我),从软件安装到环境配置过程中踩了很多雷,基本上每个坑都花了几十分钟上网寻找解决方案,但是逐渐摸索的感觉真的很有自豪感,尤其是自己懂得半加器、全加器和四位全加器的原理之后,画电路原理图很是得心应手,但是在组件接线的时候一定要细心,稍有不慎就有一个点漏接了(我就是因为线没接上,一直以为板子有问题,调试了半个钟)。同样这次实验也学会了很多,初步了解了Verilog编程的思想,总体来说,遇到困难和bug不要畏惧,学会使用搜索工具,总能在互联网上找到大佬给出的解决方法,在这里非常感谢大佬给出的各种建议和帮助。

参考

详细讲解半加器、全加器、四位全加器,并使用FPGA实现半加器、全加器
利用Logisim设计半加器、全加器及补码电路

FPGA——1位全加器的实现

Verilog基础编程练习

使用 Quartus-ll 两种方法仿真全加器并烧录到 Intel DE2-115 开发板中验证

一位全加器及四位全加器————FPGA

【Verilog设计—仿真实验】四位加法器的实现

HDLBits 中文导学

  • 21
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
好的,我来为您解答这两个问题。 首先,我们需要明确全加器半加器的定义: - 半加器:用于计算两个单独的二进制的和,输出结果包括和值和进标志; - 全加器:用于计算三个二进制的和,其中两个输入相加,再加上一个来自上一的进标志,输出结果包括和值和进标志。 根据定义,我们可以使用1半加器和1全加器来设计4全加器。首先,我们将4个二进制数的每一分别输入到相应的1全加器中,其中第一的进标志输入为0。 接下来,我们需要将前三个全加器的进标志输出连接至第四个全加器的进标志输入端,如下所示: ``` C1 --+-- FA1 --+-- FA2 --+-- FA3 --+ | | | | +-- A1 --+-- A2 --+-- A3 --+-- A4 | | | | +-- B1 --+-- B2 --+-- B3 --+-- B4 | | | | +------->+------->+------->+-- S4 | | | +------->+------->+-- C4 | | +------->+-- S3 | +-- C3 | ... ``` 其中,C1、C2和C3分别为进标志,A1、A2、A3和A4分别为第一个、第二个、第三个和第四个二进制数的对应,同理,B1、B2、B3和B4分别为第一个、第二个、第三个和第四个二进制数的对应,S4为第四个全加器的和值输出,C4为第四个全加器的进标志输出,S3为第三个全加器的和值输出,C3为第三个全加器的进标志输出,以此类推。 这样,我们就成功地使用1半加器和1全加器来设计了4全加器。 接下来,我们来介绍一下RS锁存器的内部结构。RS锁存器是一种基本的数字逻辑电路,用于存储一个比特(0或1)。它由两个输入端R和S、一个输出端Q和一个反相输出端Q'组成。 RS锁存器的内部结构如下所示: ``` +------+ +-----+ +------+ | | | | | | R --+ OR +-----+ NAND+-----+ Q | | | | | | | S --+ OR +-----+ NAND+-----+ Q' | | | | | | | +------+ +-----+ +------+ ``` 其中,OR门接收R和Q'作为输入,NAND门接收S和Q作为输入,输出分别为Q和Q'。 当R和S同时为0时,RS锁存器保持原状态不变;当R为1、S为0时,输出Q为0,Q'为1;当S为1、R为0时,输出Q为1,Q'为0;当R和S同时为1时,RS锁存器处于不稳定状态,输出随机。 希望这些解答能对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菲菲QAQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值