10 / 20 · 实验
实验:输入错位的 2×2 阵列
为单时钟沿转发延迟建模,并检查每个中间累加器。
课时内容可免费阅读,选课后可保存学习进度。
让相同的 k 值相遇
在逻辑时钟沿 k+i,将 A(i,k) 注入左边界;在 k+j,将 B(k,j) 注入上边界。寄存器转发在水平方向增加 j 个时钟沿,在垂直方向增加 i 个时钟沿。因此两个操作数都在 k+i+j 到达 PE(i,j)。这种错开的注入就是输入错位。
对于 A=[[1,2],[3,4]]、B=[[5,6],[7,8]],clear 在 E0 前完成。边界调度如下:
| 时钟沿 | 左侧行 0 | 左侧行 1 | 顶部列 0 | 顶部列 1 |
|---|---|---|---|---|
| E0 | 1(k0) | 无效 | 5(k0) | 无效 |
| E1 | 2(k1) | 3(k0) | 7(k1) | 6(k0) |
| E2 | 无效 | 4(k1) | 无效 | 8(k1) |
| E3 | 无效 | 无效 | 无效 | 无效 |
将以下内容保存为 schedule-lab.mjs,运行 node schedule-lab.mjs。无需软件包,输出 Schedule lab passed。无效令牌为 null;有效令牌携带 value 和 k。这个单任务模型省略 job 标签,但明确检查 k。
import assert from 'node:assert/strict';
const A=[[1,2],[3,4]],B=[[5,6],[7,8]],N=2,K=2;
const fresh=()=>({a:null,b:null,acc:0,count:0});
let grid=Array.from({length:N},()=>Array.from({length:N},fresh));
const expected=[[[5,0],[0,0]],[[19,6],[15,0]],
[[19,22],[43,18]],[[19,22],[43,50]]];
const token=(value,k)=>({value,k});
for(let t=0;t<K+2*N-2;t++) {
const next=grid.map(r=>r.map(p=>({...p})));
for(let i=0;i<N;i++) for(let j=0;j<N;j++) {
const ka=t-i,kb=t-j;
const a=j?grid[i][j-1].a:(ka>=0&&ka<K?token(A[i][ka],ka):null);
const b=i?grid[i-1][j].b:(kb>=0&&kb<K?token(B[kb][j],kb):null);
const p=next[i][j];p.a=a;p.b=b;
if(a&&b){assert.equal(a.k,b.k);assert.equal(a.k,p.count);
p.acc+=a.value*b.value;p.count++;}
}
grid=next;
assert.deepEqual(grid.map(r=>r.map(p=>p.acc)),expected[t]);
}
assert.deepEqual(grid.map(r=>r.map(p=>p.count)),[[2,2],[2,2]]);
console.log('Schedule lab passed');每个 PE 读取旧状态,写入下一状态。原地迭代会错误地允许一个时钟沿内多跳转发。
E0 后,只有 C(0,0) 的累加器为五。E1 时它完成并达到十九,相邻 PE 分别从六和十五开始。E2 时这两个相邻 PE 分别完成,得到二十二和四十三,而最后一个 PE 只有十八。E3 加上三十二,得到五十。
将行注入从 t−i 改为 t,标签断言应检测出错位。完成需要四个推进时钟沿,并且每个 count 都等于二。不包含初始化和串行输出传送。这个可执行模型验证规定的调度,不代表 RTL 或 DDS 执行已通过。
实际 RTL:寄存式 2×2 网格
附件 systolic_2x2.sv 连接 signed_mac_pe.sv 中的四个实例,限制为 N=K=2。A 向右、B 向下,经过携带 valid 和 k 标签的寄存器连接。外部边界供数逻辑实现输入错位;测试平台的 step 任务直接驱动 E0..E3 调度。Clear 在 E0 前完成,没有额外乘法器流水线。
将三个附件保存到同一位置,运行 Icarus Verilog:
iverilog -g2012 -s tb_systolic_2x2 -o systolic.vvp signed_mac_pe.sv systolic_2x2.sv tb_systolic_2x2.sv
vvp systolic.vvp沿后矩阵依次为 [[5,0],[0,0]]、[[19,6],[15,0]]、[[19,22],[43,18]] 和 [[19,22],[43,50]]。Done 只在 E3 后置位。两次暂停得到四个推进时钟沿和六个实际计算时钟沿。检查还覆盖 [[10,9],[−6,3]]、完整状态保持和任务中途复位。预期输出 RTL PASS:。
RTL 修改练习中,将一个寄存式操作数连接替换为组合路径。预测第一个标签对齐或中间和错误,比较日志,再恢复寄存器。将网格扩展为 N×N 时,必须一起重新考虑布线、输入错位、位宽、标签和完成条件。
自己试试
E2 后,PE(1,1) 的累加器是多少,还有哪一项未处理?为什么边界输入无效时,它仍会在 E3 改变?
阅读解释
累加器为 3×6 得到的 18,还有 4×8=32 未处理。这些操作数位于内部转发寄存器中,在 E3 到达;边界无效并不会立即使阵列变空。