source: trunk/IPs/systemC/hierarchy_memory/cache/cache_onelevel.h @ 78

Last change on this file since 78 was 78, checked in by rosiere, 16 years ago

Add :

  • Execute_loop (must be test systemC)
  • Prediction
    • Direction : predifined scheme
    • Branch Target Buffer
  • iFetch_unit
    • ifetch_queue
    • pc management
  • Decod_unit
    • coming soon : support for custom operation
  • Rename_unit
    • RAT
    • Free_list
    • Dependence RAW check
    • Load store unit pointer
  • New Environnement (hierarchy_memory will remove in a next version)


Modif :

  • Manage Custom Operation
  • All component in execute_loop to use the new statistics management

Not Finish :

  • Return Address Stack
  • Environnement
File size: 17.5 KB
Line 
1#ifndef CACHE_ONELEVEL_H
2#define CACHE_ONELEVEL_H
3
4#include <stdint.h>
5#include <math.h>
6#include <iostream>
7#include <iomanip>
8#include "../file/sort_file_dynamic.h"
9#include "type_req_cache.h"
10#include "tag.h"
11#include "address.h"
12#include "access_port.h"
13#include "write_buffer.h"
14
15namespace hierarchy_memory          {
16namespace cache                     {
17namespace cache_multilevel          {
18namespace cache_onelevel            {
19
20  class param_cache_t
21  {
22  public : const char *   name         ;
23  public : uint32_t nb_line      ;
24  public : uint32_t size_line    ;
25  public : uint32_t size_word    ;
26  public : uint32_t associativity;
27  public : uint32_t hit_latence  ;
28  public : uint32_t miss_penality;
29   
30  public : param_cache_t () {};
31
32  public : param_cache_t (const char   * name         ,
33                          uint32_t nb_line      ,
34                          uint32_t size_line    ,
35                          uint32_t size_word    ,
36                          uint32_t associativity,
37                          uint32_t hit_latence  ,
38                          uint32_t miss_penality
39                          ) :
40    name (name)
41    {
42      //this->name          = name         ;
43      this->nb_line       = nb_line      ;
44      this->size_line     = size_line    ;
45      this->size_word     = size_word    ;
46      this->associativity = associativity;
47      this->hit_latence   = hit_latence  ;
48      this->miss_penality = miss_penality;
49    }
50
51    friend ostream& operator<< (ostream& output_stream, const param_cache_t & x)
52    {
53      output_stream << "<" << x.name   << "> "
54                    << x.nb_line       << " "
55                    << x.size_line     << " "
56                    << x.size_word     << " "
57                    << x.associativity << " "
58                    << x.hit_latence   << " "
59                    << x.miss_penality;
60   
61      return output_stream;
62    }
63  };//end param_cache_t
64 
65  class param_t
66  {
67  public : uint32_t      nb_port    ;
68  public : param_cache_t param_cache;
69   
70  public : param_t (uint32_t      nb_port    ,
71                    param_cache_t param_cache)
72    {
73      this->nb_port     = nb_port      ;
74      this->param_cache = param_cache  ;
75    }
76
77    friend ostream& operator<< (ostream& output_stream, const param_t & x)
78    {
79      output_stream << x.nb_port << " " 
80                    << x.param_cache;
81      return output_stream;
82    }
83
84  };//end param_t
85
86  class Cache_OneLevel
87  {
88  protected : const uint32_t  nb_port       ;
89  protected : const uint32_t  nb_line       ;
90  protected : const uint32_t  size_line     ;
91  protected : const uint32_t  size_word     ;
92  protected : const uint32_t  associativity ;
93  protected : const uint32_t  hit_latence   ;
94  protected : const uint32_t  miss_penality ;
95   
96  private   : char          *  name;
97  private   : tag_t         ** tag;
98  private   : access_port_t *  access_port;
99  private   : address_t        size_address;
100  private   : Sort_File_Dynamic<write_buffer_t> * write_buffer;
101
102    //*****[ constructor ]*****
103  public : Cache_OneLevel (param_t param):
104      nb_port       (param.nb_port                  ),
105      nb_line       (param.param_cache.nb_line      ),
106      size_line     (param.param_cache.size_line    ),
107      size_word     (param.param_cache.size_word    ),
108      associativity (param.param_cache.associativity),
109      hit_latence   (param.param_cache.hit_latence  ),
110      miss_penality (param.param_cache.miss_penality)
111      {
112        uint32_t size_name = strlen(param.param_cache.name)+1;
113        name               = new char [size_name];
114        strncpy(name,param.param_cache.name,size_name);
115
116        if ((nb_line * size_line * associativity) == 0)
117          {
118            cerr << "<" << name << ".{Cache_OneLevel}> all parameter must be greater that 0" << endl;
119            cerr << " nb_line       : " << nb_line       << endl;
120            cerr << " size_line     : " << size_line     << endl;
121            cerr << " associativity : " << associativity << endl;
122            exit(1);
123          }
124        if ((nb_line % associativity) != 0)
125          {
126            cerr << "<" << name << ".{Cache_OneLevel}> nb_line must be a mutiple of associativity" << endl;
127            cerr << "  * nb_line       : " << nb_line       << endl;
128            cerr << "  * associativity : " << associativity << endl;
129            exit(1);
130          }
131
132        if ((double)nb_line    != ::pow(2,::log2(nb_line)))
133          {
134            cerr << "<" << name << ".{Cache_OneLevel}> nb_line must be a mutiple of 2^n" << endl;
135            cerr << "  * nb_line       : " << nb_line       << endl;
136            exit(1);
137          }
138
139        if ((double)size_line != ::pow(2,::log2(size_line)))
140          {
141            cerr << "<" << name << ".{Cache_OneLevel}> size_line must be a mutiple of 2^n" << endl;
142            cerr << "  * size_line     : " << size_line     << endl;
143            exit(1);
144          }
145
146        if ((double)size_word != ::pow(2,::log2(size_word)))
147          {
148            cerr << "<" << name << ".{Cache_OneLevel}> size_word must be a mutiple of 2^n" << endl;
149            cerr << "  * size_word     : " << size_word     << endl;
150            exit(1);
151          }
152       
153        write_buffer= new Sort_File_Dynamic<write_buffer_t> (sort_file::param_t("write_buffer",5));
154        access_port = new access_port_t [nb_port];
155        tag         = new tag_t *       [nb_line/associativity];
156        for (uint32_t it = 0; it < nb_line/associativity; it ++)
157          tag [it] = new tag_t [associativity];
158
159        size_address.offset  = (uint32_t) log2(size_line * size_word);
160        size_address.familly = (uint32_t) log2(nb_line/associativity);
161        size_address.tag     = 32 - size_address.familly - size_address.offset;
162     }
163     
164      //*****[ destructor ]*****
165    public : ~Cache_OneLevel ()
166      {
167//      delete tag;
168//      delete access_port;
169      };
170
171      //*****[ reset ]*****
172    public : void reset ()
173      {
174        for (uint32_t x = 0; x < nb_port; x ++)
175          access_port[x].valid = false;
176
177        for (uint32_t x = 0; x < nb_line/associativity; x ++)
178          for (uint32_t y = 0; y < associativity; y ++)
179            {
180              tag[x][y].valid      = false;
181              tag[x][y].index_lru  = y;
182            }
183        write_buffer->reset();
184      }
185
186      //*****[ transition ]*****
187    public : void transition ()
188    {
189        // scan all port - test if have a transaction
190        for (int32_t x = nb_port-1; x >= 0; x --)
191          {
192            if (access_port[x].valid == true)
193              {
194                access_port[x].valid = false;
195               
196                // Update LRU
197                //  * hit  : now
198                //  * miss : after the return of next cache
199               
200                if (access_port[x].hit == HIT_CACHE)
201                  {// Hit
202                    update_lru(access_port[x].address.familly,access_port[x].num_associativity);
203                  }
204
205                if (access_port[x].hit == MISS)
206                  {// Miss
207                    // Write in write_buffer
208                    write_buffer->push(access_port[x].latence,write_buffer_t(access_port[x].address,access_port[x].trdid));
209                  }
210              }
211          }
212       
213        // Test if a write_buffer have the result
214        while ((write_buffer->empty() == false) && (write_buffer->read(0).delay == 0))
215          {
216            // Save in the cache
217            write_buffer_t val         = write_buffer->pop();
218           
219            uint32_t num_tag           = val.address.tag;
220            uint32_t num_familly       = val.address.familly;
221            uint32_t num_associativity = index_victim(num_familly);
222           
223            tag [num_familly][num_associativity].valid    = true;
224            tag [num_familly][num_associativity].address  = num_tag;
225            tag [num_familly][num_associativity].trdid    = val.trdid;
226           
227            update_lru(num_familly,num_associativity);
228          }
229
230        write_buffer->transition();
231      }
232      //*****[ update_lru ]*****
233    private : void update_lru (uint32_t familly, uint32_t num_associativity)
234      {
235        uint32_t current_lru = tag [familly][num_associativity].index_lru;
236       
237        for (uint32_t k = 0; k < associativity; k ++)
238          if (tag [familly][k].index_lru < current_lru)
239            tag [familly][k].index_lru ++;
240        tag [familly][num_associativity].index_lru = 0;
241      }
242     
243    //*****[ index_victim ]*****
244    // return the index of the nex victim
245  public : uint32_t index_victim (uint32_t familly)
246    {
247      uint32_t victim = 0;
248      while (tag [familly][victim].index_lru != (associativity-1))
249        {
250          victim ++;
251        }
252
253      return victim;
254    }
255
256      //*****[ translate_address ]*****
257    private : address_t translate_address (uint32_t address)
258      {
259        address_t address_translated;
260        uint32_t  shift;
261
262        address_translated.offset  = (address & ((uint32_t)-1 >> (32-(size_address.offset          ))));
263        address                   -= address_translated.offset;
264        shift                      = size_address.offset;
265        address_translated.familly = (address & ((uint32_t)-1 >> (32-(size_address.familly + shift))))>>shift;
266        address                   -= address_translated.familly;
267        shift                     += size_address.familly;
268        address_translated.tag     = (address & ((uint32_t)-1 >> (32-(size_address.tag     + shift))))>>shift;
269
270        return address_translated;
271      }
272
273    //********************
274    //********************
275
276    //*****[ access ]*****
277    // Return hit (true)
278      // uncache is to stocke the address on the cache
279  public : type_rsp_cache_t access (uint32_t nb_port, uint32_t address, uint32_t trdid, type_req_cache_t type, direction_req_cache_t dir)
280    {
281      switch (type)
282        {
283        case UNCACHED   : return access_uncached   (nb_port,address,trdid    ); break;
284        case INVALIDATE : return access_invalidate (nb_port,address,trdid    ); break;
285        case FLUSH      : return access_flush      (nb_port,address,trdid    ); break;
286        case PREFETCH   : // no difference with the simple read cached (have no add a prefetch cache)
287        case CACHED     : return access_cached     (nb_port,address,trdid,dir); break;
288        default         : cout << "<Cache_Onelevel.access> unkonow type : " << endl; exit(1); break;
289        }
290    }
291
292    // *****[ access_cached ]*****
293  public : type_rsp_cache_t access_cached (uint32_t nb_port, uint32_t address, uint32_t trdid, direction_req_cache_t dir)
294    {
295        address_t        address_translate  = translate_address(address);
296        uint32_t         num_associativity  = hit_cache        (trdid, address_translate);
297        uint32_t         num_port           = hit_access_port  (trdid, address_translate);
298        uint32_t         num_write_buffer   = hit_write_buffer (trdid, address_translate);
299               
300        if (num_port == this->nb_port)
301          num_port = nb_port;
302
303        uint32_t         latence            ;
304        type_rsp_cache_t res                = MISS;
305
306        bool             is_in_cache        = (num_associativity != associativity);
307        bool             is_in_access_port  = (num_port != nb_port);
308        bool             is_in_write_buffer = false;
309
310        if (is_in_access_port == true)
311          {
312            res     = HIT_BYPASS;
313            latence = access_port[num_port].latence; //already compute
314          }
315        else
316          if (is_in_cache == true)
317            {   
318              res     = HIT_CACHE;
319              latence = 0; // Hit !!!
320            }
321          else
322            {
323              // Search in the write buffer, and test if have a miss
324              if ( num_write_buffer == write_buffer->nb_slot_use())
325                  {
326                    res     = MISS;
327                    latence = miss_penality; // miss -> access at down of cache,  + respons at the up of cache
328                  }
329              else
330                {
331                  res                = HIT_WRITE_BUFFER;
332                  is_in_write_buffer = true;
333                  latence            = write_buffer->read(num_write_buffer).delay;
334                }
335            }
336
337        // access_port valid = there are a new request to update
338        //  -> no previous request in the same     cycle (hit in a access port)
339        //  -> no previous request in the previous cycle (hit in the write buffer)
340       
341        access_port[nb_port].valid             = ((is_in_access_port || is_in_write_buffer) == false);
342        access_port[nb_port].address           = address_translate;
343        access_port[nb_port].trdid             = trdid;
344        access_port[nb_port].hit               = res;
345        access_port[nb_port].num_associativity = num_associativity;
346        access_port[nb_port].latence           = latence;
347
348        return res;
349    }
350
351    // *****[ access_uncached ]*****
352  public : type_rsp_cache_t access_uncached (uint32_t nb_port, uint32_t address, uint32_t trdid)
353    {
354      access_port[nb_port].valid             = false;
355      access_port[nb_port].trdid             = trdid;
356      access_port[nb_port].hit               = MISS;
357      access_port[nb_port].latence           = miss_penality;
358     
359      return MISS;
360    }
361    // *****[ access_invalidate ]*****
362  public : type_rsp_cache_t access_invalidate (uint32_t nb_port, uint32_t address, uint32_t trdid)
363    {
364      cerr << "<" << name << ".{Cache_OneLevel}.access_invalidate> Not implemented" << endl;
365      exit (0);
366      return MISS;
367    }
368
369    // *****[ access_flush ]*****
370  public : type_rsp_cache_t access_flush (uint32_t nb_port, uint32_t address, uint32_t trdid)
371    {
372      cerr << "<" << name << ".{Cache_OneLevel}.access_flush> Not implemented" << endl;
373      exit (0);
374      return MISS;
375    }
376
377    //******************************
378    //******************************
379
380    //*****[ hit_write_buffer ]*****
381
382    // If a instruction is in the write_buffer, return the position
383    // else, return the number of elt in the write_buffer
384  public : uint32_t hit_write_buffer (uint32_t trdid, address_t address)
385    {
386        uint32_t num_write_buffer = 0;
387        // Scan the write_buffer
388        for (num_write_buffer = 0; num_write_buffer < write_buffer->nb_slot_use(); num_write_buffer ++)
389          {
390            slot_t<write_buffer_t> val = write_buffer->read(num_write_buffer);
391
392            if ( (val.data.trdid           == trdid          ) &&
393                 (val.data.address.tag     == address.tag    ) &&
394                 (val.data.address.familly == address.familly))
395              break;
396          }
397       
398        return num_write_buffer;
399    }
400
401    //*****[ hit_access_port ]*****
402    // return the number of associativity if hit
403    // return nb_accosiativity if miss
404  public : uint32_t hit_cache (uint32_t trdid, address_t address)
405      {
406        uint32_t num_associativity;
407        for (num_associativity = 0; num_associativity < associativity; num_associativity ++)
408          // Hit if :
409          //  * in the line
410          //  * in a way associative
411          //  -> there are the same tag
412          //               the same trdid
413          //               is valid
414          if ( (tag [address.familly][num_associativity].address == address.tag) && 
415               (tag [address.familly][num_associativity].valid   == true       ) &&
416               (tag [address.familly][num_associativity].trdid   == trdid      ) )
417              break;
418
419        return num_associativity;
420      }
421
422    //*****[ hit_access_port ]*****
423    // Return the number of port if hit
424    // Return nb_port if miss
425  public : uint32_t hit_access_port (uint32_t trdid, address_t address)
426      {
427        uint32_t it_num_port = 0;
428
429        // scan all port - test if have a transaction
430        for (it_num_port = 0; it_num_port < nb_port; it_num_port ++)
431          if ( (access_port[it_num_port].valid           == true           ) &&
432               (access_port[it_num_port].trdid           == trdid          ) &&
433               (access_port[it_num_port].address.tag     == address.tag    ) &&
434               (access_port[it_num_port].address.familly == address.familly))
435            break;
436
437        return it_num_port;
438      }
439
440      //*****[ need_slot ]*****
441    public : uint32_t need_slot ()
442      {
443        uint32_t res = 0;
444        // scan all port - test if have a transaction
445        for (uint32_t x = 0; x < nb_port; x ++)
446          if (access_port[x].valid == true)
447            res ++;
448
449        return res;
450      }
451
452      //*****[ latence ]*****
453      // Return the time to have the data
454      // uncache is to stocke the address on the cache
455    public : uint32_t latence (uint32_t num_port)
456      {
457        uint32_t res = hit_latence + access_port[num_port].latence;
458
459        return res;
460      }
461
462      //*****[ update_latence ]*****
463      // Return the time to have the data
464      // uncache is to stocke the address on the cache
465  public : bool update_latence (uint32_t nb_port, uint32_t latence)
466      {
467        access_port[nb_port].latence = latence-hit_latence;
468        return access_port[nb_port].valid;
469      }
470
471    //*****[ information ]*****
472  public : void information (void)
473    {
474      cout << "<" << name << ">"                                                      << endl
475           << "  * Information"                                                       << endl
476           << "  * Capacity        : " << nb_line * size_line * size_word << " bytes" << endl
477           << "    * Nb line       : " << nb_line                                     << endl
478           << "    * Size line     : " << size_line                                   << endl
479           << "    * Size word     : " << size_word                                   << endl
480           << "    * Associativity : " << associativity                               << endl
481           << "  * Timing          : "                                                << endl
482           << "    * Hit  latence  : " << hit_latence                                 << endl
483           << "    * Miss penality : " << miss_penality                               << endl
484           << "    * Nb port       : " << nb_port                                     << endl
485           << endl;
486    }
487   
488      friend ostream& operator<< (ostream& output_stream, const Cache_OneLevel & x)
489      {
490        output_stream << "<" << x.name << ">"                                                          << endl
491                      << "  * Capacity        : " << x.nb_line * x.size_line * x.size_word << " bytes" << endl
492                      << "    * Nb line       : " << x.nb_line                                         << endl
493                      << "    * Size line     : " << x.size_line                                       << endl
494                      << "    * Size word     : " << x.size_word                                       << endl
495                      << "    * Associativity : " << x.associativity                                   << endl
496                      << "  * Timing          : "                                                      << endl
497                      << "    * Hit  latence  : " << x.hit_latence                                     << endl
498                      << "    * Miss penality : " << x.miss_penality                                   << endl
499                      << "    * Nb port       : " << x.nb_port                                         << endl
500                      << endl;
501
502        output_stream << "  * Tag"                                                                     << endl;
503        for (uint32_t i = 0; i < x.nb_line / x.associativity; i ++)
504          {
505            for (uint32_t j = 0; j < x.associativity; j ++)
506                output_stream << x.tag [i][j] << " | ";
507            output_stream << endl;
508          }
509       
510        output_stream << endl;
511        output_stream << *x.write_buffer << endl;
512
513        return output_stream;
514      }
515
516  };
517};};};};
518#endif //!CACHE_ONELEVEL_H
519
Note: See TracBrowser for help on using the repository browser.