`timescale 1ns / 1ps

module GammaCorrection #(
    parameter reg [4:0] COLOR_DEPTH   = 8
  ) (
    input wire clk,
    input wire reset,

    input wire in_en,
    input wire [COLOR_DEPTH - 1 : 0] in_data[3],
    output wire out_ready,
    output wire out_receive,

    output reg out_en,
    output reg [COLOR_DEPTH - 1 : 0] out_data[3],
    input wire in_ready,
    input wire in_receive,

    input wire [7:0] gamma_table[256],
    input wire enable
  );
  reg [2:0] state, nextState;
  localparam reg [2:0] READ_DATA = 0;
  localparam reg [2:0] SEND_DATA = 2;

  reg [7:0] data_cache[3];

  always @(posedge clk)
  begin
    if (reset)
      state <= READ_DATA;
    else
      state <= nextState;
  end

  always @(*)
  begin
    case (state)
      READ_DATA:
        nextState = in_en ? SEND_DATA : READ_DATA;
      SEND_DATA:
        nextState = in_receive ? READ_DATA : SEND_DATA;
      default:
        nextState = READ_DATA;
    endcase
  end

  assign out_ready   = (!in_en && state == READ_DATA && !reset) ? 1 : 0;
  assign out_receive = (in_en && state == READ_DATA && !reset) ? 1 : 0;

  always @(posedge clk)
  begin
    if (reset)
    begin
      out_en <= 0;
      out_data[0] <= 0;
      out_data[1] <= 0;
      out_data[2] <= 0;

      data_cache[0] <= 0;
      data_cache[1] <= 0;
      data_cache[2] <= 0;
    end
    else
    begin
      case (state)
        READ_DATA:
        begin
          if (in_en)
          begin
            data_cache[0] <= in_data[0];
            data_cache[1] <= in_data[1];
            data_cache[2] <= in_data[2];
          end
        end

        SEND_DATA:
        begin
          if (in_ready && !in_receive)
          begin
            out_en <= 1;
            if (enable)
            begin
              out_data[0] <= gamma_table[data_cache[0]];
              out_data[1] <= gamma_table[data_cache[1]];
              out_data[2] <= gamma_table[data_cache[2]];
            end
            else
            begin
              out_data[0] <= data_cache[0];
              out_data[1] <= data_cache[1];
              out_data[2] <= data_cache[2];
            end
          end
          else
            out_en <= 0;
        end

        default:
          ;
      endcase
    end
  end


endmodule
