//====================================================================
// framebuffer_controller.v - 帧缓冲控制器
// 第06课：双缓冲管理、VGA时序生成、像素读写
//====================================================================
module framebuffer_controller #(
    parameter FB_WIDTH    = 640,
    parameter FB_HEIGHT   = 480,
    parameter COLOR_WIDTH = 24,
    parameter ADDR_WIDTH  = 20
)(
    input  wire                     clk, rst_n,
    input  wire                     gpu_wen,
    input  wire [ADDR_WIDTH-1:0]    gpu_addr,
    input  wire [COLOR_WIDTH-1:0]   gpu_color,
    output reg                      vga_hsync, vga_vsync,
    output reg  [7:0]               vga_r, vga_g, vga_b,
    output reg                      vga_de,
    input  wire                     swap_req,
    output reg                      swap_done,
    output reg                      vblank
);
/* verilator lint_off WIDTHEXPAND */
/* verilator lint_off WIDTHTRUNC */
/* verilator lint_off CASEOVERLAP */
/* verilator lint_off CMPCONST */
/* verilator lint_off UNSIGNED */
/* verilator lint_off WIDTHCONCAT */

    localparam H_VISIBLE=640, H_FRONT=16, H_SYNC=96, H_BACK=48, H_TOTAL=800;
    localparam V_VISIBLE=480, V_FRONT=10, V_SYNC=2, V_BACK=33, V_TOTAL=525;
    reg [9:0] h_count, v_count;
    reg current_front, swap_pending;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            h_count<=0; v_count<=0; vga_hsync<=1; vga_vsync<=1;
            vga_de<=0; vga_r<=0; vga_g<=0; vga_b<=0; vblank<=0;
            swap_done<=0; current_front<=0; swap_pending<=0;
        end else begin
            swap_done <= 1'b0;
            if (h_count == H_TOTAL - 1) begin
                h_count <= 0;
                if (v_count == V_TOTAL - 1) v_count <= 0;
                else v_count <= v_count + 1;
            end else h_count <= h_count + 1;
            vga_hsync <= (h_count >= H_VISIBLE + H_FRONT && h_count < H_VISIBLE + H_FRONT + H_SYNC) ? 1'b0 : 1'b1;
            vga_vsync <= (v_count >= V_VISIBLE + V_FRONT && v_count < V_VISIBLE + V_FRONT + V_SYNC) ? 1'b0 : 1'b1;
            if (h_count < H_VISIBLE && v_count < V_VISIBLE) begin
                vga_de <= 1'b1; vblank <= 1'b0;
            end else begin vga_de <= 1'b0; vga_r<=0; vga_g<=0; vga_b<=0; end
            if (v_count >= V_VISIBLE) vblank <= 1'b1;
            if (swap_pending && v_count == V_VISIBLE + V_FRONT) begin
                current_front <= ~current_front; swap_pending <= 1'b0; swap_done <= 1'b1;
            end
            if (swap_req && !swap_pending) swap_pending <= 1'b1;
        end
    end
endmodule