module i2s_mem_controller (
  input               rst,
  input               clk,

  //control
  input               enable,
  input               post_fifo_wave_en,

  //clock divider
  input               i2s_clock,

  //memory interface
  output      [23:0]  wfifo_size,
  output      [1:0]   wfifo_ready,
  input       [1:0]   wfifo_activate,
  input               wfifo_strobe,
  input       [31:0]  wfifo_data,

  //i2s writer
  input               audio_data_request,
  output  reg         audio_data_ack,
  output  reg [23:0]  audio_data,
  output  reg         audio_lr_bit
);

//registers/wires

//input side
wire                starved;

//output side
reg                 read_strobe = 0;
wire                read_ready;
reg                 read_activate = 0;
wire        [23:0]  read_size;
wire        [31:0]  read_data;


//i2s writer interface
reg         [23:0]  read_count = 0;
reg         [3:0]   state = 0;


//waveform
reg         [31:0]  write_count = 0;
reg         [7:0]   test_pre_pos = 0;
wire        [7:0]   test_pre_wavelength;
wire        [15:0]  test_pre_value;
reg         [31:0]  test_pre_data;
reg                 test_pre_write_strobe;
wire        [31:0]  fifo_data;
wire                fifo_write_strobe;

reg         [7:0]   test_pos = 0;
wire        [7:0]   test_wavelength;
wire        [15:0]  test_value;

//parameters
parameter   READ_STROBE     = 4'h0;
parameter   DELAY           = 4'h1;
parameter   READ            = 4'h2;

//generate a Ping Pong FIFO to cross the clock domain
ppfifo #(
  .DATA_WIDTH(32),
`ifndef SIMULATION
  .ADDRESS_WIDTH(12)
  //.ADDRESS_WIDTH(4)
`else
  .ADDRESS_WIDTH(2)
`endif
)ping_pong (

  .reset           (rst || !enable    ),

  //write
  .write_clock     (clk               ),
  .write_ready     (wfifo_ready       ),
  .write_activate  (wfifo_activate    ),
  .write_fifo_size (wfifo_size        ),
  .write_strobe    (wfifo_strobe      ),
  .write_data      (wfifo_data        ),

  //.starved         (starved           ),

  //read
  .read_clock      (i2s_clock         ),
  .read_strobe     (read_strobe       ),
  .read_ready      (read_ready        ),
  .read_activate   (read_activate     ),
  .read_count      (read_size         ),
  .read_data       (read_data         )
);


waveform wave_post (
  .clk(clk),
  .rst(rst),
  .wavelength(test_wavelength),
  .pos(test_pos),
  .value(test_value)
);

//asynchronous logic

//prepare the data for the i2s writer
`ifdef SIMULATION
always @(posedge i2s_clock or posedge rst) begin
`else
always @(posedge i2s_clock) begin
`endif
  read_strobe     <=  0;
  if (rst) begin
    audio_data_ack  <=  0;
    audio_data      <=  0;
    audio_lr_bit    <=  0;
    read_count      <=  0;
    read_activate   <=  0;
    state           <=  READ_STROBE;
    test_pos        <=  0;
  end
  else if (enable) begin

    //got an ack from the writer
    if (~audio_data_request && audio_data_ack) begin
      //de-assert the ack
      audio_data_ack      <=  0;
    end

    if (post_fifo_wave_en) begin
      if (audio_data_request && ~audio_data_ack) begin
        audio_lr_bit    <=  ~audio_lr_bit;

        if (test_pos >= test_wavelength - 1) begin
          test_pos  <=  0;
        end
        else begin
          test_pos  <=  test_pos + 1;
        end

        audio_data        <=  {test_value, 8'h0};
        audio_data_ack    <=  1;
      end
    end

    else begin
      if (read_ready && !read_activate) begin
        read_count        <=  0;
        read_activate     <=  1;
      end
      else if (read_activate) begin
        if (read_count < read_size) begin
          if (audio_data_request && !audio_data_ack) begin
            audio_data    <=  read_data[23:0];
            audio_lr_bit  <=  read_data[31];
            audio_data_ack<=  1;
            read_count    <=  read_count + 1;
            read_strobe   <=  1;
          end
        end
        else begin
          read_activate   <=  0;
        end
      end
    end
  end
end

endmodule