FIFO の本質は、RAM と読み書きロジックから構成される先入先出データバッファです。RAM との違いは、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#
時系列図は以下の通りです:
データを書き込むとき、s_axis_tvalid
は高電位であり、同時にfull
は低電位で、反転後のs_axis_tready
は高電位となり、この時点でデータを書き込むことができます。
データを読み取るときも同様に、valid
とready
信号が同時に高くなったときにのみデータを読み取ることができます。
m_axis_tvalid
はfifo
のwr_en
信号に対応し、m_axis_tready
はfifo
のfull
信号の反転に対応し、s_axis_tvalid
はfifo
のempty
信号の反転に対応し、s_axis_tready
はfifo
のrd_en
に対応します。
AXIS FIFO#
Axis FIFO の IP コアインターフェースは以下の通りです:
今回は FIFO の非同期読み書きを学ぶため、independent clock
を「はい」に選択し、パケットモードを無効にします。Bd ブロック図は以下の通りです:
ここで、clk_wiz
の出力は 2 つあり、ポート 1 のクロック速度は $100MHz$、ポート 2 のクロック速度は $50MHz$ です。axis_data_source
とaxis_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$ の速度でデータを読み取ります。時系列図は以下の通りです:
最初は FIFO が満杯でないことがわかります。この時点で書き込みと読み取りは互いに干渉せず、データが継続的に書き込まれますが、すぐには読み取られません。しばらくすると FIFO のfull
信号が高くなり、対応するm_axis_tready
信号が低くなり、axis_data_source
は新しいデータを生成しなくなります。シミュレーション図は以下の通りです:
この時点で書き込みと読み取りの速度は、valid と ready 信号の有効化によって同期しています。