module stud_fifo 
       #( parameter LENGTH = 128,
	  parameter WIDTH = 16,
	  parameter SYNC_LEN = 2
  	)
	(
	  input [WIDTH-1:0] fifo_i,
	  input fifo_rdy_i, audio_rd_i, rst_n_i, clk_i,
	  output reg fifo_ack_o, fifo_full_o, fifo_empty_o,
	  output [WIDTH-1:0] audio_o
	);

	/* Internal buffers */
	reg [WIDTH-1:0] buffer [LENGTH - 1 : 0];
	reg [$clog2(LENGTH)-1:0] buffer_r_ind;
	reg [$clog2(LENGTH)-1:0] buffer_w_ind;
	wire fifo_rdy; // Synchronous fifo_rdy
	reg [WIDTH-1:0] audio_tmp;
	reg fifo_ack_next;
	reg fifo_rdy_last;
	reg audio_rd_last;

	/* External modules */
	stud_synchronizer #(SYNC_LEN,1) fifo_rdy_sync(
		.clk_i(clk_i),
		.rst_n_i(rst_n_i),
		.input_i(fifo_rdy_i),
		.output_o(fifo_rdy)
	);

	/* CLK_i process */
	always @(posedge clk_i) begin
		if(~rst_n_i) begin
			/* Reset whole buffer, for loops are allowed (according to internet) */
			buffer[0] <= {WIDTH{1'b0}};
			buffer_r_ind <= {$clog2(LENGTH){1'b0}};
			buffer_w_ind <= {$clog2(LENGTH){1'b0}};
			audio_tmp <= {WIDTH{1'b0}};
			fifo_empty_o <= 1'b1;
			fifo_full_o <= 1'b0;
			fifo_ack_o <= 1'b0;
			fifo_ack_next <= 1'b0;
		end else begin

			/* FIFO WRITE */
			if(fifo_rdy && ! fifo_rdy_last && !fifo_full_o) begin
				buffer[buffer_w_ind] <= fifo_i;
				buffer_w_ind <= buffer_w_ind + 1'b1;
				fifo_ack_next <= 1'b1;
			end else begin
				buffer[buffer_w_ind] <= buffer[buffer_w_ind];
				buffer_w_ind <= buffer_w_ind;
				fifo_ack_next <= 1'b0;
			end

			/* FIFO READ */
			if(audio_rd_i && !audio_rd_last && !fifo_empty_o) begin
				audio_tmp <= buffer[buffer_r_ind];
				buffer_r_ind <= buffer_r_ind + 1'b1;
			end else begin
				audio_tmp <= audio_tmp;
				buffer_r_ind <= buffer_r_ind;
			end

			/* FIFO status */
			if (buffer_r_ind == buffer_w_ind) begin
				fifo_empty_o <= 1'b1;
			end else begin
				fifo_empty_o <= 1'b0;
			end
			if(buffer_w_ind == (buffer_r_ind - 1'b1)) begin
				fifo_full_o <= 1'b1;
			end else begin
				fifo_full_o <= 1'b0;
			end

			fifo_ack_o <= fifo_ack_next;
			fifo_rdy_last <= fifo_rdy;
			audio_rd_last <= audio_rd_i;
		end
	end
	assign audio_o = audio_tmp;
endmodule