BMOW title
Floppy Emu banner


Everyone working on a video application using an FPGA seems to start with Pong, so why should I be any different? I put together this Pong demo as an exercise to help get more familiar with Verilog, and gain some experience working with the Xilinx tools and the Spartan 3A FPGA starter kit. It was very slow going at first, but things are slowly beginning to make sense to me now. And hey, I’ve got Pong!!

pong.v – Verilog HDL source
pong.ucf – user constaints file, with pin-mappings for the Spartan 3A starter kit

Some of the ideas were taken from fpga4fun’s Pong tutorial, and the quadrature decoding logic for the rotary knob was ripped from the tutorial verbatim.

I found that the most difficult part to get working was the collision detection. My brain kept getting tripped up by the difference between writing software where statements are executed sequentially, and HDL statements defining a bunch of operations that all happen at once. I ended up with something like this:

always @(posedge clk) begin
    if (collided)
        direction <= !direction;
    if (direction)
        position <= position + 1;
        position <= position - 1;

That looks fine for sequential code, but in hardware it didn’t work. When the ball reached a point where a collision was detected, the hardware would switch the direction and increment the position simultaneously. The position increment used the old direction value, since it was happening in parallel. The result was that the ball would move one step deeper into collision territory. On the next clock, it would move in the new direction, but since it had been two steps into collision territory, one step wasn’t enough to get out, so another collision was detected and it reversed direction yet again. This caused the ball to get stuck in the wall. Confused? Me too.

I ended up solving this by introducing an XOR:

always @(posedge clk) begin
    if (collided)
        direction <= !direction;
    if (direction ^ collided)
        position <= position + 1;
        position <= position - 1;

I think there must be some more elegant solution, but I didn’t find it.

I also had trouble handling the initial conditions, setting the ball position and direction to appropriate values at startup. Normally I’d do this with a reset line, but I’m not sure how to do it in an FPGA. The Spartan 3A starter kit doesn’t provide any kind of reset input that I could find in the documentation. And at any rate, it would need to reset the logic of the design, without resetting the FPGA itself, which clears the design entirely until it’s programmed again.

I later discovered from James Newman that “initial” blocks are actually synthesizable, so you can do something like:

initial begin
    position <= 200;

That blew my mind, because I must have read 100 different Verilog guides that say initial blocks can’t be synthesized into hardware. And yet, it’s true. I’m very curious how this actually works.

I want to review the Pong design, because it feels way more complicated than it needs to be. I described this to James as Verilog making me lazy. It seems way too easy to write some complicated expression involving a dozen equality comparisons, greater/less than comparisons, and ANDs and ORs, when with a little more thought, the logic could probably be substantially simplified. For instance, I think

wire ball = (xpos >= ballX && xpos <= ballX+7);

could be rewritten as

wire [9:0] delta = xpos - ballX;
wire ball = (delta[9:3] == 0); // or even wire ball = ~(|delta[9:3])

which only requires a 10-bit subtractor and a 7-input NOR, instead of two 10-bit comparators and a 2-input AND. Or maybe:

reg[2:0] ballCount;
always @(posedge clk) begin
    if (xpos == ballX)
       ballCount <= 7;
    else if (ballCount != 0)
        ballCount <= ballCount - 1;

wire ball;
assign ball = ballCount != 0;

That’s a 3-bit down counter, and a bunch of XORs and NORs. I’m not sure if that’s better, but you get the idea. Once you start writing complex clauses of nested ifs and lengthy boolean expressions, it’s easy to lose sight of the underlying hardware implementation.

Read 11 comments and join the conversation 

11 Comments so far

  1. Erik Petrich - June 22nd, 2009 11:36 pm

    While the initializers could potentially be synthesized, it would require specific hardware that may or may not be available in a given implementation.

    All of the flip-flops in the Spartan 3A (and all the other Xilinx parts that I’m familiar with) have an asynchronous set/reset input. By default, one of these (set or reset) will be connected to GSR, the global set/reset signal. After the configuration data is loaded, but before the clocks are enabled, GSR will be briefly asserted so that all of the flip-flops will start in a consistent state (but this behavior can be modified; see the configuration data user guide). You can also assert GSR with your own logic after configuration via the STARTUP_SPARTAN3A primitive.

    If you had an implementation in which the flip-flops did not have set/reset inputs or that did not assert them “initially”, then the initial block could not be synthesized. So I think it’s just a matter of portability.

  2. Eric - June 25th, 2009 12:54 pm

    The coding style I like is to put all the logic in combinational blocks to compute the next values of flops, and then just flop the value in the sequential block. Like:

    always @(*) begin
    next_direction = collided ? ~direction : direction;
    next_position = (direction ^ collided) ?
    position + 1 :
    position – 1;

    always @(posedge clk) begin
    direction <= next_direction;
    position <= next_position;

    I think it makes it less confusing to think of the if clauses being evaluated continuously, instead of in the always @(posedge clk) block. So you have a block that computes the inputs to the flops, and a block to flop the data.

  3. eletronline - October 16th, 2009 3:06 pm

    cara, parabens pela pagina.. Estava pensando em fazer um pong no microcontrolador microchip pic, mas resolvi encomendar uma placa spartan 3AN.. Pena que vai demorar pra chegar…

  4. AITZI - November 3rd, 2010 3:04 am


    I´m a studentd from Spain University, and I´m doing a proyect like this pong game, but I have to use VHDL code (not Verilog) to implement it in Spartan 3E,

    Could you help me? Do you have the same code but performed in VHDL?

    Thank you very much.

  5. quasimodo - June 8th, 2011 7:56 pm

    hi all,
    my project is pong game too. But i’m working on DE2 board.
    Can anybody show me how to convert this code to compile with quartus II and run on DE2 boar ?
    Thanks alot.

  6. ammad - April 8th, 2012 3:27 am

    hellow i m doing the same project i have synthesized code and burn the node in the same fpga kit u are using but problem is that paddle doesn’t move when knob is rotated

    i have checked ther’s no problem with assigning package pin thats i have assigned U15 and T16 for rota and rotb but still knob does’nt work

    can u help me to figure out the proble

    your post was really helpfull for me

    reply me soon i have to submit project earlier

  7. Chen Kan - June 6th, 2012 10:24 pm

    Will the same thing work on a dvi port of virtex 5

  8. naira - September 1st, 2012 8:59 am

    hello ………

    what type of memory you used as a frame buffer ???

    thanks in advance

  9. Steve Chamberlin - September 1st, 2012 9:16 am

    There is no frame buffer. The video signal is synthesized on the fly. Combinatorial logic takes the current location of the ball and paddle, and the current position of the video signal as it sweeps the screen, and determines the desired value for the VGA color outputs.

  10. Shubham Gore - September 14th, 2012 11:59 pm

    I’m working with Xilinx SPARTAN 3E Starter Kit, wanna try your work, i guess ,i need to change the user constaints file according to my board so as to meet the mapping requirements, i’m newbie.
    Can you elaborate how to edit the *.ucf appropriately.

  11. praveen - December 23rd, 2012 9:57 pm

    i am student.. i have xilinx spartan 3e starter kit ..

    please give me the ucf for that..

Leave a reply. For customer support issues, please use the Customer Support link instead of writing comments.