source: branches/ODCCP/lib/generic_cache_tsar/include/generic_cache.h @ 460

Last change on this file since 460 was 460, checked in by devigne, 11 years ago

Introducing merged components between the last trunk TSAR version
and the ODCCP modifications

File size: 38.4 KB
RevLine 
[297]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.
[393]36// The ZOMBI state is used by cache coherence protocols to indicate
[297]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,
[460]78    CACHE_SLOT_STATE_VALID_CC,
[297]79    CACHE_SLOT_STATE_ZOMBI,
[460]80    CACHE_SLOT_STATE_VALID_NCC,
[297]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 ;
[393]92    addr_t               *r_tag ;
[297]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    //////////////////////////////////////////////
[393]111    inline addr_t &cache_tag(size_t way, size_t set)
[297]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    }
[460]121   
[297]122    //////////////////////////////////////////////
123    inline int &cache_state(size_t way, size_t set)
124    {
125        return r_state[(way*m_sets)+set];
126    }
127
[460]128   
[297]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
[393]147    ////////////////////////////////
[297]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
[393]160    //////////////////////////////////////////
[297]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
[393]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;
[297]196#endif
197
198        r_data    = new data_t[nways*nsets*nwords];
[393]199        r_tag     = new addr_t[nways*nsets];
[297]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
[460]222    inline int get_cache_state(int way, int set)
223    {
224        return cache_state(way,set);
225    }
226   
[297]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    {
[393]235        const addr_t      tag  = m_z[ad];
[297]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)) 
[460]242                   && ( (cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC) or (cache_state(way, set) == CACHE_SLOT_STATE_VALID_NCC)) )
[297]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    {
[393]264        const addr_t      tag  = m_z[ad];
[297]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
[460]271                 ( (cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC)or (cache_state(way, set) == CACHE_SLOT_STATE_VALID_NCC)))
[297]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    {
[393]301        const addr_t      tag  = m_z[ad];
[297]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
[460]317                if ( cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC )
[297]318                {
[460]319                    *state   = CACHE_SLOT_STATE_VALID_CC;
[297]320                    *selway  = way;
321                    *selset  = set;
322                    *selword = word;
323                    *dt      = cache_data(way, set, word);
324                    cache_set_lru(way, set);
325                }
[460]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                }
[297]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    {
[393]358        const addr_t      tag  = m_z[ad];
[297]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)) 
[460]365                   && ( (cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC) or (cache_state(way, set) == CACHE_SLOT_STATE_VALID_NCC) ) )
[297]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]393        const addr_t      tag  = m_z[ad];
[297]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))   
[460]400                   &&( (cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC) ) ) 
[297]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
[337]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    {
[393]435        const addr_t      tag  = m_z[ad];
[337]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
[460]451                if ( cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC )
[337]452                {
[460]453                    *state   = CACHE_SLOT_STATE_VALID_CC;
[337]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                }
[460]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
[337]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
[297]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    {
[393]503        const addr_t      tag  = m_z[ad];
[297]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)) 
[460]510                   && ( (cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC)or(cache_state(way, set) == CACHE_SLOT_STATE_VALID_NCC) ) ) 
[297]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    ///////////////////////////////////////////////////////////////////////////////
[393]523    // Checks the cache state for a given address, when the ZOMBI state is used.
[297]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    {
[393]539        const addr_t      ad_tag  = m_z[ad];
[297]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,
[393]566                           addr_t*   tag,
[297]567                           int*     state )
568    {
569        *state = cache_state(way, set);
570        *tag   = cache_tag(way, set);
571    }
572
573    ////////////////////////////////////////////
[393]574    inline addr_t get_tag(size_t way, size_t set)
[297]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    {
[460]588       /**/ //std::cout << "write cache : way = "<<way<<" | set = "<<set<<" | word = "<<word<<" | data = "<<(uint32_t)data << std::endl;
[297]589        cache_data(way, set, word) = data;
590        cache_set_lru(way, set);
591    }
592
593    ////////////////////////////////////////////////////////////////////////////
594    // this function writes up to 4 bytes, taking into account the byte enable.
595    // It does not use the directory and cannot miss.
596    ////////////////////////////////////////////////////////////////////////////
597    inline void write(size_t    way, 
598                      size_t    set, 
599                      size_t    word, 
600                      data_t    data, 
601                      be_t          be)
602    {
603        data_t mask = be2mask(be);
604        data_t prev = cache_data(way, set, word);
605        cache_data(way, set, word) = (mask & data) | (~mask & prev);
606        cache_set_lru(way, set);
607    }
608
609    //////////////////////////////////////////////////////////////////////////
610    // This function invalidates a cache line identified by the set and way.
611    // It returns true if the line was valid, and returns the line index.
612    //////////////////////////////////////////////////////////////////////////
613    inline bool inval(size_t    way, 
614                      size_t    set, 
615                      addr_t*   nline)
616    {
[460]617        if( (cache_state(way,set) == CACHE_SLOT_STATE_VALID_CC) )
[297]618        {
619            cache_state(way,set) = CACHE_SLOT_STATE_EMPTY;
620            *nline = (data_t)cache_tag(way,set)* m_sets + set;
621            return true;
622        }
623        return false;
624    }
625
626    //////////////////////////////////////////////////////////////////////////////////
627    // This function selects a victim slot in an associative set.
628    // It cannot fail, as a slot in ZOMBI state is considered EMPTY.
629    // - we search first an EMPTY slot
630    // - if no EMPTY slot, we search an OLD slot, using lru
631    // It returns the line index (Z + Y fields), the selected slot way and set,
632    // and a Boolean indicating that a cleanup is requested.
633    //////////////////////////////////////////////////////////////////////////////////
634    inline bool victim_select(addr_t    ad, 
635                              addr_t*   victim, 
636                              size_t*   way, 
637                              size_t*   set)
638    {
639        bool   found   = false;
640        bool   cleanup = false;
641
642        *set = m_y[ad];
643        *way = 0;
644
645        // Search first empty slot
646        for ( size_t _way = 0 ; _way < m_ways && !found ; _way++ )
647        {
[460]648            if( ( cache_state(_way, *set) != CACHE_SLOT_STATE_VALID_CC ) )  // empty
[297]649            {
650                found   = true;
651                cleanup = false;
652                *way    = _way;
653            }
654        }
655
656        // If no empty slot, search first  old slot (lru == false)
657        if ( !found )
658        { 
659            for ( size_t _way = 0 ; _way < m_ways && !found ; _way++ )
660            {
661                if ( not cache_lru(_way, *set) )
662                {
663                    found   = true;
664                    cleanup = true;
665                    *way    = _way;
666                }
667            }
668        }
669
670        assert(found && "all ways can't be new at the same time");
671        *victim = (addr_t)((cache_tag(*way,*set) * m_sets) + *set);
672        return cleanup;
673    }
674
675    //////////////////////////////////////////////////////////////////////////////////
676    // This function selects a victim slot in an associative set.
677    // It can fail if all ways are in ZOMBI state.
678    // - we search first an EMPTY slot
679    // - if no empty slot, we search an OLD slot not in ZOMBI state,
680    // - if not found, we take the first not ZOMBI slot.
681    // It returns the line index (Z + Y fields), the selected slot way and set,
682    // and two Boolean indicating success and a required cleanup.
683    //////////////////////////////////////////////////////////////////////////////////
684    inline void read_select(addr_t        ad, 
685                            addr_t*   victim, 
686                            size_t*   way, 
687                            size_t*   set,
688                            bool*     found,
689                            bool*     cleanup )
690    {
[303]691        size_t _set = m_y[ad];
692
693        *found = false;
694
[297]695        // Search first empty slot
[303]696        for ( size_t _way = 0 ; _way < m_ways && !(*found) ; _way++ )
[297]697        {
[303]698            if ( cache_state(_way, _set) == CACHE_SLOT_STATE_EMPTY )
[297]699            {
700                *found   = true;
701                *cleanup = false;
702                *way     = _way;
703                *set     = m_y[ad];
704                return;
705            }
706        }
[460]707        //////////////////////////////////////////////////////////////
708        /*for ( size_t _way = 0 ; _way < m_ways && !(*found) ; _way++ )
709        {
710            if ( not cache_lru(_way, _set) and
711                 (cache_state(_way, _set) != CACHE_SLOT_STATE_ZOMBI) and
712                 (cache_state(_way, _set) == CACHE_SLOT_STATE_VALID_NCC) )
713            {
714                *found   = true;
715                *cleanup = true;
716                *way     = _way;
717                *set     = m_y[ad];
718                *victim  = (addr_t)((cache_tag(*way,_set) * m_sets) + _set);
719                return;
720            }
721        }*/
[297]722        // Search first not zombi old slot
[303]723        for ( size_t _way = 0 ; _way < m_ways && !(*found) ; _way++ )
724        {
725            if ( not cache_lru(_way, _set) and
726                 (cache_state(_way, _set) != CACHE_SLOT_STATE_ZOMBI) )
[297]727            {
[303]728                *found   = true;
729                *cleanup = true;
730                *way     = _way;
731                *set     = m_y[ad];
[393]732                *victim  = cache_tag(*way,_set) * m_sets + _set;
[303]733                return;
[297]734            }
735        }
736        // Search first not zombi slot
[303]737        for ( size_t _way = 0 ; _way < m_ways && !(*found) ; _way++ )
738        {
739            if ( cache_state(_way, _set) != CACHE_SLOT_STATE_ZOMBI) 
[297]740            {
[303]741                *found   = true;
742                *cleanup = true;
743                *way    = _way;
744                *set     = m_y[ad];
[393]745                *victim  = cache_tag(*way,_set) * m_sets + _set;
[303]746                return;
[297]747            }
748        }
749
750        // no slot found...
751        *found   = false;
752        *cleanup = false;
753    }
754
755    //////////////////////////////////////////////////////////////////
756    // This function update the directory part of a slot
757    // identified by the way & set.
758    //////////////////////////////////////////////////////////////////
759    inline void victim_update_tag( addr_t       ad, 
760                                   size_t       way, 
761                                   size_t       set )
762    {
[393]763        addr_t  tag     = m_z[ad];
[297]764
765        cache_tag(way, set)   = tag;
[460]766        cache_state(way, set) = CACHE_SLOT_STATE_VALID_CC;
[297]767        cache_set_lru(way, set);
768    }
769
770    //////////////////////////////////////////////////////////////////
771    // This function write the directory part of a slot
772    // identified by the way & set, when using the ZOMBI state.
773    //////////////////////////////////////////////////////////////////
774    inline void write_dir( addr_t       ad, 
775                           size_t       way, 
776                           size_t       set,
777                           int      state)
778    {
[393]779        addr_t  tag     = m_z[ad];
[297]780
[460]781        assert( ( (state == CACHE_SLOT_STATE_VALID_CC) or
782                  (state == CACHE_SLOT_STATE_VALID_NCC) or
[297]783                  (state == CACHE_SLOT_STATE_ZOMBI) or
784                  (state == CACHE_SLOT_STATE_EMPTY) ) and
785        "illegal slot state argument in Generic Cache write_dir()");
786
787        assert( (way < m_ways) and
788        "too large way index argument in Generic Cache write_dir()");
789
790        assert( (set < m_sets) and
791        "too large set index argument in Generic Cache write_dir()");
792
793        cache_tag(way, set)   = tag;
794        cache_state(way, set) = state;
795
[460]796        if ( (state == CACHE_SLOT_STATE_VALID_CC) or (state == CACHE_SLOT_STATE_VALID_NCC) ) cache_set_lru(way, set);
[297]797    }
798
[365]799    //////////////////////////////////////////////////////////////////
[393]800    // This function change the state of a slot
[365]801    // identified by the way & set, when using the ZOMBI state.
[393]802    // It does not affect the tag
[365]803    //////////////////////////////////////////////////////////////////
804    inline void write_dir( size_t       way, 
805                           size_t       set,
806                           int      state)
807    {
[460]808        assert( ( (state == CACHE_SLOT_STATE_VALID_CC) or
809                  (state == CACHE_SLOT_STATE_VALID_NCC) or
[365]810                  (state == CACHE_SLOT_STATE_ZOMBI) or
811                  (state == CACHE_SLOT_STATE_EMPTY) ) and
812        "illegal slot state argument in Generic Cache write_dir()");
813
814        assert( (way < m_ways) and
815        "too large way index argument in Generic Cache write_dir()");
816
817        assert( (set < m_sets) and
818        "too large set index argument in Generic Cache write_dir()");
819
820        cache_state(way, set) = state;
821
[460]822        if ( (state == CACHE_SLOT_STATE_VALID_CC) or (state == CACHE_SLOT_STATE_VALID_NCC) ) cache_set_lru(way, set);
[365]823    }
824
[297]825    ///////////////////////////////////////////////////////////////////
826    // This function writes a full cache line in one single cycle.
827    // The target slot is identified by the way & set arguments.
828    // Both DATA and DIRECTORY are written
829    ///////////////////////////////////////////////////////////////////
830    inline void update(addr_t   ad, 
831                       size_t   way, 
832                       size_t   set, 
833                       data_t*  buf)
834    {
[393]835        addr_t tag = m_z[ad];
[297]836
837        cache_tag(way, set)   = tag;
[460]838        cache_state(way, set) = CACHE_SLOT_STATE_VALID_CC;
[297]839        cache_set_lru(way, set);
840        for ( size_t word = 0 ; word < m_words ; word++ ) 
841        {
842            cache_data(way, set, word) = buf[word] ;
843        }
844    }
845
846    ///////////////////////////
847    void fileTrace(FILE* file)
848    {
849        for( size_t nway = 0 ; nway < m_ways ; nway++) 
850        {
851            for( size_t nset = 0 ; nset < m_sets ; nset++) 
852            {
853                fprintf(file, "%d / ", (int)cache_state(nway, nset));
854                fprintf(file, "way %d / ", (int)nway);
855                fprintf(file, "set %d / ", (int)nset);
856                fprintf(file, "@ = %08zX / ", 
857                        ((cache_tag(nway, nset)*m_sets+nset)*m_words*4));
858                for( size_t nword = m_words ; nword > 0 ; nword--) 
859                {
860                    unsigned int data = cache_data(nway, nset, nword-1);
861                    fprintf(file, "%08X ", data );
862                }
863                fprintf(file, "\n");
864            }
865        }
866    }
867
868    ////////////////////////
869    inline void printTrace()
870    {
871        for ( size_t way = 0; way < m_ways ; way++ ) 
872        {
873            for ( size_t set = 0 ; set < m_sets ; set++ )
874            {
[393]875                addr_t addr = (((addr_t)cache_tag(way,set))*m_words*m_sets+m_words*set)*4;
876                std::cout << std::dec << cache_state(way, set) 
877                          << " | way " << way
878                          << " | set " << set
879                          << std::hex << " | @ " << addr;
880
[297]881                for ( size_t word = 0 ; word < m_words ; word++ )
882                {
883                    std::cout << " | " << cache_data(way,set,word) ;
884                }
885                std::cout << std::endl ;
886            }
887        }
888    }
889
890    ///////////////////////////////////////////////////////////////////////////
891    // This function is deprecated as it is difficult to implement in 1 cycle.
892    ///////////////////////////////////////////////////////////////////////////
893    __attribute__((deprecated))
894    inline bool inval(addr_t    ad)
895    {
896        bool              hit = false;
[393]897        const addr_t      tag = m_z[ad];
[297]898        const size_t      set = m_y[ad];
899
900        for ( size_t way = 0 ; way < m_ways && !hit ; way++ ) 
901        {
902            if ( (tag == cache_tag(way, set)) and
[460]903                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC) ) 
[297]904            {
905                hit                   = true;
906                cache_state(way, set) = CACHE_SLOT_STATE_EMPTY;
907                cache_lru(way, set)   = false;
908            }
909        }
910        return hit;
911    }
912
913    ////////////////////////////////////////////////////////////////////////////////
914    // This function is deprecated as it is difficult to implement in 1 cycle.
915    ////////////////////////////////////////////////////////////////////////////////
916    __attribute__((deprecated))
917    inline bool inval( addr_t   ad, 
918                       size_t*  selway, 
919                       size_t*  selset )
920    {
[393]921        bool            hit = false;
922        const addr_t    tag = m_z[ad];
[297]923        const size_t    set = m_y[ad];
924
925        for ( size_t way = 0 ; way < m_ways && !hit ; way++ ) 
926        {
927            if ( (tag == cache_tag(way, set)) and
[460]928                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC) ) 
[297]929            {
930                hit                   = true;
931                cache_state(way, set) = CACHE_SLOT_STATE_EMPTY;
932                cache_lru(way, set)   = false;
933                *selway             = way;
934                *selset             = set;
935            }
936        }
937        return hit;
938    }
939
940    ////////////////////////////////////////////////////////////////////////////////
941    // This function is deprecated as the directory must be a dual port RAM...
942    ////////////////////////////////////////////////////////////////////////////////
943    __attribute__((deprecated))
944    inline bool update( addr_t  ad, 
945                        data_t* buf, 
946                        addr_t* victim )
947    {
948        size_t set, way;
949        bool   cleanup = victim_select(ad, victim, &way, &set);
950        victim_update_tag (ad, way, set);
951
952        for ( size_t word = 0 ; word < m_words ; word++ ) {
953            cache_data(way, set, word) = buf[word] ;
954        }
955
956        return cleanup;
957    }
958
959    ////////////////////////////////////////////////////////////////////////////
960    // this function is deprecated, as it is difficult to implement in 1 cycle.
961    ////////////////////////////////////////////////////////////////////////////
962    __attribute__((deprecated))
963    inline bool write(addr_t    ad, 
964                      data_t    dt)
965    {
[393]966        const addr_t      tag  = m_z[ad];
[297]967        const size_t      set  = m_y[ad];
968        const size_t      word = m_x[ad];
969
970        for ( size_t way = 0; way < m_ways; way++ ) 
971        {
972            if ( (tag == cache_tag(way, set)) and
[460]973                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC) ) 
[297]974            {
975                cache_data(way, set, word) = dt;
976                cache_set_lru(way, set);
977                return true;
978            }
979        }
980        return false;
981    }
982
983    ////////////////////////////////////////////////////////////////////////////
984    // this function is deprecated, as it is difficult to implement in 1 cycle.
985    ////////////////////////////////////////////////////////////////////////////
986    __attribute__((deprecated))
987    inline bool write(addr_t    ad, 
988                      data_t    dt, 
989                      be_t      be)
990    {
[393]991        const addr_t      tag  = m_z[ad];
[297]992        const size_t      set  = m_y[ad];
993        const size_t      word = m_x[ad];
994
995        for ( size_t way = 0; way < m_ways; way++ ) 
996        {
997            if ( (tag == cache_tag(way, set)) and
[460]998                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC) ) 
[297]999            {
1000                data_t mask = be2mask(be);
1001                data_t prev = cache_data(way, set, word);
1002                cache_data(way, set, word) = (mask & dt) | (~mask & prev);
1003                cache_set_lru(way, set);
1004                return true;
1005            }
1006        }
1007        return false;
1008    }
1009   
1010    /////////////////////////////////////////////////////////////////////////////
1011    // this function is deprecated, as it is difficult to implement in 1 cycle.
1012    /////////////////////////////////////////////////////////////////////////////
1013    __attribute__((deprecated))
1014    inline bool write(addr_t    ad, 
1015                      data_t    dt, 
1016                      size_t*   nway)
1017    {
[393]1018        const addr_t      tag  = m_z[ad];
[297]1019        const size_t      set  = m_y[ad];
1020        const size_t      word = m_x[ad];
1021
1022        for ( size_t way = 0; way < m_ways; way++ ) 
1023        {
1024            if ( (tag == cache_tag(way, set)) and
[460]1025                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC) ) 
[297]1026            {
1027                cache_data(way, set, word) = dt;
1028                cache_set_lru(way, set);
1029                *nway = way;
1030                return true;
1031            }
1032        }
1033        return false;
1034    }
1035
1036    /////////////////////////////////////////////////////////////////////////////
1037    // this function is deprecated, as it is difficult to implement in 1 cycle.
1038    /////////////////////////////////////////////////////////////////////////////
1039    __attribute__((deprecated))
1040    inline bool write(addr_t    ad, 
1041                      data_t    dt, 
1042                      size_t*   nway, 
1043                      be_t      be)
1044    {
[393]1045        const addr_t      tag  = m_z[ad];
[297]1046        const size_t      set  = m_y[ad];
1047        const size_t      word = m_x[ad];
1048
1049        for ( size_t way = 0; way < m_ways; way++ ) 
1050        {
1051            if ( (tag == cache_tag(way, set)) and
[460]1052                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC) ) 
[297]1053            {
1054                data_t mask = be2mask(be);
1055                data_t prev = cache_data(way, set, word);
1056                cache_data(way, set, word) = (mask & dt) | (~mask & prev);
1057                cache_set_lru(way, set);
1058                *nway = way;
1059                return true;
1060            }
1061        }
1062        return false;
1063    }
1064   
1065};
1066
1067} // namespace soclib
1068
1069#endif
1070
1071// Local Variables:
1072// tab-width: 4
1073// c-basic-offset: 4
1074// c-file-offsets:((innamespace . 0)(inline-open . 0))
1075// indent-tabs-mode: nil
1076// End:
1077
1078// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
1079
Note: See TracBrowser for help on using the repository browser.