• FPGA入门总结知识点


    这里对于FPGA的学习-B站的FPGA入门视频做了一些总结。

    https://www.bilibili.com/video/BV1J7411a7sW?p=9&spm_id_from=pageDriver&vd_source=96ad85c58bc3572b6686cdbf3a7f8cdb
    
    • 1

    总结的章节包括:

    1.FPGA概述

    1.1什么是FPGA

    1.2FPGA的应用非常的广泛

    1.3Artix-7介绍

    2.FPGA基本逻辑结构

    2.1.逻辑单元

    2.2.如何认识CLB

    2.3.如何认识IOB

    3.verilog语法

    3.1.verilog HDL基本内容

    3.2.数据类型及变量、常量

    3.3.运算符

    3.4.赋值语句

    3.5.结构说明语句

    3.6.阻塞与非阻塞

    3.7.条件语句

    1.FPGA概述

    1.1.什么是FPGA

    FPGA,即现场可编程门阵列,它是PAL,GAL,CPLD等可编程基础上进一步发展的产物,它是作为专用集成电路(ASIC)领域中的一种半定制电路而出现的,既解决了定制电路的不足,又克服了原有可编程器件门电路有限的缺点。

    1.2.FPGA应用非常的广泛

    (1)医疗
    (2)仪器
    (3)通信
    (4)航天

    1.3.Artix-7介绍

    Xilinx Artix-7系列器件以28nm高性能低功耗,尤其适合于可满足航空电子和通信等领域的尺寸,重量,功耗和成本敏感市场的需求,提供了大量的可供开发者直接使用的IP核,是市场的主流。

    2.FPGA基本逻辑结构

    2.1.逻辑单元

    xilinx FPGA采用了阵列逻辑单元LCA(logic cell Array)概念,内部包括可配置逻辑模块CLB(configurable Logic Block),输入输出模块IOB(Input output block)和内部连线(interconnect)三个部分。

    2.2.如何认识CLB

    CLB是FPGA的结构核心,一个CLB包含多个slice,一个slice包含4个查找表和其他存储元件。

    2.3.如何认识IOB

    IOB可以和外界打交道, IO管脚可以配置多种输入输出标准。

    3.verilog语法

    3.1.verilog HDL基本内容

    (1)HDL硬件描述语言是对硬件电路进行行为描述、寄存器传输描述或者结构化描述的一种语言。
    (2)verilog HDL程序是由模块构成的。每个模块嵌套在module和endmodule声明语句中。
    (3)每个verilog HDL源文件中只有一个顶层模块,其他为子模块,可以每个模块写一个文件
    (4)每个模块要进行端口定义,并说明输入输出端口,然后对模块的功能进行行为逻辑描述
    (5)模块中的时序逻辑部分在always块的内部,在always块中自由对寄存器变量赋值
    (6)模块中对端口或其他wire型变量的赋值,必须在always块的外部使用assign语句,通常是将寄存器的值送出
    (7)程序书写格式自由,一行可以写几个语句,一个语句也可以分为多行写
    (8)除了endmodule语句、begin_end语句和fork_join语句外,每个语句和数据定义的最后必须有分号。
    (9)可以用//和//…对程序的任何部分作注解,加上必要的注释,可以增强程序的可读性和可维护性。

    3.2.数据类型及变量、常量

    (1)verilog HDL有两种常用的数据类型,x线网(Net)类型及变量类型
    (2)线网常用的就是wire类型,变量常用的就是reg类型
    (3)数据类型的逻辑值有四种分别为0,1,X(未知态),Z(高阻态)
    (4)数据类型及变量、常量-数的表达在这里插入图片描述
    (5)wire可以理解为连线,定义一个n位的wire变量:wire[n-1:0]变量名;如果多个则为:wire[n-1:0]变量1,变量2等
    (6)寄存器必须在时钟的驱动下(有效边沿)才能改变其内容,代码为:always @ (posedge clk_in)
    (7)如果用关键词parameter来定义一个标识符,代表一个常量,这个常量就被称为符号常量
    (8)存储器的定义方式:reg[msb:lsb] memory1 [upper1:lower1]
    例如:reg[3:0] mymem1 [63:0] //mymem1为64个4位寄存器的数组

    3.3.运算符

    (1)算术运算符
    在这里插入图片描述

    注意点:

    在进行整数的除法运算时,结构要略去小数部分,只取整数部分;而进行取模运算时(%,亦称为求余运算符)
    结果的符号位采用摸运算符中第一个操作数的符号
    例如-10%3,结果为-111%-3结果为2
    在进行算术运算的时候,如果摸一个操作数有不确定的值x,则整个结果也为不确定值x
    
    • 1
    • 2
    • 3
    • 4

    (2).逻辑运算符
    在这里插入图片描述
    注意点:

    逻辑运算只区分真假,而不管是什么数值。逻辑运算的输入4’ha1和4’h01是没有区别的,都是逻辑真,而0为逻辑假。一般来说,逻辑运算的结果要么为真(1)要么为假(0)。
    特例是如果有一个输入为未知X,那么结果也是X。
    例如,4’ha1&&4h01是14’ha1&&4h00是0。
    只有两个输入都是0的时候,逻辑或的结果才是0。
    对于逻辑非,当输入为非0值,输出就是0。
    逻辑运算最常用于条件判断语句。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    (3)按位运算符
    在这里插入图片描述
    注意点:

    通常使用按位运算符完成基本的与,或,非,异或及同或逻辑运算。使用这些位运算进行组合,很容易完成其他的逻辑运算。
    按位运算要求对两个操作数的相应位逐位进行运算
    例如0101&1100=01000101|1100=1101
    
    • 1
    • 2
    • 3

    (4)关系运算符
    在这里插入图片描述
    注意点:

    关于运算符和逻辑运算符一般用于条件判断语句
    关系运算结果位1位的逻辑值1(真)或0(假),但也可能是x(未知)。关系运算符根据关系运算的结果是真还是加,用于条件判断。
    关系运算时,若关系为真,则返回值为1,若声明的关系为假,则返回值为0;若某操作上为不定值x,则返回值也一定为x
    
    • 1
    • 2
    • 3

    (5)等式运算符
    在这里插入图片描述
    注意点:

    ==”和“!=”称作逻辑等式运算符,其结果由两个操作数的值决定,由于操作数可能是x和z,其结果可能为x。
    “===”和“!==”常用于case表达式的判别,又称为case等式运算符。其结果只能为01,如果操作数中存在x和z,那么操作数必须完全相同结果才为1,否则为0==”和“=”是完全不同的,“=”是对寄存器赋值使用的
    
    • 1
    • 2
    • 3

    (6)缩减运算符
    在这里插入图片描述
    (7)移位运算符
    在这里插入图片描述
    都用0填充移出的空位
    (8)条件运算符
    条件运算符位?,例如:assign out = sel ? in1 : in0;
    (9)拼接运算符
    拼接运算符位{},例如:{a,2{a,b}}
    (10)运算符的优先级
    在这里插入图片描述

    3.4.赋值语句

    (1)连续赋值语句assign

    用于wire型的变量赋值,是描述组合逻辑最常用的方法之一
    例如:assign c = a & b
    //a,b可以是wire型变量或寄存器变量,c必须是wire型变量或其他线网型变量
    
    • 1
    • 2
    • 3

    (2)过程赋值语句“=”和“<=”

    用于对reg型变量赋值
    在过程快中使用过程赋值语句
    
    • 1
    • 2

    3.5.结构说明语句

    (1)always语句

    always块包含了一个或一个以上的语句(如:过程赋值语句,条件语句和循环语句等),在运行的过程中,在时钟控制下被反复执行。
    时钟有效沿来了就执行
    在always块中被赋值的只能是寄存器reg变量
    always块的写法是always @ (敏感信号表达式)
    例如:
    always @ (clk)
    always @ (posedge clk)
    always @ (negedge clk)
    always @ (posegde clk or negedge rst_n)
    always @ (*) //该语句所在模块的任何输入信号变化了都触发
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    (2)initial语句
    initial语句用于对寄存器变量赋予初值
    例子:
    initial
    begin
    b = 0,c = 0;
    end

    3.6.阻塞与非阻塞

    阻塞的概念:在一个块语句中,如果多条阻塞赋值语句,在前面的赋值语句没有完成之前,后面的语句就不能被执行,就像被阻塞了一样,因此称为阻塞赋值方式
    非阻塞的概念:多条非阻塞赋值在过程块额你同时完成赋值操作,多条语句相当于同时执行

    阻塞的赋值方式,赋值符号为=,如b = a;
    非阻塞的赋值方式,赋值符号为<=,如b <= a;
    
    • 1
    • 2
    //阻塞的例子
    //时钟到来之后,b和c的结果都为1,所以阻塞就是顺序执行
    a = 1, b = 0,c= 0
    always @ (posedge clk)
    begin
    	b = a;
    	c = b;
    end
    
    //非阻塞的例子
    //时钟到来之后,b的结果为1,c的结果为0,所以非阻塞为并行执行
    a = 1, b = 0,c= 0
    always @ (posedge clk)
    begin
    	b <= a;
    	c <= b;
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3.7.条件语句

    条件语句一般用于always或者initial语句块的内部
    主要包含if else语句和case语句
    (1)if else语句
    用于判定所给条件是否满足,根据判断的结果,真或假决定执行给出的两种操作之一,if else语句有三种模式

    1.if 语句
    2.if else语句
    3.if else if语句 
    如果语句有多条组成,必须包含在begin和end之内
    三种形式的if语句后面都有表达式,一般为逻辑表达式和关系表达式,当表达式的值为1,按真处理,若为0、x、z,按假处理。
    else语句不能单独使用,它是if语句的一部分
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (2)case语句
    case语句是一种多分支选择语句,if只有两个分支可以选择,但是case可以直接处理多个分支语句,这样程序看起来更直观简洁。

    1.case(表达式)    <case分支项>  endcase
    2.casex(表达式)  <case分支项>  endcase
    3.casez(表达式)  <case分支项>  endcase
    case语句的所有表达式的值位宽必须相等
    在case语句中,分支表达式每一位的值都是确定的(或者为0,或者为1)
    在casez语句中,若分支表达式某些位的值位高阻值z,则不考虑对这些位的比较
    在casex语句中,若分支表达式某些拉的值位z或不定值x,则不考虑对这些位的比较
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3.8.循环语句

    在verilog中存在着多种循环语句,用来控制执行语句的执行次数
    这些语句c语言中很常见,也是必须的
    在FPGA的设计中,循环语句不一定能被综合
    多用于在仿真代码生成仿真激励信号
    (1)forever语句
    格式:forever begin语句块end
    forever常用于仿真代码中
    例如:

    //产生一个周期位20ns的波形
    timescale 1ns/1ps //时间单位是1ns,精度位1ps
    forever
    begin
    #10 clk = 1;
    #10 clk = 0;
    end
    always #10 clk = ~clk
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    (2)循环语句repeat
    repeat语句:连续执行n次的语句
    格式:repeat(表达式) begin语句块end
    其中"表达式"用于指定循环次数,可以是一个整数,变量或者数值表达式,如果是变量或者数值表达式,其数值自在第一次循环时得到计算,从而得到确定的循环次数
    repeat 语句也常用于仿真
    例如:

    repeat(10)
    begin
    	#10 clk = 0;
    	#10 clk = 1;
    end
    	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (3)循环语句while
    while语句:执行语句,直至某个条件不满足
    格式:while(表达式)begin 语句块end
    在每一次执行循环体之前,都需要对这个表达式是否成立进行判断,while语句在执行时,首先判断条件执行循环执行条件表达式是否位真,如果真,执行后面的语句块,然后再重新判断循环执行条件表达式是否为真,直至条件表达式不为真为止退出循环。
    在执行语句中,如果没有改变循环执行条件表达式的值的语句,循环就会称为死循环。
    例如:
    在这里插入图片描述
    (4)循环语句for
    for语句:三个表达式
    for(表达式1;表达式2;表达式3)
    例如:for(i = 0;i<=7; i++ )
    如果让系统能够综合,那么循环的次数一定是固定的。
    程序实例实现了统计输入的8位数据in中的1的个数,每个时钟上升沿统计一次

    4.实践部分

    4.1.多数表决器的工程完整步骤

    第一个工程-多数表决器
    组合逻辑电路:有什么样的输入,就有什么样的输出,数字电路的输出只依赖于当前输入值的组合,这样的电路称为组合逻辑电路。
    题目:假设有三个举重裁判,举重选手完成比赛后,当有多数裁判判定成功,则成功,否则失败。请设计此举重裁决电路
    分析:这个举重裁判电路实际上就是一个三输入的多数表决器
    首先书写真值表
    在这里插入图片描述
    根据真值表可以得到最小表达式 f =
    然后填写卡诺图
    在这里插入图片描述
    得到逻辑表达式为:
    在这里插入图片描述
    这里开始使用vivado进行这个代码的编写,仿真,综合,时序的编写以及生成比特流
    1.工程的建立
    (1)点击create Project
    在这里插入图片描述
    (2)点击next
    在这里插入图片描述
    (3)输入工程文件的名称pro_dsbjq,然后点击next

    在这里插入图片描述
    (4)继续点击next
    在这里插入图片描述
    (5)输入FPGA的芯片型号xc7a35tfag256-1,然后点击next
    在这里插入图片描述
    (6)最后点击finish,工程新建完成

    在这里插入图片描述
    2.RTL代码的书写
    (1)新建RTL代码文件,首先点击add source
    在这里插入图片描述
    2.选择add or create design source,然后点击next
    在这里插入图片描述
    (3)点击create file,然后输入file name 为:v_dsbjq,点击ok,最后点击finish,
    在这里插入图片描述
    (4)生成文件,点击OK即可在这里插入图片描述
    (5)文件生成了
    在这里插入图片描述
    (6)首先书写输入输出模块,然后书写判断语句

    module(
    input a,
    input b,
    input c,
    output f
    
    ); 
    
    assign f = a&b | b&c | a&c;
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    (7)然后打开open elaborated Design可以看到关于代码生成的电路图
    在这里插入图片描述
    3.代码的仿真
    (1)新建仿真文件
    在这里插入图片描述
    (2)输入仿真文件名sim_dsbjq

    在这里插入图片描述
    (3)书写仿真代码

    module
    //端口定义
    	reg a,b,c;
    	wire f;
    //模块调用
    v_dsbjq u1(
    	.a  (a),
    	.b  (b),
    	.c  (c),
    	.f  (f)
    );
    //赋初始值
    initial begin
    	a = 0;
    	b = 0;
    	c = 0;
    end
    //设置变化周期
    always #10 {a,b,c} = {a,b,c}+1;
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    (4)保存文件,运行功能前仿真
    在这里插入图片描述(5)波形分析是否正确
    在这里插入图片描述
    4.时序的书写
    (1)新建时序文件
    在这里插入图片描述
    (2)文件命名
    在这里插入图片描述
    (3)时序文件书写

    set_property PACKET_PIN F3 [get_ports a]
    set_property IOSTANDARD LVCOMS33 [get_ports a]
    set_property PACKET_PIN H3 [get_ports b]
    set_property IOSTANDARD LVCOMS33 [get_ports b]
    set_property PACKET_PIN N3 [get_ports c]
    set_property IOSTANDARD LVCOMS33 [get_ports c]
    
    set_property PACKET_PIN E3 [get_ports f]
    set_property IOSTANDARD LVCOMS33 [get_ports f]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    (4)综合synthesis
    在这里插入图片描述
    在这里插入图片描述
    5.生成比特流文件
    比特流的生成有两种模式
    第一种bit文件用于调试,
    第二种bin文件用于最终下载到实验板的flash芯片,每次上电后会对根据Flash中的内容对FPGA中的内容对FPGA进行配置。

    (1)生成比特流
    在这里插入图片描述
    (2)连上实验板子之后 open target
    在这里插入图片描述
    (3) 点击program device
    在这里插入图片描述
    (4)上板验证

    这中方式只是调试,断电之后就会消失

    (5)第二种写入FLASH的方法,首先点击add Configuration memory device
    在这里插入图片描述
    (6)然后输入25q32,选择3.3V
    在这里插入图片描述
    (7)在configuration file中加入bin文件,最后点击ok,就写入了flash,掉电程序不会消失
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    4.2 38译码器以及生成IP核

    1.38译码器
    译码器74*138是数字电路课程中重点的内容之一。使用verilog语言实现译码器就比较简单。
    在完成设计并下载到电路板后,学习将工程转化为可以被其他工程调用的IP核。
    在这里插入图片描述
    (1)新建p_74x138工程
    (2)添加设计文件
    (3)书写设计代码
    模块定义,模块输入输出声明,变量定义,always块,如果有输入输出变化,
    执行,如果使能有效,根据输入端的值进行译码,如果使能无效,always块结束,模块结束

    module v74x138(g1,g2a_l,g2b_l,a,y_l);
    input g1,g2a_l,g2b_l;
    input[2:0] a;
    output [7:0]y_l;
    reg [7:0] y_l=0;
    always @(g1 or g2a_l or g2b_l or a)
    begin
    if(g1 && ~g2a_l &&~g2b_l)
    case(a)
    	7:y_l = 8'b01111111;
    	6:y_l = 8'b10111111;
    	5:y_l = 8'b11011111;
    	4:y_l = 8'b11101111;
    	3:y_l = 8'b11110111;
    	2:y_l = 8'b11111011;
    	1:y_l = 8'b11111101;
    	0:y_l = 8'b11111110;
    	default:y_l = 8'b11111111;
    endcase
    else
    	y_l = 8'b11111111;
    end
    endmudule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    (4)得到rtl原理图
    在这里插入图片描述
    (5)仿真文件书写

    module sim1;
    reg g1;
    reg g2a_l;
    reg g2b_l;
    reg [2:0] a;
    wire [7:0] y_l;
    v74x138 uut (g1,g2a_l,g2b_l,a,y_l);
    initial begin
    	g1 = 0;
    	g2a_l = 0;
    	g2b_l = 0;
    	a = 0;
    	#100;
    	g1 = 1;
    	g2a_l = 0;
    	g2b_l = 0;
    end
    always #100 a = a+1;
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    (6)波形分析
    在这里插入图片描述
    (7)约束文件的书写

    set_property PACKET_PIN F3 [get_ports g1]
    set_property PACKET_PIN H4 [get_ports g2a_l]
    set_property PACKET_PIN N4 [get_ports g2b_l]
    set_property PACKET_PIN R2 [get_ports {a[2]}]
    set_property PACKET_PIN R3 [get_ports {a[1]}]
    set_property PACKET_PIN P4 [get_ports {a[0]}]
    set_property PACKET_PIN R8 [get_ports {y_l[1]}]
    set_property PACKET_PIN R7 [get_ports {y_l[2]}]
    set_property PACKET_PIN T5 [get_ports {y_l[3]}]
    set_property PACKET_PIN N6 [get_ports {y_l[4]}]
    set_property PACKET_PIN T4 [get_ports {y_l[5]}]
    set_property PACKET_PIN T3 [get_ports {y_l[6]}]
    set_property PACKET_PIN T2 [get_ports {y_l[7]}]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    (8)上板验证

    2.生成IP核
    (1)首先点击create and packet new IP
    在这里插入图片描述(2)点击next
    在这里插入图片描述

    (3)继续点击next
    在这里插入图片描述
    (4)还是next
    在这里插入图片描述
    (5)点击finish
    在这里插入图片描述
    (6)填写供应商的名字和公司
    在这里插入图片描述
    (7)由于有所改动,所以重新生成一下ip
    在这里插入图片描述
    总体来看非常的简单,一直下一步就完事了,接下来讲解调用IP核
    3.调用IP核
    数字电路中译码器三输入的译码器可以实现任意三输入的逻辑函数,所以三变量的多数表决器也可以用译码器实现。这里使用译码器的IP核来实现多数表决器。
    在这里插入图片描述
    (1)点击setting,找到IP下的Repository,点击+号,然后找到目标,加入IP。
    在这里插入图片描述
    在这里插入图片描述
    (2)双击y74x138v1_0
    在这里插入图片描述
    (3)点击OK
    在这里插入图片描述
    (4)点击generate
    在这里插入图片描述
    (5)点击74x138_0,然后点击ok
    在这里插入图片描述
    (6)调用代码

    在这里插入图片描述

    (7)综合代码

    (8)波形验证

    写到这里,下午的效率我也是吐了,和上午的效率完全无法比较,

  • 相关阅读:
    Golang中的GMP调度模型
    Centos配置邮件发送
    SpringCloudAlibaba-Nacos集群
    前端面试,备考第 14 天 - 指向问题:this/call/apply/bind
    Linux下如何操作寄存器
    javaee springMVC model的使用
    python项目requirements.txt项目用到哪些库哪些版本
    [模型部署]:TVM模型部署实战
    用python编写远程控制程序
    【JavaEE进阶序列 | 从小白到工程师】JavaEE中的抽象类和抽象方法
  • 原文地址:https://blog.csdn.net/qq_44943193/article/details/126034751