If everything has been working out for you then you are probably ready to test the HDL code on a real device. But before we can generate the binary file used to program the FPGA we need to tell Xilinx ISE exactly how to connect the I/Os to the FPGA.
Xilinx ISE generates an optimal solution for the internal wiring; technically you can be a terrible coder yet at the end of the day if the code compiles, then it will work just like any other code designed to do the same task. The reason for this is that ISE detects all unused bits, signals, variables, and removes them from the physical implementation. The one thing that ISE can't determine on its own from the HDL code, is how the module's I/O ports connect to the physical FPGA pins. This is where the UCF file comes in. The UCF, or User Constraint File, is a file that lists the module's port mappings to the physical FPGA pins. The most generic form of a UCF statement is as follows:
PORT_NAME" LOC = " PIN_NAME"; # COMMENTS HERE
A UCF statement always starts with NET and ends with ";"; comments can be used by using the the hash symbol "#". The
PORT_NAME variable should be replaced with one of your module's ports. For instance, the most common port name would be the clock. In our previous posts we have been using a module that was defined as:
This means that we will need exactly 4 NET statements. This will lead us to:
NET "clk" LOC = "PIN_NAME
"; # Clock signal, 24MHz oscillatorNET "d" LOC = "PIN_NAME "; # Data input signal, a pushbuttonNET "q" LOC = "PIN_NAME "; # Output signal, an LEDNET "qn" LOC = "PIN_NAME "; # Inverted output signal, an LED
So the above preps us for how the module will interact with the FPGA board. I have an FPGA board with a 24MHz oscillator, a pushbutton switch, and a couple LEDs, all of which will interact with this code. The next step would be to specify the location that these ports will be mapped to on the physical FPGA. This is done by using the keyword LOC and replacing
PIN_NAME with the pin name that your FPGA uses. To determine what the pin name is, you can either look in your FPGA's documentation or you can look on the board's silkscreen as they most likely label them correctly on the board. Below is a picture of the board I am using (from KNJN.com).
As you can see, the pins, LEDs, and pushbutton are all labeled; it is generally a good idea though to skim through your documentation first as there could be silkscreen errors that would cause you to map a port to the wrong pin. Also, some FPGA boards want additional parameters other than just the NET and LOC. These parameters can be attatched by using the "|" character . One common parameter that you might define is the IOSTANDARD as can be seen below:
NET "LED" LOC = "p146" | IOSTANDARD = LVCMOS33 ;
In the case above, the IOSTANDARD is set to a low-voltage CMOS (3.3Volts). Your board may differ so make sure to consult your board's documentation. The final UCF file for my board using the dff module is:
NET "clk" LOC = "p181" | IOSTANDARD = LVCMOS33 ;
NET "d" LOC = "p148" | IOSTANDARD = LVCMOS33 ;
NET "q" LOC = "p146" | IOSTANDARD = LVCMOS33 ;
NET "qn" LOC = "p147" | IOSTANDARD = LVCMOS33 ;
Now that we have the UCF we can continue with generating the bit file. To do this all you need to do is double click on the "Generate Programming File" inside the Processes window. It will first Synthesize the HDL code and check the syntax, then it will implement the design (check for any physical routing problems and check the UCF) and then generate the bit file.
Once the bit file has been generated we are ready to launch iMPACT. Stay tuned for more...