veryl-std 0.20.0

A modern hardware description language
Documentation

/// Asynchronous handshake
///
/// Asynchronous data transmitter based on handshake protocol.
/// Generic parameter `S` is a module name of synchrinoizer.
pub module async_handshake::<S: synchronizer> #(
    param WIDTH              : u32  = 8           , /// Data width
    param TYPE               : type = logic<WIDTH>, /// Data type
    param STAGES             : u32               = 2           , /// Stages of synchrinoizer
    param INITIALIZE_DATA_OUT: bit               = 1           , /// Whether output data is reset
    param INITIAL_DATA_OUT   : bit <$bits(TYPE)> = '0          , /// Reset value of output data
    param MERGE_RESET        : bit               = '0          , /// Whether both reset are merged
    param RESET_SYNC_STAGES  : u32               = 2           , /// Stages of reset synchronizer
) (
    is_clk  : input  's clock, /// src clock
    is_rst  : input  's reset, /// src reset
    is_valid: input  's logic, /// src data is valid
    os_ready: output 's logic, /// src data is acceptable
    is_data : input  's TYPE , /// src data
    id_clk  : input  'd clock, /// dst clock
    id_rst  : input  'd reset, /// dst reset
    od_valid: output 'd logic, /// dst data is valid
    id_ready: input  'd logic, /// dst data is acceptable
    od_data : output 'd TYPE , /// dst data
) {
    var srst        : 's reset;
    var src_state_s : 's logic;
    var src_state_d : 'd logic;
    var drst        : 'd reset;
    var dst_state_s : 's logic;
    var dst_state_d : 'd logic;
    var latched_data: 's TYPE ;

    //--------------------------------------------------------------
    //  Reset
    //--------------------------------------------------------------
    inst u_reset_sync: async_fifo_reset_sync::<S> #(
        MERGE_RESET      : MERGE_RESET      ,
        RESET_SYNC_STAGES: RESET_SYNC_STAGES,
    ) (
        is_clk      ,
        is_rst      ,
        os_rst: srst,
        id_clk      ,
        id_rst      ,
        od_rst: drst,
    );

    //--------------------------------------------------------------
    //  Source Side
    //--------------------------------------------------------------
    :g_src_side {
        var ready            : 's logic;
        var state            : 's logic;
        var dst_state_changed: 's logic;

        assign os_ready = ready;
        always_ff (is_clk, srst) {
            if_reset {
                ready = '1;
            } else if (!ready) && dst_state_changed {
                ready = '1;
            } else if (is_valid) {
                ready = '0;
            }
        }

        always_ff (is_clk) {
            if is_valid && ready {
                latched_data = is_data;
            }
        }

        assign src_state_s = state;
        always_ff (is_clk, srst) {
            if_reset {
                state = '0;
            } else if is_valid && ready {
                state = ~state;
            }
        }

        inst u_edge_detector: edge_detector #(
            WIDTH        : 1 ,
            INITIAL_VALUE: '0,
        ) (
            i_clk    : is_clk           ,
            i_rst    : srst             ,
            i_clear  : '0               ,
            i_data   : dst_state_s      ,
            o_edge   : dst_state_changed,
            o_posedge: _                ,
            o_negedge: _                ,
        );
    }

    //--------------------------------------------------------------
    //  Synchronizers
    //--------------------------------------------------------------
    inst u_s_to_d: S #(
        WIDTH : 1     ,
        STAGES: STAGES,
    ) (
        i_clk: id_clk     ,
        i_rst: drst       ,
        i_d  : src_state_s,
        o_d  : src_state_d,
    );

    inst u_d_to_s: S #(
        WIDTH : 1     ,
        STAGES: STAGES,
    ) (
        i_clk: is_clk     ,
        i_rst: srst       ,
        i_d  : dst_state_d,
        o_d  : dst_state_s,
    );

    //--------------------------------------------------------------
    //  Destination Side
    //--------------------------------------------------------------
    :g_dst_side {
        var valid            : 'd logic;
        var data             : 'd TYPE ;
        var state            : 'd logic;
        var src_state_changed: 'd logic;

        assign od_valid = valid;
        always_ff (id_clk, drst) {
            if_reset {
                valid = '0;
            } else if valid && id_ready {
                valid = '0;
            } else if (!valid) && src_state_changed {
                valid = '1;
            }
        }

        assign od_data = data;

        // latched_data can caputure by id_clk safely
        // because it is stable
        unsafe (cdc) {
            if INITIALIZE_DATA_OUT :g {
                always_ff (id_clk, drst) {
                    if_reset {
                        data = INITIAL_DATA_OUT as TYPE;
                    } else if (!valid) && src_state_changed {
                        data = latched_data;
                    }
                }
            } else {
                always_ff (id_clk) {
                    if (!valid) && src_state_changed {
                        data = latched_data;
                    }
                }
            }
        }

        assign dst_state_d = state;
        always_ff (id_clk, drst) {
            if_reset {
                state = '0;
            } else if valid && id_ready {
                state = ~state;
            }
        }

        inst u_edge_detector: edge_detector #(
            WIDTH        : 1 ,
            INITIAL_VALUE: '0,
        ) (
            i_clk    : id_clk           ,
            i_rst    : drst             ,
            i_clear  : '0               ,
            i_data   : src_state_d      ,
            o_edge   : src_state_changed,
            o_posedge: _                ,
            o_negedge: _                ,
        );
    }
}