火曜日, 8月 28, 2007

8歳から学べるFPGA?

EETIMES Japanから

8歳の天才児がFPGAを使いこなす

Actelなら簡単!と言いたい所だろうか?

でも、Actelのサイトに行ってみると資料はほとんど英語ですね。
最低、ネイティブの8歳児程度の英語力は必要なのかも。。。

FPGAはALTERAかXilinxしか使ったことはありませんが
Actelは独自のFPGAを出しているので少し興味はある。

ADCやFlashが内臓だったり。
CPUコアもARMだし。

その8歳児に送ったという基板付きの開発キット、
うちにも送ってくれないかなぁ。

月曜日, 8月 27, 2007

ステートマシン その5

前回の続き。

それでは、前回作成したRTL記述で正しく動作するかどうかシミュレーションをやってみましょう。

たとえターゲットがFPGAであったとしても、この程度の規模のステートマシンであれば
少なくともRTLシミュレーションで全ての状態と全ての遷移条件についてはカバーしておきたいものです。

今回の場合は次の4つのステートを通過すること。

・ST_DoorClose
・ST_Opening
・ST_DoorOpen
・ST_Closing

そして、次の7つの遷移(同じステートにとどまるものも含めるとさらに+4)が行なわれることです。
・ST_DoorClose -> ST_Opening
・ST_Opening -> ST_DoorOpen
・ST_DoorOpen -> ST_Closing (閉ボタン)
・ST_DoorOpen -> ST_Closing (5秒経過)
・ST_Closing -> ST_DoorClose
・ST_Opening -> ST_Closing
・ST_Closing-> ST_Opening

以上の動作を確認するためのテストベンチを作成しました。
主要な部分を次に示します。


initial begin
// Initialize Inputs
reset = 1'b1;
buttonOpen = ~PUSHED;
buttonClose = ~PUSHED;

// Wait 100 us for global reset to finish
#1;
reset <= 1'b0;
// Add stimulus here
#100;
pushOpenButton();
wait(doorPosition==DOOR_POS_MAX);
#100;
pushCloseButton();
wait(doorPosition==DOOR_POS_MIN);
#100;
pushOpenButton();
#20000; // 2.0sec
pushCloseButton();
#10000; // 1.0sec
pushOpenButton();
wait(doorPosition==DOOR_POS_MAX);
wait(doorPosition==DOOR_POS_MIN);
#100;
$finish(2);
end


StateMachineSampleTB.v←完全なコードはこちら。

StateMachine.zip←RTLを含めた検証環境一式のZIPファイル。

タイムユニットは100usです。
ドアが完全に閉まった状態から完全に開いた状態(またはその逆)までには約4秒かかるようにしています。

シミュレーションの流れは次のとおりです。

・シミュレーション開始

・初期状態でドアは閉まっている。

・"開"ボタンを押して、ドアが完全に開くまで待つ。

・ドアが完全に開いたら、"閉"ボタンを押してドアが完全に閉まるまで待つ。
↓(ここまででひとまず全てのステートは通過)

・もう一度"開"ボタンを押す。

・ドアが開いている途中で"閉"ボタンを押す。

・ドアが閉まっている途中で"開"ボタンを押す。

・ドアが完全に開くまで待つ。
↓(5秒経過して自動で閉まりだす)

・ドアが完全に閉まるまで待つ。

・シミュレーション終了

シミュレーションの出力結果は次のようになりました。

# State = ST_DoorClose @ 0
# Open button pushed.
# State = ST_Opening @ 115
# State = ST_DoorOpen @ 40815
# Close button pushed.
# State = ST_Closing @ 40915
# State = ST_DoorClose @ 81615
# Open button pushed.
# State = ST_Opening @ 81715
# Close button pushed.
# State = ST_Closing @ 101725
# Open button pushed.
# State = ST_Opening @ 111735
# State = ST_DoorOpen @ 142575
# State = ST_Closing @ 192585
# State = ST_DoorClose @ 233295


一応、波形も載せておきましょう。


ST_DoorClose -> ST_Opening


ST_Opening -> ST_DoorOpen -> ST_Closing (閉ボタン)


ST_Closing -> ST_DoorClose


ST_Opening -> ST_Closing


ST_Closing-> ST_Opening


ST_DoorOpen -> ST_Closing (5秒経過)


無事動いているようですね。
今回は省略していますが、これに加えて遷移条件が重なった場合に(今回ではST_OpeningやST_Closingから他のステートに遷移する場合)期待したとおりの動作となっているかどうかを確認することも重要です。

この程度のモジュールの単体試験用にちゃんとしたテストベンチを作る必要はあるのか?と聞かれるとなかなか自分もできていない場合が多いので偉そうなことは言えませんが、小さい単位だからこそ少し手間をかけてでも一度ちゃんとしたものを作っておけば、RTLに変更を加えた場合に、論理合成をかける前や後工程に渡す前、または自分が設計するより大きな単位のモジュールに組み込む前に、サッとシミュレーションを流すだけでかなりリスクを抑えることができると思います。

話はそれますが、ソフトのプログラミング言語に比べてHDLの参考になる記述をWebなどで探すのは大変ですよね。さらにテストベンチ用のシミュレーション記述となるとRTL記述に比べてさらに少ない。
結局自分もかなり自己流の記述になっていると思うので、そのあたりを考慮に入れてコードを読んでください。

とりあえず今回でステートマシン記述については終わり。

ステートマシンに関してはもっと書いてみたい事もあるのですがそれはまたの機会に。

木曜日, 8月 23, 2007

FPGAが論理合成しなくても動く!?

なひたふさんのところで面白い記事を発見。

FPGAが論理合成しなくても動く


ようはFPGAをFPGAとして使ってないのでなんでもアリ。
ボードのデバッグなどにはかなり使えそうですよね。

JTAGのバウンダリスキャンに対応してたら、FPGAじゃなくても良いのだろうから
いっそのことJTAGのバウンダリスキャンのみで端子を制御する安価なチップを作ってしまってもいいかもしれない。

「そんなもん、遅すぎて使えねーだろ!」
という意見もあるかもしれませんが、低速でもI/Oポートを自由に制御できると便利な分野もあると思うんですよね。

FA機器の制御とかはどうかな?
ちょっと環境が厳しいかもしれないけど。

何より、簡単なスクリプトのみでハードウェアを制御できるというのは何かしら可能性を感じます。

FPGAにこだわる必要はまったく無い。

月曜日, 8月 20, 2007

ステートマシン その4

前回の続き。

私がステートマシンを記述する場合、大きく分けて2通りの方法があります。

1つは出力レジスタが無い記述で、もう一つは出力レジスタ付きの記述です。

どのような感じか、ちょっと書いてみると

出力レジスタ無しの場合は、

always @(posedge clock or posedge reset) begin
if (reset)
state <= INITIAL_STATE;
else
state <= next_state;
end

always @* begin
next_state = state;
case(state)

INITIAL_STATE: begin
output_signal = 1'b0;
if (input_signal==1'b1) begin
output_signal = 1'b1;
next_state = SECOND_STATE;
end
end

SECOND_STATE: begin
output_signal = 1'b1;
if (input_signal==1'b0)
next_state = LAST_STATE;
end

LAST_STATE: begin
output_signal = 1'b1;
next_state = INITIAL_STATE;
end

default: begin // Recovery from illegal state
next_state = INITIAL_STATE;
output_signal = 1'b0;
end

endcase
end


出力レジスタ付きの場合は、

always @(posedge clock or posedge reset) begin
if (reset) begin
state <= INITIAL_STATE;
output_signal <= 1'b0;
end
else begin
case(state)

INITIAL_STATE: begin
output_signal <= 1'b0;
if (input_signal==1'b1) begin
output_signal <= 1'b1;
state <= SECOND_STATE;
end
end

SECOND_STATE: begin
output_signal <= 1'b1;
if (input_signal==1'b0)
state <= LAST_STATE;
end

LAST_STATE: begin
output_signal <= 1'b1;
state <= INITIAL_STATE;
end

default: begin // Recovery from illegal state
state <= INITIAL_STATE;
output_signal <= 1'b0;
end

endcase // case(state)
end
end


注意すべき点としては、出力レジスタがある場合と無い場合で出力のタイミングが若干異なるところです。
上記の例で言えば、INITIAL_STATEからSECOND_STATEに移る際のoutput_signalの変化点です。
出力レジスタが無い場合はINITIAL_STATEの最後の1サイクルはoutput_signal=1'b1ですが、出力レジスタ有りの場合は、INITIAL_STATEの最後の1サイクルはoutput_signla=1'b0で、SECOND_STATEの1サイクル目にはじめてoutput_signal=1'b1となります。

また、出力レジスタ無しの場合では出力のハザードにも注意が必要です。
上記の例ではSECOND_STATE,LAST_STATEともに出力output_signal=1'b1なのでコードからはその間のステートの遷移中に出力に変化はないように見えますが、例えば各ステートが次のようにエンコードされていた場合、

INITIAL_STATE=2'b00, SECOND_STATE=2'b01, LAST_STATE=2'b10

実際はSECOND_STATEからLAST_STATEに移る際の信号の変化の過程で

2'b10 -> 2'b00 -> 2'b10

となって、一瞬の間SECOND_STATEでもLAST_STATEでもない状態になり、その瞬間の出力がヒゲのように出てしまいます。

出力レジスタ付きの場合はこのような心配はありません。

今回は出力レジスタ付きの記述でステートマシンを書いてみました。
主要な部分を抜き出すと、次のようになります。

/*
* State Machine
*/
always @(posedge clock or posedge reset) begin
if (reset) begin
state <= ST_DoorClose;
doorControl <= DOOR_STOP;
end
else begin
case(state)

ST_DoorClose: begin
doorControl <= DOOR_STOP;
if (buttonOpen==PUSHED)
state <= ST_Opening;
end

ST_Opening: begin
doorControl <= DOOR_OPEN;
if (buttonClose==PUSHED)
state <= ST_Closing;
else if (doorPosition==DOOR_POS_MAX)
state <= ST_DoorOpen;
end

ST_DoorOpen: begin
doorControl <= DOOR_STOP;
if ((buttonClose==PUSHED)||
(openCounter==TIME_LIMIT))
state <= ST_Closing;
end

ST_Closing: begin
doorControl <= DOOR_CLOSE;
if (buttonOpen==PUSHED)
state <= ST_Opening;
else if (doorPosition==DOOR_POS_MIN)
state <= ST_DoorClose;
end

default: begin
doorControl <= DOOR_STOP;
end

endcase
end
end

StateMachineSample.v←完全なコードはこちら

前回の最後の状態遷移図からこのコードに落とすのはそれほど難しくないですよね。

ちなみにこのコードではクロック入力を1KHzと想定しています。
現在、実際の設計でそんなに遅いクロックを使うことはまず無いと思いますが
練習用として大目に見てください。

次回はこのコード用にテストベンチを書いて、シミュレーションをやってみたいと思います。

金曜日, 8月 17, 2007

機能検証関係の動きが活発

米XilinxがEDA大手3社と組み,大規模FPGAの機能検証で新フローを構築へ

米Cadenceと米Mentor,SystemVerilogベースの機能検証手法を統一へ

共に興味深い。

こちらの言葉を借りれば、FPGA業界もいよいよVerification3.0に突入か?

そして、オープン化の流れもできつつあるかもしれない。

しかしまだ、アサーションやカバレッジ機能を利用できるツールは普通に高い。

FPGAの統合環境である程度使える物が出てきると一気に裾野が広がって、ハードウェア設計・検証の分野に何かしらのブレークスルーが起きるような気がするのだけれども。

でなければ、1つのチップとしてのLSIの大規模化が収束していくか。

それを設計・検証できるインフラがないと、やれったってできませんからね。
そして大きくした分、かかったコストをペイできるのかっていうことになってしまう。

PSPとDS、PS3とWiiの状況を見るとなんでも1つで大量に高速に処理できればいいという分けではなさそうだし。

使う人または使われ方のバリエーションを増やすって考え方も重要ですねー。

水曜日, 8月 08, 2007

ステートマシン その3

前回、とりあえずの状態遷移図を描いてみました。

この状態遷移図では、仕様の中の次の機能が表されていません。

・ドアが完全に開いた状態で、5秒間"閉"ボタンが押されなければドアを閉じる

どうやって実現しますか?
多分、カウンタを用意する必要がありますね。

あと、仕様に明記されていることではありませんが

・ドアが開いている最中に"閉"ボタンを押した場合

及び

・ドアが閉まっている最中に"開"ボタンを押した場合

も考えておいた方が良さそうです。
そういうシチュエーションはよくありますよね。

隠れた仕様というものは設計を進めるうちに意外に出てくるものです。
いきなりコーディングをはじめるとそういったものにかき回されて、いつの間にかスパゲッティにということになりかねません。

特にHDLはソフトのプログラミング言語と違って必ずしも上から下へ流れていくわけではないので、ある程度静的な構造が見えていないと全体が把握しづらくなります。

それでは、仕様を満足する状態遷移図を見てみましょう。



ドア状態カウンタは外部に置いても良いと思いますが、今回は同じモジュールの中に置くことにします。

ではこの状態遷移図をコーディングの1歩手前まで持っていこうと思います。
とはいってもやることは単純で、日本語のままだと変数名として使えないのでそれっぽい英語に変換して、代入や条件判断を記号に変えるだけです。

次のようになります。



ここまでくれば、ほぼそのままコーディングに持っていけるはずです。

それでは次回、これを元にVerilogでステートマシンをコーディングしてみたいと思います。

木曜日, 8月 02, 2007

ステートマシン その2

ステートマシンの題材として、
エレベータのドアの制御のようなものを考えてみようと思います。

仕様は次のとおり。
実際のエレベータのドアがどのように行なわれているのか全く知らないので
以下の仕様は想像です。なので、かなり変かもしれませんがその辺は大目に。

[エレベータ ドアの制御モジュールの仕様]
・"開"ボタンと"閉"ボタンの入力
・"開"ボタンでドアが開き、"閉"ボタンでドアが閉まる
・外部にドア制御信号を出力
・ドア制御のバリエーションは「開ける」、「閉める」、「停止」の3つ
・ドア位置情報の入力
・ドア位置情報は完全に閉まった状態を"Min"、完全に開いた状態を"Max"とする
・ドアが完全に開いた状態で、5秒間"閉"ボタンが押されなければドアを閉じる


実際のモジュールの仕様であれば信号名やタイミングなど明確になっているべきですが、今回はここから始めることにします。
現実の仕事でも曖昧な仕様が渡されて、詳細は自分で定義しなければならないことは多いと思うので。。。

まずはどういう状態があるか考えましょう。
次の4つが妥当なところでしょうか?

1.ドアが完全に閉まった状態
2.ドアが完全に開いた状態
3.ドアが開いている最中の状態
4.ドアが閉まっている最中の状態

ちょっとシナリオを書いてみると、

まずドアが閉まっている。
"開"ボタンを押すとドアが開き始める。
ドアが完全に開くとその状態でドアは停止。
"閉"ボタンを押すとドアが閉まり始める。
ドアが完全に閉まるとその状態でドアは停止。

なんとなくよさそうです。
それでは早速状態遷移図を描いてみましょう。



まだ完全というわけではありませんが、なんとなくそれらしいものができていると思います。

次回はこの状態遷移図を仕様を満足させるところまで持っていって
さらにコーディングできる1歩手前までやってみたいと思います。

このシリーズは少し長くなりそう。

ところで、普段使っていたわけではないのですが、今回の状態遷移図はJUDE Communityというツールを使ってUMLのステートチャート図で描いてみました(UMLに慣れてないので変なところがあればご指摘ください)。

個人的にはハードウェアの設計にUMLを使うのはなかなか難しいところがあるなぁと考えているのですが、ステートチャート図についてはほぼそのまま使えると思います。

逆に言うと、ステートマシンでできることはソフトでできる処理とかなりオーバーラップがあります。

実際、今回のお題のようなものであれば恐らく1チップマイコン等を使うほうが多いのではないでしょうか?

最近はコンパクトなソフトマクロCPUもあるので、下手にステートマシンを設計するよりはそういうものを使ったほうが生産性・品質の両面でお得かもしれません。

水曜日, 8月 01, 2007

ステートマシン その1

さて、今回は現在のRTLデザインにおいては欠かせないステートマシン(FSM)について書いてみようと思います。

正式には"Finite State Machine"で日本語では「有限状態機械」などと訳すのでしょうが、現場のエンジニアには単に「ステートマシン」と呼んだほうがとおりが良いと思います。

ディジタル回路でステートマシンというと、

ムーア型だのミーリ型だの

はたまた

グレイ、ジョンソン、ワンホット

だのといったキーワードが出てくると思いますが、個人的にはそういったキーワードは教科書で一度読んでおけばいいかなぁ程度に思っています。

ムーアかミーリかと悩むよりは入力を全て単一のクロックに同期させたほうが良いし、出力のハザードを考慮してステートの遷移の際のハミング距離を1に抑える努力をするよりは出力にレジスタを付けて出したほうがずっと楽な場合が多いと思うからです。

正直、ステートの宣言などは列挙型で行なって合成ツールで勝手に最適化してくれる方が自分は好きです。

最も、最近の合成ツールは勝手にやってたりするので手動で苦労してステートをエンコードしても無駄になっているかもしれませんが。。。

まあ、どうしてもパフォーマンスが達成できない場合にはそのあたりをいろいろチューニングする破目になるのかもしれませんが、生産性・検証のことを考えるとできるだけ実装に近い部分を考慮しないですむほうが良いでしょう。

では次回、具体的に(簡単な)ステートマシンの設計をやってみたいと思います。