module capture_rle_cdc_resync_bus
//-----------------------------------------------------------------
// Params
//-----------------------------------------------------------------
#(
    parameter WIDTH     = 4
)
//-----------------------------------------------------------------
// Ports
//-----------------------------------------------------------------
(
    input              wr_clk_i,
    input              wr_rst_i,
    input              wr_i,
    input  [WIDTH-1:0] wr_data_i,
    output             wr_busy_o,

    input              rd_clk_i,
    input              rd_rst_i,
    output [WIDTH-1:0] rd_data_o
);

wire rd_toggle_w;
wire wr_toggle_w;

//-----------------------------------------------------------------
// Write
//-----------------------------------------------------------------
wire write_req_w = wr_i && !wr_busy_o;

// Write storage for domain crossing
(* ASYNC_REG = "TRUE" *) reg [WIDTH-1:0] wr_buffer_q;

always @ (posedge wr_clk_i or posedge wr_rst_i)
if (wr_rst_i)
    wr_buffer_q <= {(WIDTH){1'b0}};
else if (write_req_w)
    wr_buffer_q <= wr_data_i;

reg wr_toggle_q;
always @ (posedge wr_clk_i or posedge wr_rst_i)
if (wr_rst_i)
    wr_toggle_q <= 1'b0;
else if (write_req_w)
    wr_toggle_q <= ~wr_toggle_q;

reg wr_busy_q;
always @ (posedge wr_clk_i or posedge wr_rst_i)
if (wr_rst_i)
    wr_busy_q <= 1'b0;
else if (write_req_w)
    wr_busy_q <= 1'b1;
else if (wr_toggle_q == wr_toggle_w)
    wr_busy_q <= 1'b0;

assign wr_busy_o = wr_busy_q;

//-----------------------------------------------------------------
// Write -> Read request
//-----------------------------------------------------------------
capture_rle_cdc_resync
u_sync_wr_toggle
(
    .clk_i(rd_clk_i),
    .rst_i(rd_rst_i),
    .async_i(wr_toggle_q),
    .sync_o(rd_toggle_w)
);

//-----------------------------------------------------------------
// Read
//-----------------------------------------------------------------
reg rd_toggle_q;
always @ (posedge rd_clk_i or posedge rd_rst_i)
if (rd_rst_i)
    rd_toggle_q <= 1'b0;
else
    rd_toggle_q <= rd_toggle_w;

// Read storage for domain crossing
(* ASYNC_REG = "TRUE" *) reg [WIDTH-1:0] rd_buffer_q;

always @ (posedge rd_clk_i or posedge rd_rst_i)
if (rd_rst_i)
    rd_buffer_q <= {(WIDTH){1'b0}};
else if (rd_toggle_q != rd_toggle_w)
    rd_buffer_q <= wr_buffer_q; // Capture from other domain

assign rd_data_o = rd_buffer_q;

//-----------------------------------------------------------------
// Read->Write response
//-----------------------------------------------------------------
capture_rle_cdc_resync
u_sync_rd_toggle
(
    .clk_i(wr_clk_i),
    .rst_i(wr_rst_i),
    .async_i(rd_toggle_q),
    .sync_o(wr_toggle_w)
);

endmodule