module demosaic2 #(
    parameter IM_WIDTH = 512,       // 图像宽度
    parameter IM_HEIGHT = 256,      // 图像高度
    parameter RAW_TYPE = 3          // 0:grbg 1:rggb 2:bggr 3:gbrg
)(
    // 基本信号
    input clk,
    input reset,

    // 数据输入信号
    input data_en,
    input [15:0] data_in [2:0],     // 数据输入线，0、1、2分别表示第一、二、三行
    output reg data_que,            // 数据请求线，高电平：请求三个数据，直到读取完才拉低
    output reg data_line,           // 新一行请求数据线，高电平：请求九个数据，直到读取完才拉低

    // en: 输出数据有效信号，高电平有效
    output reg out_en, 
    output reg [15:0] out_r,
    output reg [15:0] out_g,
    output reg [15:0] out_b
);

    // 常量，包括状态机
    // localparam IM_SIZE = IM_HEIGHT * IM_WIDTH;
    localparam READ_DATA = 0;
    localparam COLOR_GEN = 1;
    localparam WRITE_DATA = 2;
    localparam SLIDE_WINDOW = 3;

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

    // 三段状态机实现，窗口滑动，颜色计算
    // 状态切换
    always @(posedge clk or posedge reset) 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 = WRITE_DATA;
            WRITE_DATA: nextState = SLIDE_WINDOW;
            SLIDE_WINDOW: nextState = READ_DATA;
        endcase
    end

    // 各状态执行的操作
    always @(posedge clk or posedge reset) begin
        if (reset) begin
            // 外部输出初始化
            out_en <= 0;
            out_r <= 0;
            out_g <= 0;
            out_r <= 0;
            data_que <= 0;
            data_line <= 1;

            // 内部寄存器初始化
            pos_x <= 0;
            pos_y <= 0;
            cnt_data <= 0;
            raw_type <= RAW_TYPE;
        end
        else begin
            // 状态机执行
            case (state)
                // 读取数据
                READ_DATA: begin
                    data_que <= 1;
                    if (cnt_data < 2)
                        data_line <= 1;

                    if (data_en) begin
                        data_cache[cnt_data][0] <= data_in[0];
                        data_cache[cnt_data][1] <= data_in[1];
                        data_cache[cnt_data][2] <= data_in[2];
                        cnt_data <= cnt_data + 1;
                    end
                end 

                COLOR_GEN: begin
                    // 取消数据请求
                    data_que <= 0;
                    data_line <= 0;

                    // 生成rgb图像
                    case (raw_type)
                        0: begin // Missing B, R on G
                            red <= (data_cache[0][1] + data_cache[2][1]) / 2;
                            blue <= (data_cache[1][0] + data_cache[1][2]) / 2;
                            green <= data_cache[1][1];
                        end

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

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

                        3: begin // Missing B, R on G
                            blue <= (data_cache[0][1] + data_cache[2][1]) / 2;
                            red <= (data_cache[1][0] + data_cache[1][2]) / 2;
                            green <= data_cache[1][1];
                        end
                    endcase
                    raw_type <= raw_type + 1;
                end

                WRITE_DATA: begin
                    out_en <= 1;
                    out_r <= red;
                    out_b <= blue;
                    out_g <= green;
                    
                end

                SLIDE_WINDOW: begin
                    // 恢复相关寄存器变量
                    out_en <= 0;

                    // 记录位置寄存器自增，并处理缓存数据
                    pos_x <= pos_x + 1;
                    if (pos_x >= IM_WIDTH - 2) begin
                        cnt_data <= 0;
                        pos_x <= 0;
                        pos_y <= pos_y + 1;
                        if (pos_y >= IM_HEIGHT - 2)
                            pos_y <= 0;
                    end
                    else begin
                        cnt_data <= 2;
                        
                        // 窗口右移
                        data_cache[0][0] <= data_cache[0][1];
                        data_cache[1][0] <= data_cache[1][1];
                        data_cache[2][0] <= data_cache[2][1];
                        data_cache[0][1] <= data_cache[0][2];
                        data_cache[1][1] <= data_cache[1][2];
                        data_cache[2][1] <= data_cache[2][2];
                    end
                end
            endcase
        end
    end 

endmodule

