2018年9月13日木曜日

イーサネット + DMACの評価でやってしまいました

2009年頃、筆者はとあるプリンターメーカー向けASICの実装機評価に参加して、イーサネットインタフェースの評価を担当しました。これは、既存のイーサネットインタフェースとDMA(Direct Memory Access)コントローラを1つの機能ブロックとしてまとめたもので、この製品のために開発されたカスタム機能ブロックでした。

内蔵CPUを動かすプログラムをC言語で書いて、ソフトウエアでイーサネットコントローラーを制御し、動作させる、というのが、実装機評価の内容です。

試作品が出て来た時点で、実装機を使った通信機能の機能評価をして、通信機能に問題が無いことは確認していました。しかしお客様のセット試作品評価において、とある動作条件のときのみ発生する動作不具合が見つかってしまいました。筆者が実施した内部評価で見つけることが出来なかったのは、筆者の力不足だったのはもちろんなのですが、イーサネットコントローラー単体評価がミッションだったのか、イーサネットコントローラー+DMAコントローラーの評価がミッションだったのか、今となっては定かではありません。

しかしまた、ここでも、筆者が実装機評価に参画して担当した機能ブロックにはバグが出る、というジンクス通りのことが起こりました。

本件、記事執筆時点で9年を経過した出来事なので、記憶が曖昧な点があります。可能な限り矛盾が生じないように、内容を吟味してはいますが、お許しを。

イーサネットの通信を行う機能は、通信機能のデータの種類による不具合がないかどうかは時間がかかりすぎるので実施しなかったものの、ローカルループバックを使って確認済みでした。

DMAコントローラーを使ったDMA転送によるデータの送受信も一通りやっていたはずでした。

しかし、お客様のセットの試作評価の中で、DMAコントローラーが持っているデータパディングを有効にした転送を行うと、データ転送が正しく行われない、という連絡がお客様からありました。


データパディングとは?



この記事で言うデータパディングというのは、DMA転送をする際に、データの先頭に自動的に決まったバイト数のデータを挿入してくれる機能のことです。たとえば、データブロック1キロバイト、データパティング4バイトの設定をしてデータ転送を行うと、1ブロック1キロバイトごとに、その先頭に自動的に4バイトのダミーデータを挿入してデータ転送をしてくれる、というものです。


なぜデータパディングが必要?



そもそもなぜ、データパディングが必要なのでしょうか?イーサネットのデータ送受信の最小単位、フレームの構造を図に示します。


図の中で、プリアンプルは送受信フレームの先頭を判別する為の付帯情報、宛先MAC ADDR(Media Access Control Address、ネットワークにぶら下がっている機器に原則として一意にに割り当てられるアドレス)からデータまでがイーサネットの規格にのっとったデータのかたまり、FCSは通信の誤り検出の為のデータです。

データを受信する際には、上記の宛先MAC ADDR(宛先のMACアドレス)からデータの最後までがデータバッファにたまっていきます。

この中で、宛先と送信元のMACアドレスのバイト数、怪しくないですか?6バイトというのは随分半端なデータ幅ですよね。合計12バイト、その隣のタイプが2バイトなので、合計14バイトです。

32Bitプロセッサーシステムのメモリーアドレスのようす


上に、最近の一般的なCPUのデータ配置とアドレスの関係を図にして示します。これは、その昔組み込み用途で絶大なシェアを誇ったSH1、SH2のデータ配置を図にしたものです。アドレスバスから出力されるアドレスは、すべて4の倍数で出力され、それよりも細かいアドレス指定は、アドレスバスの出力とバス制御信号を組み合わせることによってなされます。

最近のCPU、特にRISCアーキテクチャのCPUは、データ構造が4バイト境界を跨ぐことを禁止しています。それは、アドレス出力1回でメモリーアクセスを完結させたいということだと思います。

どういうことかというと、ロングワードのデータアクセスを考えた場合、上の図のアドレスバスの数値のアドレスでメモリーアクセスをすれば、アドレス出力1回で1ロングワードのアクセスが可能であるのに対して、たとえばアドレス+2の場所からロングワードアクセスをしようとすると、アドレス+2、アドレス+3、次のアドレス+0、次のアドレス+1に格納されたデータにアクセスしなければならなくなり、1回のアドレス出力では対応できません。つまり、1回のアクセスで完結できなくなります。

このようなメモリーアクセスを許しているプロセッサーも世の中にはありますが、禁止しているプロセッサーが多いようです。

データパディングをどうやって使うのか



話を戻すと、使う側が一番、そして早く欲しいのはデータの中身なのですが、この状態では、データが半端な場所から始まるので、DMA転送で一気に引き抜くということはできません。最初の2バイトをソフトウエアでコピーしてから、17バイト目以降をDMA転送、という手順が必要になります。

ソフトウエアによる転送ということは、CPUがプログラムをフェッチして、実行して、やっとデータの転送がなされる、ということになります。えらく効率が悪いですよね。

これだと転送効率が落ちてしまうので、データの転送をDMACを使って一気にやりたい、と思うわけです。そこで登場するのがデータパディングです。

データフレームの先頭に2バイトのダミーデータを付加してあげると、ダミーデータ、転送先MACアドレス、送信元MACアドレス、タイプの合計が16バイトとなって、その次に来るデータ本体の先頭が4バイト境界にきれいに乗ります。そうなれば、DMA転送で一気に転送できます。

ちなみにイーサネットはゼロックス社のパロアルト研究所で開発され、1973年5月22日に特許が認められた規格だそうで、1974年にインテルが8080を発表する前の年です。

そういう古い時代にできた規格なので、現在のプロセッサーアーキテクチャのように、データは4バイト境界から並んでいないと、CPUがアドレスエラーを発生するなんていうことは想定出来ていなかったんでしょうね。

データパディングの必要性は、自分なりの解釈として上記のように考えていました。他に色々とその理由を探してみましたが、これ以外に必要と思われる理由は、見つけられず、考えつきません。
他に、データ長が46バイトを切るフレームを送信する際に、データ長が最小の46バイトとなるように送信データにダミーデータを付加する必要があります。しかし、これはDMACを使って自動的に付加するような性質のものではないだろうと考えています。
もし認識が違っていたらご指摘ください。

不具合が発覚する


このようなイーサネットコントローラー用DMACのデータパディング挿入機能でしたが、お客様の実装評価で不具合が発生したとの連絡をいただきました。データパディング機能を有効にすると、データがずれるというものでした。

不具合の状況


製品設計部の中で、デバイスで動かすプログラムを作成して、ICEを使って動かす経験があるのは筆者だけだったので、不良現象の再現の指示が来ました。不具合発生条件(各種レジスターの設定値などの情報)を頂いて、プログラムを書いてICEに流し込み、再現実験をしたら、あっけなく不具合が発生し、お客様で発生した現象と全く同じ現象が出ました。

まず、正しい動作をした場合のデータ転送結果を下に示します。図の例では、わかりやすいように16進数のFFと00を16バイトずつ交互に並べて転送するイメージを描いてあります。

正しい動作では下の図のように、先頭に設定したバイト数のパディングデータが1回だけ挿入されて、それ以降のデータはパティングデータのバイト数だけ後ろにずれます。図の例では、2バイトのデータパディングを設定しています。


 これに対して、発生した不具合は、データのずれ方がデータパディングの設定と一致せず、図のように変なところにデータの変わり目が出現していました。

なお、わかりやすいように16バイト単位で切り替わるデータの並びを作って、データのずれも16バイト単位で発生しているように図を描きましたが、実際にはもっと大きなデータの塊で評価していたと記憶しています。




また、データのずれがどのぐらいの頻度で発生するのか、00からFFまで1バイト単位で異なるデータを並べて細かい解析を行い、データずれの発生頻度の観測も行いました。

上記のように、本来はパディングされたデータのバイト数だけデータが後ろにずれる、という動作が正しいはずですが、お客様の環境とこちらの環境で、パディングデータのバイト数とデータのずれ方の一致しない現象が、同じように発生することが確認できました。

不具合現象の原因は?


不具合発生の原因として、デバイス内部のタイミング特性などの特性上の問題と、論理的な不具合の2つが考えられます。

特性上の問題で発生する不具合であれば、お客様の環境とこちらの環境とで、発生する現象が異なる場合が多いです。しかし、お客様サイドとデバイスも評価環境も異なる中で同じ不具合が出るということは、論理設計の不具合であるという可能性が高いと言えます。

論理設計チームにこの結果を基に解析をお願いしたところ、ステートマシンを構成する際の、遷移条件の設定漏れがあったことが判明し、明らかな論理設計ミスという結論になりました。

実装機評価と論理検証


この製品開発における問題は、1つにはDMAコントローラーの論理設計不具合があったことですが、その不具合の第一発見者がお客様だった、ということが、一番大きな問題でした。

評価内容に関して、イーサネットコントローラー自身の送受信機能はしっかり見ていましたが、DMACと併せての協調動作の評価が不十分でした。これは私の責任です。

ところで、このような機能の検証は、本来ならどう行われるべきでしょう?

  • 機能ブロック開発時、論理検証で見つける(DMAコントローラー単体レベル)
  • 機能ブロック会派時、論理検証で見つける(イーサネットコントローラーとの協調動作)
  • FPGA等の論理検証で見つける
  • チップに組み込んだあと論理検証で見つける
  • 試作後の実装機評価で見つける

まず、ブロック単体で検証できるところはブロック単体でしておくのが良いですよね。この時点だと、論理シミュレーションのためのコンピューティングパワーはそれ程必要ないはずです。DMAコントローラー単体で動かして見られるところはDMAコントローラー単体で、イーサネットコントローラーと結合しなければ見られないところは結合して見るんだと思います。

少し込み入った機能ブロックだと、論理検証のあとにFPGAに回路を焼いたりして、評価ボードを作って評価します。条件を沢山振って評価することが出来るので、論理シミュレーションよりも効率が良いです。しかし、評価ボードを作る手間とお金がかかるので、これをやる、やらないというのは1つの大きな判断になると思います。

さらに、上記にはチップに組み込んだあと論理検証とありますが、チップレベルのRTLの規模を考えると、シミュレーションにかかる時間が膨大なものになるので、チップレベルで細かく論理検証をするのは、あまり現実的な話ではありません。代表的な動作をケースを絞ってやることになりますが、そのためのテストベクタは恐らく機能ブロック開発側から供給されるものを使うことになるでしょうから、機能ブロック開発側が認識が薄ければ、やらないことになってしまいます。

次の試作後の実装機評価ですが、この時点ではすでに試作チップが存在してます。この時点で何か出たら、論理修正のあと再び試作ロットを走らせる、ということになり、かなり大きな手戻りとなります。

となると、チップに組み込む前に論理検証を終わらせて、バグを取り切っておくのが一番効率的ですね。筆者がポカをやっておいて言うのも心苦しい話ですが、試作評価では、あまり大きな不具合が出てしまうこと自体、あってほしくない話です。

この製品においては、あってほしくない話が出てしまって、しかも発覚したのがお客様の評価だったというお話でした。

その後のお話


この製品では、DMAコントローラーのデータパディングが使えないのなら、イーサネットコントローラーは使い物にならない、ということになり、かといって論理修正及び再試作は日程的に厳しいということで、チップ外部に汎用品のイーサネットコントローラーを別部品で付けるこいうことになったと記憶しています。

お客様のセットの開発計画に大きな影響を及ぼしたわけで、バグを作り込んだのは筆者ではないとは言え、かなり落ち込みました。

この製品を担当して、このバグのゴタゴタが収束して間もなく、筆者はASIC開発の部門から別のSOC設計部門に異動することになりました。会社に入ってから20年以上にわたって所属していた部門でしたので、寂しい思いをしましたし、担当した最後の製品でこのようなポカをしてしまったことが悔やまれます。

というわけで、今回はこの辺で終わります。

0 件のコメント:

コメントを投稿