module sync_fifo_128_to_64 #(
    parameter DATA_IN_WIDTH = 128,
    parameter DATA_OUT_WIDTH = 64,
    parameter FIFO_DEPTH  = 16,
    parameter ADDR_WIDTH = $clog2(FIFO_DEPTH)
)(
    input clk,
    input rst_n,
    input wr_en,
    input [DATA_IN_WIDTH-1:0] wr_data,
    output full,
    input rd_en,
    output [DATA_OUT_WIDTH-1:0] rd_data,
    output empty
);

    reg [DATA_OUT_WIDTH-1:0] mem [0 :FIFO_DEPTH -1];
    reg [ADDR_WIDTH : 0] wr_ptr, rd_ptr;
    wire [ADDR_WIDTH -1:0] wr_addr ,rd_addr;
    
    assign wr_addr = wr_ptr[ADDR_WIDTH -1:0];
    assign rd_addr = rd_ptr[ADDR_WIDTH -1:0];

    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            wr_ptr <= 'd0;    
        end else if(wr_en && !full) begin
                wr_ptr <= wr_ptr + 2'd2;
        end else begin
            wr_ptr <= wr_ptr;
        end
    end

    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            rd_ptr <= 'd0;
        end else if(rd_en && !empty) begin
                rd_ptr <= rd_ptr + 1'd1;
        end else begin
            rd_ptr <= rd_ptr;
        end
    end

    integer i;
    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            for(i=0;i<FIFO_DEPTH;i=i+1) begin
                mem[i] <= 'd0;
            end
        end else if(wr_en && !full) begin
                {mem[wr_addr+1'b1],mem[wr_addr]} <= wr_data;
        end else begin
                mem[wr_addr] <= mem[wr_addr];
        end
    end

    assign rd_data = mem[rd_addr];

    assign full = (wr_ptr - rd_ptr  == FIFO_DEPTH) ? 1:0;
    assign empty = (wr_ptr == rd_ptr) ? 1:0;

endmodule
