What I am attempting to do is create a VGA controller from a Lattice MachXO CPLD in Verilog.

The Problem

I am attempting to display the color red with a resolution of 640x480 @ 60Hz using a 25.175 MHz clock internal to the CPLD; however, when I plug the CPLD into a monitor I get an "Out of Range" message; no monitor I try can understand what resolution I would like.

What I've tried

I have simulated the code in ModelSim (pictures included), and everything appears to look good save for one issue. When I count the amount of time steps that have occurred from the during the V-Sync display zone (when H-Sync is drawing) and divided it by the frequency of H-Sync, I get 479 pulses -- one short of the 480 lines I should be drawing. I don't understand where this could be coming from as I've check my timings many times, and I suspect that this may be a symptom of the problem, but I'm not sure.

The numbers I'm using to generate my numbers for timings is from Tiny VGA: tinyvga.com/vga-timing/640x480@60Hz Instead of counting lines for V_SYNC I am counting clock pulses, however, The numbers should be equivlent (ie. 2 800 count lines = 1600 pulses). I may change this behavior to line counting later.

Below is my code, and pictures of the timings from ModelSim.

module Top(RESET, H_SYNC, V_SYNC, RED);
    input  wire RESET;
    output wire H_SYNC;
    output wire V_SYNC;
    output wire RED;

    wire rgb_en;

    /*** Test Bench Code ***/
     //reg osc_clk, reset;
     //initial begin
         //#0 reset     = 0;
         //#0 osc_clk = 0;
         //#2 reset     = 1;

     //always #1 osc_clk = ~osc_clk;

    OSCC        OSCC_1 (.OSC(osc_clk)); /*< IP clock module for Lattice CPLD    >*/
    Controller  CNTRL(.NRST(RESET), .CLK(osc_clk), .H_SYNC(H_SYNC), .V_SYNC(V_SYNC), .RGB_EN(rgb_en));

    assign RED = (rgb_en ? 1:1'bz); 


module Controller(CLK, NRST, H_SYNC, V_SYNC, RGB_EN);
    input  wire CLK;        /*< CLK input from Top module   >*/
    input  wire NRST;       /*< Reset input from Top module >*/
    output reg  H_SYNC;     /*< Goes to VGA Horizontal Sync >*/
    output reg  V_SYNC;     /*< Goes to VGA Verical Sync    >*/
    output reg  RGB_EN  ;   /*< Enables RGB values durning display time on H_SYNC >*/

    reg [9:0] h_counter;   /*< Tracks amount of pulses from CLK                 >*/
    reg [18:0] v_counter;  /*< Tracks amount of pulses from H_SYNC              >*/

    `define H_SYNC_PULSE        10'd96      /*< Length of Sync Pulse            >*/
    `define H_BACK_PORCH_END    10'd144     /*< Pulse len + Porch Len           >*/
    `define H_FRONT_PORCH_STRT  10'd784     /*< Front Porch Len - Max           >*/
    `define H_COUNT_MAX         10'd799     /*< Max line pulses for resolution  >*/

    `define V_SYNC_PULSE        19'd1600    /*< 2 H_SYNC lines       >*/
    `define V_BACK_PORCH_END    19'd28000   /*< 33+2 H_SYNC lines    >*/
    `define V_FRONT_PORCH_STRT  19'd412000  /*< 525-10 H_SYNC lines  >*/
    `define V_COUNT_MAX         19'd419999  /*< 525 H_SYNC lines     >*/

    /*** Logic for H_SYNC ***/
    always @(*) begin
        if (h_counter < `H_SYNC_PULSE) begin
            H_SYNC = 0;
            RGB_EN = 0;
        /* If H_Sync is in the display zone, enable RGB */
        else if (h_counter > `H_BACK_PORCH_END && h_counter < `H_FRONT_PORCH_STRT) begin
            H_SYNC = 1;
            RGB_EN = 1;
        /* During the Front Porch period, disable RGB */
        else begin
            H_SYNC = 1;
            RGB_EN = 0;

    /*** Logic for V_SYNC ***/
    always @(*) begin
        if (v_counter < `V_SYNC_PULSE) begin
            V_SYNC = 0;
        else begin
            V_SYNC = 1;

    /*** Counter logic ***/
    always @(posedge CLK) begin
        if (h_counter >= `H_COUNT_MAX || !NRST) begin
            h_counter <= 11'b00;
        else begin
            h_counter <= h_counter + 1;

    always @(posedge CLK) begin
        if (v_counter >= `V_COUNT_MAX || !NRST) begin
            v_counter <= 11'b00;
        else begin
            v_counter <= v_counter + 1;


H/V_SYNC and their respective counters w.r.t each other

  • 1
    \$\begingroup\$ You really should include the actual waveforms measured with an oscilloscope in your question. I've found little reason to trust programmable logic simulations. \$\endgroup\$
    – AngryEE
    Commented Apr 10, 2013 at 16:10
  • \$\begingroup\$ A general comment: in your code, you say you are making "state machines" for V_SYNC and H_SYNC, but it looks to me like those always blocks will just make combinational logic. The only state machine-ish thing you have currently is the counter. \$\endgroup\$
    – mng
    Commented Apr 10, 2013 at 21:55
  • \$\begingroup\$ I agree. Comment has been edited. \$\endgroup\$
    – Jon.H
    Commented Apr 11, 2013 at 0:58

2 Answers 2


You need to keep the H_SYNC output going even when V_SYNC is active.

  • \$\begingroup\$ Thanks Dave, I found material that also confirmed your answer. I have since adjusted the code so that H_SYNC output is always running, and will update the images as soon as I can later today. Unfortunately, the problem still persists; I am still getting "Out of Range" errors. \$\endgroup\$
    – Jon.H
    Commented Apr 10, 2013 at 20:47

I've finally zeroed in on my problem. In the documentation for the CPLD and per my professors suggestions, I thought that the internal clock on the CPLD was configurable. Turns out that what I was reading was the error margin on the clock, not the programmablity. My issue is that the internal oscillator has not been running at 25.175 MHz like I thought.

In case some other soul comes along Googling this, let it be known that the Lattice MachXO 2280 cannot be used for VGA output do to the random value and unprogrammabily of the clock without using an external oscillator.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.