Laboratory 3 (individual) -- Registers and memory
Worth: 20 points
Assigned: 23 January 2015
Due: 30 January 2015
Overview
The circuits you wrote in Labs 1 and 2 were combinational circuits; i.e.
they computed an output value based on the current values of the inputs.
In this lab, you will use sequential circuits, in which the output values
may depend on the past values of the inputs. You will use
two types of components: register and memory. These components have two
properties that distinguish them from the circuits in Labs 1 and 2:
- Their current "state" depends on the past sequence of inputs
they've seen.
- They respond to a "clock" signal, i.e. they only change behavior or
state at the instant in time when the clock signal changes from 0 to 1.
This instant is called the "positive edge" of the clock signal.
You will instantiate a register and memory component, store values in them,
and retrieve those values later. You will also gain experience with
Quartus' In-System Memory Content Editor.
Registers
A register is used to remember a multi-bit value for later use.
Each register can remember exactly one multi-bit value.
We call the value currently remembered in the register the
register's "value" or the value "stored" by the register.
The operation of a register is controlled by four signals: clock,
reset, write, and data_in. A register
supports two operations (based on the values of these signals):
- Reset sets the value of the register to all 0s. A
reset operation will occur at the positive edge of the clock if the value
of the reset signal at that time is 1.
- Write changes the value currently stored in the
register to equal the value of the input parameter data_in. For
shorthand, we say that we are "writing data_in to the register".
A write will occur at the positive edge of the clock if the value of the
write signal at that time is 1.
The register outputs a multi-bit value, data_out, which is the
value currently stored in the register. This value changes immediately after
the value stored in the register changes.
Memory
A memory is an array of registers. Like a register, memory is
controlled by the signals clock, write, and
data_in (memories have no reset signal). Like a register,
memory outputs a signal data_out. However, because memory is an
array of registers, it needs additional information to control which
element of the array is being operated on.
This additional information is called the memory's address;
it is similar to an array index.
The address is stored in an internal register of the memory, which is
called memory_address_register. To operate on the memory, one
must first write an address to memory_address_register. The
current value of memory_address_register determines which
array element is written to or read from on subsequent memory operations.
I.e., a write operation will write to the address currently stored in
memory_address_register, and the memory's data_out
always outputs the value stored at the address stored in
memory_address_register.
Like all registers, memory_address_register is controlled by
the signals write, data_in, and clock.
The memory_address_register's write signal is called
address_write, and the
memory_address_register's data_in signal is called
address_in. memory_address_register
shares the same clock signal as the memory. Unlike other registers,
memory_address_register is not affected by the reset signal.
For example, here's how to write the value V to the memory element at
address A (in C++, you might express this operation as memory[A] = V).
First, write A to memory_address_register by setting
address_write and address_in to the appropriate value
and waiting for a positive clock edge.
Next, write to memory
element A by setting the memory's write and
data_in signals and waiting for another positive clock edge.
Here's how to read the value stored in memory element A (in C++, you might
express this operation as reading memory[A]). First, write A to
memory_address_register by setting
address_write and address_in to the appropriate value
and waiting for a positive clock edge.
After this positive clock edge, the value of memory element A will start to be
output on data_out.
Demonstration circuit
All the Verilog for this lab is provided for you (except for
hexdigit.v, which you wrote for Lab 2).
Create a new Quartus project called lab3. Remember to download
top.qsf
into your project directory after you create the project
but before you add any files.
After downloading top.qsf, download
top.v, register.v,
reset_toggle.v, and
ram.v into the project directory. Also copy
your hexdigit.v from Lab 2 into the project directory. Add these
Verilog files to your project as you did in Lab 2.
Read register.v and identify the operations supported by this
component (which is a 4-bit register). This module introduces two new Verilog
constructs:
- always @(posedge clock) specifies that
the actions in this always block should occur only at the positive
edge of the clock. These are called "edge triggered" always blocks.
- <= is used as the assignment operator
(instead of the normal = operator) within an edge-triggered
always block.
Next, look through top.v. The module top connects a
register (module register) and a memory (module ram) to
the DE2-115's push buttons, switches, and LEDs. These connections allow you to
control the inputs to the register and memory components and to observe
their outputs. The only new I/O device used in top is
KEY[3:0]; these refer to the
four push buttons in the lower, right-hand corner of the DE2-115. These
buttons generate a value of 0 when they pressed down and generate a value
of 1 when they are released. This is the reverse of most people's
intuition, so we invert the values with Verilog's
~ operator. Thus, ~KEY[1] is 1 when the
button is pressed and 0 when the button is released.
Now observe how top connects the DE2-115's I/O devices to the inputs
and outputs of the register component:
- ~KEY[1] is connected to the register's clock.
- ~KEY[0] feeds into the reset_toggle module, which
generates the reset signal for the register. reset is
initialized to 1 when the circuit is downloaded to the FPGA, and changes
(between 0 and 1) each time ~KEY[0] is pushed and released. The
value of reset is displayed on
LED_GREEN[8] (located
between the 7-segment LEDs).
- SW[8] is connected to the register's write.
- SW[3:0] is connected to the register's data_in.
- The register's data_out drives the variable
register_out, which is then connected to HEX0.
Finally, look at the connections that top makes to the memory
module ram (you need not look at the file ram.v--this
is a somewhat-obscure file that Quartus uses to interface to its memory
component). The module ram is a memory with 16 words of memory,
with each word being 4 bits wide.
- SW[7:4] is connected to the memory's address_in,
i.e. the data_in signal to memory_address_register.
- SW[10] is connected to the memory's address_write,
i.e. the write signal to memory_address_register.
(side note: we invert SW[10] before passing it to the
ram module because the ram module uses an inverted version
to generate memory_address_register's write signal).
- ~KEY[1] is the clock signal for both
memory_address_register and the memory array.
- SW[3:0] is connected to the memory's data_in.
- SW[9] is connected to the memory's memory_write.
- The memory's data_out drives the variable
memory_out, which is then connected to HEX1.
Pre-lab assignment
Your pre-lab assignment is to understand the demonstration circuit and to
create a testing plan that
demonstrates the use of registers and memory on the circuit.
Your testing plan should exercise the full range of capabilities
of both components (hint: is there anything that memory can do that a
register cannot?).
Your testing plan
should show the sequence of steps you will take after
downloading the circuit. For each step, you should state:
-
the action you will take, e.g., move specific switches to a
specified value, push or release a specific push button.
- the visible effect you expect that action to have on the LEDs on the DE2-115.
If you expect no visible effects, then state what internal change you
expect to take place.
Print/export your testing plan to a PDF file.
In-lab demonstration
In the lab, you will carry out your testing plan, verify that it
behaves as you expect, and adjust it as needed to demonstrate the
full range of capabilities of both components. Then you will
demonstrate your testing plan to a lab instructor.
Submit
your testing plan after you've demonstrated it to a lab instructor.
Quartus' In-System Memory Content Editor
You've used the In-System Memory Content Editor
to download a circuit to the FPGA. The memory editor
also allows you to view and modify the contents of the memory components on
the DE2-115's Cyclone IV FPGA. Your testing plan for this lab should
not use the memory editor. However, you
should try using the memory editor after your in-lab
demonstration, as it will be an essential tool for later labs.
After you've downloaded a circuit, the main window of the memory editor
can be used to display or modify the contents of the memory component
in your circuit
(screenshot). Each row shows
the contents of a set of words in memory. The starting address of
these words is shown in hexadecimal on the left-hand side of the
memory-editor window.
The contents of memory may change as the circuit continues to operate.
You can refresh your view of the memory's contents by right-clicking
anywhere in the contents of memory and selecting
Read Data from In-System Memory. You can also edit the contents of
memory on the screen and write these new contents to the memory on the FPGA,
but you will not need to do this until Lab 4.