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

Last change on this file since 478 was 393, checked in by alain, 11 years ago

Introducing support for addresses larger than 32 bits.

File size: 36.1 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                    }
446                    cache_set_lru(way, set);
447                }
448                else if ( cache_state(way, set) == CACHE_SLOT_STATE_ZOMBI )
449                {
450                    *state   = CACHE_SLOT_STATE_ZOMBI;
451                    *selway  = way;
452                    *selset  = set;
453                    *selword = word;
454                }
455            }
456        }
457    }
458
459    ///////////////////////////////////////////////////////////////////////////////
460    // Checks the cache state for a given address.
461    // Only the directory is accessed.
462    // returns true if (matching tag) and (state == VALID)
463    // The selected way, set and first word index are returned in case of hit.
464    // This function can be used when we need to access the directory
465    // while we write in the data part with a different address in the same cycle.
466    ///////////////////////////////////////////////////////////////////////////////
467    inline bool hit(  addr_t    ad, 
468                      size_t*   selway,
469                      size_t*   selset,
470                      size_t*   selword)
471    {
472        const addr_t      tag  = m_z[ad];
473        const size_t      set  = m_y[ad];
474        const size_t      word = m_x[ad];
475
476        for ( size_t way = 0; way < m_ways; way++ ) 
477        {
478            if ( (tag == cache_tag(way, set)) 
479                   && (cache_state(way, set) == CACHE_SLOT_STATE_VALID) ) 
480            {
481                *selway  = way;
482                *selset  = set;
483                *selword = word;
484                cache_set_lru(way, set);
485                return true;
486            }
487        }
488        return false;
489    }
490 
491    ///////////////////////////////////////////////////////////////////////////////
492    // Checks the cache state for a given address, when the ZOMBI state is used.
493    // Only the directory is accessed.
494    // Returns the access status in the state argument:
495    // - VALID if (matching tag) and (state == VALID)
496    // - ZOMBI if (matching tag) and (state == ZOMBI)
497    // - EMPTY if no match or (state == EMPTY)
498    // The selected way, set and first word index are returned if not empty.
499    // This function can be used when we need to access the directory
500    // while we write in the data part with a different address in the same cycle.
501    ///////////////////////////////////////////////////////////////////////////////
502    inline void read_dir(  addr_t       ad, 
503                           int*     state,
504                           size_t*      way,
505                           size_t*      set,
506                           size_t*  word)
507    {
508        const addr_t      ad_tag  = m_z[ad];
509        const size_t      ad_set  = m_y[ad];
510        const size_t      ad_word = m_x[ad];
511
512        for ( size_t _way = 0; _way < m_ways; _way++ ) 
513        {
514            if ( (ad_tag == cache_tag(_way, ad_set) ) and
515                 (cache_state(_way, ad_set) != CACHE_SLOT_STATE_EMPTY) ) 
516            {
517                *state = cache_state(_way, ad_set);
518                *way   = _way;
519                *set   = ad_set;
520                *word  = ad_word;
521                return;
522            }
523        }
524       
525        // return value if not (VALID or ZOMBI)
526        *state = CACHE_SLOT_STATE_EMPTY;
527    }
528
529    ///////////////////////////////////////////////////////////////////////////////
530    // Checks the cache state for a slot (set,way), when the ZOMBI state is used.
531    // Only the directory is accessed.
532    // Returns the access status and the tag value in the state and tag argument.
533    ///////////////////////////////////////////////////////////////////////////////
534    inline void read_dir(  size_t       way,
535                           size_t       set,
536                           addr_t*   tag,
537                           int*     state )
538    {
539        *state = cache_state(way, set);
540        *tag   = cache_tag(way, set);
541    }
542
543    ////////////////////////////////////////////
544    inline addr_t get_tag(size_t way, size_t set)
545    {
546        return cache_tag(way, set);
547    }
548
549    ///////////////////////////////////////////////////////////////////
550    // This function writes a complete 32 bits word
551    // It does not use the directory and cannot miss.
552    //////////////////////////////////////////////////////////////////
553    inline void write(size_t    way, 
554                      size_t    set, 
555                      size_t    word, 
556                      data_t    data)
557    {
558        cache_data(way, set, word) = data;
559        cache_set_lru(way, set);
560    }
561
562    ////////////////////////////////////////////////////////////////////////////
563    // this function writes up to 4 bytes, taking into account the byte enable.
564    // It does not use the directory and cannot miss.
565    ////////////////////////////////////////////////////////////////////////////
566    inline void write(size_t    way, 
567                      size_t    set, 
568                      size_t    word, 
569                      data_t    data, 
570                      be_t          be)
571    {
572        data_t mask = be2mask(be);
573        data_t prev = cache_data(way, set, word);
574        cache_data(way, set, word) = (mask & data) | (~mask & prev);
575        cache_set_lru(way, set);
576    }
577
578    //////////////////////////////////////////////////////////////////////////
579    // This function invalidates a cache line identified by the set and way.
580    // It returns true if the line was valid, and returns the line index.
581    //////////////////////////////////////////////////////////////////////////
582    inline bool inval(size_t    way, 
583                      size_t    set, 
584                      addr_t*   nline)
585    {
586        if ( cache_state(way,set) == CACHE_SLOT_STATE_VALID ) 
587        {
588            cache_state(way,set) = CACHE_SLOT_STATE_EMPTY;
589            *nline = (data_t)cache_tag(way,set)* m_sets + set;
590            return true;
591        }
592        return false;
593    }
594
595    //////////////////////////////////////////////////////////////////////////////////
596    // This function selects a victim slot in an associative set.
597    // It cannot fail, as a slot in ZOMBI state is considered EMPTY.
598    // - we search first an EMPTY slot
599    // - if no EMPTY slot, we search an OLD slot, using lru
600    // It returns the line index (Z + Y fields), the selected slot way and set,
601    // and a Boolean indicating that a cleanup is requested.
602    //////////////////////////////////////////////////////////////////////////////////
603    inline bool victim_select(addr_t    ad, 
604                              addr_t*   victim, 
605                              size_t*   way, 
606                              size_t*   set)
607    {
608        bool   found   = false;
609        bool   cleanup = false;
610
611        *set = m_y[ad];
612        *way = 0;
613
614        // Search first empty slot
615        for ( size_t _way = 0 ; _way < m_ways && !found ; _way++ )
616        {
617            if ( cache_state(_way, *set) != CACHE_SLOT_STATE_VALID )  // empty
618            {
619                found   = true;
620                cleanup = false;
621                *way    = _way;
622            }
623        }
624
625        // If no empty slot, search first  old slot (lru == false)
626        if ( !found )
627        { 
628            for ( size_t _way = 0 ; _way < m_ways && !found ; _way++ )
629            {
630                if ( not cache_lru(_way, *set) )
631                {
632                    found   = true;
633                    cleanup = true;
634                    *way    = _way;
635                }
636            }
637        }
638
639        assert(found && "all ways can't be new at the same time");
640        *victim = (addr_t)((cache_tag(*way,*set) * m_sets) + *set);
641        return cleanup;
642    }
643
644    //////////////////////////////////////////////////////////////////////////////////
645    // This function selects a victim slot in an associative set.
646    // It can fail if all ways are in ZOMBI state.
647    // - we search first an EMPTY slot
648    // - if no empty slot, we search an OLD slot not in ZOMBI state,
649    // - if not found, we take the first not ZOMBI slot.
650    // It returns the line index (Z + Y fields), the selected slot way and set,
651    // and two Boolean indicating success and a required cleanup.
652    //////////////////////////////////////////////////////////////////////////////////
653    inline void read_select(addr_t        ad, 
654                            addr_t*   victim, 
655                            size_t*   way, 
656                            size_t*   set,
657                            bool*     found,
658                            bool*     cleanup )
659    {
660        size_t _set = m_y[ad];
661
662        *found = false;
663
664        // Search first empty slot
665        for ( size_t _way = 0 ; _way < m_ways && !(*found) ; _way++ )
666        {
667            if ( cache_state(_way, _set) == CACHE_SLOT_STATE_EMPTY )
668            {
669                *found   = true;
670                *cleanup = false;
671                *way     = _way;
672                *set     = m_y[ad];
673                return;
674            }
675        }
676        // Search first not zombi old slot
677        for ( size_t _way = 0 ; _way < m_ways && !(*found) ; _way++ )
678        {
679            if ( not cache_lru(_way, _set) and
680                 (cache_state(_way, _set) != CACHE_SLOT_STATE_ZOMBI) )
681            {
682                *found   = true;
683                *cleanup = true;
684                *way     = _way;
685                *set     = m_y[ad];
686                *victim  = cache_tag(*way,_set) * m_sets + _set;
687                return;
688            }
689        }
690        // Search first not zombi slot
691        for ( size_t _way = 0 ; _way < m_ways && !(*found) ; _way++ )
692        {
693            if ( cache_state(_way, _set) != CACHE_SLOT_STATE_ZOMBI) 
694            {
695                *found   = true;
696                *cleanup = true;
697                *way    = _way;
698                *set     = m_y[ad];
699                *victim  = cache_tag(*way,_set) * m_sets + _set;
700                return;
701            }
702        }
703
704        // no slot found...
705        *found   = false;
706        *cleanup = false;
707    }
708
709    //////////////////////////////////////////////////////////////////
710    // This function update the directory part of a slot
711    // identified by the way & set.
712    //////////////////////////////////////////////////////////////////
713    inline void victim_update_tag( addr_t       ad, 
714                                   size_t       way, 
715                                   size_t       set )
716    {
717        addr_t  tag     = m_z[ad];
718
719        cache_tag(way, set)   = tag;
720        cache_state(way, set) = CACHE_SLOT_STATE_VALID;
721        cache_set_lru(way, set);
722    }
723
724    //////////////////////////////////////////////////////////////////
725    // This function write the directory part of a slot
726    // identified by the way & set, when using the ZOMBI state.
727    //////////////////////////////////////////////////////////////////
728    inline void write_dir( addr_t       ad, 
729                           size_t       way, 
730                           size_t       set,
731                           int      state)
732    {
733        addr_t  tag     = m_z[ad];
734
735        assert( ( (state == CACHE_SLOT_STATE_VALID) or
736                  (state == CACHE_SLOT_STATE_ZOMBI) or
737                  (state == CACHE_SLOT_STATE_EMPTY) ) and
738        "illegal slot state argument in Generic Cache write_dir()");
739
740        assert( (way < m_ways) and
741        "too large way index argument in Generic Cache write_dir()");
742
743        assert( (set < m_sets) and
744        "too large set index argument in Generic Cache write_dir()");
745
746        cache_tag(way, set)   = tag;
747        cache_state(way, set) = state;
748
749        if ( state == CACHE_SLOT_STATE_VALID ) cache_set_lru(way, set);
750    }
751
752    //////////////////////////////////////////////////////////////////
753    // This function change the state of a slot
754    // identified by the way & set, when using the ZOMBI state.
755    // It does not affect the tag
756    //////////////////////////////////////////////////////////////////
757    inline void write_dir( size_t       way, 
758                           size_t       set,
759                           int      state)
760    {
761        assert( ( (state == CACHE_SLOT_STATE_VALID) or
762                  (state == CACHE_SLOT_STATE_ZOMBI) or
763                  (state == CACHE_SLOT_STATE_EMPTY) ) and
764        "illegal slot state argument in Generic Cache write_dir()");
765
766        assert( (way < m_ways) and
767        "too large way index argument in Generic Cache write_dir()");
768
769        assert( (set < m_sets) and
770        "too large set index argument in Generic Cache write_dir()");
771
772        cache_state(way, set) = state;
773
774        if ( state == CACHE_SLOT_STATE_VALID ) cache_set_lru(way, set);
775    }
776
777    ///////////////////////////////////////////////////////////////////
778    // This function writes a full cache line in one single cycle.
779    // The target slot is identified by the way & set arguments.
780    // Both DATA and DIRECTORY are written
781    ///////////////////////////////////////////////////////////////////
782    inline void update(addr_t   ad, 
783                       size_t   way, 
784                       size_t   set, 
785                       data_t*  buf)
786    {
787        addr_t tag = m_z[ad];
788
789        cache_tag(way, set)   = tag;
790        cache_state(way, set) = CACHE_SLOT_STATE_VALID;
791        cache_set_lru(way, set);
792        for ( size_t word = 0 ; word < m_words ; word++ ) 
793        {
794            cache_data(way, set, word) = buf[word] ;
795        }
796    }
797
798    ///////////////////////////
799    void fileTrace(FILE* file)
800    {
801        for( size_t nway = 0 ; nway < m_ways ; nway++) 
802        {
803            for( size_t nset = 0 ; nset < m_sets ; nset++) 
804            {
805                fprintf(file, "%d / ", (int)cache_state(nway, nset));
806                fprintf(file, "way %d / ", (int)nway);
807                fprintf(file, "set %d / ", (int)nset);
808                fprintf(file, "@ = %08zX / ", 
809                        ((cache_tag(nway, nset)*m_sets+nset)*m_words*4));
810                for( size_t nword = m_words ; nword > 0 ; nword--) 
811                {
812                    unsigned int data = cache_data(nway, nset, nword-1);
813                    fprintf(file, "%08X ", data );
814                }
815                fprintf(file, "\n");
816            }
817        }
818    }
819
820    ////////////////////////
821    inline void printTrace()
822    {
823        for ( size_t way = 0; way < m_ways ; way++ ) 
824        {
825            for ( size_t set = 0 ; set < m_sets ; set++ )
826            {
827                addr_t addr = (((addr_t)cache_tag(way,set))*m_words*m_sets+m_words*set)*4;
828                std::cout << std::dec << cache_state(way, set) 
829                          << " | way " << way
830                          << " | set " << set
831                          << std::hex << " | @ " << addr;
832
833                for ( size_t word = 0 ; word < m_words ; word++ )
834                {
835                    std::cout << " | " << cache_data(way,set,word) ;
836                }
837                std::cout << std::endl ;
838            }
839        }
840    }
841
842    ///////////////////////////////////////////////////////////////////////////
843    // This function is deprecated as it is difficult to implement in 1 cycle.
844    ///////////////////////////////////////////////////////////////////////////
845    __attribute__((deprecated))
846    inline bool inval(addr_t    ad)
847    {
848        bool              hit = false;
849        const addr_t      tag = m_z[ad];
850        const size_t      set = m_y[ad];
851
852        for ( size_t way = 0 ; way < m_ways && !hit ; way++ ) 
853        {
854            if ( (tag == cache_tag(way, set)) and
855                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID) ) 
856            {
857                hit                   = true;
858                cache_state(way, set) = CACHE_SLOT_STATE_EMPTY;
859                cache_lru(way, set)   = false;
860            }
861        }
862        return hit;
863    }
864
865    ////////////////////////////////////////////////////////////////////////////////
866    // This function is deprecated as it is difficult to implement in 1 cycle.
867    ////////////////////////////////////////////////////////////////////////////////
868    __attribute__((deprecated))
869    inline bool inval( addr_t   ad, 
870                       size_t*  selway, 
871                       size_t*  selset )
872    {
873        bool            hit = false;
874        const addr_t    tag = m_z[ad];
875        const size_t    set = m_y[ad];
876
877        for ( size_t way = 0 ; way < m_ways && !hit ; way++ ) 
878        {
879            if ( (tag == cache_tag(way, set)) and
880                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID) ) 
881            {
882                hit                   = true;
883                cache_state(way, set) = CACHE_SLOT_STATE_EMPTY;
884                cache_lru(way, set)   = false;
885                *selway             = way;
886                *selset             = set;
887            }
888        }
889        return hit;
890    }
891
892    ////////////////////////////////////////////////////////////////////////////////
893    // This function is deprecated as the directory must be a dual port RAM...
894    ////////////////////////////////////////////////////////////////////////////////
895    __attribute__((deprecated))
896    inline bool update( addr_t  ad, 
897                        data_t* buf, 
898                        addr_t* victim )
899    {
900        size_t set, way;
901        bool   cleanup = victim_select(ad, victim, &way, &set);
902        victim_update_tag (ad, way, set);
903
904        for ( size_t word = 0 ; word < m_words ; word++ ) {
905            cache_data(way, set, word) = buf[word] ;
906        }
907
908        return cleanup;
909    }
910
911    ////////////////////////////////////////////////////////////////////////////
912    // this function is deprecated, as it is difficult to implement in 1 cycle.
913    ////////////////////////////////////////////////////////////////////////////
914    __attribute__((deprecated))
915    inline bool write(addr_t    ad, 
916                      data_t    dt)
917    {
918        const addr_t      tag  = m_z[ad];
919        const size_t      set  = m_y[ad];
920        const size_t      word = m_x[ad];
921
922        for ( size_t way = 0; way < m_ways; way++ ) 
923        {
924            if ( (tag == cache_tag(way, set)) and
925                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID) ) 
926            {
927                cache_data(way, set, word) = dt;
928                cache_set_lru(way, set);
929                return true;
930            }
931        }
932        return false;
933    }
934
935    ////////////////////////////////////////////////////////////////////////////
936    // this function is deprecated, as it is difficult to implement in 1 cycle.
937    ////////////////////////////////////////////////////////////////////////////
938    __attribute__((deprecated))
939    inline bool write(addr_t    ad, 
940                      data_t    dt, 
941                      be_t      be)
942    {
943        const addr_t      tag  = m_z[ad];
944        const size_t      set  = m_y[ad];
945        const size_t      word = m_x[ad];
946
947        for ( size_t way = 0; way < m_ways; way++ ) 
948        {
949            if ( (tag == cache_tag(way, set)) and
950                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID) ) 
951            {
952                data_t mask = be2mask(be);
953                data_t prev = cache_data(way, set, word);
954                cache_data(way, set, word) = (mask & dt) | (~mask & prev);
955                cache_set_lru(way, set);
956                return true;
957            }
958        }
959        return false;
960    }
961   
962    /////////////////////////////////////////////////////////////////////////////
963    // this function is deprecated, as it is difficult to implement in 1 cycle.
964    /////////////////////////////////////////////////////////////////////////////
965    __attribute__((deprecated))
966    inline bool write(addr_t    ad, 
967                      data_t    dt, 
968                      size_t*   nway)
969    {
970        const addr_t      tag  = m_z[ad];
971        const size_t      set  = m_y[ad];
972        const size_t      word = m_x[ad];
973
974        for ( size_t way = 0; way < m_ways; way++ ) 
975        {
976            if ( (tag == cache_tag(way, set)) and
977                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID) ) 
978            {
979                cache_data(way, set, word) = dt;
980                cache_set_lru(way, set);
981                *nway = way;
982                return true;
983            }
984        }
985        return false;
986    }
987
988    /////////////////////////////////////////////////////////////////////////////
989    // this function is deprecated, as it is difficult to implement in 1 cycle.
990    /////////////////////////////////////////////////////////////////////////////
991    __attribute__((deprecated))
992    inline bool write(addr_t    ad, 
993                      data_t    dt, 
994                      size_t*   nway, 
995                      be_t      be)
996    {
997        const addr_t      tag  = m_z[ad];
998        const size_t      set  = m_y[ad];
999        const size_t      word = m_x[ad];
1000
1001        for ( size_t way = 0; way < m_ways; way++ ) 
1002        {
1003            if ( (tag == cache_tag(way, set)) and
1004                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID) ) 
1005            {
1006                data_t mask = be2mask(be);
1007                data_t prev = cache_data(way, set, word);
1008                cache_data(way, set, word) = (mask & dt) | (~mask & prev);
1009                cache_set_lru(way, set);
1010                *nway = way;
1011                return true;
1012            }
1013        }
1014        return false;
1015    }
1016   
1017};
1018
1019} // namespace soclib
1020
1021#endif
1022
1023// Local Variables:
1024// tab-width: 4
1025// c-basic-offset: 4
1026// c-file-offsets:((innamespace . 0)(inline-open . 0))
1027// indent-tabs-mode: nil
1028// End:
1029
1030// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
1031
Note: See TracBrowser for help on using the repository browser.