`timescale 1ns/1ns

module vidgen(
    input           CLK,
    input           ARESET,

    output          VSYNC,
    output          DE, 
    output [7:0]    PIX_DAT
);

wire                pixel_clock;        
//reg [3:0]           pixel_clock_count; // used to generate pixel clock
//reg [5:0]           pixel_clock_count; // used to generate pixel clock
reg [7:0]           pixel_data;
reg [8:0]           line_count;
reg [8:0]           column_count;
reg [8:0]           scroll_count;
wire [9:0]          pixel_color_pos; // sum of column count and scroll count, used to determine actual pixel color
reg                 internal_vsync;
reg                 internal_hsync;
reg                 internal_vde; // vertical data enable - tells us we're in active lines
reg                 internal_de; // pixel data is valid (active line, active column)
reg                 hsync_r; // for falling edge of hsync
reg                 vsync_r; // same for hsync

localparam hactive = 400, vactive = 400;
localparam framerate = 30;

// 30 fps = 33.3333ms per frame
// Aiming for a pixel clock of 5.55556 MHz (easy to generate with 50 / 9)
// Total pixels = 450x412
localparam hblank = 150, vblank = 24;
localparam htotal = hactive + hblank, vtotal = vactive + vblank;
localparam vpwid = 4, hpwid = 16; // lines / pixels of pulse width (low sync)
localparam vbp = 6, vfp = (vblank - vbp - vpwid); // back porch - vsync high, before lines start. front porch - vsync high, after lines end
localparam hbp = 16, hfp = (hblank - hbp - hpwid); // back porch - hsync high, before pixels start. front port - hsync high, after pixels end


/*
// generate pixel clock
localparam pixel_divider = 4'd9;
assign pixel_clock = pixel_clock_count < 4'd4; // can't do 50% duty, but this is close enough
//localparam pixel_divider = 6'd60;
//assign pixel_clock = pixel_clock_count < 6'd30; // can't do 50% duty, but this is close enough
assign PIX_CLK = pixel_clock;

always @(posedge CLK or posedge ARESET) begin
    if(ARESET) begin
        pixel_clock_count <= 4'd0;
    end
    else begin
        if(pixel_clock_count >= (pixel_divider - 4'd1)) begin
            pixel_clock_count <= 4'd0;
        end else begin
            pixel_clock_count <= 4'd1 + pixel_clock_count;
        end
    end
end
*/

assign pixel_clock = CLK;

// generate hsync and de
always @(posedge pixel_clock or posedge ARESET) begin
    if(ARESET) begin
        column_count <= 9'd0;
        internal_hsync <= 1'b0;
        internal_de <= 1'b0;
        hsync_r <= 1'b0;
    end 
    else begin
        if(column_count >= (htotal - 1)) begin
            column_count <= 9'd0;
        end else begin
            column_count <= 9'd1 + column_count;
        end
        // Hsync is high whenever not in a sync pulse
        if(column_count >= hpwid)
            internal_hsync <= 1'b1;
        else
            internal_hsync <= 1'b0;
        // DE is only high in the active region...after back porch and before front porch
        if(internal_vde && (column_count >= (hpwid + hbp)) && (column_count < (hpwid + hbp + hactive)))
            internal_de <= 1'b1;
        else
            internal_de <= 1'b0;
        hsync_r <= internal_hsync;
    end

end

// generate vsync
always @(posedge pixel_clock or posedge ARESET) begin
    if(ARESET) begin
        line_count <= 9'd0;
        internal_vsync <= 1'b0;
        internal_vde <= 1'b0;
        scroll_count <= 9'd0;
        vsync_r <= 1'b0;
    end 
    else begin
        if(!internal_hsync && hsync_r) begin 
            if(line_count >= (vtotal-1)) begin
                line_count <= 9'd0;
            end else begin
                line_count <= 9'd1 + line_count;
            end
        end
        // Vsync is high whenever we're not in a sync pulse
        if(line_count >= vpwid)
            internal_vsync <= 1'b1;
        else   
            internal_vsync <= 1'b0;
        // Vertical data enable is high after back porch and before front porch
        if((line_count >= (vpwid + vbp)) && (line_count < (vpwid + vbp + vactive)))
            internal_vde <= 1'b1;
        else
            internal_vde <= 1'b0;

        // increase the scrolling count every frame (falling edge of vsync)
        if(vsync_r && !internal_vsync) begin
            if(scroll_count >= (vtotal-1)) begin
                scroll_count <= 9'd0;
            end else begin
                scroll_count <= 9'd1 + scroll_count;
            end
        end
        vsync_r <= internal_vsync;
    end

    
end

assign pixel_color_pos = column_count + scroll_count;

// vertical stripes
// 400 pixels wide image, 8 stripes, 50 pixel wide stripes
always @(posedge pixel_clock or posedge ARESET) begin
    if(ARESET) begin
        pixel_data <= 8'h00;
    end 
    else begin
        if(pixel_color_pos <= (hpwid + hbp + 50 - 1))       pixel_data <= 8'h08;
        else if(pixel_color_pos <= (hpwid + hbp + 100 - 1)) pixel_data <= 8'h20;
        else if(pixel_color_pos <= (hpwid + hbp + 150 - 1)) pixel_data <= 8'h40;
        else if(pixel_color_pos <= (hpwid + hbp + 200 - 1)) pixel_data <= 8'h60;
        else if(pixel_color_pos <= (hpwid + hbp + 250 - 1)) pixel_data <= 8'h80;
        else if(pixel_color_pos <= (hpwid + hbp + 300 - 1)) pixel_data <= 8'hA0;
        else if(pixel_color_pos <= (hpwid + hbp + 350 - 1)) pixel_data <= 8'hC0;
        else if(pixel_color_pos <= (hpwid + hbp + 400 - 1)) pixel_data <= 8'hF1;
        // so...why are we doing this twice?
        // easiest way to perform the scrolling feature
        // add a scrolling offset to the column count, which could push the total
        // past the end of active pixels
        else if(pixel_color_pos <= (hpwid + hbp + 450 - 1)) pixel_data <= 8'h08;
        else if(pixel_color_pos <= (hpwid + hbp + 500 - 1)) pixel_data <= 8'h20;
        else if(pixel_color_pos <= (hpwid + hbp + 550 - 1)) pixel_data <= 8'h40;
        else if(pixel_color_pos <= (hpwid + hbp + 600 - 1)) pixel_data <= 8'h60;
        else if(pixel_color_pos <= (hpwid + hbp + 650 - 1)) pixel_data <= 8'h80;
        else if(pixel_color_pos <= (hpwid + hbp + 700 - 1)) pixel_data <= 8'hA0;
        else if(pixel_color_pos <= (hpwid + hbp + 750 - 1)) pixel_data <= 8'hC0;
        else                                            pixel_data <= 8'hF1;
    end
end

assign PIX_DAT = pixel_data;

// Sync outputs
assign DE = internal_de;
assign VSYNC = internal_vsync;

endmodule
