Diplomacyの論文を読むその2.前回の記事は以下。
- Diplomatic Design Patterns: A TileLink Case Study
後半はDiplomacyのデザインパタンについて。
4. Design Patterns
このセクションではDiplomacyとTileLinkをどのようにして有効化し、ハードウェアデザインパタンとして、ジェネレータを使用したデザインに組み込むかについて解説する。
4.1 DRYing Out Parameterization
"Don't Repeat Yourself(DRY)"という考え方を踏襲する。つまり、デザインを冗長に定義しない、そしてシステム全体、情報やドキュメントなども冗長化しないという考え方である。デザインを変更すると、マニュアルなどのドキュメントも変更する、という考え方である。しかし、パラメタライズしたハードウェアの生成はDRYに基づいたハードウェア設計の素晴らしいソースとなるが、パラメタライズ自身が、直行しない複雑性の根源となってしまうのが問題である。
パラメタライズされたアービタのジェネレータの例を考える。アービタはN個の入力を受け取り、Muxで1つだけを外に渡す。そしての整数をソースフィールドからアービトレーションされたメッセージに追加し、レスポンスを正しいポートに返すことができるようにする。Non-Diplomaticなコードベースでは、カーディナリティを様々な場所でバインドしなければならない。
- アービターモジュールの構築時
- すべての拡張されたソースフィールドの配線をダウンストリームに伝搬させる
これにより、デザインの中のというパラメータのために様々モジュールのインスタンスと配線のコンフィグレーションに変更が加わる。デザイン中の様々な場所でこのという要素が絡み、これらの要素について正しく接続できていることがすべて確認できないと、ミスコンフィグレーションとして問題が発生することになる。
Diplomacyによりこれらの問題を解決することができる。Diplomatic Arbiterのジェネレータの場合、我々が個のソースノードをArbiterのノードに接続したという事実は、単一の、明白な、独占的な表現である。というカーディナリティをコードベース上のどこにも宣言する必要なく、という値はデザインのグラフトポロジから自動的に算出され、アービタのジェネレータに伝えられ、さらにすべてのダウンストリームのエッジに対して伝えられる。
4.2 Viewを用いたハードウェア生成
カーディナリティの正確な情報を提供すること以上に、Diplomaticなグラフはシステム中のインターコネクトに必要な他のノードの情報をジェネレータに提供することができる。
- マスターノード : 全てのスレーブの情報を確認する
- スレーブノード : すべてのマスターの操作が到達できるかどうかを確認する
- すべてのマスターの数を数えて、ディクショナリの作成時に必要なビット数を計算する。
- 特定のマスターに対して順序を記録する。
- アダプタノード : 相互接続ジェネレータに、マスタとスレーブの両方の濃度と機能に関する情報を提供する。
全体的に見ると、このハードウェア生成のアプローチにより、設計者はシステムのグローバルな観点から見ることができるようになる。これは例えばローカルのコンポーネントに対して生成的なパラメータを定義しても同様である。
4.3 Correct by Composition
TileLinkの特性により、現状のDiplomaticグラフに対して特定の変換を行っても、別の正しいグラフwお確実に生成することができるという保証を持っている。これにより、デザインの等価性を維持したまま、サブグラフの挿入が可能となる。ここでは、Rocket Chipのコードベースの構造を形作る3つの変換について説明する。
- Combinational Composition : 複数のアダプタノードが線形シーケンスで構成されている。
- TileLinkプロトコルのReady/Validを使用し、各チャネルの信号は内側から外側へ向けてハンドシェークで進んでいく。
- これらのモジュールは、なるべく役割を分担したほうが良く、アダプタはそれぞれ直行した機能を持っているべきである。例えば:
- Figure-1では、TileLinkからAXI4への変換の例を示している。これらは、個別の直行された機能を実装したアダプタを連結させる。これらの操作はゼロレイテンシのモジュールが挿入され、機能的に等価である。
Sequential Composition : チャネルに対して機能を挿入する。
- キューの挿入など。
- キューの深さだけでなくフロー制御パラメータも提供する。
- 例えば、連続したメッセージのエンキューのキューイングや空のキューを通るメッセージのフローなど
- キューの深さだけでなくフロー制御パラメータも提供する。
- これにより、タイミングデカップリングポイントなどの問題を簡単に解決できることを目的とする。
- キューの挿入など。
Hierarchical Composition : TileLinkはデッドロックしないことが保証されているため、SoCのサブ蔵hうを等価性を維持しながら別のサブグラフに変換する。
あるタイプのノードが、ジェネレータによって特に制約もなく接続することができると宣言されると、Scala(とChisel)の多重継承により、トレイとを介してサブグラフコンポーネントを構築する。Figure-4では抽象的なプロセッサとメモリの間を接続する機能が記述されている。
// Trait containing attachment points common to all systems trait ConnectsToMemory { val processorMasterNode: TLSourceNode // abstract member val memorySlaveNode: TLSinkNode = LazyModule(new TLRAM).node } // No coherence manager provided, only a single cache is safe trait ConnectsIncoherently extends ConnectsToMemory { require(processorMasterNode.masters.size <= 1) memorySlaveNode := processorMasterNode } // Make some coherence manager and insert it in the node graph: trait ConnectsViaBroadcastHub extends ConnectsToMemory { val hub = LazyModule(new TLBroadcastHub) hub.node := processorMasterNode memorySlaveNode := hub.node } trait ConnectsViaL2Cache extends ConnectsToMemory { val l2 = LazyModule(new TLCache) l2.node := processorMasterNode memorySlaveNode := l2.node } // Add some master nodes and reify the attachment point: trait HasOneCore extends ConnectsToMemory { val core = LazyModule(new Rocket) val processorMasterNode = core.node } trait HasTwoCores extends ConnectsToMemory { val cores = List(2).fill(LazyModule(new Rocket)) val xbar = LazyModule(new TLXbar) val processorMasterNode = xbar.node cores.foreach { c => xbar.node := c.node } } // Compile and elaborate correct hardware: class SingleCoreSystem extends HasOneCore with ConnectsIncoherently class DualCoreSystem extends HasTwoCores with ConnectsViaBroadcastHub class DualCoreL2System extends HasTwoCores with ConnectsViaL2Cache // Fails at Scala compile time due to missing TLSourceNode instance: class IncompleteSystem extends ConnectsViaL2Cache // Fails during elaboration due to failed requirement: class UnsafeSystem extends HasTwoCores ConnectsIncoherently