This project will give you intimate knowledge of cache logic through implementation of the actual caching
logic. We will be providing you a MIPS simulator called TIPS (Thousands of Instructions Per Second), that
will be able to run MIPS instructions. However, the cache logic is broken (read: conveniently nonexistent)!
Your job is to implement the cache logic behind the cache so that TIPS can make use of the many beneJits
caching entails. You may choose to complete this project either by yourself or with a partner.
The initial TIPS code has a default cache size of 0 since there is no cache logic present. You can conJigure
the cache by clicking on the “ConJig Cache” button at the lower left of the interface.
The GUI was designed to be straightforward. There are four main components to the GUI interface:
register display, execution log, cache display, and control panel.
A description of each of the GUI widgets are described as follows:
1. Register display — detailed view of the current state of the registers
2. Execution log — log of actions by TIPS. Messages can be displayed in this box using the
3. Cache display — current snapshot of the state of the cache. The meaning of the column headings on
each unit are:
◦ Blk – block number
◦ V – valid bit
◦ D – dirty bit
◦ LRU – LRU data
◦ Tag – Tag for the block
◦ Numbers (00, 04, etc.) – offset in the cache block data
4. ConJig Cache — conJigure the cache parameters
5. Load Program — loads a dump Jile for execution
6. Step — execute one instruction
7. Run — automate execution
8. CPU — reset the PC and reinitialize registers
9. Cache — Jlush the cache
10. Output — clear the execution log
11. Quit — exit TIPS
There is also a text-based version of the GUI for those who prefer it. You can run it with the following call:
$ ./tips -nogui
Type help at the TIPS prompt to get a list of commands usable in this mode.
• When you are moving things between cache and physical memory, a BLOCK is transferred, NOT
just a word nor a byte. Thus, if the block size is 16 bytes, when you want to move data from cache
to memory (or vice versa) you must make sure 16 bytes travel between the cache and physical
memory on youraccessDRAM() function call.
• Write Through policy requires the ENTIRE block be transferred to physical memory on a write
• To move data to and from a cache block, the memcpy() function should be used. The function
prototype of memcpy() is deJined as follows:
void* memcpy(void* dest, void* src, size_t amount);
where dest is the destination pointer, src is the memory to be copied, and amount is the number of
bytes to copy. A more detailed description of this function can be found in K&R.
To complete this project, you must complete the accessMemory() function in cachelogic.c. This function
will handle accessing actual memory, using theaccessDRAM() function. Thus, the code in the
accessMemory() function will behave as a cache that will call the accessDRAM() function as needed (for
To ensure a variety of caches can be simulated, you will be required to dynamically support 5 properties:
• Associativity (ranges from 1 to 5)
• Number of unique indexes (2n where n ranges from 0 to 4)
• Block size (2n bytes where n ranges from 2 to 5)
• Replacement Policy (LRU and Random)
• Memory Synchronization Policy (Write Back and Write Through)
More information about the variables you will be working with and the functions at your disposal can be
ascertained by looking over tips.h.
You should keep the following things in mind when formulating the code:
• accessDRAM() requires a byte pointer when it is called.
• There are 4 bytes in 1 word.
• The tag information must be right aligned. For example, if the tag is only 25 bits for a given cache
conJiguration, the top 7 bits must always be 0.
• During a cache hit, highlight the word (not the whole block) you are accessing in GREEN color.
• During a cache miss, highlight the word (not the whole block) you are accessing in RED color.
• During a cache miss, you need to use a bounding box to indicate the block you are replacing.
you do not modify any code outside of cachelogic.c. Do not change any Jile other than cachelogic.c. Do not
change the prototypes of existing functions. To summarize, you can modify only the body of the given
functions, adding helper functions if needed.
Creating Dump Files for Testing
If you prefer to use the Mars GUI, go ahead and start Mars and open your assembly Jile. Ensure that the
“Delayed Branching” setting is enabled in the Settings menu. Now, assemble the source Jile. Then, select
the “Dump Memory” option from the File menu. Ensure that the “.text” memory segment is selected and
that the dump format is Binary, and you should be good to go. If you prefer to use the command line, you
can do something like this:
java -jar Mars.jar a db dump .text Binary output.dump input.s
Look over tips.h and cachelogic.c. tips.h gives you an overview of how the cache simulator is put together.
A section of that Jile has been marked as important, so read it to get an idea of what functions and
variables you will be using. cachelogic.c contains a slightly more detailed explanation of what you will be
writing in the accessMemory() function.
The cache data structure is divided into three levels:
• The Jirst level of entry is selecting which set you want. For example, cache states that you are
going to be accessing the 3rd set of the cache. This level is regulated by set_count.
• The next level is selecting the block you want in the set. That is speciJied by the block Jield. For
example, cache.block accesses the 5th block of the 3rd set. In the block is the tag, valid bit,
dirty bit, and lru information. This level is regulated by the associativity of the cache.
• The Jinal level of entry is selecting which bytes of the block do you want retrieve or modify. The
data contained in a block is represented by the data Jield of that block. Using the offset, a particular
byte can be referenced.
There are two methods to access the LRU information of a block. The Jirst method is via lru.value, a Jield
that will hold LRU information in integer format. The other method is via lru.data, a Jield that will hold
LRU information represented in another format (its type is void*, which means it can be a pointer to
anything). You are free to use either method to represent the LRU information, so long as the LRU behaves
in a deterministic fashion (i.e. no two valid blocks will ever be candidates for replacement at the same
Organization of the memory functions in TIPS
In a nutshell, the accessMemory() function acts as a communication layer between the CPU and DRAM.
The code within accessMemory() manipulates the cache data structure deJined in tips.h.
All your code MUST be contained in cachelogic.c – speciJically in accessMemory() and possibly the LRU
functions (depending on how you implement the LRU algorithm). You may add helper functions as long as