HW6 Task 3 - Implement Cache Flushing

Supplement to the hw6 main assignment.

Because the BlockController does Direct Memory Access (DMA) writes to main memory, a coherence issues must be solved. As an example, suppose that the value of the word at memory location 0x1000 is 0x12345678, and that that word is currently in a line of one of the caches. A disk operation may now overwrite the word at 0x1000 with a new value. Because the cache is unaware of this, if a read for 0x1000 is requested, the cache will happily hand over 0x12345678, the wrong value.

The coherence problem can arises because of DMA writes to main memory. As disk reads are the only operation that can cause such writes (in your machine), we need to worry about coherence problems only at the time of disk to memory transfers (disk reads).

We solve the problem by taking two steps. First, we create a new machine instruction, flush. that takes a base register and an offset as arguments. When a flush is executed, the effective address is computed and handed to the caches. Each checks if it has a cache line containing the address. If it does, it invalidates the line. (In reality, if the line is dirty it should first be written back to memory and then invalidated. However, in our circumstance we can cheat and simply invalidate, because we flush only when the word is about to be overwritten in memory. see the note at the end of this page, though.)

The second step is to modify the OS to use flush. When a disk read occurs, the OS pessimistically guesses that every line of main memory written by the disk is currently cached by at least one of the caches. It therefore loops over all those cache lines, issuing a flush for each.

Your Job

When you write C++ code to implement the caches (in Task 4) you will also have to write code that performs flushes of those caches. For now, though, all we need to do is get the datapath set up to provide the appropriate inputs to the caches so that it is possible to implement the flush function later, and modify the OS to actually issue flush instructions when needed. (Those instructions cannot be in the existing OS because your machine wouldn't be able to execute, at least until the flush instruction is implemented.)

  1. Modify ICache.cpp to create two new input ports on ICache components: FlushAddr and Flush. Modify DCache.cpp to create a single new input port, Flush (as the existing Addr input port can be used to hand over the effective address).

  2. Modify the data path and control to implement the flush instruction: compute the effective address and provide it to the appropriate input port on each cache component; set each cache's Flush input to 1.

  3. Modify the OS. See this page.

Note

The Cebollita OS does not implement a file system -- you don't name disk storage by giving a file name, you have to give a raw block number. For that reason, none of the Cebollita apps (including the OS) do writes to the disk (because they have no way to coordinate allocation of new disk blocks). This means that we are overlooking an issue that arises in real systems.

If a disk write is done, the disk does DMA transfer out of main memory. Thus, there is a possible coherence problem. If the cache is write-back, the contents of memory may not be up to date. Because of that, some sort of flush would have to be issued for the locations to be written to disk to ensure consistency. (See the CACHE instruction in the MIPS Architecture manual to get an idea of what kind of cache control operations are possible in real systems.)