This is an old revision of the document!
This lab and the next lab work together to build a Pong game on the VGA display.
In this lab you will again be using the BitmapToVga module. Make sure you remember how this module works.
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?
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.
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.
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.
/*************************************************************************** * Module: top_pong * * Author: Jeff Goeders * Date: May 13, 2019 * * Description: Top-level module for Pong on Nexys4DDR board. ****************************************************************************/ `default_nettype none module top_pong( 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:
// 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:
vga_color
and vga_wr_en
outputs, to instruct the VgaDrawer when to draw pixels, and which color to draw them.vga_x
and vga_y
outputs.done
signal from the BallDrawer
to determine when the ball is done drawing, allowing your state machine to transition to drawing the next ball.
Tip: So far, when you have designed your state machine modules, you have placed all of your input/output logic in a single always_comb
block. However, as you begin to design larger and more complex modules (including this lab), you may find your code is more readable if you split the logic into multiple blocks. There are many different ways you can structure your circuits in SystemVerilog, and it takes experience to learn which ways are best. In this part of the lab, you might want to try organizing your code using a few always blocks. For example, you might use one always_comb
for the next state logic, another block to control the x/y/color VGA outputs, and perhaps another to control the x/y inputs to your ball and line drawer modules.
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.
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 on 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 an instantiation of your VLineDrawer
to your Pong
module from the last exercise, and change your state machine to draw a line and a ball. Show the TA the display.