Altifigence Academy

10 / 20 · 実習

実習:入力をずらした2×2アレイ

1エッジの転送遅延をモデル化し、すべての中間アキュムレータを検査します。

等しいkを出会わせる

A(i,k)を論理エッジk+iで左境界へ、B(k,j)をk+jで上境界へ投入します。レジスタによる転送は水平方向にjエッジ、垂直方向にiエッジ追加します。したがって両オペランドはk+i+jでPE(i,j)に届きます。この投入時刻のずらしが入力スキューです。

A=[[1,2],[3,4]]、B=[[5,6],[7,8]]で、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は更新前の状態を読み、次状態へ書きます。その場での反復更新は、1エッジで複数ホップの転送を誤って可能にします。

E0後はC(0,0)のアキュムレータだけが5です。E1ではそれが19で完成し、隣は6と15で開始します。E2では隣が22と43で完成しますが、最後のPEはまだ18です。E3で32を加えて50になります。

行投入をt−iからtへ変えてください。タグのアサーションがずれを検出するはずです。完了には4回のadvanceエッジと、すべてのcountが2であることが必要です。初期化と直列の出力転送は除外します。この実行モデルは指定したスケジュールを検証するもので、RTLやDDSでの実行を主張しません。

実際のRTL:レジスタ付き2×2格子

添付systolic_2x2.svはsigned_mac_pe.svの4インスタンスをN=K=2の範囲で接続します。Aは右、Bは下へ、validとkタグを持つレジスタ接続を通って動きます。外部境界供給側がスキューを行い、テストベンチのstepタスクがE0..E3を直接駆動します。E0前にクリアを完了し、追加乗算パイプラインはありません。

全3添付を一緒に保存して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後だけにアサートします。停止2回ならadvance4、物理計算エッジ6です。[[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 ↓

選択はこのブラウザに適用されます。フッターからいつでも変更できます。