VHDL tutorial based on Xilinx Spartan 3 Starter kit board
1 of 6
http://www.derepas.com/fabrice/hard/
VHDL tutorial based on Xilinx Spartan 3 starter kit board by Fabrice Derepas. I do not know anything about hardware but it seems to be fun.
These few pages gives the opportunity for newbies (like me) to learn some stuff about VHDL and hardware design. This tutorial is based on the very affordable ($99) Spartan 3 starter kit board from Xilinx. Example name Device used FFFF 7 segment led 7 segment led and clock AnnE Squares VGA port and clock SRAM Ram tester Bouncing ball VGA port, clock and SRAM
FFFF The goal of this first step is to write "FFFF" on the seven-segment LED display. This example is simple since the only thing is to do, is to send a constant signal to the right pins. Here is the code explained. First of all include standard declarations (do not think too much, just copy this at the beginning of each VHDL file): library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL;
Then declare an entity named ffff with only an output vector of 7 (6 down to 0) elements which are either '0' or '1': entity ffff is Port ( LED : out std_logic_vector(6 downto 0)); end ffff;
Then describes the actions of this entity, in an architecture (named for instance Behavioral). Its job will be to write "0001110" (which represents the letter "F" on a LED) to the outgoing vector. Comments starts with the -- characters and ends with the end of line.
10/22/2006 11:30 PM
VHDL tutorial based on Xilinx Spartan 3 Starter kit board
2 of 6
http://www.derepas.com/fabrice/hard/
architecture Behavioral of ffff is begin LED <= "0001110"; end Behavioral;
-- writes the 'F' pattern to the led.
The value "0001110" for letter comes from an arbitrary mapping I have chosen, shown on the schema below: first digit is for segment a, 2nd for f, 3rd for e, 4th for d, ... and 7th for g.
This arbitrary mapping is described in a separate file, You just have to assign elements of the LED vector to the right pins of the FPGA. I used the following mapping, in a file named for instance constraints.ucf: NET NET NET NET NET NET NET
"LED<0>" "LED<1>" "LED<2>" "LED<3>" "LED<4>" "LED<5>" "LED<6>"
LOC LOC LOC LOC LOC LOC LOC
= = = = = = =
"E14" "G13" "N15" "P15" "R16" "F13" "N16"
; ; ; ; ; ; ;
AnnE The goal of this exercise is to write "AnnE" on the seven-segment LED display. This task is similar to the previous one. Since seven-segment LED displays are timed multiplexed, we will need "something" to tell us to write the first character, then something which tells to write the second and so on. This will be given by a clock. Here is our entity: entity vhdlmodule is Port ( CLKIN : in std_logic; AN3 : inout std_logic; AN2 : inout std_logic; AN1 : inout std_logic; AN0 : inout std_logic; LED : out std_logic_vector(6 downto 0));
10/22/2006 11:30 PM
VHDL tutorial based on Xilinx Spartan 3 Starter kit board
3 of 6
http://www.derepas.com/fabrice/hard/
end vhdlmodule;
First of all we have an input signal which is a clock. Then we have the AN0, ... , AN3 signals which tell the board which of the four digit to light up. And then we have the LED signal as in previous example. For the clock signal we use the 50Mhz clock provided on the board. Unfortunately this is too quick to switch beteen digits on the led panel. So we will be using a counter named CTR, each time the counter reaches 2^13 we change the digit to be displayed, an we reset the counter. This whole computation is put in something called a "process". Since this process will only be triggered by changes of CLKIN, process declaration is process(CLKIN). We say that the sensitivity list of this process is CLKIN. architecture Behavioral of vhdlmodule is signal CTR : STD_LOGIC_VECTOR(12 downto begin Process (CLKIN) begin if CLKIN'event and CLKIN = '1' then if (CTR="0000000000000") then if (AN0='0') then AN0 <= '1'; LED <= "0101011"; AN1 <= '0'; elsif (AN1='0') then AN1 <= '1'; LED <= "0101011"; AN2 <= '0'; elsif (AN2='0') then AN2 <= '1'; LED <= "0001000"; AN3 <= '0'; elsif (AN3='0') then AN3 <= '1'; LED <= "0000110"; AN0 <= '0'; end if; end if; CTR<=CTR+"0000000000001"; if (CTR > "1000000000000") then CTR<="0000000000000"; end if; end if; -- CLK'event and CLK = '1' End Process; End Behavioral;
0);
-- the letter n
-- the letter n
-- the letter A
-- the letter E
-- counter reaches 2^13
Here is the mapping of signals on the pins of the board: NET NET NET NET NET NET NET NET NET
"AN0" LOC = "D14" ; "AN1" LOC = "G14" ; "AN2" LOC = "F14" ; "AN3" LOC = "E13" ; "CLKIN" LOC = "T9" ; "LED<0>" LOC = "E14" "LED<1>" LOC = "G13" "LED<2>" LOC = "N15" "LED<3>" LOC = "P15"
; ; ; ;
10/22/2006 11:30 PM
VHDL tutorial based on Xilinx Spartan 3 Starter kit board
4 of 6
NET "LED<4>" NET "LED<5>" NET "LED<6>"
LOC = "R16" LOC = "F13" LOC = "N16"
http://www.derepas.com/fabrice/hard/
; ; ;
Whole vhdl file
Squares The goal of this exercise is to draw on a VGA screen squares with a side of 8 pixels as represented in the above picture (click to enlarge). This exercise is very similar to the previous one. We need a time input to know when to display a pixel on the VGA screen. We will be using the 50Mhz clock clk50_in. We will write on the red, green and blue signal. We will have to provide vertical and horizontal sync information. So our entity declaration looks like: entity clockmodule port(clk50_in : red_out : green_out : blue_out : hs_out : vs_out : end clockmodule;
is in std_logic; out std_logic; out std_logic; out std_logic; out std_logic; out std_logic);
For the architecture part we will need three signals: a 25Mhz clock, because the Spartan-3 Starter Kit Board User Guide gives VGA timing for a 25Mhz pixel frequency an horizontal_counter to count the number of pixels per line a vertical_counter to count the number of lines to dislay on the screen. So the architecture declaration starts with: architecture Behavioral of clockmodule is signal clk25 : std_logic; -- the 25Mhz clock signal horizontal_counter : std_logic_vector (9 downto 0); signal vertical_counter : std_logic_vector (9 downto 0);
This time in the body of the architecture we will find two processes: one to compute the clk25 signal, using clk50_in, one to compute all out signals from clk25. begin -- generate a 25Mhz clock process (clk50_in) begin
10/22/2006 11:30 PM
VHDL tutorial based on Xilinx Spartan 3 Starter kit board
5 of 6
http://www.derepas.com/fabrice/hard/
if clk50_in'event and clk50_in='1' then if (clk25 = '0') then clk25 <= '1'; else clk25 <= '0'; end if; end if; end process; process (clk25) begin if clk25'event and clk25 = '1' then if (horizontal_counter >= "0010010000" ) -- 144 and (horizontal_counter < "1100010000" ) -- 784 and (vertical_counter >= "0000100111" ) -- 39 and (vertical_counter < "1000000111" ) -- 519 then red_out <= horizontal_counter(3) and vertical_counter(3); green_out <= horizontal_counter(4) and vertical_counter(4); blue_out <= horizontal_counter(5) and vertical_counter(5); else red_out <= '0'; green_out <= '0'; blue_out <= '0'; end if; if (horizontal_counter > "0000000000" ) and (horizontal_counter < "0001100001" ) -- 96+1 then hs_out <= '0'; else hs_out <= '1'; end if; if (vertical_counter > "0000000000" ) and (vertical_counter < "0000000011" ) -- 2+1 then vs_out <= '0'; else vs_out <= '1'; end if; horizontal_counter <= horizontal_counter+"0000000001"; if (horizontal_counter="1100100000") then vertical_counter <= vertical_counter+"0000000001"; horizontal_counter <= "0000000000"; end if; if (vertical_counter="1000001001") then vertical_counter <= "0000000000"; end if; end if; end process; end Behavioral;
Whole VHDL file
Ram tester This exercice is just to test the SRAM. The idea is to display some values read in the ram on the leds. I read the ISSI 61LV25616AL Data sheet. I did not managed to get the data in 10ns but in only 20ns. I guess I missed something. If you have the correct way to do it just
10/22/2006 11:30 PM
VHDL tutorial based on Xilinx Spartan 3 Starter kit board
6 of 6
http://www.derepas.com/fabrice/hard/
tell me :) The global clock used is the default 50 Mhz clock with a DLL. We use a single process which has 4 states given by the value of counter ctr: 1: send read information on the SRAM, go to state 2, 2: display read information on the led, go to state 3, 3: send write information, go to state 4, 4: erase values and go to state 1. Vhdl Placement
Bouncing ball Ok, now we would like to draw something on the screen which is read from the SRAM memory. This enables us more freedom, because we design separate blocks with a given role: there will be a block named vga_ctrl in charge of displaying SRAM data on the VGA port. the role of another block named graphic_gen will be to write in the SRAM the patterns we want to display. Of course we will need a dedicated block to write to the memory, let us name it ram_ctrl, and clocks will be managed in a fourth block named clk_gen. This gives the following picture:
The pattern written in the SRAM by the graphic_gen module will be a ball bouncing on the borders of the screen. To make it simpe the ball will be represented by a single pixel (in the style of the pong game). Back to my home page
10/22/2006 11:30 PM