User Tools


This is an old revision of the document!


Pong: Part 1

This lab and the next lab work together to build a Pong game on the VGA display.

  • Exercise 1 & 2: Creating a BallDrawer module that will output (x, y) coordinates that can be used to draw a ball.
  • Exercise 3: Connecting your BallDrawer module to a BitmapToVga module that is given to you, to display your ball on the screen.
  • Exercise 4: Create a VLineDrawer module that draws vertical lines.

Learning Outcomes

  • Learn how to implement state machines using behavioral SystemVerilog.

Preliminary

Read about the BitmapToVga module that is given to you. This allows you to draw pixels to the VGA monitor. You should read about how the module works now, but you won't need to add it to your design until Exercise #3.

How many bits are required to specify the x-coordinate in the 320×240 bitmap image?

How many bits are required to specify the y-coordinate in the 320×240 bitmap image?

What is the minimum number of cycles required to change the entire image to blue? How many microseconds would this take, given your system clock?

What is the purpose of the wr_en signal?

Exercises

Exercise #1 - BallDrawer State Machine

Design a state machine (on paper) that can be used to draw a ball. The module behavior is described below:

Module Name = BallDrawer
Port Name Direction Width Description
clk Input 1 100 MHz Input Clock
reset Input 1 Reset
start Input 1 High to start drawing a ball
done Output 1 High on cycle that last pixel location is output
x_in Input 9 Leftmost x-Coordinate of ball to be drawn
y_in Input 8 Topmost y-Coordinate of ball to be drawn
x_out Output 9 x-Coordinate to be drawn
y_out Output 8 y-Coordinate to be drawn

The module should output (x_out, y_out) coordinates to write to, starting with the cycle immediately following the assertion of the start signal, and continue each cycle until complete. The done signal should be asserted during the cycle of the last pixel.

The following shows a diagram of a ball with 5 pixels, and the corresponding waveform for drawing this ball at (100,50).

Here are some other ball shapes you can use, or you can design your own. Your ball needs to have at least 4 pixels.

Did you make sure that your state machine will produce the correct behavior, based on the timing diagram above?  Make sure that the first pixel location is output in the cycle immediately after start goes high, that a new pixel is output every cycle, and that the done signal is asserted during the last pixel (not afterwards).

Exercise #1 Pass-off: Show the TA your state machine and describe how you verified that it meets the requirements described above.


Exercise #2 - BallDrawer SystemVerilog Module

Create the BallDrawer SystemVerilog module that implements your state machine.

Simulate your BallDrawer module to ensure it meets the timing behavior shown above.

Include a copy of your TCL file in your lab report.

Exercise #2 Pass-off: Show the TA a simulation of your BallDrawer module. The waveform should be similar to above. You can choose the (x_in, y_in) values, but make sure they are non-zero values.


Exercise #3 - Drawing Pong Objects on the VGA Display

In this exercise you will create a Pong module that draws draws two balls to the screen.

The top-level SystemVerilog file is provided below. It instantiates the BitmapToVga module and the glk_generator module needed to draw graphics on the VGA monitor. Your Pong module is also instantiated, and note how the modules are connected. Your Pong module is responsible for generating the signals to write pixels to the bitmap.

Note: You shouldn't change the top-level file. However, be sure to add a constraints file to your project that is configured appropriately. The top-level module contains connections for the buttons. You don't need to use the buttons in this lab, but you will be using them in the next lab. Make sure you include the appropriate constraints for them now, otherwise Vivado will error when compiling the project.

top_pong.sv
/***************************************************************************
* Module: top_pong
*
* Author: Jeff Goeders
* Date: May 13, 2019
*
* Description: Top-level module for Pong on Nexys4DDR board.
****************************************************************************/
 
`default_nettype none
 
module top_pong2(
    input wire logic            clk,
    input wire logic            CPU_RESETN,
 
    output logic        [3:0]   VGA_R,
    output logic        [3:0]   VGA_G,
    output logic        [3:0]   VGA_B,
    output logic                VGA_HS,
    output logic                VGA_VS,
 
 
    input wire logic            btnu,
    input wire logic            btnd,
    input wire logic            btnl,
    input wire logic            btnr
);
 
logic           clk_100;
logic           clk_25;
logic           reset;
 
logic   [2:0]   vga_color;
logic   [8:0]   vga_x;
logic   [7:0]   vga_y;
logic           vga_wr_en;
 
assign reset = ~CPU_RESETN;
 
Pong Pong_inst(
    .clk(clk_100),
    .reset(reset),
    .paddle1_up(btnu),
    .paddle1_down(btnl),
    .paddle2_up(btnr),
    .paddle2_down(btnd),
    .vga_x(vga_x),
    .vga_y(vga_y),
    .vga_wr_en(vga_wr_en),
    .vga_color(vga_color)
);
 
clk_generator clk_generator_inst
 (
    .clk_100(clk_100),
    .clk_25(clk_25),
    .clk_in_100(clk)
 );
 
BitmapToVga BitmapToVga_inst(
    .VGA_R(VGA_R),
    .VGA_G(VGA_G),
    .VGA_B(VGA_B),
    .clk(clk_100),
    .clk_vga(clk_25),
    .VGA_hsync(VGA_HS),
    .VGA_vsync(VGA_VS),
    .reset(reset),
    .wr_en(vga_wr_en),
    .x(vga_x),
    .y(vga_y),
    .color(vga_color)
);
 
 
endmodule

Your Pong module contains the ports described here:

Module Name = Pong
Port Name Direction Width Description
clk Input 1 100 MHz Clock
reset Input 1 Active-high reset
paddle1_up Input 1 When high, move left paddle up
paddle1_down Input 1 When high, move left paddle down
paddle2_up Input 1 When high, move right paddle up
paddle2_down Input 1 When high, move right paddle down
vga_x Output 9 BitmapToVga X-Coordinate
vga_y Output 8 BitmapToVga Y-Coordinate
vga_color Output 3 BitmapToVga Color
vga_wr_en Output 1 BitmapToVga Write Enable

A file has been provided to you to get started:

Pong.sv
// Add your header here
 
`default_nettype none
 
module Pong (
    input wire logic        clk,
    input wire logic        reset,
 
    input wire logic        paddle1_up,
    input wire logic        paddle1_down,
    input wire logic        paddle2_up,
    input wire logic        paddle2_down,
 
    output logic    [8:0]   vga_x,
    output logic    [7:0]   vga_y,
    output logic    [2:0]   vga_color,
    output logic            vga_wr_en
);
 
 
/////// Create a state machine here //////
//
// Your state machine should provide start, x_in and y_in to the BallDrawer
// Use the done signal from the BallDrawer to determine when a ball is done drawing
//
// Your state machine should also control the vga_color and vga_wr_en signals 
 
 
////////////////// Ball Drawing /////////////////////
BallDrawer BallDrawer_inst(
    .clk(clk),
    .reset(reset),
    .start(/* Todo */),
    .done(/* Todo */),
    .x_in(/* Todo */),
    .y_in(/* Todo */),
    .x_out(/* Todo */),
    .y_out(/* Todo */)
);
 
endmodule

For this exercise, your Pong module should draw 2 or more balls on the screen of different color. You can choose the locations.

You may notice that the Pong module includes one instantiation of the BallDrawer. You SHOULD NOT add any more instantiations of this module. This one instantiation will be used to draw all of the balls.

The provided Pong module provides a good starting point. You will need to add a state machine that:

  • Draws the first ball, then draws the second ball.
  • Your state machine will need to control the start, x and y signals that are input to the BallDrawer.
  • Your state machine will also need to control the vga_color and vga_wr_en outputs, to instruct the VgaDrawer when to draw pixels, and which color to draw them.
  • Decide how you will connect the vga_x and vga_y outputs. (Hint: it's easy)
  • Remember to use the done signal from the BallDrawer to determine when the ball is done drawing, allowing your state machine to transition to drawing the next ball.

Exercise #3 Pass-Off: Show your display to the TA. The TA will verify that you are drawing two balls on the screen of different color, and that you are using only one instance of your BallDrawer module.


Exercise #4 - Line Drawer (10% of lab pass-off grade)

You only need to complete this exercise if you want to complete the full Pong game next lab.

Create the following module that can be used to draw a vertical line. Use a state machine to implement the described behavior.

Module Name = VLineDrawer
Port Name Direction Width Description
clk Input 1 100 MHz Input Clock
reset Input 1 Reset
start Input 1 High to start drawing a line
done Output 1 High one cycle that last pixel is drawn
x_in Input 9 x-Coordinate of line to be drawn
y_in Input 8 y-Coordinate of top of the line
height Input 8 Height of line in pixels
x_out Output 9 x-Coordinate to be drawn
y_out Output 8 y-Coordinate to be drawn

The module should output (x_out, y_out) coordinates to write to, starting with the cycle immediately following the assertion of the start signal, and continue each cycle until complete. The done signal should be asserted during the cycle of the last pixel.

The following shows a diagram of a line 6 pixels tall, and the corresponding waveform for drawing this line at (100, 50).


Exercise #4 Pass-off: Add the VLineDrawer to your top-level module from the last exercise, and change your state machine to draw a line and a ball. Show the TA the display.