部品:AXIストリームレジスタ続き [AXI]
前回、
「値が有効を示す"valid"ももう一本増えます。」
って終わりましたが、いきなり訂正。増えません。
いや、正確には「必要だと思って作り始めたら実はいらなかったので消した」です。
ソースコード見直したらコメント残してましたよ。えらいぞ>過去の自分。でももうちょっとわかりやすく書こうな。
それにしてもまぁ自分の記憶の当てにならないこと。こういう文章書くと見直しになります。
どうせなので増やして設計始めた所から書いてみます。構成としてはこんな感じ。未接続のレジスタの値を制御することになります。
回路3
状態数を数えます。t_valid, m_ready, m_valid, s_ready, s_validの5本なので32個です。制御対象はt_valid, m_valid, s_ready、データレジスタはt_dataとm_dataです。これらをとりあえず羅列します。あまり頭使ってません。
{t_valid, m_ready, m_valid, s_ready, s_valid} -> {tv,mr,mv,sr,sv}
{t_data, m_data, s_data} -> {td,md,sd}
しばらく眺めます。…この表をそのままcase文にしてもそれはそれで良いかな…無駄なロジックがあるかもしれませんが、今のシリコンからしたら微々たるものとして、もしくはコンパイラががんばるとして「完成」としても良さそうです。物を作ることが目的で最適化が必須とは限りません。さらに、全ての状態を洗い出してるので不定状態がないという安心感も。illegalの所はシミュレーションで$stopさせるとか。
ちゃんと眺めます(笑)
・出力側を見ると、常にt_valid = not s_readyです。これは「t_dataレジスタが埋まってたらもうデータは受け取れない」と読めば当たり前です。ですので、増やしたt_valid信号はいらないのでした。けど思考補助にはなってます。
・t_valid=0もしくはm_valid=0の時、つまりどちらかのレジスタが空いているときに、s_readyを0に(受信拒否)にする理由はありません。この状態も必要ありません(never1の部分)。
・t_valid=1かつm_valid=0の条件、m_dataが空いてるのにt_dataだけにデータが存在するという状態はあり得ないので、この項目は全部消えます(never2の部分)。
・t_valid=1かつm_valid=1、両方のレジスタが埋まってる状態でs_readyを1にするのは違反です(illegalの部分)。s_validが1になったらデータロストを起こします。同時にm_ready=1ならシフトレジスタ動作になってロストしませんが、そのためにはs_readyを組み合わせ回路にする必要があります。
表の不要部分を削除します。
不要とした部分の一つが残ってますが、これをリセット状態とします。
「受信待ち」をリセット状態としても良さそうですが、m_validはともかく、s_readyが1になるのは問題です。全てのモジュールが同時にリセット解除されるという保証が無く、こちらのリセット解除の前に前段のリセットが解除されvalidが1にされた場合、データが失われます。s_readyはリセット中は0で解除後に1にします。
ほか、網掛けの「受信待ち」「空き待ち」は信号が動かないので記述する必要はありません。結果記述する条件は7個となります。
これをHDL化。
ただし、この記述にするときはちゃんとコメントや文章残しましょう。でないと後から見ると「ナニコレ?」状態になります。if~then~elseで書き直せばソースでもある程度意味がわかる記述になりますが、やっぱりコメントは残しましょう。
詠み人知らずの格言:昨日の自分は別の人。
追記
・c_rstもcase文の条件に入れてしまってます。普通の書き方(if (c_rst) ~ else case ~)にしてもリソース、速度ともに変わらなかったので(ISE S6でテスト)そのままにしてます。条件によっては変わるかも。
・「m_data <= s_data;」の記述を動作に関係ない所(例えば5'b01110のライン)に書くと、データラッチ条件のデコードビットが減って回路が小さく速くなる可能性があります。S6では変わりませんでした。
合成結果見たところ、がっつり最適化してくれてるようです。ありがたや~
追記その2
この回路、意外と入力のファンアウトが多いです。それが原因の問題には今のところ当たったことは無いですが、もし当たったら厄介そうです。
入力もレジスタ化するのは結構難儀なので、当たったときに考えようかと…(笑)
「値が有効を示す"valid"ももう一本増えます。」
って終わりましたが、いきなり訂正。増えません。
いや、正確には「必要だと思って作り始めたら実はいらなかったので消した」です。
ソースコード見直したらコメント残してましたよ。えらいぞ>過去の自分。でももうちょっとわかりやすく書こうな。
それにしてもまぁ自分の記憶の当てにならないこと。こういう文章書くと見直しになります。
どうせなので増やして設計始めた所から書いてみます。構成としてはこんな感じ。未接続のレジスタの値を制御することになります。
回路3
状態数を数えます。t_valid, m_ready, m_valid, s_ready, s_validの5本なので32個です。制御対象はt_valid, m_valid, s_ready、データレジスタはt_dataとm_dataです。これらをとりあえず羅列します。あまり頭使ってません。
{t_valid, m_ready, m_valid, s_ready, s_valid} -> {tv,mr,mv,sr,sv}
{t_data, m_data, s_data} -> {td,md,sd}
tv | mr | mv | sr | sv | tv | mv | sr | td | md | ||
---|---|---|---|---|---|---|---|---|---|---|---|
0 | x | 0 | 0 | 0 | 0 | 0 | 1 | never1 | |||
0 | x | 0 | 0 | 1 | 0 | 0 | 1 | never1 | |||
0 | x | 0 | 1 | 0 | 0 | 0 | 1 | 受信待ち | |||
0 | x | 0 | 1 | 1 | 0 | 1 | 1 | sd | m_data受信 | ||
0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | never1 | |||
0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | never1 | |||
0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 受信待ち | |||
0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | sd | t_data受信。これ以上は受け取れない | ||
0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | never1 | |||
0 | 1 | 1 | 0 | 1 | 0 | 0 | 1 | never1 | |||
0 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | m_data送信。空になる | |||
0 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | sd | m_data送信と同時に受信 | ||
1 | x | 0 | 0 | 0 | 0 | 1 | 1 | td | never12 | ||
1 | x | 0 | 0 | 1 | 0 | 1 | 1 | td | never12 | ||
1 | x | 0 | 1 | 0 | 0 | 1 | 1 | td | never2 | ||
1 | x | 0 | 1 | 1 | 1 | 1 | 0 | sd | td | never2 | |
1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 空き待ち | |||
1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 空き待ち | |||
1 | 0 | 1 | 1 | 0 | illegal | ||||||
1 | 0 | 1 | 1 | 1 | illegal | ||||||
1 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | td | m_data送信。t_data送信準備 | ||
1 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | td | m_data送信。t_data送信準備 | ||
1 | 1 | 1 | 1 | 0 | illegal | ||||||
1 | 1 | 1 | 1 | 1 | illegal |
しばらく眺めます。…この表をそのままcase文にしてもそれはそれで良いかな…無駄なロジックがあるかもしれませんが、今のシリコンからしたら微々たるものとして、もしくはコンパイラががんばるとして「完成」としても良さそうです。物を作ることが目的で最適化が必須とは限りません。さらに、全ての状態を洗い出してるので不定状態がないという安心感も。illegalの所はシミュレーションで$stopさせるとか。
ちゃんと眺めます(笑)
・出力側を見ると、常にt_valid = not s_readyです。これは「t_dataレジスタが埋まってたらもうデータは受け取れない」と読めば当たり前です。ですので、増やしたt_valid信号はいらないのでした。けど思考補助にはなってます。
・t_valid=0もしくはm_valid=0の時、つまりどちらかのレジスタが空いているときに、s_readyを0に(受信拒否)にする理由はありません。この状態も必要ありません(never1の部分)。
・t_valid=1かつm_valid=0の条件、m_dataが空いてるのにt_dataだけにデータが存在するという状態はあり得ないので、この項目は全部消えます(never2の部分)。
・t_valid=1かつm_valid=1、両方のレジスタが埋まってる状態でs_readyを1にするのは違反です(illegalの部分)。s_validが1になったらデータロストを起こします。同時にm_ready=1ならシフトレジスタ動作になってロストしませんが、そのためにはs_readyを組み合わせ回路にする必要があります。
表の不要部分を削除します。
mr | mv | sr | sv | mv | sr | td | md | ||
---|---|---|---|---|---|---|---|---|---|
x | 0 | 0 | x | 0 | 1 | リセット状態 | |||
x | 0 | 1 | 0 | 0 | 1 | 受信待ち | |||
x | 0 | 1 | 1 | 1 | 1 | sd | m_data受信 | ||
0 | 1 | 1 | 0 | 1 | 1 | 受信待ち | |||
0 | 1 | 1 | 1 | 1 | 0 | sd | t_data受信。これ以上は受け取れない | ||
1 | 1 | 1 | 0 | 0 | 1 | m_data送信。空になる | |||
1 | 1 | 1 | 1 | 1 | 1 | sd | m_data送信と同時に受信 | ||
0 | 1 | 0 | 0 | 1 | 0 | 空き待ち | |||
0 | 1 | 0 | 1 | 1 | 0 | 空き待ち | |||
1 | 1 | 0 | 0 | 1 | 1 | td | m_data送信。t_data送信準備 | ||
1 | 1 | 0 | 1 | 1 | 1 | td | m_data送信。t_data送信準備 |
不要とした部分の一つが残ってますが、これをリセット状態とします。
「受信待ち」をリセット状態としても良さそうですが、m_validはともかく、s_readyが1になるのは問題です。全てのモジュールが同時にリセット解除されるという保証が無く、こちらのリセット解除の前に前段のリセットが解除されvalidが1にされた場合、データが失われます。s_readyはリセット中は0で解除後に1にします。
ほか、網掛けの「受信待ち」「空き待ち」は信号が動かないので記述する必要はありません。結果記述する条件は7個となります。
これをHDL化。
module axis_slice #( parameter dw = 0 // Data Width ) ( // common input wire c_clk, // clock input wire c_rst, // reset // stream-in, sink, slave output wire s_ready, // ready input wire s_valid, // valid input wire [dw-1:0] s_data , // data // stream-out, source, master input wire m_ready, // ready output wire m_valid, // valid output reg [dw-1:0] m_data // data ); reg [dw-1:0] t_data; reg [2:1] mvsr; assign {m_valid,s_ready} = mvsr; always @(posedge c_clk) begin casex ({c_rst,m_ready,m_valid,s_ready,s_valid}) 5'b1xxxx : begin mvsr <= 2'b00; end 5'b0x00x : begin mvsr <= 2'b01; end 5'b0x011 : begin mvsr <= 2'b11; m_data <= s_data; end 5'b00111 : begin mvsr <= 2'b10; t_data <= s_data; end 5'b01110 : begin mvsr <= 2'b01; end 5'b01111 : begin mvsr <= 2'b11; m_data <= s_data; end 5'b0110x : begin mvsr <= 2'b11; m_data <= t_data; end endcase end endmodule表をそのままcaseにしただけ。
ただし、この記述にするときはちゃんとコメントや文章残しましょう。でないと後から見ると「ナニコレ?」状態になります。if~then~elseで書き直せばソースでもある程度意味がわかる記述になりますが、やっぱりコメントは残しましょう。
詠み人知らずの格言:昨日の自分は別の人。
追記
・c_rstもcase文の条件に入れてしまってます。普通の書き方(if (c_rst) ~ else case ~)にしてもリソース、速度ともに変わらなかったので(ISE S6でテスト)そのままにしてます。条件によっては変わるかも。
・「m_data <= s_data;」の記述を動作に関係ない所(例えば5'b01110のライン)に書くと、データラッチ条件のデコードビットが減って回路が小さく速くなる可能性があります。S6では変わりませんでした。
合成結果見たところ、がっつり最適化してくれてるようです。ありがたや~
追記その2
この回路、意外と入力のファンアウトが多いです。それが原因の問題には今のところ当たったことは無いですが、もし当たったら厄介そうです。
入力もレジスタ化するのは結構難儀なので、当たったときに考えようかと…(笑)