Wednesday 27 April 2016

PacMan running on the Mimas V2 FPGA Development Board

I recently found out that it is possible to run PacMan natively on the Numato Labs Mimas V2 development board.  Being able to implement PacMan on an FPGA is kind of like a right of passage in the FPGA circles.  I have to be honest...I had help!

Goran Mahovlić - a fellow Mimas V2 user pointed me towards this Git Repository which had an 

implementation of PacMan available for download:

https://github.com/Saanlima/Pepino/tree/master/Projects/Pepino-pacman

I downloaded a copy of it to my hardisk and then loaded up the project (pacman_LX9.ise) in Xilinx WebISE:



Some of the code is written in VHDL and some of the code is written in verilog.  The parts we need to edit are the Design Properties, the UCF file and the top level verilog file.  Lets change the design properties first to ensure we are using the correct FPGA device for the Mimas V2 Development board:


  
In the screen that appears change the parameters to match those in the image below:


Click OK to continue...

Next we need to edit the UCF file to account for the Mimas V2 board.  The design was written for a 50 MHz source clock.  However the Mimas V2 has a 100 MHz source clock.  We need to change the UCF file to utilise a 100 MHz source clock and all the connections required to the DIP switches, LEDS, VGA connector and push buttons.  Select the file Pacman.UCF and open it....then delete all of the text in file and paste in the code below:

## NUMATO Mimas V2 ucf file
## http://numato.com/
## PACMAN UCF by Alex

CONFIG VCCAUX  = 3.3;

##Clock signal 100 MHz

NET "SYS_CLK" LOC = V10 | IOSTANDARD = LVCMOS33 | PERIOD = 100MHz;
NET "SYS_CLK" TNM_NET = "sys_clk_pin";

TIMESPEC TS_sys_clk_pin = PERIOD "sys_clk_pin" 100 MHz HIGH 50 %;

# LEDS

NET "LED[3]" LOC = P15 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;
NET "LED[2]" LOC = U18 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;
NET "LED[1]" LOC = T17 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;
NET "LED[0]" LOC = T18 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;

# DIP Switches for one player, two player and credit                                                                                   

#DP 8
NET "SW[0]" LOC = C17 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST | PULLUP;
NET "SW[1]" LOC = C18 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST | PULLUP;
NET "SW[2]" LOC = D17 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST | PULLUP;
NET "SW[3]" LOC = D18 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST | PULLUP;

# Push Buttons Switches For Joystick                                                                              

#SW6 - FIRE
NET "JOYSTICK[4]" LOC = P1 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST | PULLUP;

#SW1 RIGHT
NET "JOYSTICK[3]" LOC = M18 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST | PULLUP;

#SW2 LEFT
NET "JOYSTICK[2]" LOC = L18 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST | PULLUP;

#SW1 DOWN
NET "JOYSTICK[1]" LOC = L17 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST | PULLUP;

#SW3 UP
NET "JOYSTICK[0]" LOC = M16 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST | PULLUP;

# Audio                                                                                        #

# Audio Left               
NET "audio_l" LOC = B16 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;
# Audio Right
NET "audio_r" LOC = A16 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;

# VGA Connections

NET "VGA_HSYNC"   LOC = B12 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;
NET "VGA_VSYNC"   LOC = A12 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;

NET "VGA_RED[2]"  LOC = C9  | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;
NET "VGA_RED[1]"  LOC = B9  | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;
NET "VGA_RED[0]"  LOC = A9  | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;

NET "VGA_GREEN[2]" LOC = C11 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;
NET "VGA_GREEN[1]" LOC = A10 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;
NET "VGA_GREEN[0]" LOC = C10 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;

NET "VGA_BLUE[1]" LOC = A11 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;
NET "VGA_BLUE[0]" LOC = B11 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;

Save the file once you have done that - always a good idea.

Next we need to edit the module called pacman_top.v to account for the 100 MHz source clock. Load up the file in the internal WebISE text editor and navigate to the following section of code:


Replace the code present there with the code below:

   PLL_BASE # (
    .CLKIN_PERIOD(10),
    .CLKFBOUT_MULT(5), //set VCO to 10x of CLKIN
    .CLKOUT0_DIVIDE(2),
    .CLKOUT1_DIVIDE(20),
    .CLKOUT2_DIVIDE(10),
    .COMPENSATION("INTERNAL")

The above code changes the clock period, multipliers and dividers used to account for the 100 MHz source clock.  Save the file!

Now implement a top module to compile all the code.  Once complete you should have the following warning labels but no errors:


Next generate a programming file - make sure to select to create a bitstream:


Now upload the code to your Mimas V2 development board - Very exciting times!  Make sure you connect up your development board to the PC and select the appropriate COM port, then select the bin file we just created and then click on upload:


Once it's complete connect up a spare monitor to the VGA port and speakers to the audio port on the Mimas V2 and see PacMan in all it's glory:


The controls are:

SW3 = UP
SW4 = DOWN
SW2 = LEFT
SW1 = RIGHT

In order to start the game set the DIP switch 5 or DIP switch 6 from off to On and the back to Off - then the game will start!

Here is a video of me attempting to play the game one handed - sorry there is no sound - I didn't bother to connect speakers!


I cannot take much credit for this - I believe the original FPGA PacMan implementation was written by MikeJ from http://www.fpgaarcade.com/

This was then ported by the very clever and nice people at Saanlima Electronics for the Pipistrello board.

Finally I couldn't have done this without help from Goran Mahovlić and his FPGA friends! They were kind enough to help whilst they were working on getting HDMI functionality working for the Arduino FPGA implementation!

Here is my source code in case it's required -

Alex's PacMan Source code for Mimas V2

Well that is all for now people - Take care - Langster

P.S  If people are interested I reckon we should have a competition to see who gets the highest scores - NO CHEATING!!!!

Monday 25 April 2016

A simple post on counters for the Mimas V2 FPGA development board

Here is a post on implementing a counter on the Numato Labs FPGA development board.  I am still learning FPGA technology and thought it would be useful to share what has been achieved.

One of the most useful aspects of FPGA technology is the ability to choose which pins do what and being able to customize the function of the circuit with ease.  Once it becomes apparent that this is possible and quite simple to achieve FPGAs become very attractive quite quickly.

In this tutorial I'm going to create a digital counter.  Counters are used very often in digital electronics either to aid timing circuits and also to divide the frequency of clock signals to lower values.

Wikipedia Entry on digital counters

In the time before FPGA technology was available counters could be made by connecting several JK flip flop circuits together.  It was also possible to buy counter circuits in TTL or CMOS integrated circuits.  The difficulty with these circuits is that the number of bits present in the counters were fixed.  With an FPGA any number of bits is possible - cool huh!

A 4 bit Digital counter using TTL logic
Lets implement a counter using the Mimas V2 FPGA development board!  This can also be made to work with the Elbert V2 development board if required.

Fire up Xilinx WebISE and setup a new project for the Mimas V2 FPGA Board by selecting the following settings:


Click Ok when ready and then add a new source - select VHDL module and give the source a suitable name...


Click Next when ready...and then add the details shown below:


Click Next when ready to display the summary screen:


Click Finish when ready to return to the main screen...It should look similar to this:


The source has been added and the code is displayed.  Comments are the statements preceded with '--' and in green text.  I like to remove them unless the comment is useful, mostly I write my own comments.  Comments are ignored during the 'compiling' process.

Here is the code without comments:

LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY LED_flasher IS PORT ( clock_in : IN STD_LOGIC; LED_out : OUT STD_LOGIC); END LED_flasher; ARCHITECTURE Behavioral OF LED_flasher IS BEGIN END Behavioral;

Lets discuss the code very quickly to explain what it does:

LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL;

These two lines open the STD_LOGIC_1164 package of the IEEE library.  They add useful functions and definitions similar to a library file in C.

ENTITY LED_flasher IS PORT ( clock_in : IN STD_LOGIC; LED_out : OUT STD_LOGIC); END LED_flasher;

The entity statement is the section of the code where all the inputs and outputs are
defined. I like to think of it as the part of the code which describes what will happen.  In this case there is an input called clock_in which will read a digital signal in from a pin and LED_out which will drive a pin as an output.

ARCHITECTURE Behavioral OF LED_flasher IS BEGIN END Behavioral;

The architecture statement is the section of the code that fetches the inputs, performs some processing and then displays the outputs.  In this case we are going to write VHDL code in the architecture section which reads in the 100 MHz clock signal and then divides that down to a much lower frequency so that we can use the lower frequency signal to drive an LED.  The method we are going to use to achieve this is to implement a counter - a section of code which will essentially count how many clock cycles have occurred and when the required number is reached, flash an LED!

A counter is a common method for reducing a 100 MHz clock down to a lower frequency - lets say a 1 Hz waveform. Why use a counter? Because a binary counter increments whenever the 100 MHz clock pulses and it goes through a transition sequence from 0 to 1 each time.  We can use binary to represent this as counting as 0000, 0001, 0010, 0011, 0100, 0101, 0110, 0111...all the way up to 101111101011110000100000000(2) - 100,000,000(10)

If we look carefully it can be seen when the clock pulses that each bit of the count is half the value of the previous bit and that means that whilst counting the clock pulses the clock frequency is being divided by two.  If we keep counting the clock pulses eventually we will divide the clock down to a frequency that can be seen by the human eye, we just need a counter with enough bits to do that.  

Here is a useful page on counters if things are unclear:  


What we need to do is calculate how many bits we need to divide 100 MHz down to 1 Hz.  We know that if we had a 1 bit counter then the 100 MHz clock will be divided down to 50 MHz.  If we have a 4 bit counter then the 100 MHz clock will be divided down to 12.5 MHz as:

100 MHz / 2 = 50 MHz....50 MHz / 2 = 25 MHz....25 MHz / 2 = 12.5 MHz etc

We could just perform all of the calculations and count how many times the division occurs...that tells us how many bits are required or...we can use binary representation of the decimal numbers and count how many bits we need!  

100 000 000 is represented as 101 1111 0101 1110 0001 0000 0000(2) in binary.  Lets count how many digits are present in the binary number as this tells us how many bits we will need. The binary number has 27 bits so a 27 bit counter is required in order to divide 100 MHz to 1 Hz....that is a lot of bits, its a good thing we don't have to build this with JK flip flops....27 flip flops to be powered and wired up and clocked would be months of work!

Lets plan to write the code - we need an If statement which counts how many clock pulses has occurred and then divide the count by two each time a clock pulse occurs and then repeat this process twenty seven times.  We need this to happen when the clock pulse changes state from Low to High....here is the code for the architecture statement:   

ARCHITECTURE Behavioral OF LED_flasher IS SIGNAL counter : STD_LOGIC_VECTOR(27 DOWNTO 0); BEGIN
PROCESS (clock_in) IS BEGIN IF rising_edge(clock_in) THEN counter <= counter + 1; END IF; END PROCESS LED_out <= counter(27); END Behavioral;

Lets discuss how the code works...

SIGNAL counter : STD_LOGIC_VECTOR(27 DOWNTO 0);

The above line implements an internal 27 bit counter circuit in the FPGA.  It is not passed to the any of the external pins at the moment so it will be completely invisible.

PROCESS (clock_in) IS BEGIN IF rising_edge(clock_in) THEN counter <= counter + 1; END IF; END PROCESS

The process section is fairly self explanatory when the 100 MHz clock pulse goes from low to high the signal counter is incremented by one.  Its almost exactly the same as an IF statement in C or C++.

LED_out <= counter(27);

The above line of code tells the output pin called LED_out to mirror the state of the 27th bit of the counter.  When bit 27 of the counter is high then LED_out will be high.  If we choose to connect this pin to an LED it will flash.

In order for this code to work an extra libary must be included:

USE IEEE.STD_LOGIC_UNSIGNED.ALL;

Here is the complete code - just in case it's required:

LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL; ENTITY LED_flasher IS PORT ( clock_in : IN STD_LOGIC; LED_out : OUT STD_LOGIC ); END LED_flasher; ARCHITECTURE Behavioral OF LED_flasher IS SIGNAL counter : STD_LOGIC_VECTOR(27 DOWNTO 0); BEGIN PROCESS (clock_in) IS BEGIN IF rising_edge(clock_in) THEN counter <= counter + 1; END IF; END PROCESS; LED_out <= counter(27); END Behavioral;

At this point I would save the file...just in case!  Here is what should be on screen:


To ensure all the code has been written correctly lets 'Synthesize' the code...right click on Synthesize - XST and select Run...


At the end of the process a green tick should appear and there should not be any warnings or error messages.  If there are...there is a typing error somewhere in the code!


A useful tool with Xilinx WebISE is the ability to simulate the logic of how the code will behave.  Just for fun lets do a simulation and see what happens.  We could write an implementation constraints file here which tells the compiler which pins on the FPGA we want to be the inputs and outputs and it would perform something but we have no idea if our code will perform as intended.  This is why its sometimes a good idea to simulate what the code will perform before we upload it to the FPGA.

In order to simulate the code, we need something to exercise the inputs and monitor the
outputs. This is known as a test bench in VHDL programming. It is basically another text file which tells the simulation program to exercise the inputs with suitable signals and then display the output - whatever that might be!  


Lets add a new source to our project - select VHDL test bench and give it a sensible name:


Click Next when ready and then associate the test bench with the source code to be simulated:


Click Next when ready to display the summary screen:


Click finish when ready to return to the main project screen, helpfully Xilinx WebISE has generated a lot of code for us:


I like to remove the top comments...I don't find them useful.  Here is the full code...just in case:

LIBRARY ieee; USE ieee.std_logic_1164.ALL; -- Uncomment the following library declaration if using -- arithmetic functions with Signed or Unsigned values --USE ieee.numeric_std.ALL; ENTITY LED_flasher_TB IS END LED_flasher_TB; ARCHITECTURE behavior OF LED_flasher_TB IS -- Component Declaration for the Unit Under Test (UUT) COMPONENT LED_flasher PORT ( clock_in : IN std_logic; LED_out : OUT std_logic ); END COMPONENT; --Inputs SIGNAL clock_in : std_logic := '0'; --Outputs SIGNAL LED_out : std_logic; -- Clock period definitions CONSTANT clock_in_period : TIME := 10 ns; BEGIN -- Instantiate the Unit Under Test (UUT) uut : LED_flasher PORT MAP( clock_in => clock_in, LED_out => LED_out ); -- Clock process definitions clock_in_process : PROCESS BEGIN clock_in <= '0'; WAIT FOR clock_in_period/2; clock_in <= '1'; WAIT FOR clock_in_period/2; END PROCESS; -- Stimulus process stim_proc : PROCESS BEGIN -- hold reset state for 100 ns. WAIT FOR 100 ns; WAIT FOR clock_in_period * 10; -- insert stimulus here WAIT; END PROCESS; END;

The above test bench code is quite similar to the actual VHDL code written before it has a component declaration, the same input process etc.  The difference is however that the inputs are now being preset with values in order to assess what the output will do: 

-- Clock process definitions clock_in_process : PROCESS BEGIN clock_in <= '0'; WAIT FOR clock_in_period/2; clock_in <= '1'; WAIT FOR clock_in_period/2; END PROCESS;

The above section of test bench code simulates counter process - the clock_in signal is set to zero. the program then waits for half a clock period, the clock_in signal is set to one and then the program waits for another half clock period.  This process will repeat forever...

As the LED_out pin does not do anything there is no extra code to write in the stim_proc section. Lets see the result:

Click on the ISIM simulation button and select the test bench file and then select run 'Simulate Behavioral Model':


 Once complete a new window should appear which looks like this:


The screen shows the output of the simulation which ran for 1000 nano-seconds....not very long!  We cannot see what happened at the output as not enough time passed.  We can see that the clock_in signal changed state.  If we click on the magnifier icon we will be able to see the clock signal more clearly:


Look - a red line and an 'X' - this means that there is an issue.  The simulator cannot decide what state the LED_out pin should do.  This is because the counter has been started in an unknown state.  We need to modify the original VHDL code to initialise the counter in a zero state no matter what:

We need to change the line:

SIGNAL counter : STD_LOGIC_VECTOR(27 DOWNTO 0);

To this line:

SIGNAL counter : STD_LOGIC_VECTOR(27 DOWNTO 0) := (others=>'0');

Now save the code and then run synthesize again...and then re-run the simulate behavioral model...

This may take a while!


So the red line has disappeared...but the LED_out pin never changes state.  In order to see if the code will work we need to run the simulation for a longer time period.  The issue is that it will take a long time to process all of that data - the simulation program has to run the code in order to simulate the results...Change the simulation time to 2.5 seconds and prepare to wait:


Once the simulation has completed this what should be displayed:


The LED_out pin is changing state which means everything worked!  Lets get on with the real thing!

Click on the View radio button and then select 'add new source':


On the screen that appears select implementation constraints file and then choose a suitable file name:


Click Next to display the summary screen:


Click finish to return to the main screen.

The method of choosing which pins are connected to the FPGA are decided by the implementation constraints file.  In theory any pins could be used to read in the input and any pins could be used for an output.  In practice because a development board is being used the pin connected to the clock crystal must be selected for the clock_in signal and a pin connected to an LED must be used for the LED_out signal.

Here is the code:

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# # This file is a .ucf for Mimas V2 # # To use it in your project : # # * Remove or comment the lines corresponding to unused pins in the project # # * Rename the used signals according to the your project # #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# CONFIG VCCAUX = "3.3" ; NET "clock_in" LOC = V10 | IOSTANDARD = LVCMOS33 | PERIOD = 100MHz; ################################################################################### # LEDs # ################################################################################### NET "LED_out" LOC = P15 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;

The UCF code is fairly simple to understand....the 100 MHz clock crystal is connected to pin V10. So we tell the compiler to connect the internal signal called clock_in to pin V10.  The first LED physical LED is connected to pin P15 so connect the internal signal called LED_out to pin P15.

Save the code and then click on the green arrow to implement the top module - compile all the code!

  
If everything went according to plan there should be green ticks next to Synthesize XST and Implement Design:

Right click on Generate program file and select process properties and then select create binary configuration file:


Click Ok and then select 'Generate Programming File':


Once that is complete - connect up the Mimas V2 Development board to a suitable USB port and then load up the Mimas V2 programming tool:


Once complete the LED on position zero should flash every once a second!

Here is a video showing my board in action!


Next post will discuss generating multiple divided clock signals.  Take care - Langster!