目录
- 题目:
- 时序分析:时钟频率为50MHz
-
- [数据1: a=10, b=20, c=30, d=40, e=2](#数据1: a=10, b=20, c=30, d=40, e=2)
- [数据2: a=5, b=15, c=25, d=35, e=3](#数据2: a=5, b=15, c=25, d=35, e=3)
- [数据3: a=8, b=12, c=16, d=24, e=4](#数据3: a=8, b=12, c=16, d=24, e=4)
- 流水线效率分析
题目:
verilog中,y=(a+b+c+d)*e,时钟频率为50Mhz,用流水线的形式表示,并说明运算完需要多少ns?
图片帮助理解:T1-T4只能做1辆车,但是T4后,每个时钟周期就能做一辆车(如果没有流水线,就每做1辆车都需要4个T的时间)
在Verilog中,将表达式 y=(a+b+c+d)*e 用流水线形式实现,可以分为多个阶段,每个阶段对应一个时钟周期。
流水线设计可以提高电路的吞吐量,但会增加延迟(latency)。下面是具体实现及时序分析。
流水线实现:
将该表达式分为3个流水线阶段:
- 第一阶段:计算 a+b 和 c+d
- 第二阶段:计算 (a+b)+(c+d)
- 第三阶段:计算 ((a+b)+(c+d))*e
代码实现:
c
module pipeline_mult (
input wire clk, // 时钟信号,50MHz
input wire rst_n, // 复位信号,低电平有效
input wire [7:0] a, // 假设都是8位输入
input wire [7:0] b,
input wire [7:0] c,
input wire [7:0] d,
input wire [7:0] e,
output reg [15:0] y // 输出可能需要更宽的位宽
);
// 第一级流水线寄存器
reg [8:0] sum_ab; // a+b的结果,需要多一位防止溢出
reg [8:0] sum_cd; // c+d的结果
reg [7:0] e_reg1; // 保存e的值传递到下一级
// 第二级流水线寄存器
reg [9:0] sum_abcd; // (a+b)+(c+d)的结果
reg [7:0] e_reg2; // 保存e的值传递到下一级
// 第一级流水线
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
sum_ab <= 9'b0;
sum_cd <= 9'b0;
e_reg1 <= 8'b0;
end else begin
sum_ab <= a + b;
sum_cd <= c + d;
e_reg1 <= e; // 将e传递到下一级
end
end
// 第二级流水线
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
sum_abcd <= 10'b0;
e_reg2 <= 8'b0;
end else begin
sum_abcd <= sum_ab + sum_cd;
e_reg2 <= e_reg1; // 将e传递到下一级
end
end
// 第三级流水线 - 最终结果
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
y <= 16'b0;
end else begin
y <= sum_abcd * e_reg2; // 最终的乘法计算
end
end
endmodule
时序分析:时钟频率为50MHz
意味着时钟周期为:
T = 1/f = 1/(50*10^6) = 20 ns
在这个流水线设计中:
第一个输入需要经过3个时钟周期(3级流水线)才能产生有效输出;单次计算的延迟(latency)为:3 * 20 ns = 60 ns ;但一旦流水线填满,之后每个时钟周期都会产生一个新的结果(吞吐量为每20ns一个结果) 。因此,对于单个计算实例,从输入到计算完成需要60 ns的时间。但是流水线的优势在于可以同时处理多个计算实例,每20 ns就能输出一个结果。
给小白,解释一下这个疑问:
c
Clock : |¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|
Time (ns) : 0 20 40 60 80 100 120 140 160 180 200 220
输入数据:
a : |10 | 5| 8| | | | | | | | | | | | |
b : |20 | 15| 12| | | | | | | | | | | | |
c : |30 | 25| 16| | | | | | | | | | | | |
d : |40 | 35| 24| | | | | | | | | | | | |
e : | 2 | 3| 4| | | | | | | | | | | | |
第一级流水线:
sum_ab : | | 30| 20| 20| | | | | | | | | | | |
sum_cd : | | 70| 60| 40| | | | | | | | | | | |
e_reg1 : | | 2| 3| 4| | | | | | | | | | | |
第二级流水线:
sum_abcd : | | |100| 80| 60| | | | | | | | | | |
e_reg2 : | | | 2| 3| 4| | | | | | | | | | |
输出结果:
y : | | | |200|240|240| | | | | | | | | |
↑ ↑ ↑
数据1 数据2 数据3
看完这2个图,你应该大致明白了,不明白的话,继续看下面这个分析:
详细时序分析:
数据1: a=10, b=20, c=30, d=40, e=2
- 时钟周期1 (0-20ns):
- 输入数据: a=10, b=20, c=30, d=40, e=2
- 寄存器尚未更新
- 时钟周期2 (20-40ns):
- 第一级流水线:
- sum_ab = 10 + 20 = 30
- sum_cd = 30 + 40 = 70
- e_reg1 = 2
- 其他级别未更新
- 时钟周期3 (40-60ns):
- 第二级流水线:
- sum_abcd = 30 + 70 = 100
- e_reg2 = 2
- 第三级流水线尚未更新
- 时钟周期4 (60-80ns):
- 输出结果:
- y = 100 * 2 = 200 (实例1的最终结果)
数据2: a=5, b=15, c=25, d=35, e=3
- 时钟周期2 (20-40ns):
- 输入数据: a=5, b=15, c=25, d=35, e=3
- 寄存器尚未更新
- 时钟周期3 (40-60ns):
- 第一级流水线:
- sum_ab = 5 + 15 = 20
- sum_cd = 25 + 35 = 60
- e_reg1 = 3
- 其他级别未更新
- 时钟周期4 (60-80ns):
- 第二级流水线:
- sum_abcd = 20 + 60 = 80
- e_reg2 = 3
- 第三级流水线尚未更新
- 时钟周期5 (80-100ns):
- 输出结果:
- y = 80 * 3 = 240 (数据2的最终结果)
数据3: a=8, b=12, c=16, d=24, e=4
- 时钟周期3 (40-60ns):
- 输入数据: a=8, b=12, c=16, d=24, e=4
- 寄存器尚未更新
- 时钟周期4 (60-80ns):
- 第一级流水线:
- sum_ab = 8 + 12 = 20
- sum_cd = 16 + 24 = 40
- e_reg1 = 4
- 其他级别未更新
- 时钟周期5 (80-100ns):
- 第二级流水线:
- sum_abcd = 20 + 40 = 60
- e_reg2 = 4
- 第三级流水线尚未更新
- 时钟周期6 (100-120ns):
- 输出结果:
- y = 60 * 4 = 240 (数据3的最终结果)
流水线效率分析
- 延迟 (Latency):
- 每个计算实例从输入到输出需要3个时钟周期 = 60 ns
- 吞吐量 (Throughput):
- 流水线满载后,每20 ns产生一个结果
- 3个计算实例总共需要时间 = 60 ns (首个结果) + 40 ns (接下来2个结果) = 100 ns
- 如果是没有流水线的设计,需要 3 * 60 ns = 180 ns
- 性能提升:
- 流水线设计对于处理大量连续数据时,性能提升明显
- 在这个例子中,处理3个连续实例的时间从180 ns减少到了100 ns,提升约44%
这种波形图清晰地展示了流水线的工作原理,显示了每个计算实例如何逐级推进,最终产生结果,以及多个实例如何在流水线中重叠执行,提高总体处理效率。