62 / 63 · 概念
レジスタインターフェースと副作用の発生時点
アドレス・バイト書き込み・応答停止を定義し、一つの要求が正確に一度の状態変更につながるようにする。
レッスンは無料で読めます。受講登録すると進捗を保存できます。
「レジスタへ書く」という動作を定義する
前提知識:アドレスデコーダデコーダ 二進コードに対応する出力線を有効にする回路です。enable があれば、無効時にすべての出力を 0 にできます。 詳しく見る、ready/validハンドシェイク 送信側の valid と受信側の ready が同じエッジでともに 1 のときに転送を確定する取り決めです。待機中のデータ保持規則も含みます。 詳しく見る、enable と状態更新の優先順位。
設定レジスタレジスタ 複数ビットの状態を記憶する回路です。このコースの同期式レジスタは、クロックエッジで定められた入力を記憶します。 詳しく見るを外部の制御器へ接続するとき、アドレスが一致するかの確認だけでは足りない。要求を受け付ける時点、応答待ちの間の保持条件、読み出し専用アドレスへ書く場合まで定義する必要がある。ここでは、同じクロックを使う簡単な単一要求・応答インターフェースを使う。
以下はバイトアドレスで、32 ビット境界に整列する。各要求に対し、成功またはエラーの応答を正確に一つ生成する。
| アドレス | 名前 | 動作 |
|---|---|---|
| 0x0 | CONFIG | 読み書き可能、byte strobe を適用 |
| 0x4 | STATUS | 読み出し専用、受け付け時点の値を返す |
| 0x8 | COMMAND | 読むと 0、byte 0 の bit 0 への書き込みで start パルス |
| その他 | 未定義 | エラー応答、状態変更なし |
応答スロットが空、または空になるエッジで受け付ける
module register_interface (
input logic clk, rst,
input logic req_valid, req_write,
output logic req_ready,
input logic [3:0] req_addr,
input logic [31:0] req_wdata,
input logic [3:0] req_wstrb,
output logic rsp_valid,
input logic rsp_ready,
output logic [31:0] rsp_rdata,
output logic rsp_error,
input logic [31:0] status_value,
output logic [31:0] config_value,
output logic start_pulse
);
assign req_ready = !rsp_valid || rsp_ready;
always_ff @(posedge clk) begin
if (rst) begin
rsp_valid <= 1'b0;
config_value <= 32'd0;
start_pulse <= 1'b0;
end else begin
start_pulse <= 1'b0;
if (req_ready) begin
rsp_valid <= req_valid;
if (req_valid) begin
rsp_rdata <= 32'd0;
rsp_error <= 1'b0;
case (req_addr)
4'h0: begin
if (req_write) begin
for (int i=0; i<4; i++)
if (req_wstrb[i])
config_value[8*i +: 8]
<= req_wdata[8*i +: 8];
end else rsp_rdata <= config_value;
end
4'h4: begin
if (req_write) rsp_error <= 1'b1;
else rsp_rdata <= status_value;
end
4'h8: begin
if (req_write)
start_pulse <= req_wstrb[0] && req_wdata[0];
end
default: rsp_error <= 1'b1;
endcase
end
end
end
end
endmodule応答が止まると req_ready=0 なので、config の書き込みや command パルスを再実行しない。受け付け済み要求の副作用はすでに発生し、応答だけが待っている場合がある。応答の遅延を見て無条件に要求を再送すると、命令が重複して実行される恐れがある。
byte strobe の意味を計算する
CONFIG が 32'h11223344 のときに、req_wdata=32'hAABBCCDD、req_wstrb=4'b0101 を書くと、byte 0 と byte 2 だけが変わる。結果は 32'h11BB33DD である。アドレスの整列、ビット位置、メモリのバイト順序はそれぞれ確認する。wstrb=0000 の書き込みは成功応答を生成するが、値は変えない。
MSBMSB 最も高い桁の重みを持つビットです。ベクトルの宣言方向でインデックスが変わるため、常に最大番号とは限りません。 詳しく見る 側から byte 3、2、1、0 の順である。strobe=0101 は byte 2 と byte 0 を選ぶので、BB と DD だけを新しく書く。strobe はデータの 1 ビット単位ではなく、バイト単位の write enable である。
- 以前の CONFIG: 11 | 22 | 33 | 44
- 書き込みデータ: AA | BB | CC | DD
- strobe 0101: 保持 | 置換 | 保持 | 置換
- 新しい CONFIG: 11 | BB | 33 | DD
状態はどの時点の値か
STATUS 読み出しの応答には、要求受け付け時点の status_value を格納する。その後、応答が停止している間に実際の status が変わっても、rsp_rdata は保持する。rsp_valid=1、rsp_ready=0 の状態で、組み合わせ出力の status をそのまま応答へ接続すると、応答内容が変わるためプロトコル違反になる。
連続したエッジで req_valid と req_ready がともに 1 なら、別々の二つの要求である。送信側は受け付け後に valid を下げるか、次の要求へ更新する。同じ要求を出し続けながら、一度だけ処理されることを期待してはならない。
検証の三つの軸
- アドレスとアクセス権:有効なアドレス、非整列アドレス、STATUS 書き込み、未定義アドレスについて、エラーと副作用を確認する。
- データ選択:4 本の strobe ビットを網羅的に検査し、無効なバイトが保持されることを確認する。
- フロー制御:応答を複数サイクル止めても応答と状態が保持されること、応答消費と次の要求受け付けが重なってもトランザクション数が一致することを確認する。
自分で考えてみましょう
req_wstrb[0]=1、req_wdata[0]=1 の COMMAND 書き込みを受け付けた後、rsp_ready=0 が 3 サイクル続く。start_pulse はその 3 サイクル繰り返すべきか。STATUS への書き込みで config_value を変更してよいか。
解説を見る
start_pulse は要求を受け付けた直後の 1 サイクルだけ 1 になり、その後は 0 になる。応答の停止は命令の再実行条件ではない。STATUS への書き込みはエラー応答を返し、config_value を含む他の状態を変更しない。応答完了前の再試行方針も、送受信側で合意する必要がある。