//====================================================================
// gpu_pipeline_top.v - GPU渲染管线顶层状态机
// 第01课：渲染管线概述
// 功能：定义管线各阶段的状态流转，协调各模块工作
//====================================================================

module gpu_pipeline_top #(
    parameter DATA_WIDTH    = 32,    // 数据位宽
    parameter COORD_WIDTH   = 16,    // 坐标位宽(定点数)
    parameter COLOR_WIDTH   = 24,    // 颜色位宽(RGB各8位)
    parameter FB_WIDTH      = 640,   // 帧缓冲宽度
    parameter FB_HEIGHT     = 480,   // 帧缓冲高度
    parameter VERTEX_SIZE   = 32     // 顶点属性大小(bytes)
)(
    input  wire                     clk,        // 系统时钟
    input  wire                     rst_n,      // 异步复位，低有效
    
    // 顶点数据输入接口
    input  wire                     vdata_valid,// 顶点数据有效
    input  wire [DATA_WIDTH-1:0]    vdata_in,   // 顶点数据输入
    output reg                      vdata_ready,// 准备接收顶点数据
    
    // 帧缓冲写入接口
    output reg  [COORD_WIDTH-1:0]   fb_x,       // 帧缓冲x坐标
    output reg  [COORD_WIDTH-1:0]   fb_y,       // 帧缓冲y坐标
    output reg  [COLOR_WIDTH-1:0]   fb_color,   // 帧缓冲颜色
    output reg                      fb_wen,     // 帧缓冲写使能
    
    // 状态输出
    output reg  [3:0]               pipeline_stage,// 当前管线阶段
    output reg                      frame_done  // 一帧渲染完成
);
/* verilator lint_off WIDTHEXPAND */
/* verilator lint_off WIDTHTRUNC */
/* verilator lint_off CASEOVERLAP */
/* verilator lint_off CMPCONST */
/* verilator lint_off UNSIGNED */
/* verilator lint_off CASEINCOMPLETE */
/* verilator lint_off WIDTHCONCAT */


    //================================================================
    // 管线阶段定义
    //================================================================
    localparam STAGE_IDLE       = 4'd0;  // 空闲状态
    localparam STAGE_VERTEX     = 4'd1;  // 顶点处理
    localparam STAGE_ASSEMBLY   = 4'd2;  // 图元装配
    localparam STAGE_CLIP       = 4'd3;  // 裁剪
    localparam STAGE_RASTER     = 4'd4;  // 光栅化
    localparam STAGE_FRAGMENT   = 4'd5;  // 片段着色
    localparam STAGE_DEPTH      = 4'd6;  // 深度测试
    localparam STAGE_BLEND      = 4'd7;  // 混合
    localparam STAGE_FRAMEBUFFER= 4'd8;  // 帧缓冲写入
    localparam STAGE_DONE       = 4'd9;  // 渲染完成

    //================================================================
    // 内部寄存器
    //================================================================
    reg [COORD_WIDTH-1:0] vertex_x, vertex_y, vertex_z;
    reg [COLOR_WIDTH-1:0] vertex_color;
    reg [DATA_WIDTH-1:0]  vertex_attr_buf [0:7]; // 顶点属性缓冲
    reg [2:0]             attr_count;             // 属性计数器
    
    // 图元装配缓冲(3个顶点构成一个三角形)
    reg [COORD_WIDTH-1:0] prim_v0_x, prim_v0_y, prim_v0_z;
    reg [COORD_WIDTH-1:0] prim_v1_x, prim_v1_y, prim_v1_z;
    reg [COORD_WIDTH-1:0] prim_v2_x, prim_v2_y, prim_v2_z;
    reg [COLOR_WIDTH-1:0] prim_v0_color, prim_v1_color, prim_v2_color;
    reg [1:0]             vertex_count;  // 当前图元的顶点计数
    
    // 光栅化相关
    reg [COORD_WIDTH-1:0] raster_x, raster_y;
    reg [COORD_WIDTH-1:0] raster_x_end, raster_y_end;
    
    // 片段数据
    reg [COLOR_WIDTH-1:0] frag_color;
    reg [COORD_WIDTH-1:0] frag_depth;
    
    // 统计计数器
    reg [31:0] vertices_processed;
    reg [31:0] primitives_drawn;
    reg [31:0] fragments_shaded;
    reg [31:0] pixels_written;

    //================================================================
    // 管线状态机 - 主状态转移
    //================================================================
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            pipeline_stage   <= STAGE_IDLE;
            vdata_ready      <= 1'b1;
            fb_wen           <= 1'b0;
            frame_done       <= 1'b0;
            attr_count       <= 3'd0;
            vertex_count     <= 2'd0;
            vertices_processed <= 32'd0;
            primitives_drawn   <= 32'd0;
            fragments_shaded   <= 32'd0;
            pixels_written     <= 32'd0;
            raster_x         <= {COORD_WIDTH{1'b0}};
            raster_y         <= {COORD_WIDTH{1'b0}};
        end else begin
            fb_wen      <= 1'b0;  // 默认不写帧缓冲
            frame_done  <= 1'b0;  // 默认帧未完成
            
            case (pipeline_stage)
                //------------------------------------------------
                // 空闲状态：等待顶点数据
                //------------------------------------------------
                STAGE_IDLE: begin
                    vdata_ready <= 1'b1;
                    if (vdata_valid) begin
                        pipeline_stage <= STAGE_VERTEX;
                        vdata_ready    <= 1'b0;
                        attr_count     <= 3'd0;
                    end
                end
                
                //------------------------------------------------
                // 顶点处理阶段：接收并处理顶点属性
                //------------------------------------------------
                STAGE_VERTEX: begin
                    if (vdata_valid) begin
                        // 将顶点属性存入缓冲
                        vertex_attr_buf[attr_count] <= vdata_in;
                        attr_count <= attr_count + 3'd1;
                        
                        // 8个属性接收完毕(位置xyz + 法线xyz + uv + 颜色)
                        if (attr_count == 3'd7) begin
                            // 解析顶点位置(简化：假设已为屏幕坐标)
                            vertex_x     <= vertex_attr_buf[0][COORD_WIDTH-1:0];
                            vertex_y     <= vertex_attr_buf[1][COORD_WIDTH-1:0];
                            vertex_z     <= vertex_attr_buf[2][COORD_WIDTH-1:0];
                            vertex_color <= vdata_in[COLOR_WIDTH-1:0];
                            
                            vertices_processed <= vertices_processed + 32'd1;
                            pipeline_stage <= STAGE_ASSEMBLY;
                        end
                    end
                end
                
                //------------------------------------------------
                // 图元装配：将顶点组装为三角形
                //------------------------------------------------
                STAGE_ASSEMBLY: begin
                    case (vertex_count)
                        2'd0: begin
                            prim_v0_x     <= vertex_x;
                            prim_v0_y     <= vertex_y;
                            prim_v0_z     <= vertex_z;
                            prim_v0_color <= vertex_color;
                            vertex_count  <= 2'd1;
                            vdata_ready   <= 1'b1;
                            pipeline_stage <= STAGE_VERTEX; // 继续接收下一个顶点
                        end
                        2'd1: begin
                            prim_v1_x     <= vertex_x;
                            prim_v1_y     <= vertex_y;
                            prim_v1_z     <= vertex_z;
                            prim_v1_color <= vertex_color;
                            vertex_count  <= 2'd2;
                            vdata_ready   <= 1'b1;
                            pipeline_stage <= STAGE_VERTEX;
                        end
                        2'd2: begin
                            prim_v2_x     <= vertex_x;
                            prim_v2_y     <= vertex_y;
                            prim_v2_z     <= vertex_z;
                            prim_v2_color <= vertex_color;
                            vertex_count  <= 2'd0;
                            primitives_drawn <= primitives_drawn + 32'd1;
                            pipeline_stage <= STAGE_CLIP;
                        end
                    endcase
                end
                
                //------------------------------------------------
                // 裁剪阶段：判断图元是否在可视区域内
                //------------------------------------------------
                STAGE_CLIP: begin
                    // 简化裁剪：检查三角形是否完全在屏幕外
                    if ((prim_v0_x >= FB_WIDTH && prim_v1_x >= FB_WIDTH && prim_v2_x >= FB_WIDTH) ||
                        (prim_v0_y >= FB_HEIGHT && prim_v1_y >= FB_HEIGHT && prim_v2_y >= FB_HEIGHT)) begin
                        // 完全裁剪，回到空闲
                        pipeline_stage <= STAGE_IDLE;
                        vdata_ready    <= 1'b1;
                    end else begin
                        // 部分或全部在屏幕内，进入光栅化
                        pipeline_stage <= STAGE_RASTER;
                        raster_x       <= {COORD_WIDTH{1'b0}};
                        raster_y       <= {COORD_WIDTH{1'b0}};
                    end
                end
                
                //------------------------------------------------
                // 光栅化阶段：遍历三角形包围盒内的像素
                //------------------------------------------------
                STAGE_RASTER: begin
                    frag_color <= prim_v0_color; // 简化：使用顶点0的颜色
                    
                    if (raster_y < FB_HEIGHT) begin
                        if (raster_x < FB_WIDTH) begin
                            raster_x <= raster_x + 16'd1;
                            pipeline_stage <= STAGE_FRAGMENT;
                        end else begin
                            raster_x <= {COORD_WIDTH{1'b0}};
                            raster_y <= raster_y + 16'd1;
                        end
                    end else begin
                        pipeline_stage <= STAGE_DONE;
                    end
                end
                
                //------------------------------------------------
                // 片段着色阶段
                //------------------------------------------------
                STAGE_FRAGMENT: begin
                    fragments_shaded <= fragments_shaded + 32'd1;
                    pipeline_stage <= STAGE_DEPTH;
                end
                
                //------------------------------------------------
                // 深度测试阶段
                //------------------------------------------------
                STAGE_DEPTH: begin
                    pipeline_stage <= STAGE_BLEND;
                end
                
                //------------------------------------------------
                // 混合阶段
                //------------------------------------------------
                STAGE_BLEND: begin
                    pipeline_stage <= STAGE_FRAMEBUFFER;
                end
                
                //------------------------------------------------
                // 帧缓冲写入阶段
                //------------------------------------------------
                STAGE_FRAMEBUFFER: begin
                    fb_x     <= raster_x;
                    fb_y     <= raster_y;
                    fb_color <= frag_color;
                    fb_wen   <= 1'b1;
                    pixels_written <= pixels_written + 32'd1;
                    pipeline_stage <= STAGE_RASTER;
                end
                
                //------------------------------------------------
                // 渲染完成
                //------------------------------------------------
                STAGE_DONE: begin
                    frame_done     <= 1'b1;
                    pipeline_stage <= STAGE_IDLE;
                    vdata_ready    <= 1'b1;
                end
                
                default: pipeline_stage <= STAGE_IDLE;
            endcase
        end
    end

endmodule
