You are on page 1of 6

Lab 3: VHDL


This laboratory will provide you with practice and experience writing
VHDL descriptions. Specificially, you will be interfacing to an LCD
display and register file (memory). To complete these tasks, you will
have to design a counter, register file, and state machine controller.

Task 1: Displaying to the LCD Display

A digital I/O peripheral board that contains an LCD display can be
attached to the Digilab 2E board. For this exercise, write a VHDL
state machine that will display your name on the display. (If you are
completing this lab in groups of two, then display one name on the top
line of the LCD display and the other name on the bottom line.)

Starting out
Create a new Xilinx project for this lab and create the top-level file
with the entity statement shown in Figure L3. The pin assignments for
the top-level I/O signals are shown in Figure L3.

Handling Global Clock Pins

Any time an input or output signal is defined in the top-level entity
statement, you must add an I/O Buffer component to it so the com-
piler will attach the signal to a physical I/O pin on the FPGA. By
default, Xilinx automatically adds an I/O Buffer (IOB) to all standard
I/O signals and adds a special Global Clock I/O Buffer (GCLKIOB)
to all identified clock signals. Alternatively, you can go to Synthe-
size ⇒ Properties ⇒ Xilinx Specific Options and uncheck
the Add I/O Buffers option. Of course, unchecking this option will


ENTITY top_level IS
PORT ( clock : IN STD_LOGIC;
reset_in : IN STD_LOGIC;
enable : OUT STD_LOGIC;
END top_level;

ARCHITECTURE behavioral OF top_level IS




PORT MAP ( I => reset_in,
O => reset );


END behavioral;

Figure L3.1: The top-level entity statement with a skeleton architecture.

NET clock LOC = P80;

NET reset_in LOC = P77;
NET enable LOC = P148;
NET rw LOC = P146;
NET rs LOC = P145;
NET lcd_data<0> LOC = P150;
NET lcd_data<1> LOC = P149;
NET lcd_data<2> LOC = P152;
NET lcd_data<3> LOC = P151;
NET lcd_data<4> LOC = P160;
NET lcd_data<5> LOC = P154;
NET lcd_data<6> LOC = P162;
NET lcd_data<7> LOC = P161;

Figure L3.2: The pin assignments for the top-level I/O signals. These assume
that the Digilab IO2 peripheral board is connected to the Digilab 2E board via
connectors C and D.

force you to explicitly instantiate an I/O Buffer component for each

and every top-level I/O signal.
Xilinx Spartan-IIE FPGAs have pins (or “pads”) that are specifically
designed for clock signals. These pins (pads) are attached to special
global clock busses that are designed to be low skew. Because of this,
only signals with GCLKIOBs can be assigned to the clock pins, and
likewise, only standard I/O signals (with their standard IOBs) can be
attached to standard I/O pins.
In general, the clock pins should be saved for clock signals since there
are a limited number of them. However, in the case of the Digilab
2E board, the single pushbutton on the board is tied to a global clock
pin (pin 77). This project uses the pushbutton as a non-clock, reset
signal, but the Xilinx synthesizer correctly identifies the reset signal
as a standard I/O signal and automatically adds the standard IOB
component to it. Now, the Mapper will generate an error, because it
can’t connect a standard IOB component with a global clock pad (pin).
To fix this, the GCLKIOB component must be manually added to the
reset signal. Add the BUFGP component as shown in Figure L3. When
this component is present, the Synthesizer will use the GCLKIOB com-
ponent and the Mapper will be able to attach the GCLKIOB compo-
nent to the global clock pad (pin 77).

LCD Device Driver

A low-level driver has already been designed to interface directly with
the LCD display. Download this file (lcd driver.vhd) from WebCT and
add it to your Xilinx project. Create component and port map
statements for the device driver. Create internal signals for addr in,
data in, write, and ready. All other signals, except clock, should be
mapped to the appropriate top-level I/O signal. The clock signal needs
to be driven with a 1 MHz clock signal. This can be done by using the
CLOCK DIV module (see next section).
To write to the LCD display, you must first check the ready signal.
When it is High, the display is ready for the next character. Set the
addr in signal to the desired position of the character (the top line of
the LCD display is mapped to addresses 0x00 to 0x0F and the bottom
line is mapped to 0x40 to 0x4F). Set the data in signal to the ASCII
value of the character you wish to display. Finally, set the write signal

High to indicate that the address and data lines are valid. Note that
all three of these signals can be set at the same time (i.e., in the same
state). Also, be aware that the LCD driver looks for a pulse on the
write line, so you must take it Low after each character is written.

Using the CLOCK DIV Component

A component called CLOCK DIV is provided for your use on WebCT.
This component accepts the 50 MHz clock as an input and outputs
clock signals at 1 MHz, 100 KHz, 10 KHz, 1 KHz, 100 Hz, 10 Hz, and
1 Hz. For this project, it should be used to obtain the clock signals for
the LCD driver, your state machine in Task 2, and the counter in Task
3. You may also find is helpful in generating clocks for future labs.
Also, this component can be easily modified to generate any desirable
clock period that is a mutliple of 20 ns.

Writing the State Machine

Write a VHDL description of a state machine that displays your name
in the LCD display. For simpliticy, the state machine clock can be the
ready signal coming from the lcd driver module, and the reset signal
coming from the BUFGP component should reset the state machine.
Each state should send one character to the display. After all characters
are displayed, go to a “done” state that outputs a ’0’ on the write line
and stays in the “done” state. Also, you may need an “init” state that
is your first state and also outputs a ’0’ on the write line.
Driving the write signal is complicated by the fact that the LCD driver
requires that it be pulsed High and Low for each character that is
written to the driver. One possibility is to have write follow the ready
signal when the state machine is not in the “init” or “done” states. The
concurrent signal assignment for this behavior is

write <= ’0’ WHEN ( (state = init) OR (state = done) )

ELSE ready;

When your completed project compiles correctly, ask the TA for the
Digilab DIO2 peripheral board and plug it into connectors C and D on
your Digilab 2E board. Then apply power to the board and download
your design file to the FPGA.
Remember to get checked-off by the teaching assistant before continuing!

Task 2: Changing the State Machine Clock

Change your state machine to be clocked by the 1 KHz clock signal
supplied by the CLOCK DIV component. To keep the display func-
tioning correctly, you will also need to ensure that the ready signal
is High in each state before proceeding to the next state. In Task 1,
this condition was assured, because the state machine was clocked by
the ready signal so the states only advanced when the ready signal
was High. Now, with a constant 1 KHz clock, it is possible (although
unlikely with such a slow clock) that the ready signal will not be High
when the next rising edge of the clock appears.
Additionally, you need to change how the write signal is generated.
For this task, it should be assigned with a statement
(i.e., like a standard Moore-type output). Keep in mind that the LCD
driver requires that the write signal be pulsed High and Low once for
each character sent to it. So, each character may need two states in
the state machine. During the first state, write is Low (and the ready
signal is checked), and during the second state write is High.
Compile and download the project. It’s behavior should be identical to
that of Task 1.
Remember to get checked-off by the teaching assistant before continuing!

Task 3: Scrolling Text

The final task is to make your name scroll across the LCD display. Feel
free to try your own approach in completing this exercise using VHDL.
Following is the outline of one solution, but there are certainly other
First, create a memory array that holds the character values and treat
it like a circular buffer from which the character values can be read.
Use the array construct to create an array of 16 8-bit
std logic vectors. Then use concurrent signal assignments to as-
sign the appropriate ASCII value to each element of the array to spell
out your name. Any blank characters should be filled in with the space
character, 0x20.
Create a process that implements a 0-15 counter called offset. This
process should be clocked on the falling edge of a 1 Hz clock signal,
and offset should be defined as an std logic vector(3 downto
Finally, change the line that assigns lcd data to use the character
array created earlier indexed by (addr in + offset). By truncating the
overflow bit in this summation, we can achieve the modulus operation.
This trick, of course, only works for mod’ing by powers of 2.
Remember to get checked-off by the teaching assistant before continuing!

Report for Laboratory 3

The report for Laboratory 3 is due at the beginning of the next lab
period (Sept. 23). For this report, turn in the following items:

1. Completed Check-off Sheet.

2. Properly documented VHDL code for Task 1 (follow the Format
and Style sheet).
3. Properly documented VHDL code for Task 2 (follow the Format
and Style sheet).
4. Properly documented VHDL code for Task 3 (follows the Format
and Style sheet).