Learn VHDL using a Xilinx CPLD

This introductory VHDL course uses a Xilinx CPLD board to teach the basics of logic design using VHDL. The course starts at a very basic level for absolute beginners in VHDL, but does assume some knowledge of digital electronics such as gates, truth tables, registers, etc.

This is a very practical course and consists of a brief introduction to CPLDs and VHDL, followed by a series of tutorials that teach VHDL by implementing various VHDL designs on the CPLD board.

The hardware for the course (a CPLD board and a programming cable) can be built at home on home-made single sided PCBs. The software can be downloaded for free.

The course consists of these articles and tutorials:

24 thoughts on “Learn VHDL using a Xilinx CPLD

  1. Hi,
    I just had a question in mind that why you put another controller for just giving the clock. Why can`t we able to give crystal source for that.

    • The CPLD won’t work with just a crystal, it needs to be an oscillator. There are several reasons why I chose to use the microcontroller for the clock source:
      1) 3.3V oscillators are all surface mount parts. This is a through-hole board.
      2) The clock speed can be changed in the microcontroller
      3) The microcontroller can also be used to interact with the CPLD, not just provide a clock source
      4) It was cheaper to buy a single microcontroller than a single oscillator

  2. Hi,
    I got a question referencing to Tutorial 4: Multiplexers in VHDL:

    In the chapter: “Alternate VHDL Code Using when-else” you say that the second example code is behaving exactly as the first one.
    But if I’m looking at the last line of the when else statement:
    A(3) when (SEL = “11”) else A(0);
    I think i outputs the current logical state (0 or 1) of the input A(0).
    BUT in the first example the last line says:
    ‘0’ when others;
    the multiplexer will output a defined 0 if the signal SEL is “undefined”, f.e. Z (high impedance).
    Am I wrong?

    Thanks, for a short explanation!

    • Hi Markus
      The inputs to the multiplexer will never be anything other than 00, 01, 10 an 11. The last condition is just to satisfy the VHDL compiler so that it does not generate an error.
      You can put anything in the last condition and the two circuits will still operate exactly the same.

  3. Hi,

    I was looking at the first example of tutorial 5:
    There’s the expression:
    process (B, EN)

    But there is no variable / signal called B in it at all, just A.
    Shouldn’t it be called A there?


  4. Since this is a completely CMOS circuit, why didn’t you just use pull-down resistors for the switches and connect them to +V? Pull down is not recommended for TTL but works fine for CMOS. It would have saved a lot of diversions to invert inputs in this otherwise very nice tutorial.

    • One of the Xilinx design recommendations in the application note “XAPP784 – Bulletproof CPLD Design Practices” (http://www.xilinx.com/support/documentation/application_notes/xapp784.pdf) states:
      7. Avoid pull-down resistors on pins

      I design for reliability by habit. I do agree though that it is annoying to have to invert everything in the VHDL code, but these are problems that need to be faced as a VHDL programmer – hardware that you use may or may not invert I/O signals, so you need to be prepared for both.

  5. Hi,
    I was going through the example in Tutorial 6!

    I didnt understand how this line of code worked for dividing CLK_PB4 by 32 just by incrementing it by 1. Can you please explain?
    if (CLK_PB4’Event and CLK_PB4 = ‘1’) then
    CLK_DIV <= CLK_DIV + '1';
    end if;
    Thanks in advance.

    • Hi Mary
      It does not matter how many times you are dividing the clock by, the register (CLK_DIV in this case) will always be incremented by one. The number of times that the clock is divided by is determined by the size of the register being incremented (the number of bits the register consists of), but also which bit of the register you are taking the divided clock from.

      When incrementing the regsiter, bit 0 of the register will produce a clock pulse that is half the frequency of the clock pulse that is triggering the increment. This is because bit 0 is incremented only on the rising edge of the input clock. Every full input clock cycle toggles bit 0 only once. So the input clock goes high, low and bit 0 changes state only once (say to high) then the input clock goes high, low again and bit 0 goes low.

      By incrementing the register, the following happens:
      bit 0 produces a clock frequency of half the input clock.
      bit 1 produces a clock frequency of half the frequency of bit 0 (or input clock divided by 4)
      bit 2 produces a frequency that is half the frequency of bit 1 (or input clock divided by 8), etc.

      In tutorial 6 we are tapping off bit 4 of the register:
      LED2 <= CLK_DIV(4); So LED2 is now driven by bit 4 of the clock divider register. Bit 4 is the fifth bit of the register (0 to 4 = 5 bits), so we are dividing by 2^5 (2 to the power of 5) = 32

  6. about the tutorial 19 : up/down counter
    i have made the same as yours but when i run, it’s just popped out the error that Non-static loop limit exceeded in this line “while (a < 6) loop"….
    signal s1,s2 : std_logic:='0'; –sensor s1 n s2
    signal a :std_logic_vector(1 downto 0):="00";
    if reset = '1' then
    a <= "00";
    s1 <= '0';
    elsif TEMP_T'event and TEMP_T = '1' then
    if (s1 = '1') then
    while (a < 6) loop
    a 0) loop
    a <= a – '1';–count down
    end loop;
    end if;
    end if;
    end process;
    Led <= a;
    LED2 <= s1;

  7. Hi,
    I was doing the up-down counter as same in tutorial 19 but i got the error is about Non-static loop limit exceeded…this is my code
    if reset = ‘1’ then
    a <= "00";
    s1 <= '0';
    elsif TEMP_T'event and TEMP_T = '1' then
    if s1 = '1' then
    while a < 6 loop
    a 0 loop
    a <= a – '1';–count down
    end loop;
    end if;
    end if;
    –y <= up_counter – down_counter;
    end process;
    TEMP_T is a divided clock…looking forward for your help me with this problem…I am greatly aprreciated

  8. Thanks for the board, the parallel port programmer and the course – all excellent. Had a few problems getting it all going as I was using Linux but it’s all working well now.

    For anyone looking at running this under Linux, ISE (14.5, 64bit) can be installed using guides that can be googled – needs a few libraries such as motif, x11-fonts etc to get running properly. I found what was missing by following the “getting started with ..” page on the project site and watching the terminal to see what was missing.

    Assuming a default install, to start the software, you need to run
    “source /opt/Xilinx/14.5/ISE_DS/settings64.sh” before calling “ise”

    The parallel port JTAG programmer can be made to work with iMPACT using this driver http://rmdir.de/~michael/xilinx/

    Once you have compiled and installed it (to usr/local/lib in my case), Don’t forget the
    “export LD_PRELOAD=/usr/local/lib/libusb-driver.so” before calling ise or it will not find the correct driver

    The JTAG cable also works with http://xc3sprog.sourceforge.net/

    Everything worked for me using Mint 15 64bit, so I’d guess Ubuntu and Debian should be possible too.

    Thanks for all the work you’ve put into this.

  9. Sir, thanks for an awesome course on VHDL.

    In your ‘Ring Counter in VHDL Tutorial’,(the first code), I m not able to figure out when exactly the shift register is updated and how. Does is get updated at the end of the clock_div(4) process, or does it get updated bit by bit at the same time whenever the corresponding bit assignments are made?
    If latter is the case then the shifted bit would be lost, but since it doesn’t, then how n when exactly in the former case does the shift_reg update itself?

    I guess that the shift_reg shows up on the LEDs as soon as it is updated. Pls clarify.

    Also, i wrote this code, which is more convincing for me:

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;

    entity ring_counter_top is
    Port ( CLK : in STD_LOGIC;
    LED : out STD_LOGIC_VECTOR (7 downto 0));
    end ring_counter_top;

    architecture Behavioral of ring_counter_top is
    signal clock_div : STD_LOGIC_VECTOR(4 downto 0);
    –signal shift_reg : STD_LOGIC_VECTOR(7 downto 0) := X”80″;
    signal shift_reg : STD_LOGIC_VECTOR(7 downto 0) := X”7F”;

    signal previous : STD_LOGIC;


    — clock divider: slows clock to make LEDs visible
    process (CLK)
    if (CLK’event and CLK = ‘1’) then
    clock_div <= clock_div + '1';
    end if;
    end process;

    — ring counter
    process (clock_div(4))
    if (clock_div(4)'event and clock_div(4) = '1') then

    previous <= shift_reg(0);

    shift_reg <= previous & shift_reg(7 downto 1);

    end if;
    end process;

    — hook up the ring counter register bits to the LEDs
    LED <= shift_reg;

    end Behavioral;

  10. Hi,
    I was wondering if you could please explain some of your code in tutorial 8.( chasing LED’S)

    if (shift_reg = X”40″) then
    fwd <= '0';
    Why is the bit test carried out at x"40" rather than x"80" and by a similar vein when the shift register clocks in the other direction is the bit test carried out at x"02" rather than x"01".
    I am guessing it is to do with when the outputs are updated?.

    • Hi Jim
      The new value assigned to shift_reg has not propagated by the time the check for the value X”40″ is done. The value of shift_reg will not change (to X”80″) until the process has completed execution of all sequential statements in the process.

      The delay occurs because shift_reg is a signal. If shift_reg were are variable, the value would be assigned to it immediately.

      (ref. VHDL Programming by Example, 4th Edition, Douglas L. Perry: Incorrect Mux Example and Correct Mux Example – p43 to p46)

  11. In the VHDL SPI code, you are using the external SPI clock to shift data-in. Shouldn’t you use a clock of higher frequency and then sample the SPI clock for reliable operation?

    • Hi htsh
      The microcontroller’s SPI clock drives the VHDL circuit. The microcontroller is a master SPI device and the CPLD/VHDL acts as a SPI slave device. The SPI timing diagram shows that the data on the DO(DATA) line is set up and held before the arrival of the rising edge of the clock pulse — making the operation reliable.

Leave a Reply

Your email address will not be published. Required fields are marked *