ECE3829 Lab 3
1. Introduction
This laboratory trains you how it is to play with the Nexys3 board, and show your proficiency on digital circuit design. All ECE lab computers have Xilinx tools installed with full license. If you want to install that on your own computer, you can down the free Xilinx Webpack which contains all the feature that we use in ECE3829 labs.
2. Lab Assignment
You are required to design the game Snakes, and it is expected to be shown on a computer screen via VGA interface. Here are rules for the game: The goal is to eat food while avoiding losing the snake's lives. The higher the level you are playing on, the more the speed of the game will be. Therefore the Higher the level makes the game play faster. We are totally using 3 levels for this game. The speed at which the snake moves in level 3 will comparably faster to that of level 1. The snake dies if its head collides with its body or with the walls. So, the snake should not run in to the walls or touch itself. Each time the snake eats food, the snake grows one unit longer in a level. Every time a block of food is eaten by the snake, a new food will appear on the screen. Four pushbuttons are used to control the movement of the snake.
3. Lab Description
The game should be displayed on screen, so you will need to know about VGA port on Nexys3 board.
The Nexys3 board uses 10 FPGA signals to create a VGA port with 8-bit color and the two standard sync signals (HS Horizontal Sync, and VS Vertical Sync). The color signals use resistordivider circuits that work in conjunction with the 75-ohm termination resistance of the VGA display to create eight signal levels on the red and green VGA signals, and four on blue (the human eye is less sensitive to blue levels). This circuit, shown in figure 13, produces video color signals that proceed in equal increments between 0V (fully off) and 0.7V (fully on). Using this circuit, 256 different colors can be displayed, one for each unique 8-bit pattern. A video controller circuit must be created in the FPGA to drive the sync and color signals with the correct timing in order to produce a working display system. VGA signal timings are specified, published, copyrighted and sold by the VESA organization (www.vesa.org). The following VGA system timing information is provided as an example of how a 1
VGA monitor might be driven in 640 by 480 mode. For more precise information, or for information on other VGA frequencies, refer to documentation available at the VESA website.
CRT-based VGA displays use amplitude-modulated moving electron beams (or cathode rays) to display information on a phosphor-coated screen. LCD displays use an array of switches that can impose a voltage across a small amount of liquid crystal, thereby changing light permittivity through the crystal on a pixel-by-pixel basis. Although the following description is limited to CRT displays, LCD displays have evolved to use the same signal timings as CRT displays (so the signals discussion below pertains to both CRTs and LCDs). Color CRT displays use three electron beams (one for red, one for blue, and one for green) to energize the phosphor that coats the inner side of the display end of a cathode ray tube (see illustration). Electron beams emanate from electron guns which are finely-pointed heated cathodes placed in close proximity to a positively charged annular plate called a grid. The electrostatic force imposed by the grid pulls rays of energized electrons from the cathodes, and those rays are fed by the current that flows into the cathodes. These particle rays are initially accelerated towards the grid, but they soon fall under the influence of the much larger electrostatic force that results from the entire phosphor-coated display surface of the CRT being charged to 20kV (or more). The rays are focused to a fine beam as they pass through the center of the grids, and then they accelerate to impact on the phosphor-coated display surface. The phosphor surface glows brightly at the impact point, and it continues to glow for several hundred microseconds after the beam is removed. The larger the current fed into the cathode, the brighter the phosphor will glow. Between the grid and the display surface, the beam passes through the neck of the CRT where two coils of wire produce orthogonal electromagnetic fields. Because cathode rays are composed of charged particles (electrons), they can be deflected by these magnetic fields. Current waveforms are 2
passed through the coils to produce magnetic fields that interact with the cathode rays and cause them to transverse the display surface in a raster pattern, horizontally from left to right and vertically from top to bottom. As the cathode ray moves over the surface of the display, the current sent to the electron guns can be increased or decreased to change the brightness of the display at the cathode ray impact point. Information is only displayed when the beam is moving in the forward direction (left to right and top to bottom), and not during the time the beam is reset back to the left or top edge of the display. Much of the potential display time is therefore lost in blanking periods when the beam is reset and stabilized to begin a new horizontal or vertical display pass. The size of the beams, the frequency at which the beam can be traced across the display, and the frequency at which the electron beam can be modulated determine the display resolution. Modern VGA displays can accommodate different resolutions, and a VGA controller circuit dictates the resolution by producing timing signals to control the raster patterns. The controller must produce synchronizing pulses at 3.3V (or 5V) to set the frequency at which current flows through the deflection coils, and it must ensure that video data is applied to the electron guns at the correct time. Raster video displays define a number of rows that corresponds to the number of horizontal passes the cathode makes over the display area, and a number of columns that corresponds to an area on each row that is assigned to one picture element or pixel. Typical displays use from 240 to 1200 rows and from 320 to 1600 columns. The overall size of a display and the number of rows and columns determines the size of each pixel.
Video data typically comes from a video refresh memory, with one or more bytes assigned to each pixel location (the Nexys3 uses three bits per pixel). The controller must index into video memory as the beams move across the display, and retrieve and apply video data to the display at precisely the time the electron beam is moving across a given pixel. A VGA controller circuit must generate the HS and VS timings signals and coordinate the delivery of video data based on the pixel clock. The pixel clock defines the time available to display one pixel of information. The VS signal defines the refresh frequency of the display, or the frequency at which all information on the display is redrawn. The minimum refresh frequency is a function of the displays phosphor and electron beam intensity, with practical refresh frequencies falling in the 50Hz to 120Hz range. The number of lines to be displayed at a given refresh frequency defines the horizontal retrace frequency. For a 640-pixel by 480-row display using a 25MHz pixel clock and 60 +/-1Hz refresh, the signal timings shown in the table at right can be derived. Timings for sync pulse width and front and back porch intervals (porch intervals are the pre- and post-sync pulse times during which information cannot be displayed) are based on observations taken from actual VGA displays. A VGA controller circuit decodes the output of a horizontal-sync counter driven by the pixel clock to generate HS signal timings. This counter can be used to locate any pixel location on a given row. Likewise, the output of a vertical-sync counter that increments with each HS pulse can be used to generate VS signal timings, and this counter can be used to locate any given row. These two continually running counters can be used to form an address into video RAM. No time relationship between the onset of the HS pulse and the onset of the VS pulse is specified, so the designer can arrange the counters to easily form video RAM addresses, or to minimize decoding logic for sync pulse generation.
Since the game is a little bit complicated, enough hints are given. Here is a schematic that you can refer to.
Functions of each sub modules are shown below: bot_icon: Snakes body generation Variable change in length when level changes Food eating
5
Game over logic Inputs and outputs:
module bot_icon (input [7:0] pixel_col, input [7:0]pixel_row, input [7:0] LocX_reg, input [7:0] LocY_reg, input [7:0] Food_locX, input [7:0] Food_locY, input clk, input reset, input icon_tick, input ctrl_off, output reg [2:0] icon, output reg [7:0]s_len = 8'd10, output reg game_over = 0, output reg food_gen = 0);
snake_world: Dynamic Text generation Random generation of locations for food Inputs and outputs:
module snake_world( input [7:0] pixel_col, input [7:0] pixel_row, input rand_en, input ctrl_off, input [7:0] s_len, output reg [7:0] LocX, output reg [7:0] LocY, output reg [1:0] food_icon, output reg [1:0] snake_world_pixels);
dtg:
The actual image is obtained by a sequence of horizontal lines that are constantly refreshed. The screen refresh process begins in the top left corner and paints one block at a time from left to right. At the end of the first row, the row increments and the column address are reset to the first column. Once the entire screen has been painted the refresh process begins again from the top left corner. The horiz_sync and ver_sync were used to generate horizontal (VGA_hsync) and vertical (VGA_vsync) synchronized signals for VGA monitor respectively. They are pulse signals which indicate the beginning of a new frame or row. The pictures
6
displayed on the VGA screen are realized by setting appropriate pixel values. Each pixel point on the screen has its exclusive X and Y coordinate. Inputs and outputs:
module dtg(horiz_sync, vert_sync, pixel_row, pixel_column, video_on, clock, rst); input clock, rst; output reg horiz_sync, vert_sync, video_on; output reg [9:0] pixel_row, pixel_column;
colorizer:
The colorizer module maps the background, icon and the food to the screen based on their priority. The order of priority is as follows with highest priority on the top and least at the bottom. Define the snake in red, food in green and background text to be blue. Inputs and outputs:
module colorizer( input video_on, input clk, input [1:0] world_pixel, input [1:0] food_icon, input [2:0] icon, output reg [2:0] red_green_blue);
De-bounce circuit:
Actually, you are expected to focus on the game, and the main purpose of de-bounce circuit is simply filter out mechanical bounce generated by pushbuttons. Code is provided below:
module debounce ( //inputs input input [3:0] input //outputs 7
clk, pbtn_in, rosw_in,
// clock // pushbutton inputs // rotary pushbutton input
output reg [3:0] pbtn_db , // debounced outputs of pushbuttons output reg rosw_db // debounced output of rotary encoder switch ); parameter simulate = 0; localparam debounce_cnt = simulate ? 21'd5 // debounce clock when simulating : 23'd3_000_000; // debounce count when running on HW //shift registers used to debounce switches and buttons reg [22:0] db_count = 23'h00000; //counter for debouncer reg [3:0] shift_pb0 = 4'h0, shift_pb1 = 4'h0, shift_pb2 = 4'h0, shift_pb3 = 4'h0, shift_rsw = 4'h0; // debounce clock always @(posedge clk) begin if (db_count == debounce_cnt) db_count <= 0; //takes 40mS to reach 2,000,000 else db_count <= db_count + 1; end always @(posedge clk) begin if (db_count == debounce_cnt) begin //sample every 40mS //shift registers for pushbuttons shift_pb0 <= (shift_pb0 << 1) | pbtn_in[0]; shift_pb1 <= (shift_pb1 << 1) | pbtn_in[1]; shift_pb2 <= (shift_pb2 << 1) | pbtn_in[2]; shift_pb3 <= (shift_pb3 << 1) | pbtn_in[3]; shift_rsw <= (shift_rsw << 1) | rosw_in; end //debounced pushbutton outputs case(shift_pb0) 4'b0000: pbtn_db[0] <= 0; 4'b1111: pbtn_db[0] <= 1; endcase case(shift_pb1) 4'b0000: pbtn_db[1] <= 0; 4'b1111: pbtn_db[1] <= 1; endcase case(shift_pb2) 4'b0000: pbtn_db[2] <= 0; 4'b1111: pbtn_db[2] <= 1; endcase case(shift_pb3) 4'b0000: pbtn_db[3] <= 0; 4'b1111: pbtn_db[3] <= 1; endcase case(shift_rsw) 4'b0000: rosw_db <= 0; 4'b1111: rosw_db <= 1; endcase end endmodule
DCM:
It is a digital clock manage circuit, you may use a clock divider to replace it. Or it you want to instantiate DCM in you design, here is the template:
DCM #( .CLKDV_DIVIDE(6.0), // Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5 // 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0 .CLKFX_DIVIDE(1), // Can be any integer from 1 to 32 .CLKFX_MULTIPLY(4), // Can be any integer from 2 to 32 .CLKIN_DIVIDE_BY_2("FALSE"), // TRUE/FALSE to enable CLKIN divide by two feature .CLKIN_PERIOD(20.0), // Specify period of input clock .CLKOUT_PHASE_SHIFT("NONE"), // Specify phase shift of NONE, FIXED or VARIABLE .CLK_FEEDBACK("1X"), // Specify clock feedback of NONE, 1X or 2X .DESKEW_ADJUST("SYSTEM_SYNCHRONOUS"), // SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or // an integer from 0 to 15 .DFS_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for frequency synthesis .DLL_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for DLL .DUTY_CYCLE_CORRECTION("TRUE"), // Duty cycle correction, TRUE or FALSE .FACTORY_JF(16'hC080), // FACTORY JF values .PHASE_SHIFT(0), // Amount of fixed phase shift from -255 to 255 .STARTUP_WAIT("FALSE") // Delay configuration DONE until DCM LOCK, TRUE/FALSE ) DCM_inst ( .CLK0(clk_buf), // 0 degree DCM CLK output .CLK180(), // 180 degree DCM CLK output .CLK270(), // 270 degree DCM CLK output .CLK2X(), // 2X DCM CLK output .CLK2X180(), // 2X, 180 degree DCM CLK out .CLK90(), // 90 degree DCM CLK output .CLKDV(clk25), // Divided DCM CLK out (CLKDV_DIVIDE) .CLKFX(), // DCM CLK synthesis out (M/D) .CLKFX180(), // 180 degree CLK synthesis out .LOCKED(), // DCM LOCK status output .PSDONE(), // Dynamic phase adjust done output .STATUS(), // 8-bit DCM status bits output .CLKFB(clk_in), // DCM clock feedback .CLKIN(clk50), // Clock input (from IBUFG, BUFG or DCM) .PSCLK(1'b0), // Dynamic phase adjust clock input .PSEN(1'b0), // Dynamic phase adjust enable input .PSINCDEC(1'b0), // Dynamic phase adjust increment/decrement .RST(1'b0) // DCM asynchronous reset input ); 9
snake_movement: Variable snake speeds for different levels Snake movement based on the user inputs Handling meta-stability Inputs and outputs:
module snake_movement (input clk, input reset, input [7:0] s_len, input game_over, input db_btn_west, input db_btn_east, input db_btn_north, input db_btn_south, output [7:0] LocSX, output [7:0] LocSY, output reg icon_tick, output reg ctrl_off);
This part you have to write all by yourself. To give you a hint, a detailed description of this module is given. Generally, this module sets 3 different moving speeds regarding different lengths of the snake. That is to say, when the snake gets longer, a higher speed should be applied. You decide how fast the speeds are. The length of the snake is represented by the 8 bits input s_len. Basically, to simulate a snakes movement, you need a counter that counts up to a fixed value, after then the snake is expected to change position by one position on VGA display. Four inputs with the name db_btn_* come from the debounce circuit and are connected to 4 pushbuttons on the board. Considering an input from a specific pushbutton, you have to determine whether the snake will keep current heading, turn right or turn left. The outputs LocSX and LocSY record the current position of the snake. These two outputs are connected to module ICO to show the snake on the VGA display.
4. Lab Report
A lab report describing how you design the circuits step by step is required. Besides you need to hand in a hard copy of your Verilog files (make sure you add the header and comments) and demonstrate your working design for signed-off during the lab sessions. This lab is to be completed individually.
10