FPGA学习(基于小梅哥Xilinx FPGA)学习笔记

文章目录

相关资源网站(小梅哥FPGA)

https://www.corecourse.cn/forum.php?mod=viewthread\&tid=27978

https://www.corecourse.cn/forum.php?mod=viewthread\&tid=28730

本篇文章使用的开发板为:
小梅哥 Xilinx FPGA
型号:XC7A35T
芯片型号:XC7A35TFGG484-2

以下所有文章内容,均来自小梅哥FPGA教学视频,这个文章只是针对每个教学视频的个人理解总结。

一、整个工程的流程

写一套硬件描述语言,能够在指定的硬件平台上实现相应的功能

  1. 设计定义(让LED一秒闪烁一次)
  2. 设计输入(编写逻辑(使用Verilog代码描述逻辑),画逻辑图,使用IP盒(即提供的成品功能器件))
  3. 综合工具(由专业的EDA软件进行,Quartus、Vivado、ISE),对所写的逻辑内容进行分析,并得到逻辑门级别的电路内容。(如if else就是一个二选一多路器)
  4. 功能仿真(使用专门的仿真工具进行仿真,验证设计的逻辑功能能够实现。对于数字电路来说 ,仿真时基本接近于真实情况的,是可信的)
  5. 布局布线(走线带来延迟,延迟越长,主频越低)(在指定器件上将设计的逻辑电路实现)
  6. 分析性能(1、时序仿真(非常耗费时间),仿真软件进行观察;2、静态时序分析(平时用这个))
  7. 下载到目标板运行,查看运行结果。(板级调试)(使用ILA(嵌入式逻辑分析仪)(Vivado))
  8. 让设计的逻辑在目标板上正常工作(功能正常,性能稳定)

总结

  1. 设计定义
  2. 设计输入
  3. 分析综合(EDA、Vivado、Quartus)
  4. 功能仿真(Modelsim)
  5. 布局布线(Vivado、Quartus)
  6. 分析性能(时序仿真Modelsim、静态时序分析Vivado、Quartus)
  7. 板级调试
  8. OK
    2024.12.22

二、基于Vivado的FPGA开发流程实践(二选一多路器)

打开Vivado并创建工程mux2后,Vivado界面上左边流程

即该软件就是按照开发流程进行运行的

什么是二选一多路器

当SEL=1时,out=a

当SEL=0时,out=b

用verilog语言,Vivado软件进行该电路实现

下图要注意符号的运用

1、设计输入:Design Sources中的代码

用到的语法(Verilog语言)

  1. 定义模块
c 复制代码
module xxx(
......
)
endmodule
//定义一个模块
  1. 定义输入输出
c 复制代码
input a;
output out;
  1. 赋值语句
c 复制代码
assign out = (sel==1)?a:b;
//在sel=1的情况下,将a的值赋予out,否则将b的值赋予out
assign out = ~a;
//将a取反的值赋予out

2、分析和综合:分析设计输入中是否有错误

分析综合运行后,看message,其中没有报错那么这一步就完成了,接下来就进行仿真验证

3、功能仿真,Simulation Sources中的仿真实现代码(Test_Bench)

在仿真平台中,通过代码编写,搭建一个仿真平台,取验证之前编写的module是否OK

我们个人一般用不到ps级别的延时,ns够用

c 复制代码
#1 //延时1ns
#2 //延时2ns
#1.001 //延时1.001ns,这是在配置为1ns/1ps情况下是可以实现的

写一个可以测试之前定义的module mux2的功能的仿真代码

c 复制代码
reg s_a; //定义测试平台的输入信号,可接0和1逻辑输入
c 复制代码
.a(s_a); //.代表测试端子,a代表module中a端口,(s_a)代表测试平台的reg端口
//这句话的意思是,将测试平台的(s_a)端子与module的a端子通过.来相接
c 复制代码
wire out; //定义平台的输出信号,可根据分析输入信号和module来确认这个输出信号
c 复制代码
initial begin
......
end
//测试平台的操作

跑仿真后出现这个界面,这个就是仿真的时序图,

第一次跑不全,再跑一次

此时可以看着时序图对out的信号进行对比,看是否是我们需求的信号输出结果。

仿真这一步挺重要的,建议需要掌握

4、布局布线


点击红框中的符号可以看到目前的编译状态

5、时序仿真


时序仿真电路中可以看到真实的电路中的信号延迟情况,

out都滞后于输入信号的变化,根据时序仿真,可以看出延迟情况,来判断 这个延迟我们能否接受

6、板级调试

(1)IO引脚分配






根据上图进行引脚分配

分配完成后,在引脚分配界面进行ctrl+s进行保存,保存名称和项目名称可以一样(不强求,也可以不一样)

(2)程序下载

点击后就可以进行创建,

创建完成后可以进行程序下载


这样就下载完成了,之后就可以进行板级调试。

2021.12.22

三、3-8译码器的实现

什么是3-8译码器

1、设计输入

3-8译码器

创建module,创建3-8译码器的端口

端口创建完成后,定义端口的输入输出状态

输入输出状态定义完成后,进行端口之间的逻辑编写

用到的语法

  1. always

  2. 位拼接

    d是一个4位数据,通过assign将 a, 1bit常量值为0,b , c这四个数拼在一块赋值给d

  3. 描述多位格式的常用限定符号

    这两个表达方式是一样的

c 复制代码
b  二进制        3'b101         8'b0000_1010
o  八进制
d  十进制        3'd5           8'd10
h  十六进制                     8'ha
  1. case() endcase
    case括号中,为满足操作的条件
    在满足条件下进行操作,如:\
c 复制代码
3'b000 : out = 8'b0000_0001; 

具体解释为拼接后的{a,b,c}在满足3位bit值是000的情况下,将8bit的0000_0001赋值给out

整个3-8译码器代码为下

2、分析综合

分析综合的作用,检查设计输入的语法有无问题

分析之后查看reports,有错误则报红

3、仿真

创建一个测试平台,命名规则一般为(文件名_tb),tb代表test bench

测试平台的代码具体的流程为

  1. 定义测试平台的时间尺度
  2. 定义一个测试平台
  3. 定义测试平台的端口,标注好reg型(输入)和wire型(输出)
  4. 将模块放置到测试平台上
  5. 将模块中的端口与测试平台的端口互相连接
  6. 定义测试平台的测试动作(给各信号端口激励信号并延时)
  7. end

    所有代码完成后,进行仿真

    仿真第一次跑会根据仿真设置中的默认跑1000ns来跑,所以第一次的仿真都是1000ns的时间段中的动作
    这里我们可以不用管,直接再次跑,在动作结尾加上 $stop; 即可跑到这里自动停止

4、时序仿真

跳过,这个项目中只进行了模拟仿真,并没有进行时仿真

原因是项目比较简单,无进行必要。但也可以进行。这个步骤有无都无所谓

5、IO引脚分配

打开综合类工程

必须打开后才能看到IO planning这个选项

IO设置中首先将I/O Std电压设定为3.3(LVCMOS33),只针对于目前手中的这个开发板进行的设定

其次根据引脚对应表,将拨码开关引脚进行设定

LED灯对应的引脚(高电平点亮)

根据表进行设定

设定完成后进行ctrl+s保存

6、生成代码,板级调试

因为之前没有进行布局布线,即

在生成BitStream时候会进行检查,没布局布线的话这一步会自动进行,所以这一步在之前省略了

点击之后,等待完成。

下一步连接硬件板卡进行程序下载

之后进行板级调试就OK

三个拨码开关,设定为a,b,c
8个LED灯代表out 0-7
拨码开关不同状态代表不同输出,led显示表示输出

课后题,写4-16译码器代码

1、module设计输入


代码完成后进行分析综合,即检查下代码有无错误

2、功能仿真


代码完成后进行分析综合,即检查下代码有无错误

3、布局布线

4、 时序仿真

5、IO引脚分配

6、生成代码,板级调试

2024.12.23

四、时序逻辑计数器设计

什么是D触发器

CK上升沿的时候,将D端口的信号输出给Q端口

即D触发器有存储特性,只在CK端口上升沿变化,其余时间一概不管,即Q端口可以存储D的电平状态

什么是计数器

counter = counter+1

目标,设计1s频率闪烁的LED灯(亮灭各500ms)

目前板子的时钟是50MHz,那么执行每步操作时候为20ns

则500ms需要计数500ms/20ns=25000000

用Verilog代码实现led闪烁

1、设计输入:module编写

  1. 确认module端口,需要有时钟信号Clk,复位信号Reset_n(低电平复位),Led控制信号
  2. 确认信号的类型
    时钟信号为输入 input
    复位信号为输入 input
    led信号为输出 output
    counter信号为内部计数,多位D触发器,具体多少位,通过以下计算

    即需要25位D触发器,设定为reg类型的counter:reg [24:0]counter;
    即最终的端口定义是这样的

    通过这个定义可以看出,内部端口也是需要进行定义的,而且内部端口不再试input和output类型的端口了,这里则使用的试reg寄存器类型来表示。
    同时对需要进行复杂操作的端口也要进行reg的定义,如之后的代码需要让Led端口自行取反,即Led=!Led;
  3. 端口的逻辑操作,两种写法:1:综合在一块写;2:分开写
    综合在一块写(不推荐)

    分开写(推荐,构成的电路会更简便)

即最终的module代码:

这个图试后续运行后发现代码无法实现功能反回来查找问题,各种语句使用的都是"<=",否则会有问题。
<= :非阻塞赋值
= : 阻塞赋值

c 复制代码
阻塞赋值  =
阻塞赋值是顺序执行的。在一个begin - end块中,多条阻塞赋值语句按照顺序依次执行,下一条语句会等待当前阻塞赋值语句执行完成后才开始执行。例如:
always @(posedge clk) begin
    a = b;
    c = a;
end
当clk上升沿到来时,先执行a = b,将b的值赋给a,然后执行c = a,此时a已经更新为b的值,所以c得到的是更新后的a(也就是b的值)。

应用场景:
常用于组合逻辑电路建模,特别是在需要按照特定顺序进行计算的组合逻辑中。例如,在实现一个简单的算术逻辑单元(ALU)的组合逻辑部分时,按照运算优先级进行计算就可以使用阻塞赋值。
还用于initial块中初始化变量,因为initial块主要是顺序执行的初始化代码,例如:
initial begin
    reg_a = 0;
    reg_b = 1;
end

对仿真的影响:
在仿真过程中,由于阻塞赋值是顺序执行的,所以赋值语句的执行顺序会直接影响变量的值和仿真结果。如果赋值顺序不当,可能会导致不符合预期的结果。
例如,如果在组合逻辑中有相互依赖的阻塞赋值,可能会出现竞争冒险(race condition)现象,导致输出出现毛刺(glitch)。
c 复制代码
非阻塞赋值  <=
非阻塞赋值是并发执行的。在一个always块中,所有非阻塞赋值语句在同一时刻开始计算表达式的值,但赋值操作会在当前时间步(time step)结束时同时更新目标变量。例如:
always @(posedge clk) begin
    a <= b;
    c <= a;
end
当clk上升沿到来时,a <= b和c <= a这两个赋值语句会同时开始计算右侧表达式的值。此时计算c <= a时,a的值是更新前的值,等到这个always块执行结束后,a和c才会同时更新。所以c得到的是a的旧值。

应用场景:
主要用于对时序逻辑电路进行建模,特别是在多个寄存器之间需要传递数据,并且这些寄存器的更新应该在时钟沿触发后同时进行的情况。例如,在一个简单的移位寄存器设计中:
always @(posedge clk) begin
    reg1 <= in_data;
    reg2 <= reg1;
    reg3 <= reg2;
end

对仿真的影响:
非阻塞赋值在仿真时会在每个时间步结束时更新所有被赋值的变量,这样可以更好地模拟实际硬件中的寄存器等时序元件的行为。
有助于避免在时序逻辑建模中因为赋值顺序不当而产生的错误,但如果在组合逻辑中错误地使用非阻塞赋值,也可能会导致意想不到的结果,因为组合逻辑通常期望是立即更新输出的。

使用 = ,直接结果是后续仿真的时候高电平只持续了1个周期,即20ns就又变为低电平

使用<=,则可以实现500.00002ms一反转

为什么是500.000002ms,因为计数是从0开始,计数到25000000时候多计数了一个周期,即20ns,这里需要把计数改为24999999就OK

用到的语法

c 复制代码
 always@(posedge Clk or negedge Reset_n)//当时钟(Clk)的上升沿或者复位(Reset_n)的下降沿时候,这个代码块工作,其他时候不工作。
c 复制代码
counter <= 0;//counter清零,<=是非阻塞赋值的意思
c 复制代码
counter=counter + 1'd1;//counter自加1

2、分析综合

3、仿真模拟

最终在module为以下情况下,进行仿真

得出下图:即高低电平切换时间为500ms

4、 IO设定

按键

LED灯

时钟引脚为Y18

5、生成程序、板级调试

2024.12.23

相关推荐
虾球xz16 分钟前
游戏引擎学习第55天
学习·游戏引擎
oneouto33 分钟前
selenium学习笔记(二)
笔记·学习·selenium
sealaugh3238 分钟前
aws(学习笔记第十九课) 使用ECS和Fargate进行容器开发
笔记·学习·aws
炭烤玛卡巴卡1 小时前
学习postman工具使用
学习·测试工具·postman
thesky1234561 小时前
活着就好20241224
学习·算法
蜗牛hb2 小时前
VMware Workstation虚拟机网络模式
开发语言·学习·php
汤姆和杰瑞在瑞士吃糯米粑粑2 小时前
【C++学习篇】AVL树
开发语言·c++·学习
虾球xz2 小时前
游戏引擎学习第58天
学习·游戏引擎
LuH11242 小时前
【论文阅读笔记】Scalable, Detailed and Mask-Free Universal Photometric Stereo
论文阅读·笔记
奶香臭豆腐3 小时前
C++ —— 模板类具体化
开发语言·c++·学习