Posts Issued on April 9, 2020

BSVの設計トライアル (3)

posted by sakurai on April 9, 2020 #236

サウンドFSMの作成

waveフォーマット解析とデータ供給を実行する、メインのFSMの設計を行います。このような小さいFSMであっても階層設計を行います。その理由はソフトウェアと同じで、構造化のためです。最上位ステートは図236.1のようにINIT, SOUNDの2ステートとします。基本的にINITでは外部からサウンドコードが送信されてくるのを待ち、自分のコードであればSOUNDに遷移します。サウンド出力が終了すると、またINITに戻ります。

図%%.1
図236.1 最上位ステート

フラットなFSMではステート変数を整数で持ちますが、階層FSMでは構造体で持つことにします。階層は3階層で、上位2階層が意味のある機能を示し、最下層はステップとします。次に構造体の記述を示します。

    typedef struct {
           Category_t cat;
           Function_t func;
           Step_t step;
    } State_t deriving(Bits,Eq);

上位からカテゴリー、ファンクション、ステップと名付けました。最上位のカテゴリーは先の図のように、 INIT, SOUNDの2ステートからなります。

    typedef enum { INIT, SOUND } Category_t deriving(Bits,Eq);

INITでは中間階層である機能は特になく、2ステートを持ち、LRCLKと同期させます。これはFSMクロックがLRCLKよりも速いため、LRCLKと確率的に位相が合わなくなるためです。

SOUNDでは機能としてFORMAT, DATA, PLAY, READCOUNT, READMEMの5種を持ちます。それぞれの機能は、フォーマット解析、データ長取得、演奏です。さらにそこから呼ばれる共通シーケンス(サブルーチン)として、データ長読み出し、データ1バイト読み出しが存在します。

図%%.2
図236.2 SOUND階層内ステート
第2階層であるファンクション変数の定義です。
    typedef enum { FORMAT, DATA, PLAY, READCOUNT, READMEM } Function_t deriving(Bits,Eq);

同階層内にコール関係があり、DATAからREADCOUNTをコールします。さらにREADCOUNTからREADMEMをコールするので、リターンスタックは2段必要です。

最下層のステップの名前には特に意味が無く、シーケンシャルにステートを進めるだけです。シーケンシャルになる理由は、フォーマット解析やROMのデータ待ちなど様々です。

    typedef enum { S0, S1, S2, S3, S4, S5, S6 } Step_t deriving(Bits,Eq);

以上は宣言であり、実際のインスタンシエーションは以下のようにモジュール内部で行います。

    Reg#(State_t) state <- mkReg(State_t{cat:INIT,func:?,step:S0}),
         ret <- mkRegU,
         ret2 <- mkRegU;

ステート構造体stateと、さらに同じ構造を持つ2本のリターンレジスタret, ret2をインスタンスしています。


左矢前のブログ 次のブログ右矢