fpga - My verilog VGA driver causes the screen to flicker (Basys2) -


i'm trying recreate adventure(1979) in verilog , far have character movement, collision , map generation done. didn't flicker before separated maps modules flickers constantly. when looking issue, found out clock on basys2 board pretty noisy , culprit. however, putting maps modules shouldn't have made worse unless messed up. idea happened?

here's map generator:

module map_generator(clk_vga, reset, currentx, currenty, hblank, vblank, playerposx, playerposy, mapdata );    input clk_vga;   input reset;   input [9:0]currentx;   input [8:0]currenty;   input hblank;   input vblank;   input [9:0]playerposx;   input [8:0]playerposy;    output [7:0]mapdata;    reg [7:0]mcolor;   reg [5:0]currentmap = 0;    wire [7:0]startcastle;    startcastle startcastle(     .clk_vga(clk_vga),     .currentx(currentx),     .currenty(currenty),     .mapdata(startcastle)   );    @(posedge clk_vga) begin     if(reset)begin       currentmap <= 0;     end   end    @(posedge clk_vga) begin     if(hblank || vblank) begin       mcolor <= 0;     end     else begin       if(currentmap == 4'b0000) begin         mcolor[7:0] <= startcastle[7:0];       end       //add more maps later     end   end    assign mapdata[7:0] = mcolor[7:0];  endmodule 

here's startcastle:

module startcastle(clk_vga, currentx, currenty, active, mapdata);    input clk_vga;   input [9:0]currentx;   input [8:0]currenty;   input active;    output [7:0]mapdata;    reg [7:0]mcolor;    @(posedge clk_vga) begin      if(currenty < 40) begin       mcolor[7:0] <= 8'b11100000;     end     else if(currentx < 40) begin       mcolor[7:0] <= 8'b11100000;     end     else if(~(currentx < 600)) begin       mcolor[7:0] <= 8'b11100000;     end     else if((~(currenty < 440) && (currentx < 260)) || (~(currenty < 440) && ~(currentx < 380))) begin       mcolor[7:0] <= 8'b11100000;     end else       mcolor[7:0] <= 8'b00011100;          end    assign mapdata = mcolor; endmodule 

here's vga driver connected top module:

module vga_driver(clk_50mhz, vs_vga, hs_vga, red, green, blue, hblank, vblank, curx, cury, color, clk_data, reset);    input clk_50mhz;   output vs_vga;   output hs_vga;   output [2:0] red;   output [2:0] green;   output [1:0] blue;   output hblank;   output vblank;    reg vs = 0;   reg hs = 0;    input reset;    //current client data   input [7:0] color;   output clk_data;   output [9:0] curx;   output [8:0] cury;    //##### module constants (http://tinyvga.com/vga-timing/640x480@60hz)   parameter hdisplayarea = 640;  // horizontal display area   parameter hlimit = 800;        // maximum horizontal amount (limit)   parameter hfrontporch = 16;    // h. front porch   parameter hbackporch = 48;         // h. porch   parameter hsyncwidth = 96;         // h. pulse width    parameter vdisplayarea = 480;  // vertical display area   parameter vlimit = 525;        // maximum vertical amount (limit)   parameter vfrontporch = 10;    // v. front porch   parameter vbackporch = 33;         // v. porch   parameter vsyncwidth = 2;      // v. pulse width     //##### local variables   wire clk_25mhz;    reg [9:0] curhpos = 0; //maximum of hlimit (2^10 - 1 = 1023)   reg [9:0] curvpos = 0; //maximum of vlimit   reg hblank_reg, vblank_reg, blank = 0;    reg [9:0] currentx = 0;    //maximum of hdisplayarea   reg [8:0] currenty = 0;    //maximum of vdisplayarea (2^9 - 1 = 511)    //##### submodule declaration   clock_divider clk_div(.clk_in(clk_50mhz), .clk_out(clk_25mhz));    //shifts clock half period (negates it)   //see timing diagrams better understanding of reason   clock_shift clk_shift(.clk_in(clk_25mhz), .clk_out(clk_data));    //simulate vertical , horizontal positions   @(posedge clk_25mhz) begin     if(curhpos < hlimit-1) begin       curhpos <= curhpos + 1;     end     else begin       curhpos <= 0;        if(curvpos < vlimit-1)         curvpos <= curvpos + 1;       else         curvpos <= 0;     end     if(reset) begin       curhpos <= 0;       curvpos <= 0;     end   end    //##### vga logic (http://tinyvga.com/vga-timing/640x480@60hz)    //hsync logic   @(posedge clk_25mhz)     if((curhpos < hsyncwidth) && ~reset)       hs <= 1;     else       hs <= 0;    //vsync logic        @(posedge clk_25mhz)     if((curvpos < vsyncwidth) && ~reset)       vs <= 1;     else       vs <= 0;  //horizontal logic         @(posedge clk_25mhz)      if((curhpos >= hsyncwidth + hfrontporch) && (curhpos < hsyncwidth + hfrontporch + hdisplayarea) || reset)       hblank_reg <= 0;     else       hblank_reg <= 1;    //vertical logic   @(posedge clk_25mhz)     if((curvpos >= vsyncwidth + vfrontporch) && (curvpos < vsyncwidth + vfrontporch + vdisplayarea) || reset)       vblank_reg <= 0;     else       vblank_reg <= 1;    //do not output color information when in vertical   //or horizontal blanking areas. set boolean keep track of this.   @(posedge clk_25mhz)     if((hblank_reg || vblank_reg) && ~reset)       blank <= 1;     else       blank <= 0;    //keep track of current "real" x position. actual current x   //pixel location abstracted away timing details   @(posedge clk_25mhz)     if(hblank_reg && ~reset)       currentx <= 0;     else       currentx <= curhpos - hsyncwidth - hfrontporch;    //keep track of current "real" y position. actual current y   //pixel location abstracted away timing details   @(posedge clk_25mhz)      if(vblank_reg && ~reset)       currenty <= 0;     else       currenty <= curvpos - vsyncwidth - vfrontporch;    assign curx = currentx;   assign cury = currenty;   assign vblank = vblank_reg;   assign hblank = hblank_reg;   assign hs_vga = hs;   assign vs_vga = vs;    //respects vga blanking areas   assign red = (blank) ? 3'b000 : color[7:5];   assign green = (blank) ? 3'b000 : color[4:2];   assign blue = (blank) ? 2'b00 : color[1:0]; endmodule 

clk_div:

module clock_divider(clk_in, clk_out);   input clk_in;   output clk_out;    reg clk_out = 0;    @(posedge clk_in)     clk_out <= ~clk_out;  endmodule 

clk_shift:

module clock_shift(clk_in, clk_out);   input clk_in;   output clk_out;    assign clk_out = ~clk_in; endmodule 

i'm posting answer because cannot put photo in comment.

is design looks like? vga output op design

my guess atm might have misplaced ports during instantiation of vga_driver and/or map_generator (if used old style instantiation). nevertheless, i'm going check vga timmings, can see strange vertical line @ left of screen, if hblank interval visible.

by way: i've changed way generate display. use regs hs, vs, etc, updated next clock cycle. treat display generation fsm, outputs come combinational blocks triggered values (or range of values) counters. besides, start horizontal , vertical counters position (0,0) measured in pixel coordinates in screen maps values (0,0) horizontal , vertical counters, no arithmetic needed.

this version of vga display generation:

module videosyncs (    input wire clk,     input wire [2:0] rin,    input wire [2:0] gin,    input wire [1:0] bin,     output reg [2:0] rout,    output reg [2:0] gout,    output reg [1:0] bout,     output reg hs,    output reg vs,     output wire [10:0] hc,    output wire [10:0] vc    );     /* http://www.abramovbenjamin.net/calc.html */     // vga 640x480@60hz,25mhz    parameter htotal = 800;    parameter vtotal = 524;    parameter hactive = 640;    parameter vactive = 480;    parameter hfrontporch = 16;    parameter hsyncpulse = 96;    parameter vfrontporch = 11;    parameter vsyncpulse = 2;    parameter hsyncpolarity = 0;    parameter vsyncpolarity = 0;     reg [10:0] hcont = 0;    reg [10:0] vcont = 0;    reg active_area;      assign hc = hcont;     assign vc = vcont;     @(posedge clk) begin       if (hcont == htotal-1) begin          hcont <= 0;          if (vcont == vtotal-1) begin             vcont <= 0;          end          else begin             vcont <= vcont + 1;          end       end       else begin          hcont <= hcont + 1;       end    end     @* begin       if (hcont>=0 && hcont<hactive && vcont>=0 && vcont<vactive)          active_area = 1'b1;       else          active_area = 1'b0;       if (hcont>=(hactive+hfrontporch) && hcont<(hactive+hfrontporch+hsyncpulse))          hs = hsyncpolarity;       else          hs = ~hsyncpolarity;       if (vcont>=(vactive+vfrontporch) && vcont<(vactive+vfrontporch+vsyncpulse))          vs = vsyncpolarity;       else          vs = ~vsyncpolarity;     end     @* begin       if (active_area) begin          gout = gin;          rout = rin;          bout = bin;       end       else begin          gout = 3'h00;          rout = 3'h00;          bout = 2'h00;       end    end endmodule    

which instantiated vga_driver module, becomes nothing wrapper module:

module vga_driver (   input wire clk_25mhz,   output wire vs_vga,   output wire hs_vga,   output wire [2:0] red,   output wire [2:0] green,   output wire [1:0] blue,   output wire hblank,   output wire vblank,   output [9:0] curx,   output [8:0] cury,   input [7:0] color,   input wire reset   );    assign hblank = 0;   assign vblank = 0;    videosyncs syncgen (      .clk(clk_25mhz),      .rin(color[7:5]),      .gin(color[4:2]),      .bin(color[1:0]),       .rout(red),      .gout(green),      .bout(blue),       .hs(hs_vga),      .vs(vs_vga),       .hc(curx),      .vc(cury)    ); endmodule 

note in map_generator, first if statement in always block never true. can forget it, vga display module blank rgb outputs when needed.

  @(posedge clk_vga) begin     if(hblank || vblank) begin //       mcolor <= 0;             // never reached     end                        //     else begin                 //       if(currentmap == 4'b0000) begin         mcolor[7:0] <= startcastle[7:0];       end       //add more maps later     end   end 

using same approach, i've converted map generator module combinational module. example, map 0 (the castle -without castle, see-) this:

module startcastle(   input wire [9:0] currentx,   input wire [8:0] currenty,   output wire [7:0] mapdata   );    reg [7:0] mcolor;   assign mapdata = mcolor;    @* begin     if(currenty < 40) begin       mcolor[7:0] <= 8'b11100000;     end     else if(currentx < 40) begin       mcolor[7:0] <= 8'b11100000;     end     else if(~(currentx < 600)) begin       mcolor[7:0] <= 8'b11100000;     end     else if((~(currenty < 440) && (currentx < 260)) || (~(currenty < 440) && ~(currentx < 380))) begin       mcolor[7:0] <= 8'b11100000;     end else       mcolor[7:0] <= 8'b00011100;          end endmodule 

just fsm output colour goes in pixel. input being coordinates of current pixel.

so when time display map 0, map_generator switches based upon current value of currentmap

module map_generator (   input wire clk,   input wire reset,   input wire [9:0]currentx,   input wire [8:0]currenty,   input wire hblank,   input wire vblank,   input wire [9:0]playerposx,   input wire [8:0]playerposy,   output wire [7:0]mapdata   );    reg [7:0] mcolor;   assign mapdata = mcolor;    reg [5:0]currentmap = 0;    wire [7:0] castle_map;   startcastle startcastle(     .currentx(currentx),     .currenty(currenty),     .mapdata(castle_map)   );    @(posedge clk) begin     if(reset) begin       currentmap <= 0;     end   end    @* begin     if(currentmap == 6'b000000) begin       mcolor = castle_map;     end       //add more maps later   end endmodule 

this may lot of comb logic generated , glitches may happen. it's fast, no noticeable glitches on screen, , can use actual current x , y coordinates choose display on screen. thus, no need inverted clock. final version of design has 1 25mhz clock.

by way, want keep device dependent constructions away design, placing things clock generators in separate modules connected design in top module, should device dependent module.

so, i've written device-agnostic adventure module, contain entire game:

module adventure (   input clk_vga,   input reset,   output vs_vga,   output hs_vga,   output [2:0] red,   output [2:0] green,   output [1:0] blue   );    wire hblank, vblank;   wire [7:0] color;   wire [9:0] curx;   wire [8:0] cury;   wire [9:0] playerposx = 10'd320;  // no used in design yet   wire [8:0] playerposy = 9'd240;   // no used in design yet    vga_driver the_screen (.clk_25mhz(clk_vga),                           .vs_vga(vs_vga),                           .hs_vga(hs_vga),                           .red(red),                           .green(green),                           .blue(blue),                           .hblank(hblank),                           .vblank(vblank),                           .curx(curx),                           .cury(cury),                           .color(color)                          );   map_generator the_mapper (.clk(clk_vga),                              .reset(reset),                              .currentx(curx),                              .currenty(cury),                              .hblank(hblank),                              .vblank(vblank),                              .playerposx(playerposx),                              .playerposy(playerposy),                              .mapdata(color)                             ); endmodule 

this module not complete: lacks inputs joystick or other input device update player current position. now, player current position fixed.

the top level design (tld) written exclusively fpga trainer have. here need generate proper clocks using device's available resources, such dcm in spartan 3/3e devices.

module tld_basys(   input wire clk_50mhz,   input wire reset,   output wire vs_vga,   output wire hs_vga,   output wire [2:0] red,   output wire [2:0] green,   output wire [1:0] blue   );    wire clk_25mhz;      dcm_clocks gen_vga_clock (                             .clkin_in(clk_50mhz),                              .clkdv_out(clk_25mhz)                            );    adventure the_game (.clk_vga(clk_25mhz),                        .reset(reset),                        .vs_vga(vs_vga),                        .hs_vga(hs_vga),                        .red(red),                        .green(green),                        .blue(blue)                       ); endmodule 

the dcm generated clocks goes in module (generated xilinx core generator)

module dcm_clocks (clkin_in,               clkdv_out              );     input clkin_in;    output clkdv_out;     wire clkfb_in;    wire clkfx_buf;    wire clkdv_buf;    wire clkin_ibufg;    wire clk0_buf;    wire gnd_bit;     assign gnd_bit = 0;    bufg  clkdv_bufg_inst (.i(clkdv_buf),                           .o(clkdv_out));                             ibufg  clkin_ibufg_inst (.i(clkin_in),                             .o(clkin_ibufg));    bufg  clk0_bufg_inst (.i(clk0_buf),                          .o(clkfb_in));    dcm_sp #(.clkdv_divide(2.0), .clkin_divide_by_2("false"),           .clkin_period(20.000), .clkout_phase_shift("none"),           .deskew_adjust("system_synchronous"), .dfs_frequency_mode("low"),           .dll_frequency_mode("low"), .duty_cycle_correction("true"),           .factory_jf(16'hc080), .phase_shift(0), .startup_wait("false") )           dcm_sp_inst (.clkfb(clkfb_in),                         .clkin(clkin_ibufg),                         .dssen(gnd_bit),                         .psclk(gnd_bit),                         .psen(gnd_bit),                         .psincdec(gnd_bit),                         .rst(gnd_bit),                         .clkdv(clkdv_buf),                         .clkfx(),                         .clkfx180(),                         .clk0(clk0_buf),                         .clk2x(),                         .clk2x180(),                         .clk90(),                         .clk180(),                         .clk270(),                         .locked(),                         .psdone(),                         .status()); endmodule 

although safe (for xilinx devices) use simple clock divider did. if fear synthesizer won't treat divided clock actual clock, add bufg primitive route output divider global buffer can used clock no problems (see module above example on how this).

as final note, may want add more independency final device, using 24-bit colours graphics. @ tld, use actual number of bits per colour component have, if move basys2 8-bit colour trainer board the, say, nexys4 board, 12-bit colour, automatically enjoy richer output display.

now, looks (no vertical bars @ left, , colours seem more vibrant)

another output basys using different vga display module


Comments

Popular posts from this blog

asp.net mvc - SSO between MVCForum and Umbraco7 -

Python Tkinter keyboard using bind -

ubuntu - Selenium Node Not Connecting to Hub, Not Opening Port -