从零开始的FPGA学习(Vivado和Verilog语言)


简单说明:这里我们采用Vivado软件进行仿真和编译,使用的语言为Verilog语言,这篇博客记录自己的从零开始的学习过程,还是个新人学习过程中可能会遇到问题,如有问题请在评论区中提出会尽快更正的。

第一个任务:多数表决器

(1)基础任务

选择一个人数的表决器,每个人用一位表示(如 9 人表决器就是 9 位二进制),1 表示同意,0 表示不同意,超过半数表示通过,由一位发光二极管显示输出,通过用 1 表示,发光二极管亮,不通过用 0 表示,发光二极管灭。

首先我们先做一个的3人表决器,同时感受一下VIVADO软件和Verilog语言。

1.建立工程:

点击Create Project 建立一个新的工程,下面Open Project 打开一个工程。然后点击NEXT
在这里插入图片描述
在这里修改工程的名字和位置,根据自己喜好即可,最好能够让自己方便找到,设置好后点击NEXT
在这里插入图片描述
默认选择RTL工程即可直接点击NEXT
在这里插入图片描述
在这里我们可以添加和创建文件,也可以进入之后在添加,当然如果我们之前就有写好的源文件可以直接打开,不过我们还没有直接点击NEXT即可。后面相同点击NEXT
在这里插入图片描述

选择器件:实际实验会有一个板子上面有着对应的型号,如果还不知道型号随意选择就好。进入之后也是可以重新选择型号的,不用担心。(下面是我选择的型号 xc7a35tcsg325-1)
在这里插入图片描述

接下来是VIVADO的界面,没错一脸懵逼,(这确实是我的第一反映,这都是什么东西)不过不要着急,一点一点使用下来就会熟悉了。
图中箭头标注处可以添加文件其中包括源文件,仿真文件,约束文件(你问我源文件和仿真文件干嘛用的? 我怎么知道,就是实现功能和仿真的呗,实在说不清楚,后面有更多的理解了在后面补充好了。)
在这里插入图片描述
进入到页面了,该去做我们的第一个任务喽!做一个多人表决器!

每个人用一位表示(如 9 人表决器就是 9 位二进制),1 表示同意,0 表示不同意,超过半数表示通过,由一位发光二极管显示输出,通过用 1 表示,发光二极管亮,不通过用 0 表示,发光二极管灭。

简单理解就是投票,人数过半就通过(输出1),否则就不通过(输出0)
好极了简单易懂。
那么第一步建立一个源文件!

1.建立源文件
点击add sources 在这里插入图片描述
add or create constraints(时束文件)
在这里插入图片描述
add or create design sources(源文件)
在这里插入图片描述
Add or create simulation sources(仿真文件)
在这里插入图片描述
选择第二个源文件 出现一开始建立工程的类似页面,点击Create File 给文件命名
在这里插入图片描述
在这里插入图片描述
这里命名为vote_7 附上7人表决器源文件代码

module vote_7(output pass,input [6:0] vote);
integer i;   //i用作循环
reg[2:0] vote_count;  //用来计数是否超过三人(半数)
always@(vote)begin   
  vote_count=0;   //赋初值为0
  for(i = 0;i<7;i = i+1) begin  //进行循环7if (vote[i])            //判断是否为1 统计输入为1的人数
      vote_count = vote_count+1;
  end
end
assign pass = (vote_count>3) ? 1 : 0;   //利用“? :” 判断是否大于3 是则为1   
endmodule

接下来,同样的步骤选择第三个文件 建立仿真文件 下面附上仿真文件代码

`timescale 10ns/100ps
module tb_vote_7;
reg[6:0] vote;
wire pass;
vote_7  v1(.pass(pass),.vote(vote));  //调用仿真模块
initial begin
  vote = 0;
  repeat(10) #10   // 重复十次
      begin
        vote <= (vote<<1) | 7'b1;   //每次左移并和0000001做位运算 
      end
  end
endmodule

编辑好仿真文件后,点击Run Simulation进行仿真 可以看到波形图。
在这里插入图片描述

先对仿真文件中的对vote<=(vote<<1)|7’b1详细说明:
其中<<是移位 ‘|’是做位运算 语法这里不做具体说明。
在这里插入图片描述

OK问题来了 问什么要这么做呢?
对比一下其他仿真文件激励是怎么加的?

下面是一个三人表决器的仿真文件:

module sim_multi_vote;
reg a,b,c;
wire f;
multi_vote u1(
a,
b,
c,
f
);
initial 
begin a=0;b=0;c=0;
end
always #10 {a,b,c}={a,b,c}+1;  //注意这里!!! 这里加激励的方式与上面不同
endmodule

这里的激励利用always #10 {a,b,c}={a,b,c}+1 它的含义是每过10ns后 a b c(三个输入)就会加一 。
利用always每次加1并没有进行移位 所以在二进制中得到的顺序是
000 001 010 011 100 101 110 111
虽然也结果与7人相差不多但是顺序并不是依次排列 可观性不如上面7人表决器的好,下面配上七人表决器和三人表决器波形图进行对比

三人表决器:(a,b,c为输入,f为输出)三人表决器

七人表决器:(vote为7人投票输入,pass为最后投票结果输出)
七人表决器

到这里基础任务就已经顺利结束了!

(2)提高任务和扩展任务

提高任务:
在基础任务的基础上,位数(人数)与所选基础任务一致,同时再显示出哪一个人通过,哪一个人不通过,用相应的拨码开关输入端上面的用发光二极管显示每个人的情况。

拓展任务:
在基础任务和提高任务的基础上,位数(人数)与所选基础任务一致,当一位发光二极管显示输出通过与否时,同时由数码管显示输出通过的人数。

提高任务便是要用拨码开关核发光二极管显示每个人的情况。
只需要在上面的基础上加上发光二极管计入每个人投票的结果(既vote [6:0]中的 0 和 1的取值情况)若是1二极管亮 若是0二极管则不亮

而拓展任务便是在提高任务的基础上多加一位数码管显示通过人数即可。

下面将两个任务一同实现:

改进源文件如下:

module TG(pass,segment_out,vote,an);  //重新建立的源文件TG
integer i,n;
output wire an;          //数码管位信号
output reg[7:0] pass;    //pass位8位输出,其中最后一位显示最终投票是否通过。
output reg[7:0] segment_out;    //八段数码管
input [6:0] vote;        //vote7人投票的输入
reg[3:0] vote_count;     //计数

assign an=1;    //数码管位信号
always@(vote)begin
  vote_count=0;
  for(i = 0;i<7;i = i+1) begin
    if (vote[i])
      vote_count = vote_count+1;
  end
end
always@(vote)
for(n = 0;n<7; n= n+1)
 pass[n] = vote[n];    //将投票结果赋给pass
always@(vote_count)  
pass[7] = (vote_count>3) ? 1 : 0;    //最后一位为最终投票结果

always@(vote_count)       //数码管人数显示
   begin
     case(vote_count)         
        4'd0: begin segment_out <= 8'b00111111; end
        4'd1: begin segment_out <= 8'b00000110; end
        4'd2: begin segment_out <= 8'b01011011; end
        4'd3: begin segment_out <= 8'b01001111; end
        4'd4: begin segment_out <= 8'b01100110; end
        4'd5: begin segment_out <= 8'b01101101; end
        4'd6: begin segment_out <= 8'b01111101; end
        4'd7: begin segment_out <= 8'b00000111; end
        4'd8: begin segment_out <= 8'b01111111; end
        default: begin segment_out <= 8'b11111111; end
     endcase
   end
endmodule

在这里解释一下前面没有说明的 源文件 仿真文件 约束文件都是干嘛的!(个人理解)
源文件 主要用来实现我们想要的功能。接下来功能实现了需要验证有两种方法:

第一种:没有板子的情况或者有板子不想用 或者检验一下自己写的对不对 我们可以进行一下仿真,这里便是创建仿真文件,加入激励,看波形是否是我们想要的结果。

第二种:用板子看效果。那就要创建约束文件。把源文件里的输入输出等等添加上约束,说白了就是源文件里定义的都是reg类型的数组 约束文件里将他们具体分配到板子上 比如这里将vote分给拨码开关作为输入,把segment_out分给数码管用来显示人数,把pass分给二极管用来显示是否同意。

这里直接用板子实现了,下面为用xc7a35tcsg325-1实现的约束文件

set_property -dict {
    
    PACKAGE_PIN K1 IOSTANDARD LVCMOS33} [get_ports {
    
    pass[7]}]
set_property -dict {
    
    PACKAGE_PIN P5 IOSTANDARD LVCMOS33} [get_ports {
    
    vote[0]}]
set_property -dict {
    
    PACKAGE_PIN P4 IOSTANDARD LVCMOS33} [get_ports {
    
    vote[1]}]
set_property -dict {
    
    PACKAGE_PIN P3 IOSTANDARD LVCMOS33} [get_ports {
    
    vote[2]}]
set_property -dict {
    
    PACKAGE_PIN P2 IOSTANDARD LVCMOS33} [get_ports {
    
    vote[3]}]
set_property -dict {
    
    PACKAGE_PIN R2 IOSTANDARD LVCMOS33} [get_ports {
    
    vote[4]}]
set_property -dict {
    
    PACKAGE_PIN M4 IOSTANDARD LVCMOS33} [get_ports {
    
    vote[5]}]
set_property -dict {
    
    PACKAGE_PIN N4 IOSTANDARD LVCMOS33} [get_ports {
    
    vote[6]}]

set_property -dict {
    
    PACKAGE_PIN K3 IOSTANDARD LVCMOS33} [get_ports {
    
    pass[0]}]
set_property -dict {
    
    PACKAGE_PIN M1 IOSTANDARD LVCMOS33} [get_ports {
    
    pass[1]}]
set_property -dict {
    
    PACKAGE_PIN L1 IOSTANDARD LVCMOS33} [get_ports {
    
    pass[2]}]
set_property -dict {
    
    PACKAGE_PIN K6 IOSTANDARD LVCMOS33} [get_ports {
    
    pass[3]}]
set_property -dict {
    
    PACKAGE_PIN J5 IOSTANDARD LVCMOS33} [get_ports {
    
    pass[4]}]
set_property -dict {
    
    PACKAGE_PIN H5 IOSTANDARD LVCMOS33} [get_ports {
    
    pass[5]}]
set_property -dict {
    
    PACKAGE_PIN H6 IOSTANDARD LVCMOS33} [get_ports {
    
    pass[6]}]

set_property -dict {
    
    PACKAGE_PIN G6 IOSTANDARD LVCMOS33} [get_ports {
    
    an}]

set_property -dict {
    
    PACKAGE_PIN D4 IOSTANDARD LVCMOS33} [get_ports {
    
    segment_out[0]}]
set_property -dict {
    
    PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports {
    
    segment_out[1]}]
set_property -dict {
    
    PACKAGE_PIN D3 IOSTANDARD LVCMOS33} [get_ports {
    
    segment_out[2]}]
set_property -dict {
    
    PACKAGE_PIN F4 IOSTANDARD LVCMOS33} [get_ports {
    
    segment_out[3]}]
set_property -dict {
    
    PACKAGE_PIN F3 IOSTANDARD LVCMOS33} [get_ports {
    
    segment_out[4]}]
set_property -dict {
    
    PACKAGE_PIN E2 IOSTANDARD LVCMOS33} [get_ports {
    
    segment_out[5]}]
set_property -dict {
    
    PACKAGE_PIN D2 IOSTANDARD LVCMOS33} [get_ports {
    
    segment_out[6]}]
set_property -dict {
    
    PACKAGE_PIN H2 IOSTANDARD LVCMOS33} [get_ports {
    
    segment_out[7]}]

看着复杂其实很简单一一对应好 改了名字就可以了。

添加完约束文件的后就如下图所示依次各种综合,中间弹出东西就OK OK 在OK
在这里插入图片描述

下面附上我实现后的图片:

0 1 4 5投票为1 二极管亮 , 7号位置二极管为最终投票结果,大于四人所以亮 , 上面数码管显示人数为4
在这里插入图片描述

接下来是第二个任务 38译码器 封装IP核 并且实现一位全加器。

猜你喜欢

转载自blog.csdn.net/weixin_45329944/article/details/114750151