moerjielovecookie

Sawen_Blog

一个普通工科牲的博客网站
x
github
follow
email

FIFO

FIFO の本質は、RAM と読み書きロジックで構成された先入先出データバッファです。RAM との違いは、FIFO には外部の読み書きアドレス線がなく、順序通りに書き込み、順序通りにデータを読み出します。そのデータアドレスは内部の読み書きポインタによって自動的に増加するため、FIFO では読み書きの競合を考慮する必要がありません。
FIFO の動作するクロックドメインに応じて、同期 FIFO と非同期 FIFO に分けられます。同期 FIFO の読み取りクロックと書き込みクロックは同じクロックであり、両側のデータビット幅が異なる一時的なバッファに一般的に使用されます。非同期 FIFO の読み取りクロックと書き込みクロックは一致せず、データ信号のクロックドメインを越えた処理に一般的に使用されます。

時系列図#

同期 FIFO#

同期 fifo 読書時系列
初期状態ではempty信号は高レベルであり、この時点で FIFO は空です。この時に FIFO に対して読み取り操作を行うと、読み取ったデータは無効です。wr_enが高くなると、FIFO 内部にデータを書き込み始め、FIFO にデータが存在する場合、empty信号は低くなります。その後、同時に読み書き操作を行った場合、同期 FIFO であるため、フラグは変化しません。
書き込みのみで読み取りを行わない場合、FIFO 内に 2 つ以上のデータが存在する場合、almost emptyも低くなります。FIFO が書き込み満状態にあるとき、FIFO は一度の書き込みのみを受け入れることができ、almost fullが高くなります。最後に、読み取り操作を行わずに再度書き込み操作を行うと、full信号が高くなり、この時点で FIFO はすでに満杯であることを示します。読み取り要求を出す前に、これ以上のデータを書き込むことはできず、この時にデータを書き込むとデータが失われます。

AXIS FIFO#

image
時系列図は以下の通りです:
axisfifo.svg
データを書き込むとき、s_axis_tvalidは高レベルであり、同時にfullは低レベルで、反転するとs_axis_treadyは高レベルになります。この時にデータを書き込むことができます。
データを読み取るときも同様に、validready信号が同時に高くなるときにのみデータを読み出すことができます。
m_axis_tvalidfifowr_en信号に対応し、m_axis_treadyfifofull信号の反転に対応し、s_axis_tvalidfifoempty信号の反転に対応し、s_axis_treadyfiford_enに対応します。

AXIS FIFO#

Axis FIFO の IP コアインターフェースは以下の通りです:
|500
今回は FIFO の非同期読み書きを学ぶため、independent clockを「はい」に選択し、パケットモードを無効にします。Bd ブロック図は以下の通りです:
image
ここで、clk_wizの出力は 2 つあり、ポート 1 のクロック速度は $100MHz$、ポート 2 のクロック速度は $50MHz$ です。axis_data_sourceaxis_destのソースコードは以下の通りです:

module axis_data_source (
    input s_axis_clk,
    input s_axis_rstn,
    input m_axis_tready,
    output [7:0] m_axis_tdata,
    output m_axis_tvalid 
);

reg [7:0] cnt;

always @(posedge s_axis_clk or negedge s_axis_rstn) begin
    if(!s_axis_rstn) begin
        cnt<=0;
    end
    else begin
        if(m_axis_tready) begin
            if(cnt==255) begin
                cnt<=0;
            end
            else begin
                cnt<=cnt+1'b1;
            end
        end
    end
end
assign m_axis_tdata=cnt;
assign m_axis_tvalid=1'b1;
    
endmodule

/*FIFOデータを読み取る*/
module axis_dest (
    input s_axis_clk,
    input s_axis_tvalid,
    input [7:0] s_axis_tdata,
    output s_axis_tready
);

assign s_axis_tready=1'b1;

endmodule

ここで、data_sourceは $100MHz$ の速度で $0-0xFF$ を生成して出力し、axis_destは常に $50MHz$ の速度でデータを読み取ります。時系列図は以下の通りです:
image
最初は FIFO が満杯ではなく、この時点で書き込みと読み取りは互いに干渉しません。データが継続的に書き込まれ、すぐに読み取ることができない場合、しばらくすると FIFO のfull信号が高くなり、対応するm_axis_tready信号が低くなり、axis_data_sourceは新しいデータを生成しなくなります。シミュレーション図は以下の通りです:
image
この時、書き込みと読み取りの速度は valid と ready 信号の有効化によって同期しています。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。