ステートの決め方
極端に言うと小さなカウンタでもFPGA全体でもステートマシンと見なせるので、どこをステートマシンとして区切るかは設計者のセンスによってしまうが、ステートを決める際の指針になりそうなものを考えてみる。
◇
ステートの決め方の原則は、制御信号を決める記憶素子(FF)はすべてステート、入力信号は遷移条件と分けることだが、ステートとは別にカウンタとかフラグを設けてそれを遷移条件とした方がよいこともある。
例1)単にNクロック待つ処理は、ステート内でカウンタを回して待つとよい。
Nが小さければ1クロックに1ステート割り当てるのが簡単であるが
Nが長ければ1つのステート内でカウンタを回して既定回数になったら次に進むようにした方が見通しがよい
◇◇
例2) 複数の要求元から要求パルス受けて逐次処理する場合は、パルスをフラグで受けてそれを遷移条件にするとよい。
簡単のため、次のような2つのイベント間の排他制御を考える:
・要求元A,Bから非同期に要求パルス(reqa,reqb)が来る
・要求パルスが来たら要求元に応じて処理Aか処理Bを行う
・要求元は自分の処理が終わるまで次の要求パルスは出さない前提とする
まず、要求パルスが来たことを覚えておくフラグ(flga,flgb)を設ける。
if(SA2) flga<=0 else if(reqa) flga<=1 if(SB1) flga<=0 else if(reqb) flgb<=1 |
このフラグを遷移条件として処理を開始すればよい。フラグは処理の最後にクリアする。
こうすれば、一方の処理中に他方の要求パルスが来ても取りこぼさないこと、また1つのステートマシンで処理しているので排他的であることも明らかである。
処理A,Bが同じ場合は(1つのリソースを使うなど)、A,Bの区別をステートとは別にIDとして設けてもよい。
この例のように、複数の非同期イベントを排他制御するケースは必ずステートマシンで書いて、ソースコードレビューで検証するのがよい。なぜなら、こういう時間軸方向の組合せはシミュレーションによる検証が難しく、力ずくで、イベント間の間隔を1クロックずつずらしてシミュレーションするとしても、イベント数が多くなると無理だからである。
◇◇◇
ちなみに、上記の例でフラグをステートに含めてしまうと、
IDLEは、(flga,flgb)=(0,0),(1,0),(0,1)の3状態
SA0からSA2までは、flgb=0,1の2状態
SB0からSB1までは、flga=0,1の2状態
と2倍以上の状態数に分かれてしまい、見通しが悪くなるのでよくない。