module sirv_gnrl_cdc_rx
# (
  parameter DW = 32,
  parameter SYNC_DP = 2
) (
  // The 4-phases handshake interface at in-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
  input  i_vld_a, 
  output i_rdy, 
  input  [DW-1:0] i_dat,
  // The regular handshake interface at out-side
  //         Just the regular handshake o_vld & o_rdy like AXI
  output o_vld, 
  input  o_rdy, 
  output [DW-1:0] o_dat,

  input  clk,
  input  rst_n 
);

wire i_vld_sync;
// Sync the async signal first
sirv_gnrl_sync #(.DP(SYNC_DP), .DW(1)) u_i_vld_sync (
     .clk   (clk),
     .rst_n (rst_n),
     .din_a (i_vld_a),
     .dout  (i_vld_sync)
    );

wire i_vld_sync_r;
sirv_gnrl_dffr #(1) i_vld_sync_dffr(i_vld_sync, i_vld_sync_r, clk, rst_n);
wire i_vld_sync_nedge = (~i_vld_sync) & i_vld_sync_r;

wire buf_rdy;
wire i_rdy_r;
// Because it is a 4-phases handshake, so 
//   The i_rdy is set (assert to high) when the buf is ready (can save data) and incoming valid detected
//   The i_rdy is clear when i_vld neg-edge is detected
wire i_rdy_set = buf_rdy & i_vld_sync & (~i_rdy_r);
wire i_rdy_clr = i_vld_sync_nedge;
wire i_rdy_ena = i_rdy_set |   i_rdy_clr;
wire i_rdy_nxt = i_rdy_set | (~i_rdy_clr);
sirv_gnrl_dfflr #(1) i_rdy_dfflr(i_rdy_ena, i_rdy_nxt, i_rdy_r, clk, rst_n);
assign i_rdy = i_rdy_r;


wire buf_vld_r;
wire [DW-1:0] buf_dat_r;

// The buf is loaded with data when i_rdy is set high (i.e., 
//   when the buf is ready (can save data) and incoming valid detected
wire buf_dat_ena = i_rdy_set;
sirv_gnrl_dfflr #(DW) buf_dat_dfflr(buf_dat_ena, i_dat, buf_dat_r, clk, rst_n);

// The buf_vld is set when the buf is loaded with data
wire buf_vld_set = buf_dat_ena;
// The buf_vld is clr when the buf is handshaked at the out-end
wire buf_vld_clr = o_vld & o_rdy;
wire buf_vld_ena = buf_vld_set | buf_vld_clr;
wire buf_vld_nxt = buf_vld_set | (~buf_vld_clr);
sirv_gnrl_dfflr #(1) buf_vld_dfflr(buf_vld_ena, buf_vld_nxt, buf_vld_r, clk, rst_n);
// The buf is ready when the buf is empty
assign buf_rdy = (~buf_vld_r);

assign o_vld = buf_vld_r;
assign o_dat = buf_dat_r;

endmodule 