31 / 37 · 概念
乘加流水线与数据对齐
按寄存器边界划分运算,使数据、valid 与辅助操作数属于同一事务。
课时内容可免费阅读,选课后可保存学习进度。
从计算表达式划分为两个阶段
先修知识:signed 算术、非阻塞非阻塞赋值 时序 RTL 中以 <= 表示的赋值。先计算右侧,再预约更新,使同一边沿的各寄存器能够依据旧状态计算。了解更多赋值、setupsetup 捕获时钟边沿之前,输入数据必须保持稳定的最短时间。违反建立时间就无法保证存储结果。了解更多 条件与 valid 信号。
设每个输入事务包含 signed 八位 a、b,以及 signed 十六位 c,结果为下式。这是独立处理每个事务的乘加,而不是累加器。
八位乘法的精确结果需要十六位。再加 c 时,若先按十六位计算再扩宽,就无法恢复已丢失的高位。必须先把两个操作数都符号扩展为十七位,再相加。
第一级同时存储乘积与 c,第二级将同一事务的两个值相加。若不延迟 c,就会错误地把上一事务的乘积与当前事务的 c 混合。
module multiply_add_pipeline (
input logic clk, rst, in_valid,
input logic signed [7:0] a, b,
input logic signed [15:0] c,
output logic out_valid,
output logic signed [16:0] y
);
logic v1;
logic signed [15:0] p1, c1;
logic signed [16:0] p_ext, c_ext;
assign p_ext = {p1[15], p1};
assign c_ext = {c1[15], c1};
always_ff @(posedge clk) begin
if (rst) begin
v1 <= 1'b0;
out_valid <= 1'b0;
end else begin
v1 <= in_valid;
out_valid <= v1;
if (in_valid) begin
p1 <= a * b;
c1 <= c;
end
if (v1) y <= p_ext + c_ext;
end
end
endmodule本接口假设每个边沿都能接收输入,接收方也始终能接收输出。out_valid=0 时不比较 y。即使不复位复位 将状态恢复为规定初值的控制。必须同时规定其同步或异步性质,以及相对于其他控制的优先级。了解更多数据寄存器寄存器 存储多位状态的电路。本课程中的同步寄存器在时钟边沿存储指定输入。了解更多,只要初始化 valid,就能区分不应使用的数据。
区分“两级”与观察时刻
下表在每个边沿接受输入,并记录紧接边沿之后的寄存器状态。A、B 表示不同事务。
| 边沿 | 接受的输入 | 第一级 | 输出寄存器 |
|---|---|---|---|
| E0 | A | A 的乘积与 c | invalid |
| E1 | B | B 的乘积与 c | A 的结果,valid |
| E2 | 无 | invalid | B 的结果,valid |
| E3 | 无 | invalid | invalid |
A 的结果在 E1 之后准备好。同一时钟下的后级电路在 E2 采样它,因此从输入接受 E0 到输出接收 E2 是两个周期。解释延迟时,不要混淆输出寄存器变化时刻与后级接收时刻。
每列记录一个上升沿上升沿 时钟从 0 变为 1 的瞬间。它不同于表示整个 CLK=1 区间的电平。了解更多的观察结果。输入取自边沿前,名称带 after 的状态取自更新后。列的排列表示采样顺序,并非描绘物理传播延迟传播延迟 从输入变化到输出稳定为正确值所需的时间。逻辑表达式等价与时间特性是两回事。了解更多。事务为 A=(2,3,10)、B=(4,5,100)。第一级同时存储乘积与 c,下一边沿将上一阶段的对应值相加。破折号表示 invalid 区间。
查看波形数据
| 信号 | 波形 | 总线值 |
|---|---|---|
| edge | 2345 | E0 → E1 → E2 → E3 |
| accepted | 234. | A → B → - |
| product1 after | 234. | 6 → 20 → - |
| c1 after | 234. | 10 → 100 → - |
| y after | 2345 | - → 16 → 120 → - |
| out_valid after | 01.0 |
划分流水线能快多少?
考虑一个简化模型:乘法延迟 3.2ns,加法延迟 1.1ns,寄存器开销 0.2ns。这些数值只是计算假设。
最大频率上界由约 222MHz 变为约 294MHz。两级不保证吞吐率翻倍;周期由最慢一级与寄存器开销决定,实际结果还取决于综合、布局与约束。
按事务验证
接受输入时,将整数参考模型的 a×b+c 放入队列。在接收到输出 valid 的边沿,弹出队首预期值并比较。插入 in_valid=0 区间,检查空泡是否与数据一起移动。每个事务大幅改变 c 的模式,容易暴露延迟遗漏。
自己试试
连续施加事务 A=(a=3,b=-4,c=10)、B=(a=2,b=5,c=100)。求正确输出顺序,以及不延迟 c、直接加当前输入 c 时,A 可能产生的错误结果。
阅读解释
正确结果为 A:-12+10=-2;B:10+100=110。若 A 的乘积位于第二级时,当前 c 已是 B 的 100,就会得到 88。即使 valid 延迟正确,操作数未对齐也无法避免这个错误。