You are on page 1of 22

Page 1 of 22

Digital System Design using VHDL and the


Spartan-3E FPGA Board
Gennadiy Chernyavskiy
Tech 499
12/06/06

Page 2 of 22

Contents
Chapter 2: A Design Example
2.1 Design Description..3
Chapter 3: Design Implementation using Xilinx
3.1 Introduction....4
3.2 Procedure for programming the Spartan-3E..5
References17
Appendix A: VHDL code.18
Appendix B: UCF.22

Page 3 of 22

Chapter 2
2.1 Design Description
The goal of the project is to design a digital system for controlling the tail lights of a 1965
Ford Thunderbird using VHDL and synthesizing the logic circuit into a Spartan-3E
FPGA board. The sequence of the lights for a 1965 Ford Thunderbird is shown in Figure
1-1.

Figure 1-1: The sequence of the lights for a 1965 Ford Thunderbird.
In order to get this project functioning, we first wrote a VHDL file called tail_light.vhd
(copy of this file is provided in Appendix A). The board has a 50MHz oscillator (see [2]
pages 22-23); therefore, the clock signal is so fast that the human eye is unable to see the
sequence of the flashing lights. As a consequence, we have to add an additional file
called counter.vhd (copy of this file is provided in Appendix A), which will slow the
incoming clock down. In order for these two files to work together, we have to write the
top_level.vhd (copy of this file is provided in Appendix A). A step by step tutorial will
explain how to load this project into the Xilinx board.
Note: First the user should apply power and then connect the USB cable to the Spartan3E board. If any change is done to the (vhdl) code, the user should first remove the USB
cable, second remove power, third reapply power to the Spartan-3E board and last
reconnect the USB cable. At this point it is safe to reload the modified code into the
Xilinx board.

Page 4 of 22

Chapter 3
3.1 Introduction
In order to create a project to program the Spartan-3E FPGA, it is necessary to take a few
preliminary steps. First, a project needs to be created in Xilinx. The project is named
tail_light. Then the specific characteristics of the hardware that are being used are
selected as shown in Figure 3-1.

Figure 3-1: Project Properties Window


Finally, the source files counter.vhd, tail_light.vhd, and top_level.vhd are selected as the
source code to be used to program the Spartan-3E FPGA.

Page 5 of 22

3.2 Procedure for Programming the Spartan-3E FPGA


STEP 1: Select the tail_light folder in the CD-ROM and copy to the C:\ drive of your
computer. Then double click on the highlighted icon shown below. This will open the
Xilinx Project Navigator window.

Figure 3-2: tail-light project


Once the Xilinx Project Navigator window opens there will be 4 windows available for
you to see.

Page 6 of 22

1
2
3

Figure 3-3: Four windows


Window 1: The Sources Project window lists the name of files that constitutes the
project tail_light.
Window 2: Displays the files source code. Here the user can write new code or make
changes to existing code.
Window 3: The Processes window shows the different process that can be done to the
selected code. Here the user can compile the source code, generate synthesis reports,
generates a file for an FPGA, and download files to an FPGA.
Window 4: The log window displays any messages from the processes window. For
example, after Xilinx checks the syntax of a given source code, it will display the results
of that process.
STEP 2: The tail_light project requires the use of 7 LEDs and 4 switches.
It is necessary to assign pins from the Spartan-3E FPGA to these components.
For this project, switches SW1, SW2, SW3, and SW4 are used for input from the user as
shown in Figure 3-4.

Page 7 of 22
Four Switches

Figure 3-4: Switches used for Left, Right, Hazard, and Reset signals
Pin assignments for the switches:

NET "SW<0>" LOC = "L13" | IOSTANDARD = LVTTL | PULLUP ;


NET "SW<1>" LOC = "L14" | IOSTANDARD = LVTTL | PULLUP ;
NET "SW<2>" LOC = "H18" | IOSTANDARD = LVTTL | PULLUP ;
NET "SW<3>" LOC = "N17" | IOSTANDARD = LVTTL | PULLUP ;

Taken from Spartan 3-E Starter User Guide (see Reference Manual pages 159-164)

Page 8 of 22
LEDs - LD1, LD2, LD3, LD4, LD6, LD7, and LD8 are used as output as shown in
Figure 3-5.
Eight Discrete LEDs

Figure 3-5: Eight LEDs


UCF Constraints for Eight Discrete LEDs
NET "LED<7>" LOC = "F9" | IOSTANDARD = LVTTL | SLEW = SLOW |
DRIVE = 8
NET "LED<6>" LOC = "E9" | IOSTANDARD = LVTTL | SLEW = SLOW |
DRIVE = 8
NET "LED<5>" LOC = "D11" | IOSTANDARD = LVTTL | SLEW = SLOW |
DRIVE = 8
NET "LED<4>" LOC = "C11" | IOSTANDARD = LVTTL | SLEW = SLOW |
DRIVE = 8
NET "LED<3>" LOC = "F11" | IOSTANDARD = LVTTL | SLEW = SLOW |
DRIVE = 8
NET "LED<2>" LOC = "E11" | IOSTANDARD = LVTTL | SLEW = SLOW |
DRIVE = 8
NET "LED<1>" LOC = "E12" | IOSTANDARD = LVTTL | SLEW = SLOW |
DRIVE = 8
NET "LED<0>" LOC = "F12" | IOSTANDARD = LVTTL | SLEW = SLOW |
DRIVE = 8

Taken from Spartan 3E Starter User Guide (see Reference Manual pages 159-164)

Page 9 of 22
Using the three pinout tables, it is possible to assign a switch or LED to a pin on the
Spartan-3E.
The clock signal comes from an oscillator found on the Spartan-3E board as shown in
Figure 3-6. Pin C9 on the Spartan-3E is the designated pin for the clock signal input.

On-Board 50 MHz Oscillator


CLK_50MHz: (C9)

Figure 3-6: 50 MHz Oscillator.


STEP 3: Make sure that top_level-struct is selected in the Sources window. Then
expand the User Constraints in the Processes window and double click Assign Package
Pins. This is where you tell Xilinx which pins on the Spartan-3E will be used (see Figure
3-7).

Page 10 of 22

Figure 3-7: User Constrains


A program named Xilinx PACE will open. In the Design Object List I/O Pins window
type in the following pin assignments under the heading Loc (see Figure 3-8).

Page 11 of 22
Figure 3-8
When finished, click the save icon. This action will create the .ucf file for the top_levelstruct file and it will contain the pin assignments for the Spartan-3E.
STEP 4: Again, make sure that top_level-struct is selected in the Sources window.
Then, in the Processes window, expand the Synthesize-XST process and then double
click it. This action will check the syntax of the source code for top_level-struct and
convert the source code into a netlist of gates. A synthesis report will also be produced.
When the synthesis is finished, green check marks should be displayed just like in Figure
3-9, indicating that top_level-struct has been compiled successfully.

Figure 3-9
STEP 5: Expand the Implement Design process and double click on it. This is where
the netlist is translated, mapped, placed and routed into the logic circuits of the Spartan3E FPGA. After this process has been run, green check marks should be displayed just
like in Figure 3-10.

Page 12 of 22

Figure 3-10
STEP 6: Expand the Generate Programming File process. Right click on Generate
Programming File and select Create Bit File. Double click Generate Programming
File. This process creates a bit file that is used to program the Spartan-3E chip. Again,
after this process is finished, green check marks should be shown as in Figure 3-11.

Page 13 of 22

Figure 3-11
Step 7: Now you are ready to program the Spartan-3E chip. Plug in the USB cable to
the computer. Connect the Spartan-3E board to power FIRST, and then connect the USB
cable to the board. This order must be followed for the Spartan-3E chip to be
programmed properly.
Step 8: Now double click on Configure Device (iMPACT) under the Generate
Programming File process. You will be asked how you want the device configured.
Select Boundary Scan Mode and click Next. Then select Automatically connect to
cable and identity Boundary Scan Chain and click Finish as shown in Figure 3-12.

Page 14 of 22

Figure 3-12.
The following window will display and ask you to select a bit file (See Figure 3-13).

Page 15 of 22

Figure 3-13
Open the top_level.bit file. Should a warning appear declaring that the Startup Clock has
been changed to the jtagclk, disregard the warning and click OK.
Step 9: Right click on the depiction of the Spartan 2 chip and select Program (see
Figure 3-14).

Page 16 of 22

Figure 3-14
A Programs Options window will open. Simply click OK and the top_level.bit file will
be downloaded to the Spartan-3E chip. If the download is successful, the message

will display. Also, LD should be blinking. This is the output from the counter and is
used for testing purposes.
Step 10: Now it is time to test the program. Turn on the reset button (switch SW4) and
then turn it back off. The following table shows the correct outputs with the
corresponding inputs from the user.
As the inputs are applied, only the left and right signals should flash sequentially. The
hazard signal, the left and right signal combined, should flash concurrently.

Page 17 of 22

Left
Off
Off
Off
On
On
On
On
Off

Input
Right
Off
Off
On
On
Off
Off
On
On

Hazard
Off
On
On
On
On
Off
Off
Off

Output
LD1, LD2, LD3, LD6, LD7, LD8
No output
Hazard signals on
Hazard signals on
Hazard signals on
Hazard signals on
Left signal on
Left signal on
Right signal on

After it has been verified that the given inputs produce the proper output, the project is
complete.

References
[1]

Full Spartan-3E Documentation


http://www.digilentinc.com/Products/Detail.cfm?Prod=S3EBOARD&Nav1=Prod
ucts&Nav2=Programmable

[2]

Spartan-3E Starter User Guide (Reference Manual)


http://www.digilentinc.com/Data/Products/S3EBOARD/S3EStarter_ug230.pdf

[3]

Spartan-3E Board (Schematic Diagram)


http://www.digilentinc.com/Data/Products/S3EBOARD/S3E%20Starter_sch.pdf

Page 18 of 22

Appendix A: VHDL code


The following appendix shows the VHDL code used for the tail_light project.
--file:top_level.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
entity top_level is
port(l_r_haz :in std_logic_vector(2 downto 0);
clk
: in std_logic;
rst
: in std_logic;
lights : out std_logic_vector(5 downto 0);
clkdiv : out std_logic
);
end top_level;
architecture struct of top_level is
component counter
port (clk, rst : in std_logic;
countOut : out std_logic
);
end component;
component tail_light
port ( l_r_haz : in std_logic_vector(2 downto 0);
clk : in std_logic;
rst : in std_logic;
lights : out std_logic_vector(5 downto 0)
);
end component;
--signal declaration
signal countOut
: std_logic;
signal l_r_haz_in : std_logic_vector(2 downto 0);
begin
inst_counter: counter
port map ( clk => clk,
rst => rst,
countOut => countOut
);
inst_tail_light: tail_light
port map ( l_r_haz => l_r_haz_in,
rst => rst,
clk => countOut,
lights => lights
);
l_r_haz_in <= l_r_haz;
clkdiv <= countOut;
end struct;
--------------------------------------------------------------------------------file:counter.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
entity counter is
port ( clk, rst : in std_logic;
countOut : out std_logic
);
end counter;
architecture rtl of counter is
begin
process(rst, clk)
variable count : unsigned(23 downto 0);
begin
if rst = '1' then
count := (others =>'0');

Page 19 of 22
elsif (clk ='1' and clk'event) then
count := count + 1;
end if;
countOut <= count(23);
end process;
end rtl;
--------------------------------------------------------------------------------file: tail_light.vhd
library ieee;
use ieee.std_logic_1164.all;
entity tail_light is
port (l_r_haz : in std_logic_vector(2 downto 0);
clk
: in std_logic;
rst
: in std_logic;
lights : out std_logic_vector(5 downto 0)
);
end tail_light;
architecture rtl of tail_light is
type state_t is (idle, leftOne, leftTwo, leftThree, rightOne, rightTwo,
rightThree, lr);
signal state, next_state : state_t;
signal next_all_lights : std_logic_vector(5 downto 0);
signal all_lights : std_logic_vector(5 downto 0);--oneLeft, twoLeft, etc.
begin
comb_logic : process(l_r_haz, state)
begin
next_state <= idle;
next_all_lights <= (others => '0');
case state is
when idle =>
if (l_r_haz = "000") then
next_state <= idle;
next_all_lights <= (others => '0');
elsif (l_r_haz = "001") then
next_state <= lr;
next_all_lights <= "111111";
elsif (l_r_haz = "100") then
next_state <= leftOne;
next_all_lights <= "001000";
elsif (l_r_haz = "010") then
next_state <= rightOne;
next_all_lights <= "000100";
elsif (l_r_haz = "110") then
next_state <= leftOne;
next_all_lights <= "001000";
elsif (l_r_haz = "101") then
next_state <= lr;
next_all_lights <= "111111";
elsif (l_r_haz = "011") then
next_state <= lr;
next_all_lights <= "111111";
elsif (l_r_haz = "111") then
next_state <= lr;
next_all_lights <= "111111";
end if;
when leftOne =>
if (l_r_haz = "100") then
next_state <= leftTwo;
next_all_lights <= "011000";
elsif (l_r_haz = "001") then
next_state <= lr;
next_all_lights <= "111111";
elsif (l_r_haz = "110") then
next_state <= leftTwo;

Page 20 of 22
next_all_lights <= "011000";
end if;
when leftTwo =>
if (l_r_haz = "100") then
next_state <= leftThree;
next_all_lights <= "111000";
elsif (l_r_haz = "001") then
next_state <= lr;
next_all_lights <= "111111";
elsif (l_r_haz = "110") then
next_state <= leftThree;
next_all_lights <= "111000";
end if;
when leftThree =>
if (l_r_haz = "100") then
next_state <= idle;
next_all_lights <= "000000";
elsif (l_r_haz = "001") then
next_state <= lr;
next_all_lights <= "111111";
elsif (l_r_haz = "110") then
next_state <= idle;
next_all_lights <= "000000";
end if;
when rightOne =>
if (l_r_haz = "010") then
next_state <= rightTwo;
next_all_lights <= "000110";
elsif (l_r_haz = "001") then
next_state <= lr;
next_all_lights <= "111111";
end if;
when rightTwo =>
if (l_r_haz = "010") then
next_state <= rightThree;
next_all_lights <= "000111";
elsif (l_r_haz = "001") then
next_state <= lr;
next_all_lights <= "111111";
end if;
when rightThree =>
if (l_r_haz = "010") then
next_state <= idle;
next_all_lights <= "000000";
elsif (l_r_haz = "001") then
next_state <= lr;
next_all_lights <= "111111";
end if;
when lr =>
if (l_r_haz = "001") then
next_state <= idle;
next_all_lights <= "000000";
elsif (l_r_haz = "000") then
next_state <= idle;
next_all_lights <= "000000";
end if;
when others =>
-- do nothing
end case;
end process comb_logic;
the_reg: process (clk, rst)
begin
if (rst = '1') then
state <= idle;

Page 21 of 22
all_lights <= "000000";
elsif (clk ='1' and clk'event) then
state <= next_state;
all_lights <= next_all_lights;
end if;
end process the_reg;
lights <= all_lights;
end rtl;

Page 22 of 22

Appendix B: UCF (user constraints file)


#PACE: Start of Constraints generated by PACE
#PACE: Start of PACE I/O Pin Assignments
NET "clk" LOC = "C9" ;
NET "clkdiv" LOC = "F12" | IOSTANDARD = LVTTL ;
NET "l_r_haz<0>" LOC = "L13" | IOSTANDARD = LVTTL | PULLUP ;
NET "l_r_haz<1>" LOC = "L14" | IOSTANDARD = LVTTL | PULLUP ;
NET "l_r_haz<2>" LOC = "H18" | IOSTANDARD = LVTTL | PULLUP ;
NET "lights<0>" LOC = "E12" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
NET "lights<1>" LOC = "E11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
NET "lights<2>" LOC = "F11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
NET "lights<3>" LOC = "C11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
NET "lights<4>" LOC = "D11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
NET "lights<5>" LOC = "E9" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
NET "rst" LOC = "N17" | PULLUP ;
#PACE: Start of PACE Area Constraints
#PACE: Start of PACE Prohibit Constraints
#PACE: End of Constraints generated by PACE
#Do not forget:
#Start User Defined Timing Constraints
#End User Defined Timing Constraints

You might also like