Lab 6: Moving Memory
The purpose of this lab is to give you experience working with both read-only and random-access memory. Reading and writing from memory is a multi-step process and requires setting signals in the proper order and giving the memory sufficient time to respond to the signals.
- Create a new project in a new folder for lab 6 (e.g. romtest).
Create an MIF file for your ROM that has 16 words of 4 bits each. I
would suggest using a simple text editor to do this (gEdit, emacs,
vi). Load the memory with a set of patterns. You can do this within
Quartus or using any text editor. The format is simple: define the
size and radix of the addresses and data, then define the memory
contents. The example below defines a 16-element memory with 4-bits
in each memory location, interpreted as a binary number. Note how the
last 8 elements are defined in a single statement using a range of
-- program memory file DEPTH = 16; WIDTH = 4; ADDRESS_RADIX = HEX; DATA_RADIX = BIN; CONTENT BEGIN 0 : 1010; 1 : 0101; 2 : 0010; 3 : 0001; 4 : 0000; 5 : 1000; 6 : 0100; 7 : 0010; [8..F] : 1111; -- fill A0 to A1 with all 1s END
Using the Tools::MegaWizard Plug-in Manager, select 'Create a new
custom megfunction variation', then select the 1-port ROM from under
'Memory Compiler' and give it a name like memrom.
Using the setup dialog, create a ROM that has 16 words of 4 bits each (if those values are not in the popup list, just type them in). In the Mem Init step, select the MIF file you already created. You may have to tell Quartus to look for files of type MIF before it shows up. The output of the wizard will be a VHDL file from which we can copy the component and port map statements. When you are done, open the file and look at it. Note how the generic statements define the size and functionality of the memory circuit in the port map statement.
- Create a top-level VHDL file for your project (e.g. romtest). The entity should have a clock, reset, and a 4-bit std_logic_vector output port called memview. Copy the port statement from the ROM VHDL file created above and put it in a component statement in your architecture header section.
- Add internal signals for the ROM_address (4-bit unsigned), ROM_data (4-bit std_logic_vector), ROM_wire (4-bit std_logic_vector), and a state variable that can represent 8 states (3-bit unsigned).
- Create a port map statement for the ROM circuit and link the ROM_wire signal to the ROM output (q), link the ROM_address variable to the address input, and link the clock signal to the clock input.
Make a process statement that is sensitive to the clock and reset
signals. In the reset case, set the ROM address variable to "0000",
set the state to "000", and set the ROM data register to all zeros. Do
not initialize the rom_wire, as it is driven by its connection in the
port map statement.
In the rising edge case, make a state machine with 8 states. The first five states, from "000" through "100" should increment the state variable. Note that you can make a single "when" case represent multiple states by using an expression like the following.
when "000" | "001" | "010" =>
States "101" and "110" should also each increment the state variable. State "111" should write the value in the ROM_wire variable to the ROM_data variable, increment the address, and set the state variable back to "101".
- Outside the process, make a concurrent signal assignment that assigns the ROM data to the output port signal.
Simulating this circuit is slightly more complex because we are using
the built-in Altera functions. The following commands should enable
you to simulate the circuit using ghdl and gtkwave. Note that you
should execute the first instruction only the first time you run
the simulation. Use membench.vhd to test
ghdl -a --ieee=synopsys -fexplicit --work=altera_mf /opt/altera/12.1/quartus/eda/sim_lib/altera*.vhd
ghdl -a --ieee=synopsys -fexplicit --work=altera_mf membench.vhd memtest.vhd memrom.vhd
ghdl -e --ieee=synopsys -fexplicit --work=altera_mf membench
ghdl -r membench --vcd=membench.vcd
There may be lots of warnings when compiling the altera libraries, and you may also get many warnings in the -e stage, the first time you run it.
It is not necessary to close gtkwave each time you run the simulation. Instead, leave it running, execute the -a / -e / -r ghdl commands and then select File->Relead Waveform from within gtkwave.
- Add a counter and a process to your architecture that slows down the clock so you can see the memory process occur on the board. If you want, modify your port statement so that you can also view the address. Set up the pins so 4 LEDs are connected to the circuit output. When you run the circuit on the board, you should see the contents of memory cycle by.
When you have completed the lab assignment, go ahead and get started on the current project.