这里对于FPGA的学习-B站的FPGA入门视频做了一些总结。
https://www.bilibili.com/video/BV1J7411a7sW?p=9&spm_id_from=pageDriver&vd_source=96ad85c58bc3572b6686cdbf3a7f8cdb
总结的章节包括:
FPGA,即现场可编程门阵列,它是PAL,GAL,CPLD等可编程基础上进一步发展的产物,它是作为专用集成电路(ASIC)领域中的一种半定制电路而出现的,既解决了定制电路的不足,又克服了原有可编程器件门电路有限的缺点。
(1)医疗
(2)仪器
(3)通信
(4)航天
Xilinx Artix-7系列器件以28nm高性能低功耗,尤其适合于可满足航空电子和通信等领域的尺寸,重量,功耗和成本敏感市场的需求,提供了大量的可供开发者直接使用的IP核,是市场的主流。
xilinx FPGA采用了阵列逻辑单元LCA(logic cell Array)概念,内部包括可配置逻辑模块CLB(configurable Logic Block),输入输出模块IOB(Input output block)和内部连线(interconnect)三个部分。
CLB是FPGA的结构核心,一个CLB包含多个slice,一个slice包含4个查找表和其他存储元件。
IOB可以和外界打交道, IO管脚可以配置多种输入输出标准。
(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)可以用/…/和//…对程序的任何部分作注解,加上必要的注释,可以增强程序的可读性和可维护性。
(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位寄存器的数组
(1)算术运算符
注意点:
在进行整数的除法运算时,结构要略去小数部分,只取整数部分;而进行取模运算时(%,亦称为求余运算符)
结果的符号位采用摸运算符中第一个操作数的符号
例如-10%3,结果为-1,11%-3结果为2
在进行算术运算的时候,如果摸一个操作数有不确定的值x,则整个结果也为不确定值x
(2).逻辑运算符
注意点:
逻辑运算只区分真假,而不管是什么数值。逻辑运算的输入4’ha1和4’h01是没有区别的,都是逻辑真,而0为逻辑假。一般来说,逻辑运算的结果要么为真(1)要么为假(0)。
特例是如果有一个输入为未知X,那么结果也是X。
例如,4’ha1&&4h01是1,
4’ha1&&4h00是0。
只有两个输入都是0的时候,逻辑或的结果才是0。
对于逻辑非,当输入为非0值,输出就是0。
逻辑运算最常用于条件判断语句。
(3)按位运算符
注意点:
通常使用按位运算符完成基本的与,或,非,异或及同或逻辑运算。使用这些位运算进行组合,很容易完成其他的逻辑运算。
按位运算要求对两个操作数的相应位逐位进行运算
例如0101&1100=0100,0101|1100=1101
(4)关系运算符
注意点:
关于运算符和逻辑运算符一般用于条件判断语句
关系运算结果位1位的逻辑值1(真)或0(假),但也可能是x(未知)。关系运算符根据关系运算的结果是真还是加,用于条件判断。
关系运算时,若关系为真,则返回值为1,若声明的关系为假,则返回值为0;若某操作上为不定值x,则返回值也一定为x
(5)等式运算符
注意点:
“==”和“!=”称作逻辑等式运算符,其结果由两个操作数的值决定,由于操作数可能是x和z,其结果可能为x。
“===”和“!==”常用于case表达式的判别,又称为case等式运算符。其结果只能为0和1,如果操作数中存在x和z,那么操作数必须完全相同结果才为1,否则为0
“==”和“=”是完全不同的,“=”是对寄存器赋值使用的
(6)缩减运算符
(7)移位运算符
都用0填充移出的空位
(8)条件运算符
条件运算符位?,例如:assign out = sel ? in1 : in0;
(9)拼接运算符
拼接运算符位{},例如:{a,2{a,b}}
(10)运算符的优先级
(1)连续赋值语句assign
用于wire型的变量赋值,是描述组合逻辑最常用的方法之一
例如:assign c = a & b
//a,b可以是wire型变量或寄存器变量,c必须是wire型变量或其他线网型变量
(2)过程赋值语句“=”和“<=”
用于对reg型变量赋值
在过程快中使用过程赋值语句
(1)always语句
always块包含了一个或一个以上的语句(如:过程赋值语句,条件语句和循环语句等),在运行的过程中,在时钟控制下被反复执行。
时钟有效沿来了就执行
在always块中被赋值的只能是寄存器reg变量
always块的写法是always @ (敏感信号表达式)
例如:
always @ (clk)
always @ (posedge clk)
always @ (negedge clk)
always @ (posegde clk or negedge rst_n)
always @ (*) //该语句所在模块的任何输入信号变化了都触发
(2)initial语句
initial语句用于对寄存器变量赋予初值
例子:
initial
begin
b = 0,c = 0;
end
阻塞的概念:在一个块语句中,如果多条阻塞赋值语句,在前面的赋值语句没有完成之前,后面的语句就不能被执行,就像被阻塞了一样,因此称为阻塞赋值方式
非阻塞的概念:多条非阻塞赋值在过程块额你同时完成赋值操作,多条语句相当于同时执行
阻塞的赋值方式,赋值符号为=,如b = a;
非阻塞的赋值方式,赋值符号为<=,如b <= a;
//阻塞的例子
//时钟到来之后,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
条件语句一般用于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语句的一部分
(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,则不考虑对这些位的比较
在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
(2)循环语句repeat
repeat语句:连续执行n次的语句
格式:repeat(表达式) begin语句块end
其中"表达式"用于指定循环次数,可以是一个整数,变量或者数值表达式,如果是变量或者数值表达式,其数值自在第一次循环时得到计算,从而得到确定的循环次数
repeat 语句也常用于仿真
例如:
repeat(10)
begin
#10 clk = 0;
#10 clk = 1;
end
(3)循环语句while
while语句:执行语句,直至某个条件不满足
格式:while(表达式)begin 语句块end
在每一次执行循环体之前,都需要对这个表达式是否成立进行判断,while语句在执行时,首先判断条件执行循环执行条件表达式是否位真,如果真,执行后面的语句块,然后再重新判断循环执行条件表达式是否为真,直至条件表达式不为真为止退出循环。
在执行语句中,如果没有改变循环执行条件表达式的值的语句,循环就会称为死循环。
例如:
(4)循环语句for
for语句:三个表达式
for(表达式1;表达式2;表达式3)
例如:for(i = 0;i<=7; i++ )
如果让系统能够综合,那么循环的次数一定是固定的。
程序实例实现了统计输入的8位数据in中的1的个数,每个时钟上升沿统计一次
第一个工程-多数表决器
组合逻辑电路:有什么样的输入,就有什么样的输出,数字电路的输出只依赖于当前输入值的组合,这样的电路称为组合逻辑电路。
题目:假设有三个举重裁判,举重选手完成比赛后,当有多数裁判判定成功,则成功,否则失败。请设计此举重裁决电路
分析:这个举重裁判电路实际上就是一个三输入的多数表决器
首先书写真值表
根据真值表可以得到最小表达式
然后填写卡诺图
得到逻辑表达式为:
这里开始使用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
(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
(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]
(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,掉电程序不会消失
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
(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
(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]}]
(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)波形验证
略
写到这里,下午的效率我也是吐了,和上午的效率完全无法比较,