FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

common_cells リポジトリに含まれる stream_モジュールの構成分析 (6. ストリーム・インタフェースの制御・フィルタリングモジュール)

stream_filter.sv

ストリームのドロップを制御するシンプルなフィルタモジュールである。 drop_iが1の場合、下流に関係なく上流にreadyをアサートし、validを下流へ伝播しない。

// Stream filter: If `drop_i` is `1`, signal `ready` to the upstream regardless of the downstream,
// and do not propagate `valid` downstream.  Otherwise, connect upstream to downstream.
module stream_filter (
    input  logic valid_i,
    output logic ready_o,

    input  logic drop_i,

    output logic valid_o,
    input  logic ready_i
);

    assign valid_o = drop_i ? 1'b0 : valid_i;
    assign ready_o = drop_i ? 1'b1 : ready_i;

endmodule

stream_throttle.sv

ストリームのoutstanding転送数を制限するモジュールである。 クレジットカウンタを使用し、最大outstanding転送数をコンパイル時に設定し、実際のoutstanding転送数をランタイムで設定できる。

/// Throttles a ready valid handshaked bus. The maximum number of outstanding transfers have to
/// be set as a compile-time parameter, whereas the number of outstanding transfers can be set
/// during runtime. This module assumes either in-order processing of the requests or
/// indistinguishability of the request/responses.
module stream_throttle #(
    /// The maximum amount of allowable outstanding requests
    parameter int unsigned MaxNumPending = 1,
    /// The width of the credit counter (*DO NOT OVERWRITE*)
    parameter int unsigned CntWidth = cf_math_pkg::idx_width(MaxNumPending),
    /// The type of the credit counter (*DO NOT OVERWRITE*)
    parameter type credit_t = logic [CntWidth-1:0]
) (
    /// Clock
    input  logic clk_i,
    /// Asynchronous reset, active low
    input  logic rst_ni,

    /// Request valid in
    input  logic    req_valid_i,
    /// Request valid out
    output logic    req_valid_o,
    /// Request ready in
    input  logic    req_ready_i,
    /// Request ready out
    output logic    req_ready_o,

    /// Response valid in
    input  logic    rsp_valid_i,
    /// Response ready in
    input  logic    rsp_ready_i,

    /// Amount of credit (number of outstanding transfers)
    input  credit_t credit_i
);

    // we use a credit counter to keep track of how many transfers are pending at any point in
    // time. Valid is passed-through if there is credit.
    credit_t credit_d, credit_q;

    // we have credit available
    logic credit_available;

    // implement the counter. If credit is available let the valid pass, else block it. Increment
    // the counter once a request happens, decrement once a response arrives. Assumes in-order
    // responses.
    always_comb begin : proc_credit_counter

        // default: keep state
        credit_d = credit_q;

        // on valid outgoing request: count up
        if (req_ready_o & req_valid_o) begin
            credit_d = credit_d + 'd1;
        end

        // on valid response: count down
        if (rsp_valid_i & rsp_ready_i) begin
            credit_d = credit_d - 'd1;
        end
    end

    // credit is available
    assign credit_available = credit_q <= (credit_i - 'd1);

    // a request id passed on as valid if the input is valid and we have credit.
    assign req_valid_o = req_valid_i & credit_available;

    // a request id passed on as ready if the input is ready and we have credit.
    assign req_ready_o = req_ready_i & credit_available;

    // state
    `FF(credit_q, credit_d, '0, clk_i, rst_ni)

endmodule : stream_throttle

リクエストが転送されるとカウンタをインクリメントし、レスポンスが返るとデクリメントする。クレジットが利用可能な場合のみ、リクエストが通過する。

stream_delay.sv

ストリームに固定遅延またはランダム遅延を追加するモジュールである。 テストベンチでの動作確認やタイミング調整に使用される。

// Author: Florian Zaruba, zarubaf@iis.ee.ethz.ch
// Description: Delay (or randomize) AXI-like handshaking

module stream_delay #(
    parameter bit   StallRandom = 0,
    parameter int   FixedDelay  = 1,
    parameter type  payload_t  = logic,
    parameter logic [15:0] Seed = '0
)(
    input  logic     clk_i,
    input  logic     rst_ni,

    input  payload_t payload_i,
    output logic     ready_o,
    input  logic     valid_i,

    output payload_t payload_o,
    input  logic     ready_i,
    output logic     valid_o
);

    if (FixedDelay == 0 && !StallRandom) begin : gen_pass_through
        assign ready_o = ready_i;
        assign valid_o = valid_i;
        assign payload_o = payload_i;
    end else begin : gen_delay

        localparam int unsigned CounterBits = 32;

        typedef enum logic [1:0] {
            Idle, Valid, Ready
        } state_e;

        state_e state_d, state_q;

        logic       load;
        logic [CounterBits-1:0] count_out;
        logic       en;

        logic [CounterBits-1:0] counter_load;

        assign payload_o = payload_i;

        always_comb begin
            state_d = state_q;
            valid_o = 1'b0;
            ready_o = 1'b0;
            load    = 1'b0;
            en      = 1'b0;

            unique case (state_q)
                Idle: begin
                    if (valid_i) begin
                        load = 1'b1;
                        state_d = Valid;
                        // Just one cycle delay
                        if (FixedDelay == 1 || (StallRandom && counter_load == 1)) begin
                            state_d = Ready;
                        end

                        if (StallRandom && counter_load == 0) begin
                            valid_o = 1'b1;
                            ready_o = ready_i;
                            if (ready_i) state_d = Idle;
                            else state_d = Ready;
                        end
                    end
                end
                Valid: begin
                    en = 1'b1;
                    if (count_out == 0) begin
                        state_d = Ready;
                    end
                end

                Ready: begin
                    valid_o = 1'b1;
                    ready_o = ready_i;
                    if (ready_i) state_d = Idle;
                end
                default : /* default */;
            endcase

        end

        if (StallRandom) begin : gen_random_stall
            lfsr_16bit #(
              .WIDTH ( 16   ),
              .SEED  ( Seed )
            ) i_lfsr_16bit (
              .clk_i          ( clk_i        ),
              .rst_ni         ( rst_ni       ),
              .en_i           ( load         ),
              .refill_way_oh  (              ),
              .refill_way_bin ( counter_load )
            );
        end else begin : gen_fixed_delay
            assign counter_load = FixedDelay;
        end

        counter #(
            .WIDTH      ( CounterBits )
        ) i_counter (
            .clk_i      ( clk_i        ),
            .rst_ni     ( rst_ni       ),
            .clear_i    ( 1'b0         ),
            .en_i       ( en           ),
            .load_i     ( load         ),
            .down_i     ( 1'b1         ),
            .d_i        ( counter_load ),
            .q_o        ( count_out    ),
            .overflow_o (              )
        );

        always_ff @(posedge clk_i or negedge rst_ni) begin
            if (~rst_ni) begin
                state_q <= Idle;
            end else begin
                state_q <= state_d;
            end
        end
    end

endmodule

固定遅延モードでは指定されたサイクル数だけ遅延させ、ランダム遅延モードではLFSRを使用してランダムな遅延を生成する。