ぱたへね

はてなダイアリーはrustの色分けができないのでこっちに来た

グレイコード

符号付き2進数のバリエーションのコメントで面白い話が聞けましたので検証してみました。元ネタは、第二の魚の骨発見です。どうしてこういう事が起きるのか、またグレイコードならどう違うのかをシミュレーションしてみました。Verilogによる実装も後ろで説明しています。

2008/11/12 シミュレーション結果が見えていなかったので、一部だけを表示するようにしました。クリックすると全体を表示します。

2の補数表現とグレイコードの出力を厳密に見てみる

まずは、遅延無しのシミュレーションの結果を見てください。

青(ind)が入力波形で、紫(comp2_out)がそのままFFで出力した波形です。入力が2の補数のため、出力もそのまま2の補数で出しています。入力波形をグレイコードで出力した信号がgray_out、そちらを2の補数にデコードした物が緑(gray_dedecoded)になります。これらの波形は、当然同じになります。

同じ回路を遅延付きでシミュレーションした結果がこちらです。

2の補数表現の出力は、0の値(波線)を横切るところでノイズのような物が載っています。(画像をクリックすると全シミュレーション波形が見れます)
ノイズの部分を拡大してみましょう。

 -1(0x1F)から0(0x00)になるところを拡大しました。一番上のクロックにも注目してください。遅延無しのシミュレーションではCLKの立ち上がりに会わせて信号が変化するのですが、遅延付きシミュレーションになっているため、CLKの立ち上がりから遅延分が遅れてcomp2_outが変化しています。

さらに拡大してみましょう。

0x1Fから0x00になるときに、0x1F→0x1E→0x1A→0x10→0x00と変化しています。5bit全て1の状態から、5bit同時に0にならずに、各bit独立して0になっているのがわかるでしょうか。二進数で書くとこうなります。
11111
11110
11010
10000
00000
11010から10000には2bit同時に0に落ちていますが、これはたまたまシミュレーションで使っている遅延の値が同じなだけで、厳密に測定すると11010→11000→10000か11010→10010→10000のどちらかで遷移をしています。

ハードウェアの場合、0と1は電気信号なので全く同時に変化することはありません。変化途中の波形をたまたまサンプリングしてしまうと、全く関係の無い値が読めてしまいます。今回は5bitなのでノイズ程度にしか見えないですが、これはスケールの問題で8bit、16bitと値を増やしていくと最初のリンクにあるような魚の骨状態になります。

グレイコードが正しく読める理由

グレイコードに関しても同じ箇所を拡大してみましょう。

グレイコードでは、-1から0の変化では、0x10から0x00なので1ビットしか変化しません。図に値が入っていませんが、gray_outの信号が10から00に変化しています。グレイコードでは隣への値の遷移はかならず1bitしか変化しないので、常に変化前、もしくは変化後のどちらの値を読み出すことになります。不思議に感じた人はもう一度こちらの表で確認してください。
http://d.hatena.ne.jp/natsutan/20081104/1225770179

こう見るとグレイコードが万能のようにも見えますが、グレイコードのメリットは特定の状況でのみ有効です。まず、この特徴は隣り合う値のみに有効なので、グレイコードでも0(0x00)から10(0xF)にいきなり変化する場合は同じ問題が発生します。また、こういった問題が発生しないようにクロックなり、ストローブ信号が存在するので、なにかしらの制御プロトコルがある場合には、普通の2の補数表現で問題になることはありません。

Verilogによる実装

2の補数の出力は、FFで取り込んで出力しているだけです。

always @ (posedge clk)begin
	if(reset_x == 0)begin
		comp2_out <= 0;
	end else begin
		comp2_out <= indata;
	end
end

グレイコードは、Wikipediaを参考に実装しました。

always @ (posedge clk)begin
	if(reset_x == 0)begin
		gray_out <= 0;
	end else begin
		gray_out <= {1'b0, indata[4:1]} ^ indata;
	end
end

遅延シミュレーションについて

遅延シミュレーションを実行するときは、Veritakのメッセージを見てください。Finished Reading SDF FileとSDFを読み込んだ場合は、読み込みが成功したメッセージが出ます。読み込みに失敗した場合は、エラーにはならず遅延0でシミュレーションが行われます。

上手くSDFを読んでいないときは、シミュレータが.sdoファイルを読めていないだけなので、.sdoをシミュレータが起動しているフォルダーにコピーすれば読めるはずです。

この挙動はVeritakだけでなく、いわいる商用シミュレータでも同じ動作です。遅延込みでシミュレーションを行うと、明らかにシミュレーションの速度が落ちるのですぐにわかりますが、念のために少しだけシミュレーションしてみて、ちゃんと遅延が入っていることを確認してから大規模なシミュレーションを実行する事をお勧めします。私はそれで何回も時間を無駄にしています。

ソースコード

ソースコード一式はこちら
遅延付きでシミュレーションをするには、cyclone_atoms.vが必要です。cyclone_atoms.vは、アルテラの開発環境をインストールすると、インストールしたフォルダの/eda/sim_lib/フォルダーにあります。