2025.9.13知识笔记

Sep 13 2025 每日笔记

1、上课知识

今天是AMD的工程师来深大进行FPGA创新短课讲课的第一天,学到了很多东西
LUT(查找表)全称为look up table
FIFO为frist in first out先进先出

上课的时候讲了怎么设计一个4位加法器:

1
2
3
4
5
6
7
8
9
10
11
12
13
module addrer(
input [3:0] a,
input [3:0] b,
output carry,
output [3:0] sum
);

wire [4:0] total;
assign total=a+b;
assign sum=total[3:0];
assign carry=total[4];

endmodule

2、串口通信

2.1 UART基础知识

UART为通用异步收发传输器
UART 通信只需要两根线(TX 发送数据、RX 接收数据),不需要额外的时钟线(CLK)。这减少了硬件复杂度和成本。
​依赖协议​​:双方依靠​​预先约定好的波特率(Baud Rate)​​ 来同步数据。接收方会在检测到起始位后,在预期的中间点采样数据,以此保证读取的正确性。
与之相对的是 ​​“同步”通信​​(如 SPI、I2C),它们需要一根额外的时钟线来告诉对方何时读取数据。
同步通信​​的核心特点是:通信双方​​共享一个统一的时钟信号(CLK)​​。发送方根据这个时钟来发送数据,接收方也根据这个时钟来采样数据,双方步调高度一致。

一帧数据包含什么:
1、起始位​​ ​1位​​
总是逻辑 ​​0​​(低电平),用于通知接收方“数据开始了”,是帧同步的起点。
2、​数据位​​ ​5-9位​​
​核心的有效数据​​。最常用的是 ​​8位​​(一个字节),与计算机系统的基本数据单位一致。

3、​奇偶校验位​​ ​​0或1位​​
​可选​​。用于简单的错误检测(检错,但不能纠错)。如果不用,这一位就不存在。

4、停止位​​ ​1、1.5或2位​​
总是逻辑 ​​1​​(高电平),用于表示“数据结束”。最常用的是 ​​1位​​。

再来说一下奇偶校验是什么:
奇偶校验是一种最简单的​​单比特错误检测​​方法,通过添加1个校验位,使数据中“1”的个数满足奇/偶性。

波特率(Baud):是指从一设备发到另一设备的波特率,即每秒钟可以通信的数据比特个数。典型的波特率有 300, 1200, 2400, 9600, 19200, 115200 等。一般通信两端设备都要设为相同的波特率,但有些设备也可设置为自动检测波特率。

最常用的配置是18N1(即一个起始位、八个数据位、无奇偶校验、一个停止位),

3、高云初使用

初使用设计了一个闪烁的LED灯
在 ​​50MHz​​ 的时钟频率下,FPGA 中要实现 ​​1秒​​ 的精确定时,需要一个位宽为 ​​26位​​(即 reg [25:0])的计数器。该计数器需要从 ​​0​​ 开始计数,直到达到终值 ​​49,999,999​​(即共计 ​​5千万​​ 个时钟周期),此时刚好耗时1秒,之后计数器归零并重新开始。简而言之,​​50MHz的时钟每秒钟会产生5千万个周期,因此计满5千万次就是1秒​​。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
module led_flash(
input clk,
input rst,
output reg led
);

reg [25:0] counter;

always@(posedge clk or negedge rst) begin
if(!rst)
counter<=0;
else if(counter==26'd49_999_999)
counter<=0;
else
counter<=counter+1'b1;
end


always@(posedge clk or negedge rst) begin
if(!rst)
led<=0;
else if(counter==26'd49_999_999)
led<=~led;
else
led<=led;
end

endmodule

测试文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
`timescale 1ns/1ns

module led_flash_tb;

reg rst;
reg clk;
wire led;

initial clk=1; //小梅哥的常规写法,时钟测试的写法
always #10 clk=!clk;

initial begin
rst=0;
#201;
rst=1;
#1000000000;
end

led_flash led_flash_inst(
.rst(rst),
.clk(clk),
.led(led)
);

endmodule

4、FPGA设计流程

FPGA 设计核心流程(精简版)
1.PROJECT MANAGER 工程管理 建仓库、备料:创建项目,添加代码文件、设置约束(引脚、时钟)。

2.IP INTEGRATOR IP集成 乐高拼装:用现成的功能模块(IP核)快速搭建系统。

3.SIMULATION 功能仿真 电脑彩排:在烧录前,用软件模拟运行代码,检查逻辑对不对。

4.SYNTHESIS 逻辑综合 翻译蓝图:把代码(Verilog/VHDL)“编译”成由基本电路单元组成的电路图(网表)。生成电路网表

5.IMPLEMENTATION 布局布线 芯片施工:把电路图映射到真实的FPGA芯片上,决定每个元件的位置并连线。

6.PROGRAM AND DEBUG 编程调试 烧录验收:生成最终文件(比特流)并下载到芯片中运行,同时可在线调试。

工作流程口诀:管理 → 集成 → 仿真 → 综合 → 实现 → 编程

5、使用参数化设计实现计数器

ACG525开发板上的LED 状态每500ms翻转一次。ACG525开发板上晶振为50MHz,也就是说时钟周期为 20ns,这样可以计算得出 500ms = 500_000_000ns/20ns = 25_000_000,即需要计数器计数 25_000_000 次,也就是需要一个至少 25 位的计数器(2^25>25_000_000>2^24)。且每当计数次数达到需要清零并重新计数。

因为计数器是从 0 开始计数而不是 1,因此在计数值计数到 25’d24_999_999 时清零而不是计数到 25’d25_000_000时清零,这里计数器最大值使用 parameter 进行参数化定义表示,使用参数化定义的好处是通过修改 parameter 中定义最大值的数值可以全部修改设计中用到的这个参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
module led_flash(
input clk,
input rst,
output reg led
);
parameter CNT=25'd24_999_999 ;

reg [25:0] counter;

always@(posedge clk or negedge rst) begin
if(!rst)
counter<=0;
else if(counter==CNT)
counter<=0;
else
counter<=counter+1'b1;
end


always@(posedge clk or negedge rst) begin
if(!rst)
led<=0;
else if(counter==CNT)
led<=~led;
else
led<=led;
end

endmodule

测试文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
`timescale 1ns/1ns
`define CLOCK_PERIOD 20

module led_flash_tb;

reg rst;
reg clk;
wire led;

initial clk=1;
always #(`CLOCK_PERIOD/2) clk=~clk;

initial begin
rst=0;
#(`CLOCK_PERIOD*10+1);
rst=1;
#2000000000;
$stop;
end

led_flash led_flash_inst(
.rst(rst),
.clk(clk),
.led(led)
);

endmodule

在进行上述的功能仿真时可以发现电脑需要运行的时间较长,这是由于计数器的计数值太大。可以通过更改仿真计数的最大值来缩短仿真时间。这里介绍两种更改方式,第一种方式是将设计文件 bin_counter.v 中使用 parameter 进行参数化定义的计数值最大值修改为 24_999,具体代码如下。

1
parameter MCNT = 24_999; 

我们可以使用defparam的方式修改参数值,比较简单

1
defparam bin_counter_inst.MCNT = 24_999; 

可以使用`define 某个变量的形式去定义

1
`define CLK_PERIOD 20     // 定义时钟周期为20ns

在使用的时候就直接`CLK_PERIOD,在定义的变量前面加上
`符号即可

!为逻辑取反,~为按位取反,逻辑取反的意思就是只是判断0和1,如果一个数字大于0,!后就为0,但是按位取反~不一样,他是每一位都在取反的

在markdown中使用\来解引用,例如可以使用`来解引用,否则就变成代码的形式变换格式了