![]() |
13 |
BSVの設計トライアル (5) |
![]() |
サウンドFSMの作成(3)
FORMAT機能、DATA機能からコールされるREADCOUNT共通シーケンス及び、そこからコールされるREADMEM共通シーケンスを解説します。
// input: romaddr // output: (romaddr,...,romaddr+3) => dcount; // romaddr + 4 => romaddr; // rule ruleREADCOUNT (state.func == READCOUNT); rule ruleS0 (state.step == S0); state.step <= S1; ret2 <= ret; // push to stack i <= 3; workd <= 0; endrule rule ruleS1 (state.step == S1); state <= State_t {cat:state.cat, func:READMEM, step:S0}; ret <= State_t {cat:state.cat, func:READCOUNT, step:S2}; worka <= romaddr + i; endrule rule ruleS2 (state.step == S2); if (i == 0) begin state <= ret2; dcount <= workd<<8 | extend(romdata); romaddr <= romaddr + 4; end else begin state.step <= S1; workd <= workd<<8 | extend(romdata); i <= i - 1; end endrule endrule // READCOUNT
図示すると、図238.1のようなステート遷移となり、リトルエンディアンで格納されている4バイトの数値を1バイトずつ4回取り出し、dcountにまとめる機能を持ちます。

次にREADMEMはROMから1バイト読み出す共通シーケンスです。当初はwireを用いても階層の上り下りでレイテンシがかかり、7サイクルとなりましたが、後述のmkConnectionを用いたことにより、RTLと同様の3サイクルの設計とすることができました。
上記のREADCOUNTから呼ばれる際はサイクル数は無関係ですが、サウンド再生中は正しいスループットで読み出す必要があるため、過去記事にもあるように、コール元が1サイクルとコール先(READMEM)が3サイクルの4サイクルで1バイトを読み出す前提で、FSMのクロック周波数=176.4KHzを決めています。
// READ MEM // input: worka // output: romdata; // rule ruleREADMEM (state.func == READMEM); rule ruleS0 (state.step == S0); addr <= worka; state.step <= S1; endrule rule ruleS1 (state.step == S1); // ROM address phase state.step <= S2; endrule rule ruleS2 (state.step == S2); // ROM data phase data <= romdata; state <= ret; endrule endrule // READMEM