1
votes

I am facing an interesting issue in SystemVerilog where the comparison with a register isn't working.

module VGA_Colours 
(
        input wire clk, reset,
//      input wire [3:0] swred, swgreen,
//      input wire [1:0]  swblue,
        output wire hsync, vsync,
        output wire [3:0] r, g, b
        
    );
    
    // constant declarations for VGA sync parameters
    localparam H_DISPLAY       = 640; // horizontal display area
    localparam H_L_BORDER      =  48; // horizontal left border
    localparam H_R_BORDER      =  16; // horizontal right border
    localparam H_RETRACE       =  96; // horizontal retrace
    localparam H_MAX           = H_DISPLAY + H_L_BORDER + H_R_BORDER + H_RETRACE - 1;
    localparam START_H_RETRACE = H_DISPLAY + H_R_BORDER;
    localparam END_H_RETRACE   = H_DISPLAY + H_R_BORDER + H_RETRACE - 1;
    
    localparam V_DISPLAY       = 480; // vertical display area
    localparam V_T_BORDER      =  10; // vertical top border
    localparam V_B_BORDER      =  33; // vertical bottom border
    localparam V_RETRACE       =   2; // vertical retrace
    localparam V_MAX           = V_DISPLAY + V_T_BORDER + V_B_BORDER + V_RETRACE - 1;
   localparam START_V_RETRACE = V_DISPLAY + V_B_BORDER;
    localparam END_V_RETRACE   = V_DISPLAY + V_B_BORDER + V_RETRACE - 1;
    
    wire video_on, p_tick;
    reg [9:0] ii;
    reg j;
    
    reg [3:0] red_reg, green_reg, blue_reg;
    reg [11:0] rbg;
    
    // mod-2 counter to generate 25 MHz pixel tick
    reg pixel_reg = 0;
    wire pixel_next;
    wire    pixel_tick;
    
    always @(posedge clk)
        pixel_reg <= pixel_next;
    
    assign pixel_next = ~pixel_reg; // next state is complement of current
    
    assign pixel_tick = (pixel_reg == 0); // assert tick half of the time
    
    // registers to keep track of current pixel location
    reg [9:0] h_count_reg, h_count_next, v_count_reg, v_count_next;
    
    // register to keep track of vsync and hsync signal states
    reg vsync_reg, hsync_reg;
    wire vsync_next, hsync_next;
 
    // infer registers
    always @(posedge clk)
        if(~reset)
            begin
                    v_count_reg <= 0;
                    h_count_reg <= 0;
                    vsync_reg   <= 0;
                    hsync_reg   <= 0;
                end
        else
            begin
                    v_count_reg <= v_count_next;
                    h_count_reg <= h_count_next;
                    vsync_reg   <= vsync_next;
                    hsync_reg   <= hsync_next;
                end
            
    // next-state logic of horizontal vertical sync counters
    always @*
        begin
        h_count_next = pixel_tick ? 
                       h_count_reg == H_MAX ? 0 : h_count_reg + 1
                   : h_count_reg;
        
        v_count_next = pixel_tick && h_count_reg == H_MAX ? 
                       (v_count_reg == V_MAX ? 0 : v_count_reg + 1) 
                   : v_count_reg;
                     
                     
            
                     
                     
                     
        end 
                
            
        // hsync and vsync are active low signals
        // hsync signal asserted during horizontal retrace
        assign hsync_next = h_count_reg >= START_H_RETRACE 
                            && h_count_reg <= END_H_RETRACE;
   
        // vsync signal asserted during vertical retrace
        assign vsync_next = v_count_reg >= START_V_RETRACE 
                            && v_count_reg <= END_V_RETRACE;

        // video only on when pixels are in both horizontal and vertical display region
        assign video_on = (h_count_reg < H_DISPLAY) 
                           && (v_count_reg < V_DISPLAY);

        // output signals
        assign hsync  = hsync_reg;
        assign vsync  = vsync_reg;
        assign p_tick = pixel_tick; 
          
          
          
    always @(posedge p_tick) begin
    if (~reset) begin

        rbg <= 12'b000000000000;
        ii <= 9'b0;
    end else begin

        
        if (h_count_reg == 0) begin
        
        rbg <= 12'b000000000000;
        ii <= 9'b0;
        end else if (h_count_reg == ii) begin
        ii <= ii + 9'b001010000;
        
        rbg <= rbg + 12'b000010000000;
        end


    
    end
end
// output
        assign r = (video_on) ? rbg[11:8] : 4'b0;
          assign g = (video_on) ? rbg[7:4] : 4'b0;
          assign b = (video_on) ? rbg[3:0] : 4'b0;
          

                    
endmodule

In the above code h_count_reg is 0 works fine. If I change 0 to any different number, it will work as expected. However, if I replace that number with a variable (which is "ii", declared on top of my module as reg[9:0] ii), the code seems to ignore it, which is weird. Replacing the ii variable with any number will work. Why?

TestBench file:

module VGA_Colours_tb ();

logic clk;
reg reset;
wire hsync, vsync;
wire [3:0] r, g, b;
        
VGA_Colours scr0 (

.clk (clk),
.reset (reset),
.hsync (hsync),
.vsync (vsync),
.r (r),
.b (b),
.g (g)


);

initial begin
        clk = 0;
        forever #10 clk = ~clk;
end

 always @(posedge clk) begin
 
 #20
 
 reset <= 1'b0;
 
 #20
 
 reset <= 1'b1;
 
 
 #100000
 
 $finish;
 
 
 end



endmodule




Simulation wave:

Simulation wave

As you can see from the code, when h_count_reg is == to ii, increment the rbg and the value of ii. However, based on the simulation waves, it is not doing that as if the value of h_count_reg is not equal to ii while it actually is.

1
Hello, I am trying to use the VGA of my FPGA board to display different colors depending on the pixel location. When I hardcode the location of the pixel on a horizontal scale, I can see different columns with different colors which is the result I'm looking for (similar to the old tv channels when they go offline, you see columns of different colors). Now since I don't want to hardcode the pixel locations I have created a variable "i" that will increment by 80 every time the location of the pixel is equal to the value of "i".However, the screen shows the color black which is the initial color - jeysee
The issue you see is for synthesis or behavioral simulation? - Bob
Not sure what you meant by synthesis or behavioral ,user12750353. - jeysee
Hello, I have edited the code again as I have modified some parts of the code while investigating the issue. I have also included my Testbench code and the simulation graph - jeysee

1 Answers

2
votes

You have a logic error in the VGA_Colours module.

Here is your code with more consistent indentation:

   always @(posedge p_tick) begin
      if (~reset) begin
         rbg <= 12'b000000000000;
         ii  <= 9'b0;
      end else begin
         if (h_count_reg == 0) begin
            rbg <= 12'b000000000000;
            ii  <= 9'b0;
         end else if (h_count_reg == ii) begin
            rbg <= rbg + 12'b000010000000;
            ii  <= ii + 9'b001010000;
         end
      end
   end

When I run your simulation, I observe ii is always 0 after the initial reset.

The code has 3 if statements. The 1st if statement is true at the beginning of the simulation, when reset=0. This sets ii to 0.

After reset, I see h_count_reg=0 4 times. This means the 2nd if statement is true 4 times. This keeps ii = 0.

The 3rd if statement is evaluated only when h_count_reg is not 0. It should be clear now that the 3rd if statement can never be true. This means that ii will not be incremented and it will remain at 0. For example, when h_count_reg=1, then (h_count_reg == ii) is false because ii is always 0.