Friday, June 7, 2013

The Video Generator

The SOCoco-80 Project

 

The SOCoCo-80 Project   

 

 

I plan on updating the main page of this blog with more details as I go forward. Each section of this blog will cover specific aspects of the project. This section will cover the details of the video controller as is morphs into reality.

 

The Video

To create the timing needed for most VGA monitors we must start with the proper clock. The VGA standard calls for a clock frequency of 25.175 MHz or a  28.322 MHz master. The more common standard is the 25.175 MHz so I will be using that as my base frequency. To accomplish this I will use a Megafunction Phase Lock Loop which can take a base clock and create up to three output clocks which run at a harmonic frequency of the base. Although this magic Megafunction works well, it’s not perfect. The planned output frequency is not exactly 25.175 MHz. This causes some problems which will be detailed later.

 

To create a 640x480 pixel resolution frame we need to generate the horizontal frame. This consists of a total of 800 clock pulse. 640 of those pulses will be for the video. 16 for the front porch delay. 96 for the Horizontal Sync. Pulse width and finally 48 for the back porch.

 

I used this site as a reference to generate the signals:

 

VGA Signal Information

 

If you look at the code below, there’s an additional 7 clock cycles called the H_SYNC_DELAY for a total of 807 clock cycles. This is to correct for the Phase Lock Loop variance on the 25.175 MHz clock. It’s actually about 25.2 MHz which is slightly faster.

 

The Vertical timing is a slave function of the horizontal. In other words, the counting of the vertical is based on the number of horizontal scans and not the main clock. The VGA standard calls for a total of 525 horizontal scans to make up the total vertical frame. I have added one more scan frame to make up for the clock frequency variance. Doing this was the preferred method because just adding more delay to the horizontal caused my monitor to loose sync. occasionally.

 

 

 

The code below work perfectly but handles only one video mode (640 x 480 x 64 colors). The plan is to expand this controller to many other modes, so more to come!!!

 

The Code

//

//##############################################################

//

//     This source code is the proprty of Tim Franklin

//     Modifications to this code is prohibited under

//     all software copyright laws. So don't do it!!!

//

//     support@franklinlabs.com

//

//     Rev: 1.0.0.014

//

//##############################################################

//

module  VideoController

 (

 

    input               i_VGA_CLK,

    input               i_RST_N,

 

    output [ 3:0 ]      o_Red,

    output [ 3:0 ]      o_Green,

    output [ 3:0 ]      o_Blue,

 

    output  reg         o_VGA_H_SYNC,

    output  reg         o_VGA_V_SYNC,

 

    // Memory Control Signals

    input [ 15:0 ]      i_VGA_DATA,

    output [ 15:0 ]     o_VGA_DATA,

    output [ 17:0 ]     o_VGA_ADDR,

    output  reg         o_VGA_WE_N,

    output  reg         o_VGA_OE_N,

    output  reg         o_VGA_CE_N,

    output  reg         o_VGA_LB_N,

    output  reg         o_VGA_UB_N

 

 );

 

//

//##############################################################

//

 

    //

    // ============================================================

    // Parameter Definitions

    // ============================================================

    //

 

    parameter   VIDEO_WIDTH         = 640;

    parameter   VIDEO_HEIGHT        = 480;

 

    parameter   H_SYNC_VIDEO        = VIDEO_WIDTH;

    parameter   H_SYNC_FRONT        = 16;

    parameter   H_SYNC_CYC          = 96;

    parameter   H_SYNC_BACK         = 48;

    parameter   H_SYNC_DELAY        = 7;

 

    parameter   H_TIME_ACT          = H_SYNC_VIDEO;

    parameter   H_TIME_FRONT        = H_TIME_ACT + H_SYNC_FRONT;

    parameter   H_TIME_CYC          = H_TIME_FRONT + H_SYNC_CYC;

    parameter   H_TIME_BACK         = H_TIME_CYC + H_SYNC_BACK;

    parameter   H_TIME_DELAY        = H_TIME_BACK + H_SYNC_DELAY;

 

    parameter   V_SYNC_VIDEO        = VIDEO_HEIGHT;

    parameter   V_SYNC_FRONT        = 31;

    parameter   V_SYNC_CYC          = 2;

    parameter   V_SYNC_BACK         = 11;

    parameter   V_SYNC_DELAY        = 2;

 

    parameter   V_TIME_ACT          = V_SYNC_VIDEO;

    parameter   V_TIME_FRONT        = V_TIME_ACT + V_SYNC_FRONT;

    parameter   V_TIME_CYC          = V_TIME_FRONT + V_SYNC_CYC;

    parameter   V_TIME_BACK         = V_TIME_CYC + V_SYNC_BACK;

    parameter   V_TIME_DELAY        = V_TIME_BACK + V_SYNC_DELAY;

 

    parameter   BLANK_ON            = 1;

    parameter   BLANK_OFF           = 0;

 

    parameter   H_SYNC_ON           = 0;

    parameter   H_SYNC_OFF          = 1;

 

    parameter   V_SYNC_ON           = 0;

    parameter   V_SYNC_OFF          = 1;

 

    parameter   SYNC_STATE_RESET    = 4'd0;

    parameter   SYNC_STATE_VIDEO    = 4'd1;

    parameter   SYNC_STATE_FRONT    = 4'd2;

    parameter   SYNC_STATE_SYNC     = 4'd3;

    parameter   SYNC_STATE_BACK     = 4'd4;

    parameter   SYNC_STATE_DELAY    = 4'd5;

 

    //

    // ============================================================

    // Declarations

    // ============================================================

    //

 

    reg [ 3:0 ]     r_ColorR;

    reg [ 3:0 ]     r_ColorG;

    reg [ 3:0 ]     r_ColorB;

 

    reg [ 3:0 ]     H_State;

    reg [ 3:0 ]     V_State;

 

    reg [ 15:0 ]    r_Coord_X;

    reg [ 15:0 ]    r_Coord_Y;

 

    reg [ 15:0 ]    r_HCount;

    reg [ 15:0 ]    r_VCount;

 

    reg             r_VBlank;

    reg             r_HBlank;

 

    reg [ 18:0 ]    r_VGA_Address;

 

    wire [ 7:0 ]    w_ImageData;

 

    wire [ 1:0 ]    w_PIX16_Rc;

    wire [ 1:0 ]    w_PIX16_Gc;

    wire [ 1:0 ]    w_PIX16_Bc;

 

    //

    // ============================================================

    // Assignments - Asynchronous

    // ============================================================

    //

 

    assign o_VGA_ADDR [ 17:0 ] = r_VGA_Address[ 18:1 ];

 

    assign w_ImageData = r_VGA_Address[ 0 ] ? i_VGA_DATA [ 7:0 ] : i_VGA_DATA [ 15:8 ];

 

    // 16 color mode data aquisition

    assign w_PIX16_Rc = w_ImageData[ 1:0 ];

    assign w_PIX16_Gc = w_ImageData[ 3:2 ];

    assign w_PIX16_Bc = w_ImageData[ 5:4 ];

 

    assign o_Red    = r_HBlank ? 4'b0000 : r_VBlank ? 4'b0000 : r_ColorR;

    assign o_Green  = r_HBlank ? 4'b0000 : r_VBlank ? 4'b0000 : r_ColorG;

    assign o_Blue   = r_HBlank ? 4'b0000 : r_VBlank ? 4'b0000 : r_ColorB;

 

    assign o_VGA_DATA = 16'hzzzz;

 

    //

    // ============================================================

    // Methods - Synchronous

    // ============================================================

    //

 

    always@ ( posedge i_VGA_CLK or negedge i_RST_N )

    begin

 

        o_VGA_WE_N = 1;

        o_VGA_CE_N = 0;

        o_VGA_OE_N = 0;

        o_VGA_UB_N = 0;

        o_VGA_LB_N = 0;

       

        r_VGA_Address <= ( r_Coord_Y * VIDEO_WIDTH ) + r_Coord_X;

 

        //

        // ============================================================

        // This code displays the pixels during the scan time and

        // turns them off during the blank pulses

        // ============================================================

        //

        if ( !i_RST_N )

        begin

 

            r_ColorR        <= 0;

            r_ColorG        <= 0;

            r_ColorB        <= 0;

 

            r_Coord_X       <= 0;

            r_Coord_Y       <= 0;

 

            r_HCount        <= -1;

            r_VCount        <= 0;

 

            o_VGA_H_SYNC    <= V_SYNC_OFF;

            o_VGA_V_SYNC    <= V_SYNC_OFF;

 

            r_HBlank        <= BLANK_ON;

            r_VBlank        <= BLANK_ON;

 

            H_State         <= SYNC_STATE_RESET;

            V_State         <= SYNC_STATE_RESET;

 

        end

        else

        begin

 

            r_HCount = r_HCount + 1;

 

            // ============================================================

            // Generate Horizontal sync timing

            // ============================================================

 

            case( H_State )

            SYNC_STATE_RESET:

                    begin

                        r_ColorR <= 0;

                        r_ColorG <= 0;

                        r_ColorB <= 0;

                        r_HBlank <= BLANK_OFF;

                        o_VGA_H_SYNC <= H_SYNC_OFF;

                        H_State <= SYNC_STATE_VIDEO;

                    end

            SYNC_STATE_VIDEO:

                    begin

                        r_Coord_X <= r_HCount;

 

                        if( r_HCount >= H_TIME_ACT )

                        begin

                            r_HBlank <= BLANK_ON;

                            o_VGA_H_SYNC <= H_SYNC_OFF;

                            H_State <= SYNC_STATE_FRONT;

                        end

                    end

            SYNC_STATE_FRONT:

                    begin

                        if( r_HCount >= ( H_TIME_FRONT ) )

                        begin

                            r_HBlank <= BLANK_ON;

                            o_VGA_H_SYNC <= H_SYNC_ON;

                            H_State <= SYNC_STATE_SYNC;

                        end

                    end

            SYNC_STATE_SYNC:

                    begin

                        if( r_HCount >= ( H_TIME_CYC ) )

                        begin

                            r_HBlank <= BLANK_ON;

                            o_VGA_H_SYNC <= H_SYNC_OFF;

                            H_State <= SYNC_STATE_BACK;

                        end

                    end

            SYNC_STATE_BACK:

                    begin

                        if( r_HCount >= ( H_TIME_BACK ) )

                        begin

                            r_HBlank <= BLANK_ON;

                            o_VGA_H_SYNC <= H_SYNC_OFF;

                            H_State <= SYNC_STATE_DELAY;

                        end

                    end

            SYNC_STATE_DELAY:

                    begin

                        if( r_HCount >= ( H_TIME_DELAY ) )

                        begin

                            r_HBlank <= BLANK_OFF;

                            o_VGA_H_SYNC <= H_SYNC_OFF;

                            H_State <= SYNC_STATE_VIDEO;

                            r_HCount = 0;

                            r_Coord_X <= 0;

                            r_VCount = r_VCount + 1;

                        end

                    end

            endcase

 

            // ============================================================

            // Generate Vertical sync timing

            // ============================================================

 

            case( V_State )

            SYNC_STATE_RESET:

                    begin

                        r_VBlank <= BLANK_OFF;

                        o_VGA_V_SYNC <= V_SYNC_OFF;

                        V_State <= SYNC_STATE_VIDEO;

                    end

            SYNC_STATE_VIDEO:

                    begin

                        r_Coord_Y <= r_VCount;

 

                        if( r_VCount >= V_TIME_ACT )

                        begin

                            r_VBlank <= BLANK_ON;

                            o_VGA_V_SYNC <= V_SYNC_OFF;

                            V_State <= SYNC_STATE_FRONT;

                        end

                    end

            SYNC_STATE_FRONT:

                    begin

                        if( r_VCount >= ( V_TIME_FRONT ) )

                        begin

                            r_VBlank <= BLANK_ON;

                            o_VGA_V_SYNC <= V_SYNC_ON;

                            V_State <= SYNC_STATE_SYNC;

                        end

                    end

            SYNC_STATE_SYNC:

                    begin

                        if( r_VCount >= ( V_TIME_CYC ) )

                        begin

                            r_VBlank <= BLANK_ON;

                            o_VGA_V_SYNC <= V_SYNC_OFF;

                            V_State <= SYNC_STATE_BACK;

                        end

                    end

            SYNC_STATE_BACK:

                    begin

                        if( r_VCount >= ( V_TIME_BACK ) )

                        begin

                            r_VBlank <= BLANK_ON;

                            o_VGA_V_SYNC <= V_SYNC_OFF;

                            V_State <= SYNC_STATE_DELAY;

                        end

                    end

            SYNC_STATE_DELAY:

                    begin

                        if( r_VCount >= ( V_TIME_DELAY ) )

                        begin

                            r_VBlank <= BLANK_OFF;

                            o_VGA_V_SYNC <= V_SYNC_OFF;

                            V_State <= SYNC_STATE_VIDEO;

                            r_VCount = 0;

                            r_Coord_Y <= 0;

                        end

                    end

            endcase

 

        end

 

        //

        // ============================================================

        // This code populated the three color registers depending on

        // what color mode we are in

        // ============================================================

        //

        case (  w_PIX16_Rc )

        2'b00:      r_ColorR <= 4'b0000;

        2'b01:      r_ColorR <= 4'b0011;

        2'b10:      r_ColorR <= 4'b0111;

        2'b11:      r_ColorR <= 4'b1111;

        endcase

 

        case (  w_PIX16_Gc )

        2'b00:      r_ColorG <= 4'b0000;

        2'b01:      r_ColorG <= 4'b0011;

        2'b10:      r_ColorG <= 4'b0111;

        2'b11:      r_ColorG <= 4'b1111;

        endcase

 

        case (  w_PIX16_Bc )

        2'b00:      r_ColorB <= 4'b0000;

        2'b01:      r_ColorB <= 4'b0011;

        2'b10:      r_ColorB <= 4'b0111;

        2'b11:      r_ColorB <= 4'b1111;

        endcase

    end

 

endmodule

 

 

 

© 2013 - FranklinLabs

www.franklinlabs.com

 

No comments:

Post a Comment