source: trunk/lib/generic_cache_tsar/include/generic_cache.h @ 778

Last change on this file since 778 was 534, checked in by bouyer, 11 years ago

Add an assert that *dt_next is always initialised if entry is found.

File size: 36.2 KB
Line 
1/* -*- c++ -*-
2 *
3 * SOCLIB_LGPL_HEADER_BEGIN
4 *
5 * This file is part of SoCLib, GNU LGPLv2.1.
6 *
7 * SoCLib is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; version 2.1 of the License.
10 *
11 * SoCLib is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with SoCLib; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301 USA
20 *
21 * SOCLIB_LGPL_HEADER_END
22 *
23 * Copyright (c) UPMC, Lip6
24 *         Alain Greiner <alain.greiner@lip6.fr> July 2008
25 *
26 * Maintainers: alain
27 */
28
29////////////////////////////////////////////////////////////////////////////////
30// File         : generic_cache.h
31// Date         : 07/01/2012
32// Authors      : Alain Greiner
33/////////////////////////////////////////////////////////////////////////////////
34// This object is a generic, set associative, cache.
35// Each slot can be in three states: VALID, EMPTY or ZOMBI.
36// The ZOMBI state is used by cache coherence protocols to indicate
37// a pending cleanup request.
38// Hit if ( (matching tag) and (state == VALID).
39// The replacement policy is pseudo-LRU. The victim selection process cannot
40// fail if the ZOMBI state is not used.
41// But it can fail if all ways are in ZOMBI state.
42/////////////////////////////////////////////////////////////////////////////////
43// Implementation note
44// The DATA part is implemented as an uint32_t array[nways*nsets*nwords].
45// The DIRECTORY part is implemented as an uint32_t array[nways*nsets].
46// All methods requiring a dual port RAM or cache modification using
47// an associative search have been deprecated.
48/////////////////////////////////////////////////////////////////////////////////
49// Constructor parameters are :
50// - std::string    &name
51// - size_t         nways   : number of associativity levels
52// - size_t         nsets   : number of sets
53// - size_t         nwords  : number of words in a cache line
54// The nways, nsets, nwords parameters must be power of 2
55// The nsets parameter cannot be larger than 1024
56// The nways parameter cannot be larger than 16
57// The nwords parameter cannot be larger than 64
58/////////////////////////////////////////////////////////////////////////////////
59// Template parameter is :
60// - addr_t : address format to access the cache
61/////////////////////////////////////////////////////////////////////////////////
62
63#ifndef SOCLIB_GENERIC_CACHE_H
64#define SOCLIB_GENERIC_CACHE_H
65
66#include <systemc>
67#include <cassert>
68#include "arithmetics.h"
69#include "static_assert.h"
70#include "mapping_table.h"
71#include <cstring>
72
73namespace soclib { 
74
75enum cache_slot_state_e
76{
77    CACHE_SLOT_STATE_EMPTY,
78    CACHE_SLOT_STATE_VALID,
79    CACHE_SLOT_STATE_ZOMBI,
80};
81
82//////////////////////////
83template<typename addr_t>
84class GenericCache
85//////////////////////////
86{
87    typedef uint32_t    data_t;
88    typedef uint32_t    be_t;
89
90    data_t              *r_data ;
91    addr_t               *r_tag ;
92    int                 *r_state;
93    bool                *r_lru ;
94
95    size_t              m_ways; 
96    size_t              m_sets; 
97    size_t              m_words;
98
99    const soclib::common::AddressMaskingTable<addr_t>  m_x ;
100    const soclib::common::AddressMaskingTable<addr_t>  m_y ;
101    const soclib::common::AddressMaskingTable<addr_t>  m_z ;
102
103    //////////////////////////////////////////////////////////////
104    inline data_t &cache_data(size_t way, size_t set, size_t word)
105    {
106        return r_data[(way*m_sets*m_words)+(set*m_words)+word];
107    }
108
109    //////////////////////////////////////////////
110    inline addr_t &cache_tag(size_t way, size_t set)
111    {
112        return r_tag[(way*m_sets)+set];
113    }
114
115    //////////////////////////////////////////////
116    inline bool &cache_lru(size_t way, size_t set)
117    {
118        return r_lru[(way*m_sets)+set];
119    }
120
121    //////////////////////////////////////////////
122    inline int &cache_state(size_t way, size_t set)
123    {
124        return r_state[(way*m_sets)+set];
125    }
126
127    /////////////////////////////////////////////////
128    inline void cache_set_lru(size_t way, size_t set)
129    {
130            size_t way2;
131
132        cache_lru(way, set) = true;
133
134            for (way2 = 0; way2 < m_ways; way2++ ) 
135        {
136                if (cache_lru(way2, set) == false) return;
137            }
138            // all lines are new -> they all become old
139            for (way2 = 0; way2 < m_ways; way2++ ) 
140        {
141                cache_lru(way2, set) = false;
142            }
143    }
144
145    ////////////////////////////////
146    inline data_t be2mask( be_t be )
147    {
148        data_t mask = 0;
149        if ( (be & 0x1) == 0x1 ) mask = mask | 0x000000FF;
150        if ( (be & 0x2) == 0x2 ) mask = mask | 0x0000FF00;
151        if ( (be & 0x4) == 0x4 ) mask = mask | 0x00FF0000;
152        if ( (be & 0x8) == 0x8 ) mask = mask | 0xFF000000;
153        return mask;
154    }
155
156public:
157
158    //////////////////////////////////////////
159    GenericCache(   const std::string   &name,
160                    size_t              nways, 
161                    size_t              nsets, 
162                    size_t              nwords)
163        : m_ways(nways),
164          m_sets(nsets),
165          m_words(nwords),
166
167#define l2 soclib::common::uint32_log2
168
169          m_x( l2(nwords), l2(sizeof(data_t))),
170          m_y( l2(nsets), l2(nwords) + l2(sizeof(data_t))),
171          m_z( 8*sizeof(addr_t) - l2(nsets) - l2(nwords) - l2(sizeof(data_t)),
172               l2(nsets) + l2(nwords) + l2(sizeof(data_t)))
173#undef l2
174    {
175        assert(IS_POW_OF_2(nways));
176        assert(IS_POW_OF_2(nsets));
177        assert(IS_POW_OF_2(nwords));
178        assert(nwords);
179        assert(nsets);
180        assert(nways);
181        assert(nwords <= 64);
182        assert(nsets <= 1024);
183        assert(nways <= 16);
184
185#ifdef GENERIC_CACHE_DEBUG
186std::cout << "constructing " << name << std::endl
187          << "- nways  = " << nways << std::endl
188          << "- nsets  = " << nsets << std::endl
189          << "- nwords = " << nwords << std::endl
190          << " m_x: " << m_x
191          << " m_y: " << m_y
192          << " m_z: " << m_z
193          << std::endl;
194#endif
195
196        r_data    = new data_t[nways*nsets*nwords];
197        r_tag     = new addr_t[nways*nsets];
198        r_state   = new int[nways*nsets];
199        r_lru     = new bool[nways*nsets];
200    }
201
202    ////////////////
203    ~GenericCache()
204    {
205        delete [] r_data;
206        delete [] r_tag;
207        delete [] r_state;
208        delete [] r_lru;
209    }
210
211    ////////////////////
212    inline void reset( )
213    {
214        std::memset(r_data, 0, sizeof(*r_data)*m_ways*m_sets*m_words);
215        std::memset(r_tag, 0, sizeof(*r_tag)*m_ways*m_sets);
216        std::memset(r_state, CACHE_SLOT_STATE_EMPTY, sizeof(*r_state)*m_ways*m_sets);
217        std::memset(r_lru, 0, sizeof(*r_lru)*m_ways*m_sets);
218    }
219
220    /////////////////////////////////////////////////////////////////////
221    // Read a single 32 bits word.
222    // returns true if (matching tag) and (state == VALID)
223    // Both data & directory are accessed.
224    /////////////////////////////////////////////////////////////////////
225    inline bool read( addr_t    ad, 
226                      data_t*   dt)
227    {
228        const addr_t      tag  = m_z[ad];
229        const size_t      set  = m_y[ad];
230        const size_t      word = m_x[ad];
231
232        for ( size_t way = 0; way < m_ways; way++ ) 
233        {
234            if ( (tag == cache_tag(way, set)) 
235                   && (cache_state(way, set) == CACHE_SLOT_STATE_VALID) )
236            {
237                *dt = cache_data(way, set, word);
238                cache_set_lru(way, set);
239                return true;
240            }
241        }
242        return false;
243    }
244
245    ////////////////////////////////////////////////////////////////////
246    // Read a single 32 bits word.
247    // returns true if (matching tag) and (state == VALID)
248    // Both data & directory are accessed.
249    // The selected way, set and word index are returned in case of hit.
250    /////////////////////////////////////////////////////////////////////
251    inline bool read( addr_t    ad, 
252                      data_t*   dt,
253                      size_t*   selway,
254                      size_t*   selset,
255                      size_t*   selword) 
256    {
257        const addr_t      tag  = m_z[ad];
258        const size_t      set  = m_y[ad];
259        const size_t      word = m_x[ad];
260
261        for ( size_t way = 0; way < m_ways; way++ ) 
262        {
263            if ( (tag == cache_tag(way, set)) and
264                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID) )
265            {
266                *selway  = way;
267                *selset  = set;
268                *selword = word;
269                *dt = cache_data(way, set, word);
270                cache_set_lru(way, set);
271                return true;
272            }
273        }
274        return false;
275    }
276
277    ////////////////////////////////////////////////////////////////////
278    // Read a single 32 bits word when the ZOMBI state is used.
279    // Both data and directory are accessed.
280    // returns the access status in the state argument:
281    // - VALID : (matching tag) and (state == VALID)
282    // - ZOMBI : (matching tag) and (state == ZOMBI)
283    // - MISS  : no matching tag or EMPTY state
284    // If VALID or ZOMBI, the data, the way, set and word index are
285    // returned in the other arguments.
286    ////////////////////////////////////////////////////////////////////
287    inline void read( addr_t    ad,
288                      data_t*   dt,
289                      size_t*   selway,
290                      size_t*   selset,
291                      size_t*   selword,
292                      int*      state ) 
293    {
294        const addr_t      tag  = m_z[ad];
295        const size_t      set  = m_y[ad];
296        const size_t      word = m_x[ad];
297
298        // default return values
299        *state   = CACHE_SLOT_STATE_EMPTY;
300        *selway  = 0;
301        *selset  = 0;
302        *selword = 0;
303        *dt      = 0;
304
305        for ( size_t way = 0; way < m_ways; way++ ) 
306        {
307            if ( tag == cache_tag(way, set) )  // matching tag
308            {
309
310                if ( cache_state(way, set) == CACHE_SLOT_STATE_VALID )
311                {
312                    *state   = CACHE_SLOT_STATE_VALID;
313                    *selway  = way;
314                    *selset  = set;
315                    *selword = word;
316                    *dt      = cache_data(way, set, word);
317                    cache_set_lru(way, set);
318                }
319                else if ( cache_state(way, set) == CACHE_SLOT_STATE_ZOMBI )
320                {
321                    *state   = CACHE_SLOT_STATE_ZOMBI;
322                    *selway  = way;
323                    *selset  = set;
324                    *selword = word;
325                }
326            }
327        }
328    }
329             
330    ////////////////////////////////////////////////////////////////////
331    // Read a single 32 bits word, without LRU update.
332    // returns true if (matching tag) and (state == VALID)
333    // Both data & directory are accessed.
334    // The selected way, set and word index are returned in case of hit.
335    /////////////////////////////////////////////////////////////////////
336    inline bool read_neutral( addr_t    ad, 
337                                      data_t*   dt,
338                                          size_t*   selway,
339                                          size_t*   selset,
340                                          size_t*   selword) 
341    {
342        const addr_t      tag  = m_z[ad];
343        const size_t      set  = m_y[ad];
344        const size_t      word = m_x[ad];
345
346        for ( size_t way = 0; way < m_ways; way++ ) 
347        {
348            if ( (tag == cache_tag(way, set)) 
349                   && (cache_state(way, set) == CACHE_SLOT_STATE_VALID) )
350            {
351                *selway  = way;
352                *selset  = set;
353                *selword = word;
354                *dt = cache_data(way, set, word);
355                return true;
356            }
357        }
358        return false;
359    }
360
361    /////////////////////////////////////////////////////////////////////////////
362    // Read one or two 32 bits word.
363    // Both data & directory are accessed.
364    // Hit if (matching tag) and (valid == true) and (zombi == false)
365    // If the addressed word is not the last in the cache line,
366    // two successive words are returned.
367    // The selected way, set and first word index are returned in case of hit.
368    // This function is used by the cc_vcache to get a 64 bits page table entry.
369    /////////////////////////////////////////////////////////////////////////////
370    inline bool read( addr_t    ad, 
371                      data_t*   dt, 
372                      data_t*   dt_next,
373                      size_t*   selway,
374                      size_t*   selset,
375                      size_t*   selword)
376    {
377        const addr_t      tag  = m_z[ad];
378        const size_t      set  = m_y[ad];
379        const size_t      word = m_x[ad];
380
381        for ( size_t way = 0; way < m_ways; way++ ) 
382        {
383            if ( (tag == cache_tag(way, set))   
384                   && (cache_state(way, set) == CACHE_SLOT_STATE_VALID) ) 
385            {
386                *dt      = cache_data(way, set, word);
387                if ( word+1 < m_words) 
388                {
389                    *dt_next = cache_data(way, set, word+1);
390                }
391                *selway  = way;
392                *selset  = set;
393                *selword = word;
394                cache_set_lru(way, set);
395                return true;
396            }
397        }
398        return false;
399    }
400
401    ////////////////////////////////////////////////////////////////////
402    // Read one or two 32 bits word.
403    // Both data and directory are accessed.
404    // returns the access status in the state argument:
405    // - VALID : (matching tag) and (state == VALID)
406    // - ZOMBI : (matching tag) and (state == ZOMBI)
407    // - MISS  : no matching tag or EMPTY state
408    // If VALID or ZOMBI, the data, the way, set and word index are
409    // returned in the other arguments.
410    ////////////////////////////////////////////////////////////////////
411    inline void read( addr_t    ad,
412                      data_t*   dt,
413                      data_t*   dt_next,
414                      size_t*   selway,
415                      size_t*   selset,
416                      size_t*   selword,
417                      int*      state ) 
418    {
419        const addr_t      tag  = m_z[ad];
420        const size_t      set  = m_y[ad];
421        const size_t      word = m_x[ad];
422
423        // default return values
424        *state   = CACHE_SLOT_STATE_EMPTY;
425        *selway  = 0;
426        *selset  = 0;
427        *selword = 0;
428        *dt      = 0;
429
430        for ( size_t way = 0; way < m_ways; way++ ) 
431        {
432            if ( tag == cache_tag(way, set) )  // matching tag
433            {
434
435                if ( cache_state(way, set) == CACHE_SLOT_STATE_VALID )
436                {
437                    *state   = CACHE_SLOT_STATE_VALID;
438                    *selway  = way;
439                    *selset  = set;
440                    *selword = word;
441                    *dt      = cache_data(way, set, word);
442                    if ( word+1 < m_words) 
443                    {
444                        *dt_next = cache_data(way, set, word+1);
445                    } else {
446                        assert(false && "can't request 2 words at end of line");
447                    }
448                    cache_set_lru(way, set);
449                }
450                else if ( cache_state(way, set) == CACHE_SLOT_STATE_ZOMBI )
451                {
452                    *state   = CACHE_SLOT_STATE_ZOMBI;
453                    *selway  = way;
454                    *selset  = set;
455                    *selword = word;
456                }
457            }
458        }
459    }
460
461    ///////////////////////////////////////////////////////////////////////////////
462    // Checks the cache state for a given address.
463    // Only the directory is accessed.
464    // returns true if (matching tag) and (state == VALID)
465    // The selected way, set and first word index are returned in case of hit.
466    // This function can be used when we need to access the directory
467    // while we write in the data part with a different address in the same cycle.
468    ///////////////////////////////////////////////////////////////////////////////
469    inline bool hit(  addr_t    ad, 
470                      size_t*   selway,
471                      size_t*   selset,
472                      size_t*   selword)
473    {
474        const addr_t      tag  = m_z[ad];
475        const size_t      set  = m_y[ad];
476        const size_t      word = m_x[ad];
477
478        for ( size_t way = 0; way < m_ways; way++ ) 
479        {
480            if ( (tag == cache_tag(way, set)) 
481                   && (cache_state(way, set) == CACHE_SLOT_STATE_VALID) ) 
482            {
483                *selway  = way;
484                *selset  = set;
485                *selword = word;
486                cache_set_lru(way, set);
487                return true;
488            }
489        }
490        return false;
491    }
492 
493    ///////////////////////////////////////////////////////////////////////////////
494    // Checks the cache state for a given address, when the ZOMBI state is used.
495    // Only the directory is accessed.
496    // Returns the access status in the state argument:
497    // - VALID if (matching tag) and (state == VALID)
498    // - ZOMBI if (matching tag) and (state == ZOMBI)
499    // - EMPTY if no match or (state == EMPTY)
500    // The selected way, set and first word index are returned if not empty.
501    // This function can be used when we need to access the directory
502    // while we write in the data part with a different address in the same cycle.
503    ///////////////////////////////////////////////////////////////////////////////
504    inline void read_dir(  addr_t       ad, 
505                           int*     state,
506                           size_t*      way,
507                           size_t*      set,
508                           size_t*  word)
509    {
510        const addr_t      ad_tag  = m_z[ad];
511        const size_t      ad_set  = m_y[ad];
512        const size_t      ad_word = m_x[ad];
513
514        for ( size_t _way = 0; _way < m_ways; _way++ ) 
515        {
516            if ( (ad_tag == cache_tag(_way, ad_set) ) and
517                 (cache_state(_way, ad_set) != CACHE_SLOT_STATE_EMPTY) ) 
518            {
519                *state = cache_state(_way, ad_set);
520                *way   = _way;
521                *set   = ad_set;
522                *word  = ad_word;
523                return;
524            }
525        }
526       
527        // return value if not (VALID or ZOMBI)
528        *state = CACHE_SLOT_STATE_EMPTY;
529    }
530
531    ///////////////////////////////////////////////////////////////////////////////
532    // Checks the cache state for a slot (set,way), when the ZOMBI state is used.
533    // Only the directory is accessed.
534    // Returns the access status and the tag value in the state and tag argument.
535    ///////////////////////////////////////////////////////////////////////////////
536    inline void read_dir(  size_t       way,
537                           size_t       set,
538                           addr_t*   tag,
539                           int*     state )
540    {
541        *state = cache_state(way, set);
542        *tag   = cache_tag(way, set);
543    }
544
545    ////////////////////////////////////////////
546    inline addr_t get_tag(size_t way, size_t set)
547    {
548        return cache_tag(way, set);
549    }
550
551    ///////////////////////////////////////////////////////////////////
552    // This function writes a complete 32 bits word
553    // It does not use the directory and cannot miss.
554    //////////////////////////////////////////////////////////////////
555    inline void write(size_t    way, 
556                      size_t    set, 
557                      size_t    word, 
558                      data_t    data)
559    {
560        cache_data(way, set, word) = data;
561        cache_set_lru(way, set);
562    }
563
564    ////////////////////////////////////////////////////////////////////////////
565    // this function writes up to 4 bytes, taking into account the byte enable.
566    // It does not use the directory and cannot miss.
567    ////////////////////////////////////////////////////////////////////////////
568    inline void write(size_t    way, 
569                      size_t    set, 
570                      size_t    word, 
571                      data_t    data, 
572                      be_t          be)
573    {
574        data_t mask = be2mask(be);
575        data_t prev = cache_data(way, set, word);
576        cache_data(way, set, word) = (mask & data) | (~mask & prev);
577        cache_set_lru(way, set);
578    }
579
580    //////////////////////////////////////////////////////////////////////////
581    // This function invalidates a cache line identified by the set and way.
582    // It returns true if the line was valid, and returns the line index.
583    //////////////////////////////////////////////////////////////////////////
584    inline bool inval(size_t    way, 
585                      size_t    set, 
586                      addr_t*   nline)
587    {
588        if ( cache_state(way,set) == CACHE_SLOT_STATE_VALID ) 
589        {
590            cache_state(way,set) = CACHE_SLOT_STATE_EMPTY;
591            *nline = (data_t)cache_tag(way,set)* m_sets + set;
592            return true;
593        }
594        return false;
595    }
596
597    //////////////////////////////////////////////////////////////////////////////////
598    // This function selects a victim slot in an associative set.
599    // It cannot fail, as a slot in ZOMBI state is considered EMPTY.
600    // - we search first an EMPTY slot
601    // - if no EMPTY slot, we search an OLD slot, using lru
602    // It returns the line index (Z + Y fields), the selected slot way and set,
603    // and a Boolean indicating that a cleanup is requested.
604    //////////////////////////////////////////////////////////////////////////////////
605    inline bool victim_select(addr_t    ad, 
606                              addr_t*   victim, 
607                              size_t*   way, 
608                              size_t*   set)
609    {
610        bool   found   = false;
611        bool   cleanup = false;
612
613        *set = m_y[ad];
614        *way = 0;
615
616        // Search first empty slot
617        for ( size_t _way = 0 ; _way < m_ways && !found ; _way++ )
618        {
619            if ( cache_state(_way, *set) != CACHE_SLOT_STATE_VALID )  // empty
620            {
621                found   = true;
622                cleanup = false;
623                *way    = _way;
624            }
625        }
626
627        // If no empty slot, search first  old slot (lru == false)
628        if ( !found )
629        { 
630            for ( size_t _way = 0 ; _way < m_ways && !found ; _way++ )
631            {
632                if ( not cache_lru(_way, *set) )
633                {
634                    found   = true;
635                    cleanup = true;
636                    *way    = _way;
637                }
638            }
639        }
640
641        assert(found && "all ways can't be new at the same time");
642        *victim = (addr_t)((cache_tag(*way,*set) * m_sets) + *set);
643        return cleanup;
644    }
645
646    //////////////////////////////////////////////////////////////////////////////////
647    // This function selects a victim slot in an associative set.
648    // It can fail if all ways are in ZOMBI state.
649    // - we search first an EMPTY slot
650    // - if no empty slot, we search an OLD slot not in ZOMBI state,
651    // - if not found, we take the first not ZOMBI slot.
652    // It returns the line index (Z + Y fields), the selected slot way and set,
653    // and two Boolean indicating success and a required cleanup.
654    //////////////////////////////////////////////////////////////////////////////////
655    inline void read_select(addr_t        ad, 
656                            addr_t*   victim, 
657                            size_t*   way, 
658                            size_t*   set,
659                            bool*     found,
660                            bool*     cleanup )
661    {
662        size_t _set = m_y[ad];
663
664        *found = false;
665
666        // Search first empty slot
667        for ( size_t _way = 0 ; _way < m_ways && !(*found) ; _way++ )
668        {
669            if ( cache_state(_way, _set) == CACHE_SLOT_STATE_EMPTY )
670            {
671                *found   = true;
672                *cleanup = false;
673                *way     = _way;
674                *set     = m_y[ad];
675                return;
676            }
677        }
678        // Search first not zombi old slot
679        for ( size_t _way = 0 ; _way < m_ways && !(*found) ; _way++ )
680        {
681            if ( not cache_lru(_way, _set) and
682                 (cache_state(_way, _set) != CACHE_SLOT_STATE_ZOMBI) )
683            {
684                *found   = true;
685                *cleanup = true;
686                *way     = _way;
687                *set     = m_y[ad];
688                *victim  = cache_tag(*way,_set) * m_sets + _set;
689                return;
690            }
691        }
692        // Search first not zombi slot
693        for ( size_t _way = 0 ; _way < m_ways && !(*found) ; _way++ )
694        {
695            if ( cache_state(_way, _set) != CACHE_SLOT_STATE_ZOMBI) 
696            {
697                *found   = true;
698                *cleanup = true;
699                *way    = _way;
700                *set     = m_y[ad];
701                *victim  = cache_tag(*way,_set) * m_sets + _set;
702                return;
703            }
704        }
705
706        // no slot found...
707        *found   = false;
708        *cleanup = false;
709    }
710
711    //////////////////////////////////////////////////////////////////
712    // This function update the directory part of a slot
713    // identified by the way & set.
714    //////////////////////////////////////////////////////////////////
715    inline void victim_update_tag( addr_t       ad, 
716                                   size_t       way, 
717                                   size_t       set )
718    {
719        addr_t  tag     = m_z[ad];
720
721        cache_tag(way, set)   = tag;
722        cache_state(way, set) = CACHE_SLOT_STATE_VALID;
723        cache_set_lru(way, set);
724    }
725
726    //////////////////////////////////////////////////////////////////
727    // This function write the directory part of a slot
728    // identified by the way & set, when using the ZOMBI state.
729    //////////////////////////////////////////////////////////////////
730    inline void write_dir( addr_t       ad, 
731                           size_t       way, 
732                           size_t       set,
733                           int      state)
734    {
735        addr_t  tag     = m_z[ad];
736
737        assert( ( (state == CACHE_SLOT_STATE_VALID) or
738                  (state == CACHE_SLOT_STATE_ZOMBI) or
739                  (state == CACHE_SLOT_STATE_EMPTY) ) and
740        "illegal slot state argument in Generic Cache write_dir()");
741
742        assert( (way < m_ways) and
743        "too large way index argument in Generic Cache write_dir()");
744
745        assert( (set < m_sets) and
746        "too large set index argument in Generic Cache write_dir()");
747
748        cache_tag(way, set)   = tag;
749        cache_state(way, set) = state;
750
751        if ( state == CACHE_SLOT_STATE_VALID ) cache_set_lru(way, set);
752    }
753
754    //////////////////////////////////////////////////////////////////
755    // This function change the state of a slot
756    // identified by the way & set, when using the ZOMBI state.
757    // It does not affect the tag
758    //////////////////////////////////////////////////////////////////
759    inline void write_dir( size_t       way, 
760                           size_t       set,
761                           int      state)
762    {
763        assert( ( (state == CACHE_SLOT_STATE_VALID) or
764                  (state == CACHE_SLOT_STATE_ZOMBI) or
765                  (state == CACHE_SLOT_STATE_EMPTY) ) and
766        "illegal slot state argument in Generic Cache write_dir()");
767
768        assert( (way < m_ways) and
769        "too large way index argument in Generic Cache write_dir()");
770
771        assert( (set < m_sets) and
772        "too large set index argument in Generic Cache write_dir()");
773
774        cache_state(way, set) = state;
775
776        if ( state == CACHE_SLOT_STATE_VALID ) cache_set_lru(way, set);
777    }
778
779    ///////////////////////////////////////////////////////////////////
780    // This function writes a full cache line in one single cycle.
781    // The target slot is identified by the way & set arguments.
782    // Both DATA and DIRECTORY are written
783    ///////////////////////////////////////////////////////////////////
784    inline void update(addr_t   ad, 
785                       size_t   way, 
786                       size_t   set, 
787                       data_t*  buf)
788    {
789        addr_t tag = m_z[ad];
790
791        cache_tag(way, set)   = tag;
792        cache_state(way, set) = CACHE_SLOT_STATE_VALID;
793        cache_set_lru(way, set);
794        for ( size_t word = 0 ; word < m_words ; word++ ) 
795        {
796            cache_data(way, set, word) = buf[word] ;
797        }
798    }
799
800    ///////////////////////////
801    void fileTrace(FILE* file)
802    {
803        for( size_t nway = 0 ; nway < m_ways ; nway++) 
804        {
805            for( size_t nset = 0 ; nset < m_sets ; nset++) 
806            {
807                fprintf(file, "%d / ", (int)cache_state(nway, nset));
808                fprintf(file, "way %d / ", (int)nway);
809                fprintf(file, "set %d / ", (int)nset);
810                fprintf(file, "@ = %08zX / ", 
811                        ((cache_tag(nway, nset)*m_sets+nset)*m_words*4));
812                for( size_t nword = m_words ; nword > 0 ; nword--) 
813                {
814                    unsigned int data = cache_data(nway, nset, nword-1);
815                    fprintf(file, "%08X ", data );
816                }
817                fprintf(file, "\n");
818            }
819        }
820    }
821
822    ////////////////////////
823    inline void printTrace()
824    {
825        for ( size_t way = 0; way < m_ways ; way++ ) 
826        {
827            for ( size_t set = 0 ; set < m_sets ; set++ )
828            {
829                addr_t addr = (((addr_t)cache_tag(way,set))*m_words*m_sets+m_words*set)*4;
830                std::cout << std::dec << cache_state(way, set) 
831                          << " | way " << way
832                          << " | set " << set
833                          << std::hex << " | @ " << addr;
834
835                for ( size_t word = 0 ; word < m_words ; word++ )
836                {
837                    std::cout << " | " << cache_data(way,set,word) ;
838                }
839                std::cout << std::endl ;
840            }
841        }
842    }
843
844    ///////////////////////////////////////////////////////////////////////////
845    // This function is deprecated as it is difficult to implement in 1 cycle.
846    ///////////////////////////////////////////////////////////////////////////
847    __attribute__((deprecated))
848    inline bool inval(addr_t    ad)
849    {
850        bool              hit = false;
851        const addr_t      tag = m_z[ad];
852        const size_t      set = m_y[ad];
853
854        for ( size_t way = 0 ; way < m_ways && !hit ; way++ ) 
855        {
856            if ( (tag == cache_tag(way, set)) and
857                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID) ) 
858            {
859                hit                   = true;
860                cache_state(way, set) = CACHE_SLOT_STATE_EMPTY;
861                cache_lru(way, set)   = false;
862            }
863        }
864        return hit;
865    }
866
867    ////////////////////////////////////////////////////////////////////////////////
868    // This function is deprecated as it is difficult to implement in 1 cycle.
869    ////////////////////////////////////////////////////////////////////////////////
870    __attribute__((deprecated))
871    inline bool inval( addr_t   ad, 
872                       size_t*  selway, 
873                       size_t*  selset )
874    {
875        bool            hit = false;
876        const addr_t    tag = m_z[ad];
877        const size_t    set = m_y[ad];
878
879        for ( size_t way = 0 ; way < m_ways && !hit ; way++ ) 
880        {
881            if ( (tag == cache_tag(way, set)) and
882                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID) ) 
883            {
884                hit                   = true;
885                cache_state(way, set) = CACHE_SLOT_STATE_EMPTY;
886                cache_lru(way, set)   = false;
887                *selway             = way;
888                *selset             = set;
889            }
890        }
891        return hit;
892    }
893
894    ////////////////////////////////////////////////////////////////////////////////
895    // This function is deprecated as the directory must be a dual port RAM...
896    ////////////////////////////////////////////////////////////////////////////////
897    __attribute__((deprecated))
898    inline bool update( addr_t  ad, 
899                        data_t* buf, 
900                        addr_t* victim )
901    {
902        size_t set, way;
903        bool   cleanup = victim_select(ad, victim, &way, &set);
904        victim_update_tag (ad, way, set);
905
906        for ( size_t word = 0 ; word < m_words ; word++ ) {
907            cache_data(way, set, word) = buf[word] ;
908        }
909
910        return cleanup;
911    }
912
913    ////////////////////////////////////////////////////////////////////////////
914    // this function is deprecated, as it is difficult to implement in 1 cycle.
915    ////////////////////////////////////////////////////////////////////////////
916    __attribute__((deprecated))
917    inline bool write(addr_t    ad, 
918                      data_t    dt)
919    {
920        const addr_t      tag  = m_z[ad];
921        const size_t      set  = m_y[ad];
922        const size_t      word = m_x[ad];
923
924        for ( size_t way = 0; way < m_ways; way++ ) 
925        {
926            if ( (tag == cache_tag(way, set)) and
927                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID) ) 
928            {
929                cache_data(way, set, word) = dt;
930                cache_set_lru(way, set);
931                return true;
932            }
933        }
934        return false;
935    }
936
937    ////////////////////////////////////////////////////////////////////////////
938    // this function is deprecated, as it is difficult to implement in 1 cycle.
939    ////////////////////////////////////////////////////////////////////////////
940    __attribute__((deprecated))
941    inline bool write(addr_t    ad, 
942                      data_t    dt, 
943                      be_t      be)
944    {
945        const addr_t      tag  = m_z[ad];
946        const size_t      set  = m_y[ad];
947        const size_t      word = m_x[ad];
948
949        for ( size_t way = 0; way < m_ways; way++ ) 
950        {
951            if ( (tag == cache_tag(way, set)) and
952                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID) ) 
953            {
954                data_t mask = be2mask(be);
955                data_t prev = cache_data(way, set, word);
956                cache_data(way, set, word) = (mask & dt) | (~mask & prev);
957                cache_set_lru(way, set);
958                return true;
959            }
960        }
961        return false;
962    }
963   
964    /////////////////////////////////////////////////////////////////////////////
965    // this function is deprecated, as it is difficult to implement in 1 cycle.
966    /////////////////////////////////////////////////////////////////////////////
967    __attribute__((deprecated))
968    inline bool write(addr_t    ad, 
969                      data_t    dt, 
970                      size_t*   nway)
971    {
972        const addr_t      tag  = m_z[ad];
973        const size_t      set  = m_y[ad];
974        const size_t      word = m_x[ad];
975
976        for ( size_t way = 0; way < m_ways; way++ ) 
977        {
978            if ( (tag == cache_tag(way, set)) and
979                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID) ) 
980            {
981                cache_data(way, set, word) = dt;
982                cache_set_lru(way, set);
983                *nway = way;
984                return true;
985            }
986        }
987        return false;
988    }
989
990    /////////////////////////////////////////////////////////////////////////////
991    // this function is deprecated, as it is difficult to implement in 1 cycle.
992    /////////////////////////////////////////////////////////////////////////////
993    __attribute__((deprecated))
994    inline bool write(addr_t    ad, 
995                      data_t    dt, 
996                      size_t*   nway, 
997                      be_t      be)
998    {
999        const addr_t      tag  = m_z[ad];
1000        const size_t      set  = m_y[ad];
1001        const size_t      word = m_x[ad];
1002
1003        for ( size_t way = 0; way < m_ways; way++ ) 
1004        {
1005            if ( (tag == cache_tag(way, set)) and
1006                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID) ) 
1007            {
1008                data_t mask = be2mask(be);
1009                data_t prev = cache_data(way, set, word);
1010                cache_data(way, set, word) = (mask & dt) | (~mask & prev);
1011                cache_set_lru(way, set);
1012                *nway = way;
1013                return true;
1014            }
1015        }
1016        return false;
1017    }
1018   
1019};
1020
1021} // namespace soclib
1022
1023#endif
1024
1025// Local Variables:
1026// tab-width: 4
1027// c-basic-offset: 4
1028// c-file-offsets:((innamespace . 0)(inline-open . 0))
1029// indent-tabs-mode: nil
1030// End:
1031
1032// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
1033
Note: See TracBrowser for help on using the repository browser.