module sirv_gnrl_cdc_tx
# (
  parameter DW = 32,
  parameter SYNC_DP = 2
) (
  // The regular handshake interface at in-side
  //         Just the regular handshake o_vld & o_rdy like AXI
  input  i_vld, 
  output i_rdy, 
  input  [DW-1:0] i_dat,

  // The 4-phases handshake interface at out-side
  //     There are 4 steps required for a full transaction. 
  //         (1) The i_vld is asserted high 
  //         (2) The i_rdy is asserted high
  //         (3) The i_vld is asserted low 
  //         (4) The i_rdy is asserted low
  output o_vld, 
  input  o_rdy_a, 
  output [DW-1:0] o_dat,

  input  clk,
  input  rst_n 
);

wire o_rdy_sync;

// Sync the async signal first
sirv_gnrl_sync #(
    .DP(SYNC_DP), 
    .DW(1)
) u_o_rdy_sync (
         .clk   (clk),
         .rst_n (rst_n),
         .din_a (o_rdy_a),
         .dout  (o_rdy_sync)
        );

wire vld_r;
wire [DW-1:0] dat_r;

// Valid set when it is handshaked
wire vld_set = i_vld & i_rdy;
// Valid clr when the TX o_rdy is high
wire vld_clr = o_vld & o_rdy_sync;
wire vld_ena = vld_set | vld_clr;
wire vld_nxt = vld_set | (~vld_clr);
sirv_gnrl_dfflr #(1) vld_dfflr(vld_ena, vld_nxt, vld_r, clk, rst_n);
// The data buf is only loaded when the vld is set 
sirv_gnrl_dfflr #(DW) dat_dfflr(vld_set, i_dat, dat_r, clk, rst_n);

        // Detect the neg-edge
wire o_rdy_sync_r;
sirv_gnrl_dffr #(1) o_rdy_sync_dffr(o_rdy_sync, o_rdy_sync_r, clk, rst_n);
wire o_rdy_nedge = (~o_rdy_sync) & o_rdy_sync_r;

// Not-ready indication
wire nrdy_r;
// Not-ready is set when the vld_r is set
wire nrdy_set = vld_set;
// Not-ready is clr when the o_rdy neg-edge is detected
wire nrdy_clr = o_rdy_nedge;
wire nrdy_ena = nrdy_set | nrdy_clr;
wire nrdy_nxt = nrdy_set | (~nrdy_clr);
sirv_gnrl_dfflr #(1) buf_nrdy_dfflr(nrdy_ena, nrdy_nxt, nrdy_r, clk, rst_n);

//  The output valid
assign o_vld = vld_r;
//  The output data
assign o_dat = dat_r;

// The input is ready when the  Not-ready indication is low or under clearing
assign i_rdy = (~nrdy_r) | nrdy_clr;

endmodule 