source: branches/RWT/lib/generic_cache_tsar/include/generic_cache.h @ 767

Last change on this file since 767 was 767, checked in by devigne, 10 years ago

RWT commit :

  • Merge with trunk.
  • Cosmetic
  • Bugfix in state WRITE_IVT_LOCK_HIT_WB.

MemCache? records invalidation in IVT in this state but we do not check that
the IVT was full. Thus invalidation was issued without actually recorded in the
query IVT ...

  • Bugfix :

When a NCC line owned by a L1 cache with srcid != 0 was removed from MemCache?,
the owner field was reset to 0. If this same L1 cache was sending a read to
retrieve this line the MemCache? sent this line on CC mode.

  • Bugfix :

The MemCache? reset the 'inst' field to 0 when solving a
invalidation due to a change of state of line (NCC to CC).
But a line can be NCC (ie contained in a DATA cache) then asked by INST cache,
this read triggers a transition NCC to CC but we must save the nature of this read.
Now this information is stored in a register (r_read_to_cleanup_inst).

  • Add a counter for the number of minimum inputs available

in the heap. This counter indicates whether the heap size of 4096 is relevant.

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