Solved

Could Someone Please Help Me with CACHE?

Posted on 1998-01-11
7
218 Views
Last Modified: 2010-04-02
This is a program I started on last November. It is a cache
simulation program in C. I include the instructions for this
program as well as the source code file itself.

Here are the instructions(what is required of the program)..........

1) OVERVIEW

    You are to design and implement a software-simulated cache memory subsystem. You can use any language.
Note that any real cache is invisible to high-level and assembly language programmers. This will be a simulation of the way that a real cache works. Your "cache" will be 512 bytes of data plus however much overhead you need. Your "main memory" that the cache will be handling will be 8K bytes.
You will provide for these two areas by defining an array for main memory and a structure for the cache. For example:
         unsigned char Main_mem[8192];

Note that this does NOT mean you are handling characters. this is just the way in C to specify one byte of storage. Points will be deducted for anything other than one byte since memories are byte-addressable and I want you to reflect that. So, each of your memory locations can contain values from 0 to 255 decimal (which is the same as 0 to FF hex or 0 to 1111 1111 binary).

    So, in effect, this Main_mem array will be the "pretend" main memory area, your cache structure which you define will be the "pretend" cache, your code will pretend to be the intelligence of the memory sub-system, and requests that you type in will be the equivalent of a processor making requests of the memory sub-system. You will implement a two-way set-associative write-through scheme that uses a least-used replacement algorithm. (Least-used simply counts how many times a block is referenced and throws out the least referenced block. You MUST adhere to this scheme to get all the points.) The block size will be 16 bytes so that means you'll have 16 slots. (This is because each slot has
two blocks. so 2 blocks * 16 bytes/block * 16 slots = 512 bytes of cache.) You'll also have as many overhead bytes as you need to keep track of the "valid" and "tag" information for each slot. This isn't included in the total.) You should use a structure to manage each slot, where the structure
is comprised of the valid indicators, the tag fields, the usage counter (to decide which block gets replaced if necessary), and the actual data for each block. This will result in an array of structures, since there will be a
structure for each slot.
    2) INITIALIZATION

You should initialize your main memory in such a way that you'll be able to know whether or not you have the original value or not and also such that you'll be able to tell one byte from another. To achieve this, I'd like you to assign the value 0 to the zeroth byte, 1 to byte 1, and so on until
FF to byte FF (255), then resuming 0, 1, 2, and so on for bytes 100hex (256) and up until you are finished.

You should also initialize your cache to all zeros so that it will be easy (from a debugging and correcting point of view) to see which slots in the cache have something in them. USE HEX FOR ALL ADDRESSES AND VALUES. This will actually make your life easier. Until you start doing writes to these addresses, you will know that a read of address 7AE should result in the value AE, a read of the address E22 should result in the value 22, and so on. (Note: some languages expect that any hex number that begins with an A-F be preceeded with a zero. So if you're typing in a read for address E22, you will probably want to type in 0E22.)

         3) SUPPORTED OPERATIONS

    You will need to support 3 types of requests from the screen once you have initialized your "main memory" and "cache" : Read, Write, and Display Cache.

If a Read is requested, then you should ask what "address" in your 8K "main memory" the read is for. Note that references to a memory location 802, for example, are not to the physical memory location 802 in your computer's memory, but rather to byte 802 in your Main_Mem array. You should
then simulate a real-life cache by checking to see if that address is in your cache. If it is, display the value you found for it in cache and note that a cache hit took place. If not, go to your main memory instead, bring the entire block into your cache, display the value found and note a cache miss. So, for example, the screesn could look like the following, where the second and fourth lines are typed by the user.

(R)ead, (W)rite, or (D)isplay Cache?
R
What address would you like to read?
7AE
At that byte there is the value AE (Cache hit)

Writes would be very similar, except that the user must also
indicate what the data to be written is. For example, (lines 2, 4, and 6 are typed by the user)

(R)ead, (W)rite, or (D)isplay Cache?
W
What address would you like to write to?
562
What data would you like to write at that address?
23

Display Cache will display the contents of each slot in the cache.
For example, if the first three reads were for addresses 2E, 2F and 225 you would display something like the following:

(R)ead, (W)rite, or (D)isplay Cache?
D

SET   USAGE   VALID   TAG   DATA
0     0       0       0      0  0  0  0  0  0  0  0  0  0  0  
0     0       0       0      0  0  0  0  0  0  0  0  0  0  0  
1     0       0       0      0  0  0  0  0  0  0  0  0  0  0  
1     0       0       0      0  0  0  0  0  0  0  0  0  0  0  
2     2       1       0      20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
2     1       1       2      20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
3     0       0       0      0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
3     0       0       0      0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
4     0       0       0      0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
4     0       0       0      0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .

e     0       0       0      0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
e     0       0       0      0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
f     0       0       0      0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
f     0       0       0      0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0

As you perform more operations, more of the cache will be filled in.

         4) TEST VALUES

Use the following test values to test you program:

(R)ead
66 (or 42H)
(R)ead
67, 68, 69, 233, 234, 4, 5, 6, 7, 324, 325, 326, 327, 328, 329, 330,
331, 332, 333, 334, 335, 336, 337

(D)isplay

Display the cache. Be sure that all the blocks you have brought in show up and be especially careful that ALL of the bytes are in the cache. (For example, when you read address 43H, that should cause addresses 40H through 4FH to be brought into the cache. Then when you read address 44H, you'll find it already in the cache.)

(W)rite
76) ( or 4CH )
153 ( or 99H )

Write the value 99 hex to address 4CH. Make sure that memory and the cache both reflect the new value. If the block is not in the cache, bring it in on writes as you would for a read, but make sure main memory and the cache both have the updated value.


HERE IS THE CODE. . . . . . . . . .

/* This assignment is a simulation of both a processor's cache and the hardware's main memory. The user enters a series of simulated addresses supplied by the test team. In *this* simulation, a 2-way set-associative cache representation, a user, after selecting an 'r' for a *READ*, enters a number in decimal, 2, 3 or 4 digits, and the program determines the tag number, the slot number and the block offset of this address, this "data". Subsequently, the program needs to determine if this data is contained in the cache. If "Yes", then a data *HIT* is said to have occured. If "No", then a data *MISS* has occured. If there is a data *MISS*, ALL of the data block *must* be brought into
the cache. At certain points of the execution of this program, a *DISPLAY* or a *WRITE* may be requested.

*/

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>             // A Borland header file for clrscr()

#define MAIN_MEM_ARRAY_SIZE 8192
#define CACHE_MEM_ARRAY_SIZE 512
#define DATA_SIZE 20
#define BLOCKS 32              // defined macros used in this program
#define BLOCK_SIZE 16
#define CHAR_VALUE 256


typedef struct {
      unsigned char slot_byte;
      unsigned char tag_byte;     // This is the structure
      int usage_freq;             // for the cache structs
      int data[DATA_SIZE];       // 'valid_byte'
      } my_cache;                 // 'tag_byte'                                 // 'usage_freq'                                           



my_cache cache[BLOCKS];    // cache[BLOCKS] is now an array                            //   of 'my_cache' structs


// FUNCTION DECLARATIONS

void Write_to_the_cache(my_cache the_cache[BLOCKS], my_cache current_cache[BLOCKS]
, int Index, int address, int offset, int Slot);

void Direct_cache_write(my_cache written_cache[BLOCKS]);
void Display_cache(my_cache display_cache_NOW[BLOCKS], int Index);
void Read_from_memory(my_cache a_cache[BLOCKS]);
static unsigned char Main_mem[MAIN_MEM_ARRAY_SIZE]; //initialization of 'simulated'
// main memory

void Miss( my_cache missed_the_cache[BLOCKS],
        unsigned char Main_memory[MAIN_MEM_ARRAY_SIZE], int address, int offset,
        int slot);

int main(void)  // It ALL BEGINS HERE.

{

int i = 0, j = 0; // for loop variables
int init_to_zero = 0; // used in for loop
int inc = 0;
char letter;




// Initialize here ......
// Each one-byte array element is assigned the modulo of // CHAR_VALUE,
// #define'd to be 256.

  for(i=0; i<MAIN_MEM_ARRAY_SIZE; i++)
      Main_mem[i]=i%CHAR_VALUE;


   // The following for loop construct is written to    // initialize the cache
  // used in this program, member element by member element,  // to zeros.

      for ( j = 0; j <= BLOCKS; j++ )  {
       cache[j].slot_byte = init_to_zero;
       cache[j].tag_byte = init_to_zero;
       cache[j].usage_freq = init_to_zero;
       cache[j].data[0] = init_to_zero;

 }

// do-while construct to loop continuously to allow the // "processor"
// to make as many read or write or display requests as it // needs.

      do {

 printf("Which operation do you choose to perform, (R)ead, (W)rite or(D)isplay?\n");
 printf("Or, 'q' to quit this program? ");

      letter = getchar();

      switch (letter)  {
            case 'r':
            case 'R':
                                          Read_from_memory(cache); break;

            case 'd':
            case 'D':      // set up to TRY to display 4                                // slots at a time
            for ( inc = 0; inc < BLOCKS; inc++) {
               if ( inc % 4 ==0 ) getchar();
                                                          Display_cache(cache, inc);
}
                                          break;

            case 'w':
            case 'W':
                                          Direct_cache_write(cache); break;


            case 'q':
            case 'Q':
             {
                                    printf("Program finished.");
exit(0);
                               }
            default:
                               {
            clrscr();
      continue;   // Why is this needed to keep looping?
                               }

            }  // end switch

  } while ( letter != ('q' || 'Q') );  // end while

return 0;

}



// The following function, Read_from_memory(a_cache), is // designed to
// get a simulated memory address from Main_mem[8192]. It // then needs  to manipulate the number in such a way as:
// address entered: 146
// where 1 is the valid_byte tag,
// 4 is the slot number for this particular address,
// and 6 is the block offset, the location where our data // begins.


void Read_from_memory(my_cache a_cache[BLOCKS])
{
   my_cache Current_cache[BLOCKS];
      int tag_number = 0, mem_address = 0, block_offset = 0, i = 0;
int slot_number, Address = 0, cache_index = 0;

// block to send to cache struct: 40, 41, 42, 43  .... 54, // 55 (decimal)
// populate temp cache with data


clrscr();
printf("What address in main memory would you like to read? ");
scanf("%d", &mem_address);

 tag_number = mem_address / 100;  // 1st number of address                                   // is tag number
       slot_number = ( mem_address/10 ) % 10;  
         // to obtain a slot number
       block_offset = mem_address % 10;    
         // to obtain block offset
       Address =  (mem_address % 100) - block_offset;  
         // address to be displayed

                                                                                     
// these 2 lines are how we start                                                                               
// the array -                                          
// i.e. address:146                                                                        
// tag_number:   1                                                                        
// slot_number:  4
                                          
// block offset: 6

// check to make sure we DON'T overwrite the cache!!

while ( Current_cache[cache_index].data != NULL )  cache_index++;

Current_cache[cache_index].slot_byte = slot_number;
Current_cache[cache_index].tag_byte = tag_number;
 // for loop to stuff the above values into a // my_cache[x].data[1] struct
   for ( i=0; i <= BLOCK_SIZE; i++ ) {
                        Current_cache[cache_index].data[i] =Address;
Address++;
 }

// Now write it to main cache.....

Write_to_the_cache( a_cache, Current_cache, cache_index, mem_address,block_offset, slot_number );

// Display_cache ( Current_cache, cache_index );

}

// The following function, Write_to_the_cache() as it's currently written, is
// primarily designed to be called from within the function, Read_from_memory().

// It needs to be expanded to handle a pure cache write // situation, whereby if a block in the defined cache is // needed for use, the data, checked to
// see if there IS data there, needs to be MOVED back out to // RAM ( main memory, A.K.A. Main_mem[8192].



void Write_to_the_cache(my_cache the_cache[BLOCKS], my_cache current_cache[BLOCKS]
, int Index, int address, int offset, int Slot)
{

int j = 0;
int replace_index = BLOCKS + 1;
int hit = 0;
clrscr();
getchar();

for ( j = 0; j < BLOCKS; j++ )
{

// already in memory, incrememt usage_freq
if ( the_cache[j].slot_byte == current_cache[Index].slot_byte &&
the_cache[j].tag_byte == current_cache[Index].tag_byte )
       {
      printf("We have a hit!\n");
      the_cache[j].usage_freq++;
      hit = 1;
       }
       else
 // Call the function Miss() to bring the entire block, //(i.e. if address 146 is entered for a read, bring in //entire block, as in: 40, 41, 42, .... 53, 54, 55) from //main memory into the cache.

 Miss( current_cache, Main_mem, address, offset, Slot);

// if the_cache[j] has NOT yet been populated, store this // index for later use

if ( the_cache[j].usage_freq == 0 )
       replace_index = j;

}  // end for loop

// if NOT found in mem, write current_cache to cache.
      if ( hit ==0 )
      if ( replace_index != BLOCKS + 1 )
                              the_cache[replace_index] = current_cache[j];

}


// The desired operation of this this function is to display // the cache
// at any given point of the program when called. Therefore, //when called after a user(processor request) enters a 'd' //upon being prompted at the beginning, Display_cache() //should display an initialized cache ( all zeros).
// As addresses are read (requested from the CPU) // Display_cache()
// should display that instance of the cache accordingly, in // hexadecimal format.

void Display_cache(my_cache display_cache_NOW[BLOCKS], int Index)
{

int i =0; // use in the for loop.

printf("TAG#  SLOT# \t DATA\n");
printf("%2d    %2d          ",  display_cache_NOW[Index].tag_byte,
display_cache_NOW[Index].slot_byte);

      for (i=0; i<BLOCK_SIZE; i++){
        printf("%2x ",display_cache_NOW[Index].data[i]);
      }
        Index++;

       printf("\n");
       printf("Press a key to continue. . . .\n");
       getchar();
}


// The following function, Direct_write_cache is to be // written to enable the user, in this case our 'processor' // to perform a write-back to the cache, which, supposedly // up to this point, has been initialized to all zeros and // has perhaps performed a few reads. Although as incomplete // as *most* of this code, eventually it needs to check each // instance in time of each cache block to see:
// 1) That the least-used block is referenced
// 2) Upon finding the least-used block, it must
//    determine if data exists there and move said data
//    BACK to main memory to insure NO DATA LOSS, CORRUPTION
//    or OVERWRITE OCCURS. Then and ONLY then can the     //    present desired data be placed there.



// Function Miss() has not been tested/implemented. Code // contained within the function. Write_to_the_cache() // should perform the desired goal.(SHOULD)
// The parameters passed are a cache, main memory, the  // address, the block offset and the slot number.

void Miss( my_cache missed_the_cache[BLOCKS],
        unsigned char Main_memory[MAIN_MEM_ARRAY_SIZE], int address, int offset, int slot)
{

      int i = 0, j = 0;  // for loop variables

      for ( i = address - offset, j = 0; i<(address -        offset) + BLOCK_SIZE, j<BLOCKS; ++i, ++j)
   missed_the_cache[slot].data[j] = Main_memory[i];


}


void Direct_cache_write(my_cache written_cache[BLOCKS])
{ // Incomplete

 // return an int ( maybe an_index ) to the call instead of // void? As in:
 // int Direct_cache_write(my_cache written_cache[BLOCKS])

  int tag_number = 0, mem_address = 0, block_offset = 0;
      int slot_number, Address = 0;
   int cache_index = 0, an_index=0;
   int testval = 0, val = written_cache[0].usage_freq;

printf("What address in the cache would you like to write to? ");
 scanf("%d", &mem_address);


tag_number = mem_address / 100;  // 1st number of address is // tag number
 slot_number = ( mem_address/10 ) % 10;    // to obtain a // slot number
 block_offset = mem_address % 10;    // to obtain block // offset
 Address =  (mem_address % 100) - block_offset;  // address // to be displayed


 // test *each* cache block's usage_freq member element and //  compare
 // testval to val using written_cache[cache_index].usage_freq.

 for( cache_index=1; (cache_index<BLOCKS)&&(val!=0); cache_index++) {

 // testval assigned the value contained in usage_freq each //  time through
 // and compared to val.

 if ((testval = written_cache[cache_index].usage_freq) < val )
 {
 an_index=cache_index;
 val=testval;
 }
  } // end: for loop

}  // end: Direct_cache_write()

*********************************************************
*********************************************************

JIM NOWLIN
0
Comment
Question by:jnowlin
  • 3
  • 3
7 Comments
 
LVL 15

Accepted Solution

by:
Tommy Hui earned 850 total points
ID: 1256968
Jim, I'm working on this for you. Wait until I post the program.
0
 
LVL 15

Expert Comment

by:Tommy Hui
ID: 1256969
What's your email account?

0
 
LVL 5

Expert Comment

by:julio011597
ID: 1256970
IMO, it is not any correct to lock a 800 points question just saying "wait, i'm working on it".

I already have the answer; what am i supposed to do??
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 
LVL 15

Expert Comment

by:Tommy Hui
ID: 1256971
#include <stdio.h>
#include <stdlib.h>

#define MAIN_MEM_ARRAY_SIZE 8192
char g_MainMemoryBuffer[MAIN_MEM_ARRAY_SIZE];

#define DATA_BLOCK_SIZE 16
typedef struct
{
      int m_Valid;
      int m_UsageCount;
      int m_Address;
      char m_Data[DATA_BLOCK_SIZE];
} CacheBlock;

int g_UseCache = 1;

#define CACHE_SIZE 16
CacheBlock g_Cache[CACHE_SIZE];

void InitializeCacheBlock(CacheBlock* cacheBlock)
{
      cacheBlock->m_Valid = 0;
      cacheBlock->m_UsageCount = 0;
      cacheBlock->m_Address = 0;

      for (int i = 0; i < DATA_BLOCK_SIZE; i++)
      {
            cacheBlock->m_Data[i] = 0;
      }
}

void InitializeCache(CacheBlock cache[])
{
      for (int i = 0; i < CACHE_SIZE; i++)
            InitializeCacheBlock(&cache[i]);
}

void InitializeMainMemory()
{
      for (int i = 0; i < MAIN_MEM_ARRAY_SIZE; i++)
            g_MainMemoryBuffer[i] = i & 0xFF;
}

void PutAddressIntoCache(CacheBlock cache[], int address, int* found, int* indexOfSlottedAddress)
{
      int slottedAddress = address & 0xFFF0;
      int indexOfLeastUsage = 0;
      int minUsage = 0xFFFF;

      *found = 0;
      *indexOfSlottedAddress = -1;

      for (int i = 0; i < CACHE_SIZE; i++)
      {
            if (!cache[i].m_Valid)
            {
                  indexOfLeastUsage = i;
                  break;
            }

            if (cache[i].m_UsageCount < minUsage)
            {
                  minUsage = cache[i].m_UsageCount;
                  indexOfLeastUsage = i;
            }

            if (cache[i].m_Address == slottedAddress)
            {
                  *found = 1;
                  cache[i].m_UsageCount++;
                  *indexOfSlottedAddress = i;
                  break;
            }
      }

      if (*found != 1)
      {
            cache[indexOfLeastUsage].m_Valid = 1;
            cache[indexOfLeastUsage].m_UsageCount = 1;
            cache[indexOfLeastUsage].m_Address = slottedAddress;
            *indexOfSlottedAddress = indexOfLeastUsage;

            for (int j = 0; j < DATA_BLOCK_SIZE; j++)
            {
                  cache[indexOfLeastUsage].m_Data[j] = g_MainMemoryBuffer[slottedAddress + j];
            }
      }
}

int ReadCache(CacheBlock cache[], int address, char* value)
{
      int found = 0;
      int indexOfSlottedAddress = -1;

      PutAddressIntoCache(cache, address, &found, &indexOfSlottedAddress);

      if (found)
      {
            printf("Found in cache\n");
      }
      else
      {
            printf("Not previously found in cache\n");
      }

      int offset = address & 0xF;

      *value = cache[indexOfSlottedAddress].m_Data[offset];

      return 1;
}

int ReadMemory(CacheBlock cache[], int address, char* value)
{
      if (address < 0 || MAIN_MEM_ARRAY_SIZE <= address)
      {
            return 0;
      }

      if (g_UseCache)
      {
            return ReadCache(cache, address, value);
      }
      else
      {
            *value = g_MainMemoryBuffer[address];
      }

      return 1;
}

int WriteCache(CacheBlock cache[], int address, char value)
{
      int found = 0;
      int indexOfSlottedAddress = -1;

      PutAddressIntoCache(cache, address, &found, &indexOfSlottedAddress);

      if (found)
      {
            printf("Found in cache\n");
      }
      else
      {
            printf("Not previously found in cache\n");
      }

      int offset = address & 0xF;

      cache[indexOfSlottedAddress].m_Data[offset] = value;
      g_MainMemoryBuffer[address] = value;

      return 1;
}

int WriteMemory(CacheBlock cache[], int address, char value)
{
      if (address < 0 || MAIN_MEM_ARRAY_SIZE <= address)
      {
            return 0;
      }

      if (g_UseCache)
      {
            return WriteCache(cache, address, value);
      }
      else
      {
            g_MainMemoryBuffer[address] = value;
      }

      return 1;
}

void DisplayCache(CacheBlock cache[])
{
      printf("Valid?\tCount\tAddress\tData\n");
      for (int i = 0; i < CACHE_SIZE; i++)
      {
            printf("%d\t%d\t0x%04X\t", cache[i].m_Valid,
                  cache[i].m_UsageCount, cache[i].m_Address);

            for (int j = 0; j < DATA_BLOCK_SIZE; j++)
            {
                  printf("%02X ", cache[i].m_Data[j] & 0xFF);
            }

            printf("\n");
      }
}


int DoLoop()
{
      printf("Which operation do you choose to perform, (R)ead, (W)rite or (D)isplay?\n");
      printf("Or, 'q' to quit this program? ");

      int ch = getchar();

      switch (ch)
      {
            case 'Q':
            case 'q':
            {
                  printf("Quiting...\n");
                  return 1;
            }

            case 'D':
            case 'd':
            {
                  printf("Displaying cache\n");
                  DisplayCache(g_Cache);
                  break;
            }

            case 'R':
            case 'r':
            {
                  printf("Read memory. ");
                  printf("What address would you like to read? ");
                  int address = 0;

                  if (scanf("%x", &address) == 1)
                  {
                        char value = 0;
                        int success = ReadMemory(g_Cache, address, &value);

                        if (success)
                        {
                              int v = value;
                              printf("Value is 0x%02x\n", v & 0xFF);
                        }
                        else
                        {
                              printf("Address 0x%x is out of bounds.\n", address);
                        }
                  }
                  else
                  {
                        printf("Invalid address entered\n");
                  }

                  break;
            }

            case 'W':
            case 'w':
            {
                  printf("Write memory\n");
                  printf("What address would you like to write? ");
                  int address = 0;

                  if (scanf("%x", &address) == 1)
                  {
                        printf("What value do you want to write? ");

                        int value = 0;
                        if (scanf("%x", &value) == 1)
                        {
                              char ch = value;

                              if (WriteMemory(g_Cache, address, ch))
                              {
                                    printf("Succeeded\n");
                              }
                              else
                              {
                                    printf("Write memory failed\n");
                              }
                        }
                        else
                        {
                              printf("Invalid value entered\n");
                        }
                  }
                  else
                  {
                        printf("Address 0x%x is out of bounds.\n", address);
                  }

                  break;
            }
      }

      while (getchar() != '\n')
            ;

      return 0;
}

int main(int argc, char* argv[])
{
      InitializeMainMemory();
      InitializeCache(g_Cache);

      int done = 0;

      while (!done)
      {
            done = DoLoop();
      }

      return 0;
}

0
 

Author Comment

by:jnowlin
ID: 1256972
Hello thui.

I'll give this a try. it looks good. My Email?
--> jnowlin@ma.ultranet.com

Jim
0
 

Author Comment

by:jnowlin
ID: 1256973
Hello thui.
It works very well. There's just a little fine-tuning left to do.

As I showed above.. . . . . . . .this is what I'm aiming for:

Which operation do you choose to perform, (R)ead, (W)rite or                           (D)isplay?
Or, 'q' to quit this program? Read memory. What address would you like to read? Not previously found in cache
Value is 0x2e
Which operation do you choose to perform, (R)ead, (W)rite or                           (D)isplay?
Or, 'q' to quit this program? Read memory. What address would you like to read? Found in cache
Value is 0x2f
Which operation do you choose to perform, (R)ead, (W)rite or                           (D)isplay?
Or, 'q' to quit this program? Read memory. What address would you like to read? Not previously found in cache
Value is 0x25
Which operation do you choose to perform, (R)ead, (W)rite or                           (D)isplay?
Or, 'q' to quit this program? Displaying cache
Valid?      Count      Address      Data
1      2      0x0020      20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
1      1      0x0220      20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
0      0      0x0000      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0      0x0000      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0      0x0000      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0      0x0000      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0      0x0000      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0      0x0000      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0      0x0000      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0      0x0000      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0      0x0000      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0      0x0000      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0      0x0000      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0      0x0000      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0      0x0000      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0      0x0000      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Which operation do you choose to perform, (R)ead, (W)rite or                           (D)isplay?
Or, 'q' to quit this program? Quiting...

It needs to have a Set number as well as a tag number, such that for 3 reads in succession: 2E, 2F and 225 should look as follows:

Set    Usage   Valid   Tag  Data
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
2      2       1       0    20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
2      1       1       2    20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0      0       0       0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

16 slots in this cache with 2 sets(blocks)per slot, for a total
of 32 blocks, from block numbers 0 through 16.

(I apologize; I wish Experts Exchange would allow better formats
on copying and pasting, as well as wrapping.)

I'll continue to work with it at my end.

Jim
0
 

Author Comment

by:jnowlin
ID: 1256974
Hello thui;

Sorry it took so long to get back to you. The program still needs
some tweeking but you did a superb job. Thanks ever so much!

Jim Nowlin

P.S. I have another project that needs your level of C expertise,
if you're interested.
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Have you thought about creating an iPhone application (app), but didn't even know where to get started? Here's how: ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Important pre-programming comments: I’ve never tri…
Summary: This tutorial covers some basics of pointer, pointer arithmetic and function pointer. What is a pointer: A pointer is a variable which holds an address. This address might be address of another variable/address of devices/address of fu…
The goal of this video is to provide viewers with basic examples to understand opening and reading files in the C programming language.
The goal of this video is to provide viewers with basic examples to understand how to create, access, and change arrays in the C programming language.

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now