`timescale 1ns / 1ps
/* TODO 1. ISP寄存器配置模式，如配置是否启用什么什么矫正，矫正系数多少。能读能写。选好通信协议，要不要用AXI？
        2. 白平衡，GAMMA矫正。白平衡做RAW白平衡吗？
        3. 寄存器中应该有一个寄存器标识ISP运行状态。比如裁切模块，直接修改寄存器值数据就乱了。
        4. 缩放模块。如何处理模块进出数据量不匹配？
        5. 旋转模块。这怎么做？
        6. ISP不应该只有一条线，比如存进SDRAM后，读出来时也可以做处理。
*/
module isp_Pipeline #(
    parameter reg [15:0] DATA_WIDTH  = 12,
    parameter reg [15:0] IN_WIDTH    = 1936,
    parameter reg [15:0] IN_HEIGHT   = 1088,
    parameter            OFFSET_X    = 7,
    parameter            OFFSET_Y    = 3,
    parameter reg [15:0] OUT_WIDTH   = 1920,
    parameter reg [15:0] OUT_HEIGHT  = 1080,
    parameter reg [ 4:0] COLOR_DEPTH = 8,     // Can't Change!!!
    parameter reg [ 1:0] RAW_TYPE    = 3      // 0:grbg 1:rggb 2:bggr 3:gbrg
) (
    // 基本信号
    input wire clk,
    input wire reset,

    // 数据线
    input wire [DATA_WIDTH-1:0] in_data,  // 数据输入线
    output wire [3 * COLOR_DEPTH - 1:0] out_data,
    output wire fsync,
    output wire hsync,

    // 数据有效信号
    input  wire in_valid,
    output wire out_valid,

    // 准备信号
    input  wire in_ready,
    output wire out_ready,

    // 颜色校正，低八位为小数位，高八位为整数位
    input wire [15:0] gain_red,
    input wire [15:0] gain_green,
    input wire [15:0] gain_blue,
    input wire blender_enable  // 是否启用颜色校正
);

  wire [DATA_WIDTH-1:0] DPC_data;
  wire [DATA_WIDTH-1:0] Demosaic_data[3];
  wire [DATA_WIDTH-1:0] Windows_DPC_data[5*5];
  wire [DATA_WIDTH-1:0] Windows_Demosaic_data[3*3];
  wire [COLOR_DEPTH - 1 : 0] Blender_data[3];
  wire [COLOR_DEPTH - 1 : 0] Crop_data[3];
  wire Windows_DPC_valid, DPC_valid, Windows_Demosaic_valid, Demosaic_valid, Blender_valid, Crop_valid;
  wire Windows_DPC_ready, DPC_ready, Windows_Demosaic_ready, Demosaic_ready, Blender_ready, Crop_ready;
  wire Demosaic_hsync, Blender_hsync, Crop_hsync;
  wire Demosaic_fsync, Blender_fsync, Crop_fsync;
  assign out_valid = Crop_valid;
  assign out_ready = Windows_DPC_ready;
  assign out_data = {Crop_data[2], Crop_data[1], Crop_data[0]};
  assign fsync = Crop_fsync;
  assign hsync = Crop_hsync;

  Windows #(
      .DATA_WIDTH      (DATA_WIDTH),
      .IMAGE_WIDTH     (IN_WIDTH),
      .WINDOWS_WIDTH   (5),
      .WINDOWS_ANCHOR_X(2),
      .WINDOWS_ANCHOR_Y(2)
  ) Windows_DPC_inst (
      .clk      (clk),
      .reset    (reset),
      .in_data  (in_data),
      .out_data (Windows_DPC_data),
      .in_valid (in_valid),
      .out_valid(Windows_DPC_valid),
      .in_ready (DPC_ready),
      .out_ready(Windows_DPC_ready)
  );

  DPC #(
      .TOTAL_WIDTH (IN_WIDTH),
      .TOTAL_HEIGHT(IN_HEIGHT),
      .RAW_TYPE    (3),
      .DATA_WIDTH  (DATA_WIDTH)
  ) DPC_inst (
      .clk      (clk),
      .reset    (reset),
      .in_data  (Windows_DPC_data),
      .out_data (DPC_data),
      .in_valid (Windows_DPC_valid),
      .out_valid(DPC_valid),
      .in_ready (Windows_Demosaic_ready),
      .out_ready(DPC_ready)
  );

  Windows #(
      .DATA_WIDTH      (DATA_WIDTH),
      .IMAGE_WIDTH     (IN_WIDTH),
      .WINDOWS_WIDTH   (3),
      .WINDOWS_ANCHOR_X(1),
      .WINDOWS_ANCHOR_Y(1)
  ) Windows_Demosaic_inst (
      .clk      (clk),
      .reset    (reset),
      .in_data  (DPC_data),
      .out_data (Windows_Demosaic_data),
      .in_valid (DPC_valid),
      .out_valid(Windows_Demosaic_valid),
      .in_ready (Demosaic_ready),
      .out_ready(Windows_Demosaic_ready)
  );


  Demosaic_Pipeline #(
      .WINDOW_LENGTH(3),
      .TOTAL_WIDTH  (IN_WIDTH),
      .TOTAL_HEIGHT (IN_HEIGHT),
      .RAW_TYPE     (3),
      .DATA_WIDTH   (DATA_WIDTH)
  ) Demosaic_inst (
      .clk      (clk),
      .reset    (reset),
      .in_data  (Windows_Demosaic_data),
      .out_data (Demosaic_data),
      .in_valid (Windows_Demosaic_valid),
      .out_valid(Demosaic_valid),
      .in_ready (Blender_ready),
      .out_ready(Demosaic_ready),
      .out_hsync(Demosaic_hsync),
      .out_fsync(Demosaic_fsync)
  );

  ColorBlender_Pipeline #(
      .DATA_WIDTH(DATA_WIDTH),  // 输入图像的色深
      .OUT_DEPTH (COLOR_DEPTH)  // 输出图像的色深
  ) ColorBlender_inst (
      .clk      (clk),
      .reset    (reset),
      .in_data  (Demosaic_data),
      .out_data (Blender_data),
      .in_valid (Demosaic_valid),
      .out_valid(Blender_valid),
      .in_ready (Crop_ready),
      .out_ready(Blender_ready),
      .in_hsync (Demosaic_hsync),
      .in_fsync (Demosaic_fsync),
      .out_hsync(Blender_hsync),
      .out_fsync(Blender_fsync),

      .gain_red  (gain_red),
      .gain_green(gain_green),
      .gain_blue (gain_blue),
      .enable    (blender_enable)
  );

  Crop_Pipeline #(
      .IN_WIDTH   (IN_WIDTH),
      .IN_HEIGHT  (IN_HEIGHT),
      .OFFSET_X   (OFFSET_X),
      .OFFSET_Y   (OFFSET_Y),
      .OUT_WIDTH  (OUT_WIDTH),
      .OUT_HEIGHT (OUT_HEIGHT),
      .COLOR_DEPTH(COLOR_DEPTH)
  ) Crop_inst (
      .clk      (clk),
      .reset    (reset),
      .in_data  (Blender_data),
      .out_data (Crop_data),
      .in_valid (Blender_valid),
      .out_valid(Crop_valid),
      .in_ready (in_ready),
      .out_ready(Crop_ready),
      .in_hsync (Blender_hsync),
      .in_fsync (Blender_fsync),
      .out_hsync(Crop_hsync),
      .out_fsync(Crop_fsync)
  );

  // reg [15:0] data_out_temp[8192];
  // reg [31:0] now;
  // reg [2:0] cnt_www;
  // reg flag_ifdataerror;

  // initial cnt_www = 0;
  // always @(posedge reset) begin
  //     cnt_www <= cnt_www + 1;
  // end

  // integer i;
  // always @(posedge clk) begin
  //     if(reset) begin
  //         flag_ifdataerror <= 0;
  //         if(cnt_www==1) for(i=0;i<8192;i=i+1) data_out_temp[i] <= 0;
  //         now <= 0;
  //     end else if(Crop_valid && in_ready)begin
  //         now <= now + 1;
  //         if(cnt_www==1)begin
  //             if(now<8192) data_out_temp[now] <= Crop_data[0];
  //         end else if(cnt_www==2)begin
  //             flag_ifdataerror <= (data_out_temp[now] != Crop_data[0]);
  //         end else flag_ifdataerror <= flag_ifdataerror;
  //     end
  // end

endmodule
