module vga(
    input clk,
    input [6:0] in,
    input in_stb,
    output vga_h_sync,
    output vga_v_sync,
    output reg vga_red,
    output reg vga_grn,
    output reg vga_blu
    );
    
    reg [5:0] v_ram[0:959] /* synthesis syn_ramstyle = "block_ram" */;
    reg [4:0] c_rom[0:447] /* synthesis syn_ramstyle = "block_ram" */;
    initial begin
        $readmemb("../roms/vga_vram.bin", v_ram, 0, 959);
        $readmemb("../roms/vga_font.bin", c_rom, 0, 447);
    end

    // generate 25MHz pixel clock enable
    reg vga_cnt;
    wire vga_clk_en;

    always @(posedge clk)
    begin
        vga_cnt <= vga_cnt + 1;
    end
    assign vga_clk_en = vga_cnt;

    // video structure constants
    parameter hpixels = 800;    // horizontal pixels per line
    parameter vlines = 521;     // vertical lines per frame
    parameter hpulse = 96;      // hsync pulse length
    parameter vpulse = 2;       // vsync pulse length
    parameter hbp = 144;        // end of horizontal back porch
    parameter hfp = 784;        // beginning of horizontal front porch
    parameter vbp = 31;         // end of vertical back porch
    parameter vfp = 511;        // beginning of vertical front porch

    // registers for storing the horizontal & vertical counters
    reg [9:0] hc;
    reg [9:0] vc;
    reg [5:0] hpos;
    reg [4:0] vpos;
    reg [3:0] hdot;
    reg [4:0] vdot;

    always @(posedge clk)
    begin
        if (vga_clk_en)
        begin
            if (hc < hpixels - 1)
            begin
                hc <= hc + 1;

                // count 16 pixels, so 640px / 16 = 40 characters
                if (vga_h_act)
                begin
                    hdot <= hdot + 1;

                    if (hdot == 4'hF)
                    begin
                        hdot <= 0;
                        hpos <= hpos + 1;
                    end
                end
            end
            else
            begin
                // reset horizontal counters
                hc <= 0;
                hdot <= 0;
                hpos <= 0;

                if (vc < vlines - 1)
                begin
                    vc <= vc + 1;
            
                    // count 20 rows, so 480px / 20 = 24 rows
                    if (vga_v_act)
                    begin
                        vdot <= vdot + 1;

                        if (vdot == 5'd19)
                        begin
                            vdot <= 0;
                            vpos <= vpos + 1;
                        end
                    end
                end
                else
                begin
                    vc <= 0;
                    vdot <= 0;
                    vpos <= 0;
                end
            end
        end
    end

    assign vga_h_act = (hc >= hbp && hc < hfp);
    assign vga_v_act = (vc >= vbp && vc < vfp);

    assign vga_h_sync = (hc < hpulse) ? 0 : 1;
    assign vga_v_sync = (vc < vpulse) ? 0 : 1;
    // assign vblank = (vc >= vbp && vc < vfp) ? 0:1;

    always @(posedge clk)
    begin
        if (~(vga_h_act && vga_v_act))
        begin
            // outside display area
            vga_red = 0;

        end else begin
            // inside display area

            if (vdot[4:1] == 0 || vdot[4:1] == 1 || vdot[4:1] == 9 || hdot[3:1] == 0 || hdot[3:1] == 6 || hdot[3:1] == 7)
                vga_red = 0;
            else
                vga_red = c_rom[(v_ram[hpos + (vpos * 40)] * 7) + (vdot[4:1] - 2)][5 - hdot[3:1]];

        end

        vga_grn = vga_red;
        vga_blu = vga_red;
    end

    reg [5:0] cur_pos;
    reg stb;
    always @(posedge clk)
    begin
        if (in_stb & ~stb)
        begin
            v_ram[cur_pos] <= {~in[6], in[4:0]};
            stb <= 1;
            cur_pos <= cur_pos + 1;
        end

        if (~in_stb & stb)
        begin
            stb <= 0;
        end
    end
endmodule
