Description
In computer systems it is necessary to provide a substantial amount of memory. If a system is
implemented using FPGA technology, it is possible to provide some amount of memory by using the
memory resources that exist in the FPGA device. In this lab we will examine the general issues involved
in implementing such memory.
Introduction
A diagram of the Random Access Memory (RAM) module that we will implement is shown in Figure 1a.
It contains 32 four-bit words (rows), which are accessed using a five-bit address port, a four-bit data port,
and a write control input.
Figure 1. 32×4 RAM module
The FPGA included on the DE1-SoC board provides dedicated memory resources and has M10K blocks,
where each M10K block contains 10240 memory bits. The M10k blocks can be configured to implement
memories of various sizes. A common term used to specify the size of a memory is its aspect ratio, which
gives the depth in words and the width in bits (depth x width). In this lab we will use an aspect ratio that
is four bits wide, and we will use only the first 32 words in the memory.
There are two important features of the M10K blocks. First, they include registers that can be used to
synchronize all the input and output signals to a clock input. Second, the blocks have separate ports for
data being written to the memory and data being read from the memory. Given these requirements, we
will implement the modified 32 x 4 RAM module shown in Figure 1b. It includes registers for the
address, data input, and write ports, and uses a separate unregistered data output port.
Task 1:
Commonly used logic structures, such as adders, registers, counters and memories, can be implemented in
an FPGA chip by using prebuilt modules that are provided in libraries. In this exercise we will use such a
module to implement the memory shown in Figure 1b.
1. Create a new Quartus project to implement the memory module.
2. To open the IP Catalog in the Quartus software click on Tools > IP Catalog.
a. In the IP Catalog window choose the RAM: 1-PORT module, which is found under the
Basic Functions > On Chip Memory category.
b. Select SystemVerilog HDL as the type of output file to create, give the file the name
ram32x4.sv, and click OK. If SystemVerilog is not available as an option, create the file
in Verilog, and name it ram32x4.v.
c. In the configuration window, specify a memory size of 32 four-bit words. Select M10K.
Also on this screen accept the default setting to use a single clock for the memory’s
registers, and then advance to the next page.
d. On this page deselect the setting called ’q’ output port under the category Which ports
should be registered? This setting creates a RAM module that matches the structure in
Figure 1b, with registered input ports and unregistered output ports.
e. Accept defaults for the rest of the settings in the Wizard and click the Finish button to
exit from this tool.
Examine the ram32x4.sv (or ram32x4.v) file which defines the following module:
module ram32x4 (address, clock, data, wren, q);
input [4:0] address;
input clock;
input [3:0] data;
input wren;
output [3:0] q;
3. Create a new top-level SystemVerilog file and instantiate the ram32x4 module, using appropriate
input and output signals for the memory ports given in Figure 1b. Compile the circuit. Observe in
the Compilation Report, under “Total block memory bits,” that the Quartus Compiler uses 128
bits in one of the FPGA memory blocks to implement the RAM circuit.
4. Simulate the behavior of your circuit in ModelSim and ensure that you can read and write data in
the memory.
a. You may encounter simulation errors. Try the following:
i. Module ‘ram_testbench’ does not have a timeunit/timeprecision specification in
effect, but other modules do.
Solution: Add the following line above your testbench module declaration
`timescale 1 ps / 1 ps
ii. Instantiation of ‘altsyncram’ failed. The design unit was not found.
Solution: Go to “Start Simulation…” under “Simulate” and under the libraries
tab, add “altera_mf_ver” under “Search Libraries First ( -Lf ).” Then, select your
testbench module under the “Design” tab and select “OK”
Task 2:
Now, we want to realize the memory circuit in the FPGA on the DE1-SoC board and use slide switches to
load some data into the created memory. We also want to display the contents of the RAM on the 7-
segment displays.
1. Make a new Quartus project.
2. Create another SystemVerilog file that instantiates the ram32x4 module and that includes the
required input and output pins on your DE1-SoC board.
a. Use slide switches SW 3−0 to provide input data for the RAM and switches SW 8−4 to
specify the address
b. Use SW 9 as the Write signal and use KEY 0 as the Clock input
c. Using hexadecimal, show the address value on the 7-segment displays HEX5 − 4, show the
data being input to the memory on HEX2, and show the data read out of the memory on
HEX0.
3. Test your circuit and make sure that data can be stored into the memory at various locations.
Demonstrate the circuit to your TA.
Task 3:
Instead of creating a memory module by using the IP Catalog, we can implement the required memory by
specifying its structure in SystemVerilog code. In a SystemVerilog-specified design it is possible to
define the memory as a multidimensional array. A 32 x 4 array, which has 32 words with 4 bits per word,
can be declared by the statement
logic [3:0] memory_array [31:0];
In the FPGAs, such an array can be implemented either by using the flip-flops that each logic element
contains or, more efficiently, by using the built-in memory blocks.
Perform the following steps:
1. Create a new Quartus project.
2. Write a SystemVerilog file that provides the necessary functionality, including the ability to load
the RAM and read its contents as was done in task 2.
3. Assign the pins on the FPGA to connect to the switches and the 7-segment displays.
4. Compile the circuit and download it into the DE1_SoC.
5. Test the functionality of your design by applying some inputs and observing the output.
Demonstrate to your TA.
Task 4:
The RAM block in Figure1 has a single port that provides the address for both read and write operations.
For this task you will create a different type of memory module, in which there is one port for supplying
the address for a read operation, and a separate port that gives the address for a write operation. Perform
the following steps.
1. Create a new Quartus project for your circuit. To generate the desired memory module open the
IP Catalog and select the RAM: 2-PORT module in the Basic Functions > On Chip Memory
category. Choose “With one read port and one write port” in the category called “How will you
be using the dual port ram?”
a. Configure the memory size, clocking method, and registered ports the same way as in
task 2.
b. Select I do not care (The outputs will be undefined) for Mixed Port Read-During-Write
for Single Input Clock RAM. This setting specifies that it does not matter whether the
memory outputs the new data being written, or the old data previously stored, in the case
that the write and read addresses are the same during a write operation.
c. On the following configuration window, choose the setting Yes, use this file for the
memory content data, and specify the filename ram32x4.mif. This configuration window
shows how the memory words can be initialized to specific values. It makes use of a
feature that allows the memory module to be loaded with data when the circuit is
programmed into the FPGA chip.
i. An example of a MIF file is provided in Figure 2. You can also learn about the
format of a memory initialization file (MIF) by using the Quartus Help. You will
need to create a MIF file like the one in Figure 2 to test your circuit.
d. Finish the Wizard and then examine the generated memory module in the file
ram32x4.sv.
DEPTH = 32;
WIDTH = 4;
ADDRESS_RADIX = HEX;
DATA_RADIX = BIN;
CONTENT
BEGIN
0 : 0000;
1 : 0001;
2 : 0010;
3 : 0011;
… (some lines not shown)
1E : 1110;
1F : 1111;
END;
Figure 2: An example memory initialization file (MIF).
2. Write a SystemVerilog file that instantiates your dual-port memory.
a. To see the RAM contents, add to your design a capability to display the content of each
four-bit word (in hexadecimal format) on the 7-segment display HEX0
b. Use a counter as a read address and scroll through the memory locations by displaying
each word for about one second. As each word is being displayed, show its address (in
hex format) on the 7-segment displays HEX3−2
c. Use the 50 MHz clock, CLOCK_50, and use KEY 0 as a reset input
d. For the write address and corresponding data use switches SW 8−4 and SW 3−0
e. Show the write address on HEX5−4 and show the write data on HEX1.
f. Make sure that you properly synchronize the slide switch inputs to the 50 MHz clock
signal.
3. Test your circuit and verify that the initial contents of the memory match your ram32x4.mif file.
Make sure that you can independently write data to any address by using the slide switches.
4. Use the SignalTap II functionality of Quartus to verify the contents of your RAM module. Find
the Intel SignalTap II tutorial on canvas (SignalTap.pdf) to get started. For your RAM module,
you’ll probably want to probe the read address and data output port.
5. Demonstrate to your TA.
Lab Demonstration and Submission Requirements
• Submit a lab report that includes the procedures and results obtained in the lab.
• Include any hurdles or challenges (if any) that you faced in finishing this lab and how you
overcome them.
• Submit the SystemVerilog code for all tasks and include screenshots for the ModelSim waveforms
of all modules.
• Submit the Flow Summary (produced during compilation) of compiling your system.
• In your report, include the number of hours (estimated) it took to complete this lab, including
reading, planning, design, coding, debugging, testing, etc. Everything related to the lab (in total).
• Submit your report and programs to Canvas. No hard copies.