UNIT 5: A memory model for the multicycle CPU


At this point you should have finished your multi-cycle CPU (including state controller) design. You have also simulated the design for correct execution of each instruction (one-at-a-time). When we proceed to synthesis, your CPU will fetch instructions and data from  a memory module which emulates the memory on the Wild-Star board. Before we can make this work, we must perform two tasks.

1)Reconcile the interfaces between memory operations on the CPU with memory operation for the Wild-One board hardware. As you will see below, there are significant differences between the control signals, bus structure, word format, and timing of these two interfaces.

2) Model and simulate the entire system (memory and CPU) in the simulator.

When you are done, this is a block diagram of what your design will look like.

         The CPU block is your multi-cycle CPU design from the previous unit.

         The Memory block is a model of the Wild-One board memory hardware. You can find this block in the COELib library as the component "memory_1502".

         Memory Controller is a block that you will design to reconcile the timing and control signals between the two interfaces.

         Alignment Unit is a block that you will design to reconcile to memory word format between the two interfaces.

Lets take a detailed look at each of these units.

Memory

Memory serves as a storage space for your data and program. The Memory block shown above is actually the memory_1502 component in the COELib library. The symbol for this component is show below.

The address size of the memory model is 24-bits. This address selects a 64-bit block of memory. When you add an instance of this component to your design, you will notice a "generic" declaration attached with a pointer to a file. Using this generic, it is possible to initialize the memory contents for the memory model from a text file in the group project directory. You will use this feature to load the memory with a test program to be executed. See the section below on how to prepare this program. Once prepared, modify the generic declaration that is included in the symbol file to point to the file that contains your program and recompile the design.

Memory Controller

You may have noticed that the signals at the pin-out of the Memory_1502 and the pin-out of your CPU do not match. In fact, they differ significantly both in function and timing. The purpose of the Memory Controller is to reconcile this difference. It will be a state machine that accepts requests from the CPU for read or write operations, synchronizes the CPU with the memory using the MEMWait signal, and manages the interface to the memory model in order to make the transfer happen.

To understand how this will work, lets begin with a description of the memory interface signals coming to and from your CPU. These are the signals shown to the right of the memory controller in the diagram below. These read and write transfers and are the same whether your CPU is doing an instruction fetch, a load, or a store operation. (except for differences in the read/write controls)

.


CPU to Memory Controller Interface

Memory operations from the CPU proceed as follows. Refer to the timingdiagram below.

Clock cycle 1 - the requested memory address is placed on the MemoryAddress bus. One of MEMRead or MEMWrite becomes active for a read or write operation respectively.

Clock cycle 2 - the memory controller asserts MEMWait back to the CPU

The CPU now holds in a wait state until the first clock edge (Cycle n) after wait is de-asserted.

Clock cycle n - The memory controller places read data on the data input bus and deasserts MEMWait. The CPU deasserts MEMRead and latches the data into the input buffer register at the end of this cycle to complete the read operation.

(Note - a practical design choice would be to have buffers on the input to and the output from the CPU, however if you look at your CPU design you will see that these buffers are already in place.)

TIMING DIAGRAM FOR CPU TO MEMORY INTERFACE


Memory Controller to MEMORY_1502 INTERFACE

To write data to the SDRAM, first check that the ‘write_rdy’ signal is high. This step ensures that the write FIFOs are not full. If ‘write_rdy’ is high, the interface is ready to accept write data. Next, put the address on the ‘addr’ lines and the 64-bit data on the ‘data_out’ lines and then pulse ‘write’. Data can be sent in continuously as long as ‘write_rdy’ is high. To read data back, first check that ‘read_rdy’ is high to make sure that the read address FIFOs are not full. Then, put the address on the ‘addr’ lines and pulse ‘read’. Again, the address of data to be read can be continuously written into the interface as long as ‘read_rdy’ is high. Soon afterwards, the ‘data_in_available’signal will go high. To get the read data, the data_in_ce line must be pulsed (or held high to retrieve data continuously). One clock later, data will be available on the ‘data in’ lines .

The waveform is shown below.

 

 

Notice, that simulated memory is small, therefore the address bus thatgoes to the Memory_1502 is only 24 bits wide.


Alignment logic

The final block is this part of your design is the alignment logic. This block has the function of reconciling the 64-bit word organization of the memory with the byte addresses coming out of the CPU. The first step in this process is to realize that each memory word contains eight bytes and thus the address input to the memory model will always be the CPU address shifted right by three bits. The low order three bits will select the particular byte lane within the 64-bit word that is returned.

The second part of the problem has to do with the fact when the CPU asks for a byte, it always expects that the byte with be in the low order 8-bits of the input bus. However, unless the low order three bits of the address are zero, this byte will not be in the low order byte lane of the memory word. The function of the data alignment network is to examine the low order three bits of the CPU address and in the case of LB instructions, shift the selected byte lane of the incoming memory word to the low order byte.

An analogous problem arises for half-word (16 bits) accesses, since there will be four 16-bit halfword lanes in each memory word.

Store byte and store half-word instructions present a special problem. If the CPU asks to write a particular byte lane or half-word lane of a 64-bit memory word, you must do so without overwriting the other parts of the memory word. Thus, Store byte and Store halfword instructions must pre-read the contents of the memory word in question, insert the byte or half-word and then write the memory word. Do this last, but you will need to design both your control unit and alignment network to handle this case.


 

Building and Running a Test Program

We mentioned above that it is possible to point the memory model to an initialization file through the generic declaration attached to the symbol. We will talk more about his in a moment. First, we need to look at how this file can be created. As an diagnostic program for your design, we have written and supplied a test program written in MIPs assembler called simpletest64.s . To convince yourself how this program works, you may wish to download a copy and run it in the PCPSPIM simulator. A full program listing with load addresses and machine language shown is available in simpletest64.lst. We have also prepared a loadable memory image of this program, with the first instruction set up to load into memory location 0x000000. This file can be found in simpletest64.bin. Note that this test assumes that your branch is implemented so that NextPC = PC + 4 * Offset.

1) Make a copy of this file and place it in your group directory.

2) Modify the generic in your memory model component to point to this file.

3) Compile and run your design in the simulator. You should have setup your reset line to force the PC to location zero. Start your simulation run by toggling the reset line then monitor the memory data bus as the program executes. When finished you can monitor the data transfer of the registers back into memory to verify your results.

Exception-enabled Simpletest files *YOU MUST RUN THESE FOR SUBMISSION*


simpletest64_ex.lst, simpletest64_ex.s, simpletest64_ex.bin