module jpeg_output_y_ram
(
    // Inputs
     input           clk_i
    ,input           rst_i
    ,input  [  5:0]  wr_idx_i
    ,input  [ 31:0]  data_in_i
    ,input           push_i
    ,input           pop_i
    ,input           flush_i

    // Outputs
    ,output [ 31:0]  data_out_o
    ,output          valid_o
    ,output [ 31:0]  level_o
);



//-----------------------------------------------------------------
// Registers
//-----------------------------------------------------------------
reg [8:0]   rd_ptr_q;
reg [8:0]   wr_ptr_q;

//-----------------------------------------------------------------
// Write Side
//-----------------------------------------------------------------
wire [8:0] write_next_w = wr_ptr_q + 9'd1;

always @ (posedge clk_i )
if (rst_i)
    wr_ptr_q <= 9'b0;
else if (flush_i)
    wr_ptr_q <= 9'b0;
// Push
else if (push_i)
    wr_ptr_q <= write_next_w;

//-----------------------------------------------------------------
// Read Side
//-----------------------------------------------------------------
wire read_ok_w = (wr_ptr_q != rd_ptr_q);
reg  rd_q;

always @ (posedge clk_i )
if (rst_i)
    rd_q <= 1'b0;
else if (flush_i)
    rd_q <= 1'b0;
else
    rd_q <= read_ok_w;

wire [8:0] rd_ptr_next_w = rd_ptr_q + 9'd1;

always @ (posedge clk_i )
if (rst_i)
    rd_ptr_q <= 9'b0;
else if (flush_i)
    rd_ptr_q <= 9'b0;
else if (read_ok_w && ((!valid_o) || (valid_o && pop_i)))
    rd_ptr_q <= rd_ptr_next_w;

wire [8:0] rd_addr_w = rd_ptr_q;

//-------------------------------------------------------------------
// Read Skid Buffer
//-------------------------------------------------------------------
reg                rd_skid_q;
reg [31:0] rd_skid_data_q;

always @ (posedge clk_i )
if (rst_i)
begin
    rd_skid_q <= 1'b0;
    rd_skid_data_q <= 32'b0;
end
else if (flush_i)
begin
    rd_skid_q <= 1'b0;
    rd_skid_data_q <= 32'b0;
end
else if (valid_o && !pop_i)
begin
    rd_skid_q      <= 1'b1;
    rd_skid_data_q <= data_out_o;
end
else
begin
    rd_skid_q      <= 1'b0;
    rd_skid_data_q <= 32'b0;
end

//-------------------------------------------------------------------
// Combinatorial
//-------------------------------------------------------------------
assign valid_o       = rd_skid_q | rd_q;

//-------------------------------------------------------------------
// Dual port RAM
//-------------------------------------------------------------------
wire [31:0] data_out_w;

jpeg_output_y_ram_ram_dp_512_9
u_ram
(
    // Inputs
    .clk0_i(clk_i),
    .rst0_i(rst_i),
    .clk1_i(clk_i),
    .rst1_i(rst_i),

    // Write side
    .addr0_i({wr_ptr_q[8:6], wr_idx_i}),
    .wr0_i(push_i),
    .data0_i(data_in_i),
    .data0_o(),

    // Read side
    .addr1_i(rd_addr_w),
    .data1_i(32'b0),
    .wr1_i(1'b0),
    .data1_o(data_out_w)
);

assign data_out_o = rd_skid_q ? rd_skid_data_q : data_out_w;


//-------------------------------------------------------------------
// Level
//-------------------------------------------------------------------
reg [31:0]  count_q;
reg [31:0]  count_r;

always @ *
begin
    count_r = count_q;

    if (pop_i && valid_o)
        count_r = count_r - 32'd1;

    if (push_i)
        count_r = count_r + 32'd1;
end

always @ (posedge clk_i )
if (rst_i)
    count_q   <= 32'b0;
else if (flush_i)
    count_q   <= 32'b0;
else
    count_q <= count_r;

assign level_o = count_q;

endmodule