`timescale 1ns/1ps
module Demosaic2 #(
    parameter reg [15:0] IM_WIDTH  = 512,  // 图像宽度
    parameter reg [15:0] IM_HEIGHT = 256,  // 图像高度
    parameter reg [ 1:0] RAW_TYPE  = 3,    // 0:grbg 1:rggb 2:bggr 3:gbrg
    parameter reg [ 4:0] DATA_SIZE = 16
  ) (
    // 基本信号
    input wire clk,
    input wire reset,

    // 数据输入信号
    input wire in_en,
    input wire [DATA_SIZE - 1:0] in_data [3],     // 数据输入线，0、1、2分别表示第一、二、三行
    output wire out_ready,            // 数据请求线，高电平：请求三个数据，直到读取完才拉低
    output wire out_receive,

    // en: 输出数据有效信号，高电平有效
    input wire in_ready,
    input wire in_receive,
    output reg out_en,
    output reg [DATA_SIZE - 1:0] out_r,
    output reg [DATA_SIZE - 1:0] out_g,
    output reg [DATA_SIZE - 1:0] out_b
  );


  // 常量，包括状态机
  // localparam IM_SIZE = IM_HEIGHT * IM_WIDTH;
  localparam reg [2:0] READ_DATA = 0;
  localparam reg [2:0] COLOR_GEN = 1;
  localparam reg [2:0] SEND_DATA = 2;
  localparam reg [2:0] SLIDE_WINDOW = 3;

  // 寄存器
  reg [2:0] state, nextState;
  reg [15:0] data_cache[9];  // 缓存颜色数据，行列3x3
  reg [15:0] pos_x, pos_y;  // 滑动窗口左上角位置
  reg [2:0] cnt_data;  // 记录输入数据数量，最大值256
  reg [1:0] raw_type;
  reg [15:0] red, blue, green;

  // 三段状态机实现，窗口滑动，颜色计算
  // 状态切换
  always @(posedge clk)
  begin
    if (reset)
      state <= READ_DATA;
    else
      state <= nextState;
  end

  // 下一状态更新
  always @(*)
  begin
    case (state)
      // 记录够3x3个数据后，进行rgb转换
      READ_DATA:
        nextState = (cnt_data >= 3) ? COLOR_GEN : READ_DATA;
      COLOR_GEN:
        nextState = SEND_DATA;
      SEND_DATA:
        nextState = (in_receive) ? SLIDE_WINDOW : SEND_DATA;
      SLIDE_WINDOW:
        nextState = READ_DATA;
      default:
        nextState = READ_DATA;
    endcase
  end

  // 请求数据
  assign out_ready   = (cnt_data <= 2 && !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_r <= 0;
      out_g <= 0;
      out_r <= 0;

      // 内部寄存器初始化
      pos_x <= 0;
      pos_y <= 0;
      cnt_data <= 0;
      raw_type <= RAW_TYPE;
    end
    else
    begin
      // 状态机执行
      case (state)
        // 读取数据
        READ_DATA:
        begin
          if (in_en)
          begin
            data_cache[0 + cnt_data * 3] <= in_data[0];
            data_cache[1 + cnt_data * 3] <= in_data[1];
            data_cache[2 + cnt_data * 3] <= in_data[2];

            cnt_data <= cnt_data + 1;
          end
        end

        COLOR_GEN:
        begin
          // 生成rgb图像
          //  data       case 0      case 1      case 2      case 3
          //  0 3 6      G R G       R G R       B G B       G B G
          //  1 4 7      B G B       G B G       G R G       R G R
          //  2 5 8      G R G       R G R       B G B       G B G
          case (raw_type)
            0:
            begin  // Missing B, R on G
              blue  <= (data_cache[1] + data_cache[7]) >> 1;
              red   <= (data_cache[3] + data_cache[5]) >> 1;
              green <= data_cache[4];
            end

            1:
            begin  // Missing G, R on B
              green <= (data_cache[1] + data_cache[3] + data_cache[5] + data_cache[7]) >> 2;
              red <= (data_cache[0] + data_cache[2] + data_cache[6] + data_cache[8]) >> 2;
              blue <= data_cache[4];
            end

            2:
            begin  // Missing G, B on R
              green <= (data_cache[1] + data_cache[3] + data_cache[5] + data_cache[7]) >> 2;
              blue <= (data_cache[0] + data_cache[2] + data_cache[6] + data_cache[8]) >> 2;
              red <= data_cache[4];
            end


            3:
            begin  // Missing B, R on G
              red   <= (data_cache[1] + data_cache[7]) >> 1;
              blue  <= (data_cache[3] + data_cache[5]) >> 1;
              green <= data_cache[4];
            end
            default:
              ;
          endcase

          case (raw_type)
            0:
              raw_type <= 1;
            1:
              raw_type <= 0;
            2:
              raw_type <= 3;
            3:
              raw_type <= 2;
          endcase
        end

        SEND_DATA:
        begin
          if (in_ready && !in_receive)
          begin
            out_en <= 1;
            out_r  <= red;
            out_b  <= blue;
            out_g  <= green;
            pos_x <= pos_x + 1;
          end
          else
            out_en <= 0;
        end

        SLIDE_WINDOW:
        begin
          // 记录位置寄存器自增，并处理缓存数据
          if (pos_x >= IM_WIDTH - 2)
          begin
            cnt_data <= 0;
            pos_x <= 0;
            pos_y <= pos_y + 1;
            if (pos_y >= IM_HEIGHT - 2)
            begin
              pos_y <= 0;
            end
            // 换行后切换Bayer格式
            if (pos_y % 2 == 1)
            begin
              raw_type <= RAW_TYPE;
            end
            else
            begin
              case (RAW_TYPE)
                0:
                  raw_type <= 2;
                1:
                  raw_type <= 3;
                2:
                  raw_type <= 0;
                3:
                  raw_type <= 1;
                default:
                  ;
              endcase
            end
          end
          else
          begin
            cnt_data <= 2;

            // 窗口右移
            data_cache[0] <= data_cache[3];
            data_cache[1] <= data_cache[4];
            data_cache[2] <= data_cache[5];
            data_cache[3] <= data_cache[6];
            data_cache[4] <= data_cache[7];
            data_cache[5] <= data_cache[8];
          end
        end

        default:
          ;
      endcase
    end
  end

endmodule

