`timescale 1ns / 1ps

// latency_buffer_2159_fixed.v
module latency_buffer_2159 #(
    parameter DATA_WIDTH = 32,
    parameter LATENCY = 3187
) (
    input wire clk,
    input wire reset_n,
    input wire [DATA_WIDTH-1:0] data_in,
    input wire valid_in,
    output wire [DATA_WIDTH-1:0] data_out,
    output wire valid_out
);

// ========== FIXED PARAMETERS ==========
localparam ADDR_WIDTH = 12;  // Enough for 4096 entries (>2159)

// ========== FIXED LOGIC ==========
(* ram_style = "block" *) reg [DATA_WIDTH-1:0] bram [0:4095];
reg [ADDR_WIDTH-1:0] write_ptr;
reg [ADDR_WIDTH-1:0] read_ptr;
reg valid_out_reg;

// Delay counter to track when LATENCY cycles have passed
reg [ADDR_WIDTH-1:0] delay_counter;
reg buffer_has_data;  // Flag when buffer has accumulated LATENCY samples

// ========== FIXED INITIALIZATION ==========
integer k;
initial begin
    for (k = 0; k < 4096; k = k + 1) begin
        bram[k] = {DATA_WIDTH{1'b0}};
    end
    write_ptr = 0;
    read_ptr = 0;
    valid_out_reg = 0;
    delay_counter = 0;
    buffer_has_data = 0;
end

// ========== FIXED STATE MACHINE ==========
always @(posedge clk or negedge reset_n) begin
    if (!reset_n) begin
        write_ptr <= 0;
        read_ptr <= 0;
        valid_out_reg <= 0;
        delay_counter <= 0;
        buffer_has_data <= 0;
    end else begin
        // Default: no valid output
        valid_out_reg <= 0;
        
        // ===== WRITE SIDE =====
        if (valid_in) begin
            // Store data
            bram[write_ptr] <= data_in;
            
            // Increment write pointer (wrap at 4095)
            if (write_ptr == 4095) begin
                write_ptr <= 0;
            end else begin
                write_ptr <= write_ptr + 1;
            end
            
            // Count how many samples we've written
            if (delay_counter < LATENCY) begin
                delay_counter <= delay_counter + 1;
                
                // When we've written LATENCY samples, buffer is "primed"
                if (delay_counter == LATENCY - 1) begin
                    buffer_has_data <= 1'b1;
                //    $display("[LAT_BUF] Buffer now has %d samples (primed)", LATENCY);
                end
            end
        end
        
        // ===== READ SIDE =====
        // Only start reading after we have LATENCY samples in buffer
        if (buffer_has_data && valid_in) begin
            // Read pointer follows write pointer with LATENCY delay
            // Calculate: read_ptr = (write_ptr - LATENCY) mod 4096
            
            // Handle wrap-around correctly
            if (write_ptr >= LATENCY) begin
                read_ptr <= write_ptr - LATENCY;
            end else begin
                // Wrap around: 4096 + write_ptr - LATENCY
                read_ptr <= 4096 + write_ptr - LATENCY;
            end
            
            // Output is valid
            valid_out_reg <= 1'b1;
            
            //$display("[LAT_BUF] Reading: write_ptr=%d, read_ptr=%d, data=%h",
              //       write_ptr, read_ptr, bram[read_ptr]);
        end
    end
end

// ========== OUTPUTS ==========
assign data_out = bram[read_ptr];
assign valid_out = valid_out_reg;



endmodule