`timescale 1ns / 1ps
module Demosaic_Pipeline #(
parameter WINDOW_LENGTH = 3,
parameter reg [15:0] TOTAL_WIDTH  = 512+3, // 总图像宽度
parameter reg [15:0] TOTAL_HEIGHT = 256+3, // 总图像高度
parameter reg [ 1:0] RAW_TYPE  = 3,        // (0,0)位置算起RAW_TYPE的值
parameter reg [ 4:0] DATA_WIDTH = 16       // 输入/输出数据位宽
)(
    input wire clk,
    input wire reset,
    
    input wire [DATA_WIDTH - 1:0] in_data [WINDOW_LENGTH*WINDOW_LENGTH],     // 数据输入线.第一列数据在[0],[1],[2]中
    output reg [DATA_WIDTH - 1:0] out_data [3],   // 数据输出线，3、2、1分别表示r、g、b
    
    input wire in_valid,
    output wire out_valid,
    
    input wire in_ready,
    output wire out_ready,
    
    output reg out_hsync,     // 行同步，一行第一个像素点输出的同时高电平
    output reg out_fsync      // 帧同步，一帧第一个像素点输出的同时高电平
);

  localparam DATA_NUM = WINDOW_LENGTH*WINDOW_LENGTH;
  localparam PIPILINE = 3;

  reg [PIPILINE-1:0] pipeline_valid;
  wire pipeline_running;
  assign pipeline_running = in_ready | ~pipeline_valid[PIPILINE-1];

  //out_ready ：只要本模块可以接收数据就一直拉高
  assign out_ready = pipeline_running;
  //out_valid ：只要本模块可以发出数据就一直拉高
  assign out_valid = pipeline_valid[PIPILINE-1];

  reg [DATA_WIDTH-1:0] data_cache[DATA_NUM];  // 缓存颜色数据，行列nxn
  reg [31:0] pos_x, pos_y, temp_pos_x, temp_pos_y;
  reg [DATA_WIDTH-1:0] red, blue, green;
  reg [1:0] raw_type;

  integer i;
  always @(posedge clk) begin
    if(reset) begin
      for(i=0;i<DATA_NUM;i=i+1) data_cache[i] <= 0;
      pipeline_valid <= 0;
      {red, green, blue} <= 0;
      {out_data[2],out_data[1],out_data[0]}  <= 0;
      {out_hsync,out_fsync} <= 0;
      pos_x <= ~0;
      pos_y <= ~0;
      temp_pos_x <= 0;
      temp_pos_y <= 0;
    end else if(pipeline_running) begin

      pipeline_valid <= {pipeline_valid[PIPILINE-2:0], in_valid};

      if(in_valid) begin
        for(i=0;i<DATA_NUM;i=i+1) data_cache[i] <= in_data[i];
        pos_x <= (pos_x >= TOTAL_WIDTH - 1)?(0):(pos_x + 1);
        pos_y <= (pos_x >= TOTAL_WIDTH - 1)?((pos_y >= TOTAL_HEIGHT - 1)?(0):(pos_y + 1)):(pos_y);
      end

      if(pipeline_valid[0]) begin
        temp_pos_x <= pos_x;
        temp_pos_y <= pos_y;
        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
        endcase
      end

      if(pipeline_valid[1]) begin
        {out_data[2],out_data[1],out_data[0]}  <= {red,blue,green};
        out_hsync <= (temp_pos_x == 0);
        out_fsync <= ((temp_pos_x == 0) && (temp_pos_y == 0));
      end
    end
  end

  // 0:gr 1:rg 2:bg 3:gb  窗口右移，0<->1 2<->3; 窗口下移，0<->2，1<->3。
  //   bg   gb   gr   rg
  always @(*) begin
    if(reset) raw_type = RAW_TYPE;
    else case (RAW_TYPE)
          2'b00: raw_type = {pos_y[0], pos_x[0]};
          2'b01: raw_type = {pos_y[0], ~pos_x[0]};
          2'b10: raw_type = {~pos_y[0], pos_x[0]};
          2'b11: raw_type = {~pos_y[0], ~pos_x[0]};
    endcase
  end

endmodule

