えー、セカンド・オピニオンも300回を迎えることができました。いやまぁ酒井センセの「理系のための恋愛論」なんてとっくに300回超えてて、しかも相変わらず大人気だったりするので、それに比べるとまだまだなんですが。とはいえ、お読みいただいている読者の皆様と、連載を続けさせていただける編集部のご好意には深く感謝いたします。ということで、300回目を迎えても、やってることは相変わらずであります。


このLink Commandを発行するタイミングであるが、

  • 他のHeader Packet、つまりLMP(Link Management Packet)やTP(Transaction Packet)、ITP(Isochronous Timestamp Packet)、DTH(Data Packet Header)の中には含まれない
  • DP(Data Packet)やDPP(Data Packet Payload)の中にも含まれない
  • Packet Headerの前もしくは後に入るが、ただしDPHとDPPの間に入ったりはしない
  • 複数のLink Commandを連続して転送することは許される

といった事が定義されている(細かくは他にもいくつかあるが、それはまぁいいだろう)。要するに、他の転送を行っていない時に、間をぬって送りあう感じだと思えばよい。

ただLink Commandではやはり非常にプリミティブな制御しか出来ない(というか、プリミティブな制御をするのがLink Commandの目的である)ので、Flow ControlやError Recoveryはより上位で行う必要がある。これを行うのがHeader Packetである。

このHeader Packetを使い、どんな形でFlow ControlやError Recoveryを行っているか、を説明するためにまずは正常な状態の流れを追ってみたい。

まずInitialization(Photo01)の状態である。ここで言うInitializationは、送信側と受信側がどちらもU0にあって、これからまさに送信を開始しようという状態にあることを指す。

Photo01: 双方のバッファは空になり、ポインタはBuffer Aを指し、またCreditは4となっている。これがノーマル状態の初期段階である。

次に送信側のHeader Bufferに値をセットする(Photo02)。これが終わったら、実際に送信側から受信側にHeader Packetが送出される(Photo03)。この際に、送信側はPending_HT_TIMERとCREDIT_HP_TIMERの2つのタイマーをスタートさせる。一方受信側は自動的にHeader Buffer Aに送信された内容が入る形だ。転送が終わったら、受信側は受け取ったパケットの内容からCRC(CRC5とCRC16の両方)を算出し、それを受信したCRCと比較する(Photo04)。これが一致していれば問題なしと判断される。そこで、受信側から送信側に、正常に転送されたことを通知する(Photo05)。これを受けて、送信側はTX Bufferに残っていたデータをクリアすると共に、Header Sequence Numberを1インクリメントする。また、PENDING_HT_TIMERはこの時点でとめられ、0クリアされる。

Photo02: Tx側のSequence Numberが1に変わっていることに注意。

Photo03: この時点で送信側Creditの残量が3に減る。

Photo04: Sequence NumberやBuffer Creditは、CRCが正常だった時点で初めて変更される。

Photo05: ここで使われるメッセージがLink CommandのLGOOD_0となる。

さて、次に受信側であるが、受け取ったヘッダの内容を今度は解釈する(Photo06)。この解釈が終了したら、バッファをクリアすると共に、受信側のCreditを4に復活させる。ここまでが完了したら、受信側からやはりLink Commandを使いLCRD_Aを送信側に送る(Photo07)。これを受けて送信側はRemote Buffer Creditを4に戻し、またCREDIT_HT_TIMERをリセット、0クリアする。以上で一連の転送作業が終了という訳だ。ちなみにこの時点で送受信共に、Buffer IndexはBになるので、例えば次に転送が行われる場合、今度はHeader Buffer Bが使われるという仕組みだ。

Photo06: この時点では、まだ送信側のCREDIT_HP_TIMERが動いている事に注意

Photo07: LCRD_Aの送信のタイミングで、受信側のIndexもBに変更される。LCRD_Aを送信する前では無いのがちょっと面白い。

今回の流れはあくまで1 Packetでのケースだが、複数パケットの場合多少順序を変えることが可能だ。例えば4つのパケットからなるデータを一気に送る場合、

送信側 受信側
Framed HP #0→
←LGOOD_0
Framed HP #1→
←LGOOD_1
Framed HP #2→
←LGOOD_2
Framed HP #3→
←LGOOD_3
←LCRD_A
←LCRD_B
←LCRD_C
←LCRD_D

なんて形で、まずパケット4つを兎に角受信側に送ってしまい、4パケットまとめて処理後にLCRDを連続して送り返すなんてことも仕様上は許される。PENDING_HP_TIMERはあくまで1回の転送のタイマーなので(Timeoutは3μs)、こまめにLGOODを送り返す必要があるが、CREDIT_HT_TIMERは「全ての」転送が終わるまでの時間を管理しており、Timeoutは5000μsと遥かに長いので、LCRDの送信は後に回すことが出来る。

(続く)