Altifigence Academy

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
E01(k0)无效5(k0)无效
E12(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。

javascript
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:

bash
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 到达;边界无效并不会立即使阵列变空。

Lesson files

schedule-lab.mjs ↓signed_mac_pe.sv ↓systolic_2x2.sv ↓tb_systolic_2x2.sv ↓

你的选择适用于此浏览器,可随时在页脚更改。