/**
 * $Id: bus_clk_bridge.v 961 2014-01-21 11:40:39Z matej.oblak $
 *
 * @brief Red Pitaya system bus clock crossing bridge.
 *
 * @Author Matej Oblak
 *
 * (c) Red Pitaya  http://www.redpitaya.com
 *
 * This part of code is written in Verilog hardware description language (HDL).
 * Please visit http://en.wikipedia.org/wiki/Verilog
 * for more details on the language used herein.
 */



/**
 * GENERAL DESCRIPTION:
 *
 * Clock domain bridge for system bus.
 *
 *
 *                  /------\
 *   SYSTEM         |      |         PROCESSING
 *   BUS    <-----> | SYNC | <----->    BUS
 *                  |      |
 *                  \------/
 *
 *
 * System bus runs on one clock domain while processing runs on separate. To 
 * simplify transition of writing and reading data this bridge was created.
 * 
 */




module bus_clk_bridge
(
   // system bus
   input                 sys_clk_i     ,  //!< bus clock
   input                 sys_rstn_i    ,  //!< bus reset - active low
   input      [ 32-1: 0] sys_addr_i    ,  //!< bus address
   input      [ 32-1: 0] sys_wdata_i   ,  //!< bus write data
   input      [  4-1: 0] sys_sel_i     ,  //!< bus write byte select
   input                 sys_wen_i     ,  //!< bus write enable
   input                 sys_ren_i     ,  //!< bus read enable
   output     [ 32-1: 0] sys_rdata_o   ,  //!< bus read data
   output                sys_err_o     ,  //!< bus error indicator
   output                sys_ack_o     ,  //!< bus acknowledge signal


   // Destination bus
   input                 clk_i         ,  //!< clock
   input                 rstn_i        ,  //!< reset - active low
   output reg [ 32-1: 0] addr_o        ,  //!< address
   output reg [ 32-1: 0] wdata_o       ,  //!< write data
   output                wen_o         ,  //!< write enable
   output                ren_o         ,  //!< read enable
   input      [ 32-1: 0] rdata_i       ,  //!< read data
   input                 err_i         ,  //!< error indicator
   input                 ack_i            //!< acknowledge signal
);



//---------------------------------------------------------------------------------
//  Synchronize signals between clock domains

reg            sys_rd    ;
reg            sys_wr    ;
reg            sys_do    ;
reg  [ 2-1: 0] sys_sync  ;
reg            sys_done  ;
reg            dst_do    ;
reg  [ 2-1: 0] dst_sync  ;
reg            dst_done  ;

always @(posedge sys_clk_i) begin
   if (sys_rstn_i == 1'b0) begin
      sys_rd   <= 1'b0 ;
      sys_wr   <= 1'b0 ;
      sys_do   <= 1'b0 ;
      sys_sync <= 2'h0 ;
      sys_done <= 1'b0 ;
   end 
   else begin

      if ((sys_do == sys_done) && (sys_wen_i || sys_ren_i)) begin
         addr_o  <= sys_addr_i    ;
         wdata_o <= sys_wdata_i   ;
         sys_rd  <= sys_ren_i     ;
         sys_wr  <= sys_wen_i     ;
         sys_do  <= !sys_do       ;
      end

      sys_sync <= {sys_sync[0], dst_done};
      sys_done <= sys_sync[1];
   end
end


always @(posedge clk_i) begin
   if (rstn_i == 1'b0) begin
      dst_do    <= 1'b0 ;
      dst_sync  <= 2'h0 ;
      dst_done  <= 1'b0 ;
   end
   else begin
      dst_sync <= {dst_sync[0], sys_do};
      dst_do   <= dst_sync[1];

      if (ack_i && (dst_do != dst_done))
         dst_done <= dst_do;
   end
end

assign ren_o = sys_rd && (dst_sync[1]^dst_do);
assign wen_o = sys_wr && (dst_sync[1]^dst_do);


assign sys_rdata_o = rdata_i                ;
assign sys_err_o   = err_i                  ;
assign sys_ack_o   = sys_done ^ sys_sync[1] ;



endmodule