当前位置: 首页 > news >正文

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

文章目录

  • 一、整个工程的流程
  • 二、基于Vivado的FPGA开发流程实践(二选一多路器)
    • 什么是二选一多路器
    • 用verilog语言,Vivado软件进行该电路实现
      • 1、设计输入:Design Sources中的代码
      • 2、分析和综合:分析设计输入中是否有错误
      • 3、功能仿真,Simulation Sources中的仿真实现代码(Test_Bench)
      • 4、布局布线
      • 5、时序仿真
      • 6、板级调试
        • (1)IO引脚分配
        • (2)程序下载
  • 三、3-8译码器的实现
    • 什么是3-8译码器
    • 1、设计输入
      • 用到的语法
      • 整个3-8译码器代码为下
    • 2、分析综合
    • 3、仿真
    • 4、时序仿真
    • 5、IO引脚分配
    • 6、生成代码,板级调试
    • 课后题,写4-16译码器代码
      • 1、module设计输入
      • 2、功能仿真
      • 3、布局布线
      • 4、 时序仿真
      • 5、IO引脚分配
      • 6、生成代码,板级调试
  • 四、时序逻辑计数器设计
    • 什么是D触发器
    • 什么是计数器
    • 用Verilog代码实现led闪烁
      • 1、设计输入:module编写
      • 2、分析综合
      • 3、仿真模拟
      • 4、 IO设定
      • 5、生成程序、板级调试

相关资源网站(小梅哥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. 定义模块
module xxx(
......
)
endmodule
//定义一个模块
  1. 定义输入输出
input a;
output out;
  1. 赋值语句
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够用

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

写一个可以测试之前定义的module mux2的功能的仿真代码
在这里插入图片描述

reg s_a; //定义测试平台的输入信号,可接0和1逻辑输入
.a(s_a); //.代表测试端子,a代表module中a端口,(s_a)代表测试平台的reg端口
//这句话的意思是,将测试平台的(s_a)端子与module的a端子通过.来相接
wire out; //定义平台的输出信号,可根据分析输入信号和module来确认这个输出信号
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. 描述多位格式的常用限定符号
    在这里插入图片描述
    这两个表达方式是一样的
    在这里插入图片描述

b  二进制        3‘b101         8'b0000_1010
o  八进制
d  十进制        3'd5           8'd10
h  十六进制                     8'ha
  1. case() endcase
    case括号中,为满足操作的条件
    在满足条件下进行操作,如:\
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代码:
在这里插入图片描述
在这里插入图片描述
这个图试后续运行后发现代码无法实现功能反回来查找问题,各种语句使用的都是“<=”,否则会有问题。
<= :非阻塞赋值
= : 阻塞赋值

阻塞赋值  =
阻塞赋值是顺序执行的。在一个begin - end块中,多条阻塞赋值语句按照顺序依次执行,下一条语句会等待当前阻塞赋值语句执行完成后才开始执行。例如:
always @(posedge clk) begina = b;c = a;
end
当clk上升沿到来时,先执行a = b,将b的值赋给a,然后执行c = a,此时a已经更新为b的值,所以c得到的是更新后的a(也就是b的值)。应用场景:
常用于组合逻辑电路建模,特别是在需要按照特定顺序进行计算的组合逻辑中。例如,在实现一个简单的算术逻辑单元(ALU)的组合逻辑部分时,按照运算优先级进行计算就可以使用阻塞赋值。
还用于initial块中初始化变量,因为initial块主要是顺序执行的初始化代码,例如:
initial beginreg_a = 0;reg_b = 1;
end对仿真的影响:
在仿真过程中,由于阻塞赋值是顺序执行的,所以赋值语句的执行顺序会直接影响变量的值和仿真结果。如果赋值顺序不当,可能会导致不符合预期的结果。
例如,如果在组合逻辑中有相互依赖的阻塞赋值,可能会出现竞争冒险(race condition)现象,导致输出出现毛刺(glitch)。
非阻塞赋值  <=
非阻塞赋值是并发执行的。在一个always块中,所有非阻塞赋值语句在同一时刻开始计算表达式的值,但赋值操作会在当前时间步(time step)结束时同时更新目标变量。例如:
always @(posedge clk) begina <= b;c <= a;
end
当clk上升沿到来时,a <= b和c <= a这两个赋值语句会同时开始计算右侧表达式的值。此时计算c <= a时,a的值是更新前的值,等到这个always块执行结束后,a和c才会同时更新。所以c得到的是a的旧值。应用场景:
主要用于对时序逻辑电路进行建模,特别是在多个寄存器之间需要传递数据,并且这些寄存器的更新应该在时钟沿触发后同时进行的情况。例如,在一个简单的移位寄存器设计中:
always @(posedge clk) beginreg1 <= in_data;reg2 <= reg1;reg3 <= reg2;
end对仿真的影响:
非阻塞赋值在仿真时会在每个时间步结束时更新所有被赋值的变量,这样可以更好地模拟实际硬件中的寄存器等时序元件的行为。
有助于避免在时序逻辑建模中因为赋值顺序不当而产生的错误,但如果在组合逻辑中错误地使用非阻塞赋值,也可能会导致意想不到的结果,因为组合逻辑通常期望是立即更新输出的。

使用 = ,直接结果是后续仿真的时候高电平只持续了1个周期,即20ns就又变为低电平
使用<=,则可以实现500.00002ms一反转
在这里插入图片描述

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

用到的语法

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

2、分析综合

在这里插入图片描述

3、仿真模拟

在这里插入图片描述
最终在module为以下情况下,进行仿真
在这里插入图片描述
得出下图:即高低电平切换时间为500ms
在这里插入图片描述

4、 IO设定

按键
在这里插入图片描述
LED灯
在这里插入图片描述
时钟引脚为Y18
在这里插入图片描述

5、生成程序、板级调试

2024.12.23


http://www.mrgr.cn/news/81162.html

相关文章:

  • STM32高级 以太网通讯案例1:网络搭建(register代码)
  • 【动手学轨迹预测】2.3 场景表征方法
  • LLM客户端开源工具cherry studio
  • redis数据类型:list
  • locust性能测试指南
  • uniapp 微信小程序 页面部分截图实现
  • YoloV8改进策略:Head改进|DynamicHead,利用注意力机制统一目标检测头部|即插即用
  • sqlite 自定以脚本解释器
  • 时空信息平台架构搭建:基于netty封装TCP通讯模块(IdleStateHandler网络连接监测,处理假死)
  • UE5 渲染管线 学习笔记
  • 【Rust自学】6.1. 定义枚举
  • 设计模式七大原则
  • idea2024创建JavaWeb项目以及配置Tomcat详解
  • 达梦数据库-单机部署
  • Nvidia环境配置again—cuda、cudnn、TensorRT
  • Linux运维常见命令
  • js 深度克隆
  • (高可用版本)Kubeadm+Containerd+keepalived部署高可用k8s(v1.28.2)集群
  • VIVO Android面试题及参考答案
  • dvwa靶场
  • 《近世代数基础 第二版》思维导图
  • 捋一捋相关性运算,以及DTD和NLP中的应用
  • 汽车IVI中控开发入门及进阶(47):CarPlay开发
  • Linux下Java通过JNI调用C++
  • 004最长回文子串
  • 麒麟V10,arm64,离线安装docker和docker-compose