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